1 /* SPDX-License-Identifier: GPL-2.0 */
2 /* copy_user.S: Sparc optimized copy_from_user and copy_to_user code.
4 * Copyright(C) 1995 Linus Torvalds
5 * Copyright(C) 1996 David S. Miller
6 * Copyright(C) 1996 Eddie C. Dost
7 * Copyright(C) 1996,1998 Jakub Jelinek
10 * e-mail between David and Eddie.
12 * Returns 0 if successful, otherwise count of bytes not copied yet
15 #include <linux/export.h>
16 #include <asm/ptrace.h>
17 #include <asm/asmmacro.h>
19 #include <asm/thread_info.h>
21 /* Work around cpp -rob */
23 #define EXECINSTR #execinstr
25 #define EX_ENTRY(l1, l2) \
26 .section __ex_table,ALLOC; \
33 .section .fixup,ALLOC,EXECINSTR; \
39 #define EX2(x,y,c,d,e,a,b) \
41 .section .fixup,ALLOC,EXECINSTR; \
52 #define LD(insn, src, offset, reg, label) \
53 98: insn [%src + (offset)], %reg; \
54 .section .fixup,ALLOC,EXECINSTR; \
59 #define ST(insn, dst, offset, reg, label) \
60 98: insn %reg, [%dst + (offset)]; \
61 .section .fixup,ALLOC,EXECINSTR; \
66 /* Both these macros have to start with exactly the same insn */
67 /* left: g7 + (g1 % 128) - offset */
68 #define MOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \
69 LD(ldd, src, offset + 0x00, t0, bigchunk_fault) \
70 LD(ldd, src, offset + 0x08, t2, bigchunk_fault) \
71 LD(ldd, src, offset + 0x10, t4, bigchunk_fault) \
72 LD(ldd, src, offset + 0x18, t6, bigchunk_fault) \
73 ST(st, dst, offset + 0x00, t0, bigchunk_fault) \
74 ST(st, dst, offset + 0x04, t1, bigchunk_fault) \
75 ST(st, dst, offset + 0x08, t2, bigchunk_fault) \
76 ST(st, dst, offset + 0x0c, t3, bigchunk_fault) \
77 ST(st, dst, offset + 0x10, t4, bigchunk_fault) \
78 ST(st, dst, offset + 0x14, t5, bigchunk_fault) \
79 ST(st, dst, offset + 0x18, t6, bigchunk_fault) \
80 ST(st, dst, offset + 0x1c, t7, bigchunk_fault)
82 /* left: g7 + (g1 % 128) - offset */
83 #define MOVE_BIGALIGNCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \
84 LD(ldd, src, offset + 0x00, t0, bigchunk_fault) \
85 LD(ldd, src, offset + 0x08, t2, bigchunk_fault) \
86 LD(ldd, src, offset + 0x10, t4, bigchunk_fault) \
87 LD(ldd, src, offset + 0x18, t6, bigchunk_fault) \
88 ST(std, dst, offset + 0x00, t0, bigchunk_fault) \
89 ST(std, dst, offset + 0x08, t2, bigchunk_fault) \
90 ST(std, dst, offset + 0x10, t4, bigchunk_fault) \
91 ST(std, dst, offset + 0x18, t6, bigchunk_fault)
93 .section .fixup,#alloc,#execinstr
100 /* left: offset + 16 + (g1 % 16) */
101 #define MOVE_LASTCHUNK(src, dst, offset, t0, t1, t2, t3) \
102 LD(ldd, src, -(offset + 0x10), t0, lastchunk_fault) \
103 LD(ldd, src, -(offset + 0x08), t2, lastchunk_fault) \
104 ST(st, dst, -(offset + 0x10), t0, lastchunk_fault) \
105 ST(st, dst, -(offset + 0x0c), t1, lastchunk_fault) \
106 ST(st, dst, -(offset + 0x08), t2, lastchunk_fault) \
107 ST(st, dst, -(offset + 0x04), t3, lastchunk_fault)
109 .section .fixup,#alloc,#execinstr
115 /* left: o3 + (o2 % 16) - offset */
116 #define MOVE_HALFCHUNK(src, dst, offset, t0, t1, t2, t3) \
117 LD(lduh, src, offset + 0x00, t0, halfchunk_fault) \
118 LD(lduh, src, offset + 0x02, t1, halfchunk_fault) \
119 LD(lduh, src, offset + 0x04, t2, halfchunk_fault) \
120 LD(lduh, src, offset + 0x06, t3, halfchunk_fault) \
121 ST(sth, dst, offset + 0x00, t0, halfchunk_fault) \
122 ST(sth, dst, offset + 0x02, t1, halfchunk_fault) \
123 ST(sth, dst, offset + 0x04, t2, halfchunk_fault) \
124 ST(sth, dst, offset + 0x06, t3, halfchunk_fault)
126 /* left: o3 + (o2 % 16) + offset + 2 */
127 #define MOVE_SHORTCHUNK(src, dst, offset, t0, t1) \
128 LD(ldub, src, -(offset + 0x02), t0, halfchunk_fault) \
129 LD(ldub, src, -(offset + 0x01), t1, halfchunk_fault) \
130 ST(stb, dst, -(offset + 0x02), t0, halfchunk_fault) \
131 ST(stb, dst, -(offset + 0x01), t1, halfchunk_fault)
133 .section .fixup,#alloc,#execinstr
140 /* left: offset + 2 + (o2 % 2) */
141 #define MOVE_LAST_SHORTCHUNK(src, dst, offset, t0, t1) \
142 LD(ldub, src, -(offset + 0x02), t0, last_shortchunk_fault) \
143 LD(ldub, src, -(offset + 0x01), t1, last_shortchunk_fault) \
144 ST(stb, dst, -(offset + 0x02), t0, last_shortchunk_fault) \
145 ST(stb, dst, -(offset + 0x01), t1, last_shortchunk_fault)
147 .section .fixup,#alloc,#execinstr
148 last_shortchunk_fault:
156 .globl __copy_user_begin
160 EXPORT_SYMBOL(__copy_user)
166 EXO2(ldub [%o1], %g2)
173 EXO2(lduh [%o1], %g2)
180 EXO2(lduh [%o1], %g2)
187 __copy_user: /* %o0=dst %o1=src %o2=len */
195 bleu short_aligned_end
211 andcc %g1, 0xffffff80, %g7
217 MOVE_BIGCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5)
218 MOVE_BIGCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5)
219 MOVE_BIGCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
220 MOVE_BIGCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
227 be copy_user_table_end
230 sethi %hi(copy_user_table_end), %o5
235 jmpl %o5 + %lo(copy_user_table_end), %g0
238 MOVE_LASTCHUNK(o1, o0, 0x60, g2, g3, g4, g5)
239 MOVE_LASTCHUNK(o1, o0, 0x50, g2, g3, g4, g5)
240 MOVE_LASTCHUNK(o1, o0, 0x40, g2, g3, g4, g5)
241 MOVE_LASTCHUNK(o1, o0, 0x30, g2, g3, g4, g5)
242 MOVE_LASTCHUNK(o1, o0, 0x20, g2, g3, g4, g5)
243 MOVE_LASTCHUNK(o1, o0, 0x10, g2, g3, g4, g5)
244 MOVE_LASTCHUNK(o1, o0, 0x00, g2, g3, g4, g5)
249 EX(ldd [%o1], %g2, and %g1, 0xf)
252 EX(st %g2, [%o0 - 0x08], and %g1, 0xf)
253 EX2(st %g3, [%o0 - 0x04], and %g1, 0xf, %g1, sub %g1, 4)
258 EX(ld [%o1], %g2, and %g1, 7)
260 EX(st %g2, [%o0], and %g1, 7)
266 EX(lduh [%o1], %g2, and %g1, 3)
268 EX(sth %g2, [%o0], and %g1, 3)
274 EX(ldub [%o1], %g2, add %g0, 1)
275 EX(stb %g2, [%o0], add %g0, 1)
281 MOVE_BIGALIGNCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5)
282 MOVE_BIGALIGNCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5)
283 MOVE_BIGALIGNCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
284 MOVE_BIGALIGNCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
291 be copy_user_table_end
294 sethi %hi(copy_user_table_end), %o5
299 jmpl %o5 + %lo(copy_user_table_end), %g0
307 and %o2, 0xfffffff0, %o3
313 EXO2(ldub [%o1], %g2)
317 andcc %o2, 0xfffffff0, %o3
321 MOVE_HALFCHUNK(o1, o0, 0x00, g2, g3, g4, g5)
322 MOVE_HALFCHUNK(o1, o0, 0x08, g2, g3, g4, g5)
331 MOVE_SHORTCHUNK(o1, o0, -0x02, g2, g3)
332 MOVE_SHORTCHUNK(o1, o0, -0x04, g2, g3)
333 MOVE_SHORTCHUNK(o1, o0, -0x06, g2, g3)
334 MOVE_SHORTCHUNK(o1, o0, -0x08, g2, g3)
335 MOVE_SHORTCHUNK(o1, o0, -0x0a, g2, g3)
336 MOVE_SHORTCHUNK(o1, o0, -0x0c, g2, g3)
337 MOVE_SHORTCHUNK(o1, o0, -0x0e, g2, g3)
338 MOVE_SHORTCHUNK(o1, o0, -0x10, g2, g3)
347 sethi %hi(short_table_end), %o5
352 jmpl %o5 + %lo(short_table_end), %g0
354 MOVE_LAST_SHORTCHUNK(o1, o0, 0x0c, g2, g3)
355 MOVE_LAST_SHORTCHUNK(o1, o0, 0x0a, g2, g3)
356 MOVE_LAST_SHORTCHUNK(o1, o0, 0x08, g2, g3)
357 MOVE_LAST_SHORTCHUNK(o1, o0, 0x06, g2, g3)
358 MOVE_LAST_SHORTCHUNK(o1, o0, 0x04, g2, g3)
359 MOVE_LAST_SHORTCHUNK(o1, o0, 0x02, g2, g3)
360 MOVE_LAST_SHORTCHUNK(o1, o0, 0x00, g2, g3)
364 EX(ldub [%o1], %g2, add %g0, 1)
365 EX(stb %g2, [%o0], add %g0, 1)
377 EXO2(ld [%o1 + 0x00], %g2)
378 EXO2(ld [%o1 + 0x04], %g3)
380 EXO2(st %g2, [%o0 + 0x00])
381 EX(st %g3, [%o0 + 0x04], sub %o2, 4)
387 .section .fixup,#alloc,#execinstr
393 .globl __copy_user_end