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