1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/param.h> 29 #include <sys/errno.h> 30 #include <sys/asm_linkage.h> 31 #include <sys/vtrace.h> 32 #include <sys/machthread.h> 33 #include <sys/clock.h> 34 #include <sys/asi.h> 35 #include <sys/fsr.h> 36 #include <sys/privregs.h> 37 38 #if !defined(lint) 39 #include "assym.h" 40 #endif /* lint */ 41 42 /* 43 * Error barrier: 44 * We use membar sync to establish an error barrier for 45 * deferred errors. Membar syncs are added before any update 46 * to t_lofault to ensure that deferred errors from earlier 47 * accesses will not be reported after the membar. This error 48 * isolation is important when we try to recover from async 49 * errors which tries to distinguish kernel accesses to user 50 * data. 51 */ 52 53 /* 54 * Copy a null terminated string from one point to another in 55 * the kernel address space. 56 * NOTE - don't use %o5 in this routine as copy{in,out}str uses it. 57 * 58 * copystr(from, to, maxlength, lencopied) 59 * caddr_t from, to; 60 * u_int maxlength, *lencopied; 61 */ 62 63 #if defined(lint) 64 65 /* ARGSUSED */ 66 int 67 copystr(const char *from, char *to, size_t maxlength, size_t *lencopied) 68 { return(0); } 69 70 #else /* lint */ 71 72 ENTRY(copystr) 73 orcc %o2, %g0, %o4 ! save original count 74 bg,a %ncc, 1f 75 sub %o0, %o1, %o0 ! o0 gets the difference of src and dst 76 77 ! 78 ! maxlength <= 0 79 ! 80 bz %ncc, .cs_out ! maxlength = 0 81 mov ENAMETOOLONG, %o0 82 83 b 2f ! maxlength < 0 84 mov EFAULT, %o0 ! return failure 85 86 ! 87 ! Do a byte by byte loop. 88 ! We do this instead of a word by word copy because most strings 89 ! are small and this takes a small number of cache lines. 90 ! 91 0: 92 stb %g1, [%o1] ! store byte 93 tst %g1 94 bnz,pt %icc, 1f 95 add %o1, 1, %o1 ! incr dst addr 96 97 ba,pt %ncc, .cs_out ! last byte in string 98 mov 0, %o0 ! ret code = 0 99 1: 100 subcc %o2, 1, %o2 ! test count 101 bgeu,a %ncc, 0b 102 ldub [%o0 + %o1], %g1 ! delay slot, get source byte 103 104 mov 0, %o2 ! max number of bytes moved 105 mov ENAMETOOLONG, %o0 ! ret code = ENAMETOOLONG 106 .cs_out: 107 tst %o3 108 bz %ncc, 2f 109 sub %o4, %o2, %o4 ! compute length and store it 110 stn %o4, [%o3] 111 2: 112 retl 113 nop 114 SET_SIZE(copystr) 115 116 #endif /* lint */ 117 118 119 /* 120 * Copy a null terminated string from the user address space into 121 * the kernel address space. 122 */ 123 #if defined(lint) 124 125 /* ARGSUSED */ 126 int 127 copyinstr(const char *uaddr, char *kaddr, size_t maxlength, 128 size_t *lencopied) 129 { return (0); } 130 131 #else /* lint */ 132 133 ENTRY(copyinstr) 134 sethi %hi(.copyinstr_err), %o4 135 ldn [THREAD_REG + T_LOFAULT], %o5 ! catch faults 136 or %o4, %lo(.copyinstr_err), %o4 137 membar #Sync ! sync error barrier 138 stn %o4, [THREAD_REG + T_LOFAULT] 139 140 brz,a,pn %o2, .copyinstr_out 141 mov ENAMETOOLONG, %o0 142 143 mov %o2, %g3 ! g3 is the current count 144 mov %o1, %g4 ! g4 is the dest addr 145 146 b 1f 147 sub %o0, %o1, %g2 ! g2 gets the difference of src and dst 148 149 ! 150 ! Do a byte by byte loop. 151 ! We do this instead of a word by word copy because most strings 152 ! are small and this takes a small number of cache lines. 153 ! 154 0: 155 stb %g1, [%g4] ! store byte 156 tst %g1 157 bnz,pt %icc, 1f 158 add %g4, 1, %g4 ! incr dst addr 159 160 ba,pt %ncc, .copyinstr_out ! last byte in string 161 mov 0, %o0 ! ret code = 0 162 1: 163 subcc %g3, 1, %g3 ! test count 164 bgeu,a %ncc, 0b 165 lduba [%g2+%g4]ASI_USER, %g1 ! delay slot, get source byte 166 167 mov 0, %g3 ! max number of bytes moved 168 ba,pt %ncc, .copyinstr_out 169 mov ENAMETOOLONG, %o0 ! ret code = ENAMETOOLONG 170 171 /* 172 * Fault while trying to move from or to user space. 173 * Set and return error code. 174 */ 175 .copyinstr_err: 176 membar #Sync ! sync error barrier 177 stn %o5, [THREAD_REG + T_LOFAULT] 178 ldn [THREAD_REG + T_COPYOPS], %o4 179 brz %o4, 1f 180 nop 181 ldn [%o4 + CP_COPYINSTR], %g1 182 jmp %g1 183 nop 184 1: 185 retl 186 mov EFAULT, %o0 187 .copyinstr_out: 188 tst %o3 ! want length? 189 bz %ncc, 2f 190 sub %o2, %g3, %o2 ! compute length and store it 191 stn %o2, [%o3] 192 2: 193 membar #Sync ! sync error barrier 194 retl 195 stn %o5, [THREAD_REG + T_LOFAULT] ! stop catching faults 196 SET_SIZE(copyinstr) 197 #endif 198 199 #if defined(lint) 200 201 /* ARGSUSED */ 202 int 203 copyinstr_noerr(const char *uaddr, char *kaddr, size_t maxlength, 204 size_t *lencopied) 205 { return (0); } 206 207 #else /* lint */ 208 209 ENTRY(copyinstr_noerr) 210 mov %o2, %o4 ! save original count 211 212 ! maxlength is unsigned so the only error is if it's 0 213 brz,a,pn %o2, .copyinstr_noerr_out 214 mov ENAMETOOLONG, %o0 215 216 b 1f 217 sub %o0, %o1, %o0 ! o0 gets the difference of src and dst 218 219 ! 220 ! Do a byte by byte loop. 221 ! We do this instead of a word by word copy because most strings 222 ! are small and this takes a small number of cache lines. 223 ! 224 0: 225 stb %g1, [%o1] ! store byte 226 tst %g1 ! null byte? 227 bnz 1f 228 add %o1, 1, %o1 ! incr dst addr 229 230 ba,pt %ncc, .copyinstr_noerr_out ! last byte in string 231 mov 0, %o0 ! ret code = 0 232 1: 233 subcc %o2, 1, %o2 ! test count 234 bgeu,a %ncc, 0b 235 lduba [%o0 + %o1]ASI_USER, %g1 ! delay slot, get source byte 236 237 mov 0, %o2 ! max number of bytes moved 238 b .copyinstr_noerr_out 239 mov ENAMETOOLONG, %o0 ! ret code = ENAMETOOLONG 240 .copyinstr_noerr_out: 241 tst %o3 ! want length? 242 bz %ncc, 2f 243 sub %o4, %o2, %o4 244 stn %o4, [%o3] 245 2: 246 retl 247 nop 248 SET_SIZE(copyinstr_noerr) 249 250 #endif /* lint */ 251 252 /* 253 * Copy a null terminated string from the kernel 254 * address space to the user address space. 255 */ 256 257 #if defined(lint) 258 259 /* ARGSUSED */ 260 int 261 copyoutstr(const char *kaddr, char *uaddr, size_t maxlength, 262 size_t *lencopied) 263 { return (0); } 264 265 #else /* lint */ 266 267 ENTRY(copyoutstr) 268 sethi %hi(.copyoutstr_err), %o5 269 ldn [THREAD_REG + T_LOFAULT], %o4 ! catch faults 270 or %o5, %lo(.copyoutstr_err), %o5 271 membar #Sync ! sync error barrier 272 stn %o5, [THREAD_REG + T_LOFAULT] 273 mov %o4, %o5 274 275 brz,a,pn %o2, .copyoutstr_out 276 mov ENAMETOOLONG, %o0 277 278 mov %o2, %g3 ! g3 is the current count 279 mov %o1, %g4 ! g4 is the dest addr 280 281 b 1f 282 sub %o0, %o1, %g2 ! g2 gets the difference of src and dst 283 284 ! 285 ! Do a byte by byte loop. 286 ! We do this instead of a word by word copy because most strings 287 ! are small and this takes a small number of cache lines. 288 ! 289 0: 290 stba %g1, [%g4]ASI_USER ! store byte 291 tst %g1 292 bnz,pt %icc, 1f 293 add %g4, 1, %g4 ! incr dst addr 294 295 ba,pt %ncc, .copyoutstr_out ! last byte in string 296 mov 0, %o0 ! ret code = 0 297 1: 298 subcc %g3, 1, %g3 ! test count 299 bgeu,a %ncc, 0b 300 ldub [%g2 + %g4], %g1 ! delay slot, get source byte 301 302 mov 0, %g3 ! max number of bytes moved 303 ba,pt %ncc, .copyoutstr_out 304 mov ENAMETOOLONG, %o0 ! ret code = ENAMETOOLONG 305 306 /* 307 * Fault while trying to move from or to user space. 308 * Set and return error code. 309 */ 310 .copyoutstr_err: 311 membar #Sync ! sync error barrier 312 stn %o5, [THREAD_REG + T_LOFAULT] 313 ldn [THREAD_REG + T_COPYOPS], %o4 314 brz %o4, 1f 315 nop 316 ldn [%o4 + CP_COPYOUTSTR], %g1 317 jmp %g1 318 nop 319 1: 320 retl 321 mov EFAULT, %o0 322 .copyoutstr_out: 323 tst %o3 ! want length? 324 bz %ncc, 2f 325 sub %o2, %g3, %o2 ! compute length and store it 326 stn %o2, [%o3] 327 2: 328 membar #Sync ! sync error barrier 329 retl 330 stn %o5, [THREAD_REG + T_LOFAULT] ! stop catching faults 331 SET_SIZE(copyoutstr) 332 333 #endif /* lint */ 334 335 #if defined(lint) 336 337 /* ARGSUSED */ 338 int 339 copyoutstr_noerr(const char *kaddr, char *uaddr, size_t maxlength, 340 size_t *lencopied) 341 { return (0); } 342 343 #else /* lint */ 344 345 ENTRY(copyoutstr_noerr) 346 mov %o2, %o4 ! save original count 347 348 brz,a,pn %o2, .copyoutstr_noerr_out 349 mov ENAMETOOLONG, %o0 350 351 b 1f 352 sub %o0, %o1, %o0 ! o0 gets the difference of src and dst 353 354 ! 355 ! Do a byte by byte loop. 356 ! We do this instead of a word by word copy because most strings 357 ! are small and this takes a small number of cache lines. 358 ! 359 0: 360 stba %g1, [%o1]ASI_USER ! store byte 361 tst %g1 ! null byte? 362 bnz 1f 363 add %o1, 1, %o1 ! incr dst addr 364 365 b .copyoutstr_noerr_out ! last byte in string 366 mov 0, %o0 ! ret code = 0 367 1: 368 subcc %o2, 1, %o2 ! test count 369 bgeu,a %ncc, 0b 370 ldub [%o0+%o1], %g1 ! delay slot, get source byte 371 372 mov 0, %o2 ! max number of bytes moved 373 b .copyoutstr_noerr_out 374 mov ENAMETOOLONG, %o0 ! ret code = ENAMETOOLONG 375 .copyoutstr_noerr_out: 376 tst %o3 ! want length? 377 bz %ncc, 2f 378 sub %o4, %o2, %o4 379 stn %o4, [%o3] 380 2: 381 retl 382 nop 383 SET_SIZE(copyoutstr_noerr) 384 385 #endif /* lint */ 386 387 388 /* 389 * Copy a block of storage. If the source and target regions overlap, 390 * one or both of the regions will be silently corrupted. 391 * No fault handler installed (to be called under on_fault()) 392 */ 393 394 #if defined(lint) 395 396 /* ARGSUSED */ 397 void 398 ucopy(const void *ufrom, void *uto, size_t ulength) 399 {} 400 401 #else /* lint */ 402 403 ENTRY(ucopy) 404 save %sp, -SA(MINFRAME), %sp ! get another window 405 406 subcc %g0, %i2, %i3 407 add %i0, %i2, %i0 408 bz,pn %ncc, 5f 409 add %i1, %i2, %i1 410 lduba [%i0 + %i3]ASI_USER, %i4 411 4: stba %i4, [%i1 + %i3]ASI_USER 412 inccc %i3 413 bcc,a,pt %ncc, 4b 414 lduba [%i0 + %i3]ASI_USER, %i4 415 5: 416 ret 417 restore %g0, 0, %o0 ! return (0) 418 419 SET_SIZE(ucopy) 420 #endif /* lint */ 421 422 /* 423 * Copy a user-land string. If the source and target regions overlap, 424 * one or both of the regions will be silently corrupted. 425 * No fault handler installed (to be called under on_fault()) 426 */ 427 428 #if defined(lint) 429 430 /* ARGSUSED */ 431 void 432 ucopystr(const char *ufrom, char *uto, size_t umaxlength, size_t *ulencopied) 433 {} 434 435 #else /* lint */ 436 437 ENTRY(ucopystr) 438 save %sp, -SA(MINFRAME), %sp ! get another window 439 440 brz %i2, 5f 441 clr %i5 442 443 lduba [%i0 + %i5]ASI_USER, %i4 444 4: stba %i4, [%i1 + %i5]ASI_USER 445 brz,pn %i4, 5f 446 inc %i5 447 deccc %i2 448 bnz,a,pt %ncc, 4b 449 lduba [%i0 + %i5]ASI_USER, %i4 450 5: 451 brnz,a,pt %i3, 6f 452 stn %i5, [%i3] 453 6: 454 ret 455 restore %g0, 0, %o0 ! return (0) 456 457 SET_SIZE(ucopystr) 458 #endif /* lint */