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