1/* copy_in_user.S: Copy from userspace to userspace. 2 * 3 * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com) 4 */ 5 6#include <asm/asi.h> 7 8#define XCC xcc 9 10#define EX(x,y) \ 1198: x,y; \ 12 .section .fixup; \ 13 .align 4; \ 1499: retl; \ 15 mov 1, %o0; \ 16 .section __ex_table,"a";\ 17 .align 4; \ 18 .word 98b, 99b; \ 19 .text; \ 20 .align 4; 21 22 .register %g2,#scratch 23 .register %g3,#scratch 24 25 .text 26 .align 32 27 28 /* Don't try to get too fancy here, just nice and 29 * simple. This is predominantly used for well aligned 30 * small copies in the compat layer. It is also used 31 * to copy register windows around during thread cloning. 32 */ 33 34 .globl ___copy_in_user 35 .type ___copy_in_user,#function 36___copy_in_user: /* %o0=dst, %o1=src, %o2=len */ 37 /* Writing to %asi is _expensive_ so we hardcode it. 38 * Reading %asi to check for KERNEL_DS is comparatively 39 * cheap. 40 */ 41 rd %asi, %g1 42 cmp %g1, ASI_AIUS 43 bne,pn %icc, memcpy_user_stub 44 nop 45 46 cmp %o2, 0 47 be,pn %XCC, 85f 48 or %o0, %o1, %o3 49 cmp %o2, 16 50 bleu,a,pn %XCC, 80f 51 or %o3, %o2, %o3 52 53 /* 16 < len <= 64 */ 54 andcc %o3, 0x7, %g0 55 bne,pn %XCC, 90f 56 sub %o0, %o1, %o3 57 58 andn %o2, 0x7, %o4 59 and %o2, 0x7, %o2 601: subcc %o4, 0x8, %o4 61 EX(ldxa [%o1] %asi, %o5) 62 EX(stxa %o5, [%o1 + %o3] ASI_AIUS) 63 bgu,pt %XCC, 1b 64 add %o1, 0x8, %o1 65 andcc %o2, 0x4, %g0 66 be,pt %XCC, 1f 67 nop 68 sub %o2, 0x4, %o2 69 EX(lduwa [%o1] %asi, %o5) 70 EX(stwa %o5, [%o1 + %o3] ASI_AIUS) 71 add %o1, 0x4, %o1 721: cmp %o2, 0 73 be,pt %XCC, 85f 74 nop 75 ba,pt %xcc, 90f 76 nop 77 7880: /* 0 < len <= 16 */ 79 andcc %o3, 0x3, %g0 80 bne,pn %XCC, 90f 81 sub %o0, %o1, %o3 82 8382: 84 subcc %o2, 4, %o2 85 EX(lduwa [%o1] %asi, %g1) 86 EX(stwa %g1, [%o1 + %o3] ASI_AIUS) 87 bgu,pt %XCC, 82b 88 add %o1, 4, %o1 89 9085: retl 91 clr %o0 92 93 .align 32 9490: 95 subcc %o2, 1, %o2 96 EX(lduba [%o1] %asi, %g1) 97 EX(stba %g1, [%o1 + %o3] ASI_AIUS) 98 bgu,pt %XCC, 90b 99 add %o1, 1, %o1 100 retl 101 clr %o0 102 103 .size ___copy_in_user, .-___copy_in_user 104 105 /* Act like copy_{to,in}_user(), ie. return zero instead 106 * of original destination pointer. This is invoked when 107 * copy_{to,in}_user() finds that %asi is kernel space. 108 */ 109 .globl memcpy_user_stub 110 .type memcpy_user_stub,#function 111memcpy_user_stub: 112 save %sp, -192, %sp 113 mov %i0, %o0 114 mov %i1, %o1 115 call memcpy 116 mov %i2, %o2 117 ret 118 restore %g0, %g0, %o0 119 .size memcpy_user_stub, .-memcpy_user_stub 120