Commit | Line | Data |
---|---|---|
1da177e4 LT |
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) \ | |
11 | 98: x,y; \ | |
12 | .section .fixup; \ | |
13 | .align 4; \ | |
14 | 99: retl; \ | |
15 | mov 1, %o0; \ | |
4d000d5b | 16 | .section __ex_table,"a";\ |
1da177e4 LT |
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 | |
60 | 1: 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 | |
72 | 1: cmp %o2, 0 | |
73 | be,pt %XCC, 85f | |
74 | nop | |
75 | ba,pt %xcc, 90f | |
76 | nop | |
77 | ||
78 | 80: /* 0 < len <= 16 */ | |
79 | andcc %o3, 0x3, %g0 | |
80 | bne,pn %XCC, 90f | |
81 | sub %o0, %o1, %o3 | |
82 | ||
83 | 82: | |
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 | ||
90 | 85: retl | |
91 | clr %o0 | |
92 | ||
93 | .align 32 | |
94 | 90: | |
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 | |
111 | memcpy_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 |