Print this page
de-linting of .s files


   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:


  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.


 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


 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


 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 */


   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 #include <sys/param.h>
  27 #include <sys/errno.h>
  28 #include <sys/asm_linkage.h>
  29 #include <sys/vtrace.h>
  30 #include <sys/machthread.h>
  31 #include <sys/clock.h>
  32 #include <sys/asi.h>
  33 #include <sys/fsr.h>
  34 #include <sys/privregs.h>
  35 

  36 #include "assym.h"

  37 
  38 /*
  39  * Error barrier:
  40  * We use membar sync to establish an error barrier for
  41  * deferred errors. Membar syncs are added before any update
  42  * to t_lofault to ensure that deferred errors from earlier
  43  * accesses will not be reported after the membar. This error
  44  * isolation is important when we try to recover from async
  45  * errors which tries to distinguish kernel accesses to user
  46  * data.
  47  */
  48 
  49 /*
  50  * Copy a null terminated string from one point to another in
  51  * the kernel address space.
  52  * NOTE - don't use %o5 in this routine as copy{in,out}str uses it.
  53  *
  54  * copystr(from, to, maxlength, lencopied)
  55  *      caddr_t from, to;
  56  *      u_int maxlength, *lencopied;
  57  */
  58 









  59         ENTRY(copystr)
  60         orcc    %o2, %g0, %o4           ! save original count
  61         bg,a    %ncc, 1f
  62           sub   %o0, %o1, %o0           ! o0 gets the difference of src and dst
  63 
  64         !
  65         ! maxlength <= 0
  66         !
  67         bz      %ncc, .cs_out           ! maxlength = 0
  68         mov     ENAMETOOLONG, %o0
  69 
  70         b       2f                      ! maxlength < 0
  71         mov     EFAULT, %o0             ! return failure
  72 
  73         !
  74         ! Do a byte by byte loop.
  75         ! We do this instead of a word by word copy because most strings
  76         ! are small and this takes a small number of cache lines.
  77         !
  78 0:


  83 
  84         ba,pt   %ncc, .cs_out           ! last byte in string
  85         mov     0, %o0                  ! ret code = 0
  86 1:
  87         subcc   %o2, 1, %o2             ! test count
  88         bgeu,a  %ncc, 0b
  89         ldub    [%o0 + %o1], %g1        ! delay slot, get source byte
  90 
  91         mov     0, %o2                  ! max number of bytes moved
  92         mov     ENAMETOOLONG, %o0       ! ret code = ENAMETOOLONG
  93 .cs_out:
  94         tst     %o3
  95         bz      %ncc, 2f
  96         sub     %o4, %o2, %o4           ! compute length and store it
  97         stn     %o4, [%o3]
  98 2:
  99         retl
 100         nop
 101         SET_SIZE(copystr)
 102 

 103 

 104 /*
 105  * Copy a null terminated string from the user address space into
 106  * the kernel address space.
 107  */

 108 








 109         ENTRY(copyinstr)
 110         sethi   %hi(.copyinstr_err), %o4
 111         ldn     [THREAD_REG + T_LOFAULT], %o5   ! catch faults
 112         or      %o4, %lo(.copyinstr_err), %o4
 113         membar  #Sync                           ! sync error barrier
 114         stn     %o4, [THREAD_REG + T_LOFAULT]
 115 
 116         brz,a,pn %o2, .copyinstr_out
 117         mov     ENAMETOOLONG, %o0
 118 
 119         mov     %o2, %g3                ! g3 is the current count
 120         mov     %o1, %g4                ! g4 is the dest addr
 121 
 122         b       1f
 123         sub     %o0, %o1, %g2           ! g2 gets the difference of src and dst
 124 
 125         !
 126         ! Do a byte by byte loop.
 127         ! We do this instead of a word by word copy because most strings
 128         ! are small and this takes a small number of cache lines.


 153         stn     %o5, [THREAD_REG + T_LOFAULT]
 154         ldn     [THREAD_REG + T_COPYOPS], %o4
 155         brz     %o4, 1f
 156         nop
 157         ldn     [%o4 + CP_COPYINSTR], %g1
 158         jmp     %g1
 159         nop
 160 1:
 161         retl
 162         mov     EFAULT, %o0
 163 .copyinstr_out:
 164         tst     %o3                     ! want length?
 165         bz      %ncc, 2f
 166         sub     %o2, %g3, %o2           ! compute length and store it
 167         stn     %o2, [%o3]
 168 2:
 169         membar  #Sync                   ! sync error barrier
 170         retl
 171         stn     %o5, [THREAD_REG + T_LOFAULT]   ! stop catching faults
 172         SET_SIZE(copyinstr)

 173 










 174         ENTRY(copyinstr_noerr)
 175         mov     %o2, %o4                ! save original count
 176 
 177         ! maxlength is unsigned so the only error is if it's 0
 178         brz,a,pn %o2, .copyinstr_noerr_out
 179         mov     ENAMETOOLONG, %o0
 180 
 181         b       1f
 182         sub     %o0, %o1, %o0           ! o0 gets the difference of src and dst
 183 
 184         !
 185         ! Do a byte by byte loop.
 186         ! We do this instead of a word by word copy because most strings
 187         ! are small and this takes a small number of cache lines.
 188         !
 189 0:
 190         stb     %g1, [%o1]              ! store byte
 191         tst     %g1                     ! null byte?
 192         bnz     1f
 193         add     %o1, 1, %o1             ! incr dst addr


 195         ba,pt   %ncc, .copyinstr_noerr_out      ! last byte in string
 196         mov     0, %o0                  ! ret code = 0
 197 1:
 198         subcc   %o2, 1, %o2             ! test count
 199         bgeu,a  %ncc, 0b
 200         lduba   [%o0 + %o1]ASI_USER, %g1        ! delay slot, get source byte
 201 
 202         mov     0, %o2                  ! max number of bytes moved
 203         b       .copyinstr_noerr_out
 204           mov   ENAMETOOLONG, %o0       ! ret code = ENAMETOOLONG
 205 .copyinstr_noerr_out:
 206         tst     %o3                     ! want length?
 207         bz      %ncc, 2f
 208         sub     %o4, %o2, %o4
 209         stn     %o4, [%o3]
 210 2:
 211         retl
 212         nop
 213         SET_SIZE(copyinstr_noerr)
 214 


 215 /*
 216  * Copy a null terminated string from the kernel
 217  * address space to the user address space.
 218  */
 219 










 220         ENTRY(copyoutstr)
 221         sethi   %hi(.copyoutstr_err), %o5
 222         ldn     [THREAD_REG + T_LOFAULT], %o4   ! catch faults
 223         or      %o5, %lo(.copyoutstr_err), %o5
 224         membar  #Sync                           ! sync error barrier
 225         stn     %o5, [THREAD_REG + T_LOFAULT]
 226         mov     %o4, %o5
 227 
 228         brz,a,pn %o2, .copyoutstr_out
 229         mov     ENAMETOOLONG, %o0
 230 
 231         mov     %o2, %g3                ! g3 is the current count
 232         mov     %o1, %g4                ! g4 is the dest addr
 233 
 234         b       1f
 235         sub     %o0, %o1, %g2           ! g2 gets the difference of src and dst
 236 
 237         !
 238         ! Do a byte by byte loop.
 239         ! We do this instead of a word by word copy because most strings


 266         ldn     [THREAD_REG + T_COPYOPS], %o4
 267         brz     %o4, 1f
 268         nop
 269         ldn     [%o4 + CP_COPYOUTSTR], %g1
 270         jmp     %g1
 271         nop
 272 1:
 273         retl
 274         mov     EFAULT, %o0
 275 .copyoutstr_out:
 276         tst     %o3                     ! want length?
 277         bz      %ncc, 2f
 278         sub     %o2, %g3, %o2           ! compute length and store it
 279         stn     %o2, [%o3]
 280 2:
 281         membar  #Sync                   ! sync error barrier
 282         retl
 283         stn     %o5, [THREAD_REG + T_LOFAULT]   ! stop catching faults
 284         SET_SIZE(copyoutstr)
 285 












 286         ENTRY(copyoutstr_noerr)
 287         mov     %o2, %o4                ! save original count
 288 
 289         brz,a,pn %o2, .copyoutstr_noerr_out
 290         mov     ENAMETOOLONG, %o0
 291 
 292         b       1f
 293         sub     %o0, %o1, %o0           ! o0 gets the difference of src and dst
 294 
 295         !
 296         ! Do a byte by byte loop.
 297         ! We do this instead of a word by word copy because most strings
 298         ! are small and this takes a small number of cache lines.
 299         !
 300 0:
 301         stba    %g1, [%o1]ASI_USER      ! store byte
 302         tst     %g1                     ! null byte?
 303         bnz     1f
 304         add     %o1, 1, %o1             ! incr dst addr
 305 
 306         b       .copyoutstr_noerr_out   ! last byte in string
 307         mov     0, %o0                  ! ret code = 0
 308 1:
 309         subcc   %o2, 1, %o2             ! test count
 310         bgeu,a  %ncc, 0b
 311         ldub    [%o0+%o1], %g1  ! delay slot, get source byte
 312 
 313         mov     0, %o2                  ! max number of bytes moved
 314         b       .copyoutstr_noerr_out
 315           mov   ENAMETOOLONG, %o0       ! ret code = ENAMETOOLONG
 316 .copyoutstr_noerr_out:
 317         tst     %o3                     ! want length?
 318         bz      %ncc, 2f
 319         sub     %o4, %o2, %o4
 320         stn     %o4, [%o3]
 321 2:
 322         retl
 323         nop
 324         SET_SIZE(copyoutstr_noerr)
 325 

 326 

 327 /*
 328  * Copy a block of storage.  If the source and target regions overlap,
 329  * one or both of the regions will be silently corrupted.
 330  * No fault handler installed (to be called under on_fault())
 331  */
 332 









 333         ENTRY(ucopy)
 334         save    %sp, -SA(MINFRAME), %sp ! get another window
 335 
 336         subcc   %g0, %i2, %i3
 337         add     %i0, %i2, %i0
 338         bz,pn   %ncc, 5f
 339         add     %i1, %i2, %i1
 340         lduba   [%i0 + %i3]ASI_USER, %i4
 341 4:      stba    %i4, [%i1 + %i3]ASI_USER
 342         inccc   %i3
 343         bcc,a,pt %ncc, 4b
 344         lduba  [%i0 + %i3]ASI_USER, %i4
 345 5:
 346         ret
 347         restore %g0, 0, %o0             ! return (0)
 348 
 349         SET_SIZE(ucopy)

 350 
 351 /*
 352  * Copy a user-land string.  If the source and target regions overlap,
 353  * one or both of the regions will be silently corrupted.
 354  * No fault handler installed (to be called under on_fault())
 355  */
 356 









 357         ENTRY(ucopystr)
 358         save    %sp, -SA(MINFRAME), %sp ! get another window
 359 
 360         brz     %i2, 5f
 361         clr     %i5
 362 
 363         lduba   [%i0 + %i5]ASI_USER, %i4
 364 4:      stba    %i4, [%i1 + %i5]ASI_USER
 365         brz,pn  %i4, 5f
 366         inc     %i5
 367         deccc   %i2
 368         bnz,a,pt %ncc, 4b
 369         lduba   [%i0 + %i5]ASI_USER, %i4
 370 5:
 371         brnz,a,pt %i3, 6f
 372         stn     %i5, [%i3]
 373 6:
 374         ret
 375         restore %g0, 0, %o0             ! return (0)
 376 
 377         SET_SIZE(ucopystr)