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 #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:
  79         stb     %g1, [%o1]              ! store byte
  80         tst     %g1
  81         bnz,pt  %icc, 1f
  82         add     %o1, 1, %o1             ! incr dst addr
  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.
 129         !
 130 0:
 131         stb     %g1, [%g4]              ! store byte
 132         tst     %g1
 133         bnz,pt  %icc, 1f
 134         add     %g4, 1, %g4             ! incr dst addr
 135 
 136         ba,pt   %ncc, .copyinstr_out    ! last byte in string
 137         mov     0, %o0                  ! ret code = 0
 138 1:
 139         subcc   %g3, 1, %g3             ! test count
 140         bgeu,a  %ncc, 0b
 141         lduba   [%g2+%g4]ASI_USER, %g1  ! delay slot, get source byte
 142 
 143         mov     0, %g3                  ! max number of bytes moved
 144         ba,pt   %ncc, .copyinstr_out
 145           mov   ENAMETOOLONG, %o0       ! ret code = ENAMETOOLONG
 146 
 147 /*
 148  * Fault while trying to move from or to user space.
 149  * Set and return error code.
 150  */
 151 .copyinstr_err:
 152         membar  #Sync                   ! sync error barrier
 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
 194 
 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
 240         ! are small and this takes a small number of cache lines.
 241         !
 242 0:
 243         stba    %g1, [%g4]ASI_USER      ! store byte
 244         tst     %g1
 245         bnz,pt  %icc, 1f
 246         add     %g4, 1, %g4             ! incr dst addr
 247 
 248         ba,pt   %ncc, .copyoutstr_out   ! last byte in string
 249         mov     0, %o0                  ! ret code = 0
 250 1:
 251         subcc   %g3, 1, %g3             ! test count
 252         bgeu,a  %ncc, 0b
 253         ldub    [%g2 + %g4], %g1        ! delay slot, get source byte
 254 
 255         mov     0, %g3                  ! max number of bytes moved
 256         ba,pt   %ncc, .copyoutstr_out
 257           mov   ENAMETOOLONG, %o0       ! ret code = ENAMETOOLONG
 258 
 259 /*
 260  * Fault while trying to move from or to user space.
 261  * Set and return error code.
 262  */
 263 .copyoutstr_err:
 264         membar  #Sync                   ! sync error barrier
 265         stn     %o5, [THREAD_REG + T_LOFAULT]
 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)