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