diff options
Diffstat (limited to 'arch/arm26/lib/uaccess-user.S')
-rw-r--r-- | arch/arm26/lib/uaccess-user.S | 718 |
1 files changed, 718 insertions, 0 deletions
diff --git a/arch/arm26/lib/uaccess-user.S b/arch/arm26/lib/uaccess-user.S new file mode 100644 index 000000000000..130b8f28610a --- /dev/null +++ b/arch/arm26/lib/uaccess-user.S | |||
@@ -0,0 +1,718 @@ | |||
1 | /* | ||
2 | * linux/arch/arm26/lib/uaccess-user.S | ||
3 | * | ||
4 | * Copyright (C) 1995, 1996,1997,1998 Russell King | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * Routines to block copy data to/from user memory | ||
11 | * These are highly optimised both for the 4k page size | ||
12 | * and for various alignments. | ||
13 | */ | ||
14 | #include <linux/linkage.h> | ||
15 | #include <asm/assembler.h> | ||
16 | #include <asm/errno.h> | ||
17 | #include <asm/page.h> | ||
18 | |||
19 | .text | ||
20 | |||
21 | //FIXME - surely this can be done in C not asm, removing the problem of keeping C and asm in sync? (this is a struct uaccess_t) | ||
22 | .globl uaccess_user | ||
23 | uaccess_user: | ||
24 | .word uaccess_user_put_byte | ||
25 | .word uaccess_user_get_byte | ||
26 | .word uaccess_user_put_half | ||
27 | .word uaccess_user_get_half | ||
28 | .word uaccess_user_put_word | ||
29 | .word uaccess_user_get_word | ||
30 | .word uaccess_user_put_dword | ||
31 | .word uaccess_user_copy_from_user | ||
32 | .word uaccess_user_copy_to_user | ||
33 | .word uaccess_user_clear_user | ||
34 | .word uaccess_user_strncpy_from_user | ||
35 | .word uaccess_user_strnlen_user | ||
36 | |||
37 | |||
38 | @ In : r0 = x, r1 = addr, r2 = error | ||
39 | @ Out: r2 = error | ||
40 | uaccess_user_put_byte: | ||
41 | stmfd sp!, {lr} | ||
42 | USER( strbt r0, [r1]) | ||
43 | ldmfd sp!, {pc}^ | ||
44 | |||
45 | @ In : r0 = x, r1 = addr, r2 = error | ||
46 | @ Out: r2 = error | ||
47 | uaccess_user_put_half: | ||
48 | stmfd sp!, {lr} | ||
49 | USER( strbt r0, [r1], #1) | ||
50 | mov r0, r0, lsr #8 | ||
51 | USER( strbt r0, [r1]) | ||
52 | ldmfd sp!, {pc}^ | ||
53 | |||
54 | @ In : r0 = x, r1 = addr, r2 = error | ||
55 | @ Out: r2 = error | ||
56 | uaccess_user_put_word: | ||
57 | stmfd sp!, {lr} | ||
58 | USER( strt r0, [r1]) | ||
59 | ldmfd sp!, {pc}^ | ||
60 | |||
61 | @ In : r0 = x, r1 = addr, r2 = error | ||
62 | @ Out: r2 = error | ||
63 | uaccess_user_put_dword: | ||
64 | stmfd sp!, {lr} | ||
65 | USER( strt r0, [r1], #4) | ||
66 | USER( strt r0, [r1], #0) | ||
67 | ldmfd sp!, {pc}^ | ||
68 | |||
69 | 9001: mov r2, #-EFAULT | ||
70 | ldmfd sp!, {pc}^ | ||
71 | |||
72 | |||
73 | @ In : r0 = addr, r1 = error | ||
74 | @ Out: r0 = x, r1 = error | ||
75 | uaccess_user_get_byte: | ||
76 | stmfd sp!, {lr} | ||
77 | USER( ldrbt r0, [r0]) | ||
78 | ldmfd sp!, {pc}^ | ||
79 | |||
80 | @ In : r0 = addr, r1 = error | ||
81 | @ Out: r0 = x, r1 = error | ||
82 | uaccess_user_get_half: | ||
83 | stmfd sp!, {lr} | ||
84 | USER( ldrt r0, [r0]) | ||
85 | mov r0, r0, lsl #16 | ||
86 | mov r0, r0, lsr #16 | ||
87 | ldmfd sp!, {pc}^ | ||
88 | |||
89 | @ In : r0 = addr, r1 = error | ||
90 | @ Out: r0 = x, r1 = error | ||
91 | uaccess_user_get_word: | ||
92 | stmfd sp!, {lr} | ||
93 | USER( ldrt r0, [r0]) | ||
94 | ldmfd sp!, {pc}^ | ||
95 | |||
96 | 9001: mov r1, #-EFAULT | ||
97 | ldmfd sp!, {pc}^ | ||
98 | |||
99 | /* Prototype: int uaccess_user_copy_to_user(void *to, const char *from, size_t n) | ||
100 | * Purpose : copy a block to user memory from kernel memory | ||
101 | * Params : to - user memory | ||
102 | * : from - kernel memory | ||
103 | * : n - number of bytes to copy | ||
104 | * Returns : Number of bytes NOT copied. | ||
105 | */ | ||
106 | |||
107 | .c2u_dest_not_aligned: | ||
108 | rsb ip, ip, #4 | ||
109 | cmp ip, #2 | ||
110 | ldrb r3, [r1], #1 | ||
111 | USER( strbt r3, [r0], #1) @ May fault | ||
112 | ldrgeb r3, [r1], #1 | ||
113 | USER( strgebt r3, [r0], #1) @ May fault | ||
114 | ldrgtb r3, [r1], #1 | ||
115 | USER( strgtbt r3, [r0], #1) @ May fault | ||
116 | sub r2, r2, ip | ||
117 | b .c2u_dest_aligned | ||
118 | |||
119 | ENTRY(uaccess_user_copy_to_user) | ||
120 | stmfd sp!, {r2, r4 - r7, lr} | ||
121 | cmp r2, #4 | ||
122 | blt .c2u_not_enough | ||
123 | ands ip, r0, #3 | ||
124 | bne .c2u_dest_not_aligned | ||
125 | .c2u_dest_aligned: | ||
126 | |||
127 | ands ip, r1, #3 | ||
128 | bne .c2u_src_not_aligned | ||
129 | /* | ||
130 | * Seeing as there has to be at least 8 bytes to copy, we can | ||
131 | * copy one word, and force a user-mode page fault... | ||
132 | */ | ||
133 | |||
134 | .c2u_0fupi: subs r2, r2, #4 | ||
135 | addmi ip, r2, #4 | ||
136 | bmi .c2u_0nowords | ||
137 | ldr r3, [r1], #4 | ||
138 | USER( strt r3, [r0], #4) @ May fault | ||
139 | mov ip, r0, lsl #32 - PAGE_SHIFT @ On each page, use a ld/st??t instruction | ||
140 | rsb ip, ip, #0 | ||
141 | movs ip, ip, lsr #32 - PAGE_SHIFT | ||
142 | beq .c2u_0fupi | ||
143 | /* | ||
144 | * ip = max no. of bytes to copy before needing another "strt" insn | ||
145 | */ | ||
146 | cmp r2, ip | ||
147 | movlt ip, r2 | ||
148 | sub r2, r2, ip | ||
149 | subs ip, ip, #32 | ||
150 | blt .c2u_0rem8lp | ||
151 | |||
152 | .c2u_0cpy8lp: ldmia r1!, {r3 - r6} | ||
153 | stmia r0!, {r3 - r6} @ Shouldnt fault | ||
154 | ldmia r1!, {r3 - r6} | ||
155 | stmia r0!, {r3 - r6} @ Shouldnt fault | ||
156 | subs ip, ip, #32 | ||
157 | bpl .c2u_0cpy8lp | ||
158 | .c2u_0rem8lp: cmn ip, #16 | ||
159 | ldmgeia r1!, {r3 - r6} | ||
160 | stmgeia r0!, {r3 - r6} @ Shouldnt fault | ||
161 | tst ip, #8 | ||
162 | ldmneia r1!, {r3 - r4} | ||
163 | stmneia r0!, {r3 - r4} @ Shouldnt fault | ||
164 | tst ip, #4 | ||
165 | ldrne r3, [r1], #4 | ||
166 | strnet r3, [r0], #4 @ Shouldnt fault | ||
167 | ands ip, ip, #3 | ||
168 | beq .c2u_0fupi | ||
169 | .c2u_0nowords: teq ip, #0 | ||
170 | beq .c2u_finished | ||
171 | .c2u_nowords: cmp ip, #2 | ||
172 | ldrb r3, [r1], #1 | ||
173 | USER( strbt r3, [r0], #1) @ May fault | ||
174 | ldrgeb r3, [r1], #1 | ||
175 | USER( strgebt r3, [r0], #1) @ May fault | ||
176 | ldrgtb r3, [r1], #1 | ||
177 | USER( strgtbt r3, [r0], #1) @ May fault | ||
178 | b .c2u_finished | ||
179 | |||
180 | .c2u_not_enough: | ||
181 | movs ip, r2 | ||
182 | bne .c2u_nowords | ||
183 | .c2u_finished: mov r0, #0 | ||
184 | LOADREGS(fd,sp!,{r2, r4 - r7, pc}) | ||
185 | |||
186 | .c2u_src_not_aligned: | ||
187 | bic r1, r1, #3 | ||
188 | ldr r7, [r1], #4 | ||
189 | cmp ip, #2 | ||
190 | bgt .c2u_3fupi | ||
191 | beq .c2u_2fupi | ||
192 | .c2u_1fupi: subs r2, r2, #4 | ||
193 | addmi ip, r2, #4 | ||
194 | bmi .c2u_1nowords | ||
195 | mov r3, r7, pull #8 | ||
196 | ldr r7, [r1], #4 | ||
197 | orr r3, r3, r7, push #24 | ||
198 | USER( strt r3, [r0], #4) @ May fault | ||
199 | mov ip, r0, lsl #32 - PAGE_SHIFT | ||
200 | rsb ip, ip, #0 | ||
201 | movs ip, ip, lsr #32 - PAGE_SHIFT | ||
202 | beq .c2u_1fupi | ||
203 | cmp r2, ip | ||
204 | movlt ip, r2 | ||
205 | sub r2, r2, ip | ||
206 | subs ip, ip, #16 | ||
207 | blt .c2u_1rem8lp | ||
208 | |||
209 | .c2u_1cpy8lp: mov r3, r7, pull #8 | ||
210 | ldmia r1!, {r4 - r7} | ||
211 | orr r3, r3, r4, push #24 | ||
212 | mov r4, r4, pull #8 | ||
213 | orr r4, r4, r5, push #24 | ||
214 | mov r5, r5, pull #8 | ||
215 | orr r5, r5, r6, push #24 | ||
216 | mov r6, r6, pull #8 | ||
217 | orr r6, r6, r7, push #24 | ||
218 | stmia r0!, {r3 - r6} @ Shouldnt fault | ||
219 | subs ip, ip, #16 | ||
220 | bpl .c2u_1cpy8lp | ||
221 | .c2u_1rem8lp: tst ip, #8 | ||
222 | movne r3, r7, pull #8 | ||
223 | ldmneia r1!, {r4, r7} | ||
224 | orrne r3, r3, r4, push #24 | ||
225 | movne r4, r4, pull #8 | ||
226 | orrne r4, r4, r7, push #24 | ||
227 | stmneia r0!, {r3 - r4} @ Shouldnt fault | ||
228 | tst ip, #4 | ||
229 | movne r3, r7, pull #8 | ||
230 | ldrne r7, [r1], #4 | ||
231 | orrne r3, r3, r7, push #24 | ||
232 | strnet r3, [r0], #4 @ Shouldnt fault | ||
233 | ands ip, ip, #3 | ||
234 | beq .c2u_1fupi | ||
235 | .c2u_1nowords: mov r3, r7, lsr #byte(1) | ||
236 | teq ip, #0 | ||
237 | beq .c2u_finished | ||
238 | cmp ip, #2 | ||
239 | USER( strbt r3, [r0], #1) @ May fault | ||
240 | movge r3, r7, lsr #byte(2) | ||
241 | USER( strgebt r3, [r0], #1) @ May fault | ||
242 | movgt r3, r7, lsr #byte(3) | ||
243 | USER( strgtbt r3, [r0], #1) @ May fault | ||
244 | b .c2u_finished | ||
245 | |||
246 | .c2u_2fupi: subs r2, r2, #4 | ||
247 | addmi ip, r2, #4 | ||
248 | bmi .c2u_2nowords | ||
249 | mov r3, r7, pull #16 | ||
250 | ldr r7, [r1], #4 | ||
251 | orr r3, r3, r7, push #16 | ||
252 | USER( strt r3, [r0], #4) @ May fault | ||
253 | mov ip, r0, lsl #32 - PAGE_SHIFT | ||
254 | rsb ip, ip, #0 | ||
255 | movs ip, ip, lsr #32 - PAGE_SHIFT | ||
256 | beq .c2u_2fupi | ||
257 | cmp r2, ip | ||
258 | movlt ip, r2 | ||
259 | sub r2, r2, ip | ||
260 | subs ip, ip, #16 | ||
261 | blt .c2u_2rem8lp | ||
262 | |||
263 | .c2u_2cpy8lp: mov r3, r7, pull #16 | ||
264 | ldmia r1!, {r4 - r7} | ||
265 | orr r3, r3, r4, push #16 | ||
266 | mov r4, r4, pull #16 | ||
267 | orr r4, r4, r5, push #16 | ||
268 | mov r5, r5, pull #16 | ||
269 | orr r5, r5, r6, push #16 | ||
270 | mov r6, r6, pull #16 | ||
271 | orr r6, r6, r7, push #16 | ||
272 | stmia r0!, {r3 - r6} @ Shouldnt fault | ||
273 | subs ip, ip, #16 | ||
274 | bpl .c2u_2cpy8lp | ||
275 | .c2u_2rem8lp: tst ip, #8 | ||
276 | movne r3, r7, pull #16 | ||
277 | ldmneia r1!, {r4, r7} | ||
278 | orrne r3, r3, r4, push #16 | ||
279 | movne r4, r4, pull #16 | ||
280 | orrne r4, r4, r7, push #16 | ||
281 | stmneia r0!, {r3 - r4} @ Shouldnt fault | ||
282 | tst ip, #4 | ||
283 | movne r3, r7, pull #16 | ||
284 | ldrne r7, [r1], #4 | ||
285 | orrne r3, r3, r7, push #16 | ||
286 | strnet r3, [r0], #4 @ Shouldnt fault | ||
287 | ands ip, ip, #3 | ||
288 | beq .c2u_2fupi | ||
289 | .c2u_2nowords: mov r3, r7, lsr #byte(2) | ||
290 | teq ip, #0 | ||
291 | beq .c2u_finished | ||
292 | cmp ip, #2 | ||
293 | USER( strbt r3, [r0], #1) @ May fault | ||
294 | movge r3, r7, lsr #byte(3) | ||
295 | USER( strgebt r3, [r0], #1) @ May fault | ||
296 | ldrgtb r3, [r1], #0 | ||
297 | USER( strgtbt r3, [r0], #1) @ May fault | ||
298 | b .c2u_finished | ||
299 | |||
300 | .c2u_3fupi: subs r2, r2, #4 | ||
301 | addmi ip, r2, #4 | ||
302 | bmi .c2u_3nowords | ||
303 | mov r3, r7, pull #24 | ||
304 | ldr r7, [r1], #4 | ||
305 | orr r3, r3, r7, push #8 | ||
306 | USER( strt r3, [r0], #4) @ May fault | ||
307 | mov ip, r0, lsl #32 - PAGE_SHIFT | ||
308 | rsb ip, ip, #0 | ||
309 | movs ip, ip, lsr #32 - PAGE_SHIFT | ||
310 | beq .c2u_3fupi | ||
311 | cmp r2, ip | ||
312 | movlt ip, r2 | ||
313 | sub r2, r2, ip | ||
314 | subs ip, ip, #16 | ||
315 | blt .c2u_3rem8lp | ||
316 | |||
317 | .c2u_3cpy8lp: mov r3, r7, pull #24 | ||
318 | ldmia r1!, {r4 - r7} | ||
319 | orr r3, r3, r4, push #8 | ||
320 | mov r4, r4, pull #24 | ||
321 | orr r4, r4, r5, push #8 | ||
322 | mov r5, r5, pull #24 | ||
323 | orr r5, r5, r6, push #8 | ||
324 | mov r6, r6, pull #24 | ||
325 | orr r6, r6, r7, push #8 | ||
326 | stmia r0!, {r3 - r6} @ Shouldnt fault | ||
327 | subs ip, ip, #16 | ||
328 | bpl .c2u_3cpy8lp | ||
329 | .c2u_3rem8lp: tst ip, #8 | ||
330 | movne r3, r7, pull #24 | ||
331 | ldmneia r1!, {r4, r7} | ||
332 | orrne r3, r3, r4, push #8 | ||
333 | movne r4, r4, pull #24 | ||
334 | orrne r4, r4, r7, push #8 | ||
335 | stmneia r0!, {r3 - r4} @ Shouldnt fault | ||
336 | tst ip, #4 | ||
337 | movne r3, r7, pull #24 | ||
338 | ldrne r7, [r1], #4 | ||
339 | orrne r3, r3, r7, push #8 | ||
340 | strnet r3, [r0], #4 @ Shouldnt fault | ||
341 | ands ip, ip, #3 | ||
342 | beq .c2u_3fupi | ||
343 | .c2u_3nowords: mov r3, r7, lsr #byte(3) | ||
344 | teq ip, #0 | ||
345 | beq .c2u_finished | ||
346 | cmp ip, #2 | ||
347 | USER( strbt r3, [r0], #1) @ May fault | ||
348 | ldrgeb r3, [r1], #1 | ||
349 | USER( strgebt r3, [r0], #1) @ May fault | ||
350 | ldrgtb r3, [r1], #0 | ||
351 | USER( strgtbt r3, [r0], #1) @ May fault | ||
352 | b .c2u_finished | ||
353 | |||
354 | .section .fixup,"ax" | ||
355 | .align 0 | ||
356 | 9001: LOADREGS(fd,sp!, {r0, r4 - r7, pc}) | ||
357 | .previous | ||
358 | |||
359 | /* Prototype: unsigned long uaccess_user_copy_from_user(void *to,const void *from,unsigned long n); | ||
360 | * Purpose : copy a block from user memory to kernel memory | ||
361 | * Params : to - kernel memory | ||
362 | * : from - user memory | ||
363 | * : n - number of bytes to copy | ||
364 | * Returns : Number of bytes NOT copied. | ||
365 | */ | ||
366 | .cfu_dest_not_aligned: | ||
367 | rsb ip, ip, #4 | ||
368 | cmp ip, #2 | ||
369 | USER( ldrbt r3, [r1], #1) @ May fault | ||
370 | strb r3, [r0], #1 | ||
371 | USER( ldrgebt r3, [r1], #1) @ May fault | ||
372 | strgeb r3, [r0], #1 | ||
373 | USER( ldrgtbt r3, [r1], #1) @ May fault | ||
374 | strgtb r3, [r0], #1 | ||
375 | sub r2, r2, ip | ||
376 | b .cfu_dest_aligned | ||
377 | |||
378 | ENTRY(uaccess_user_copy_from_user) | ||
379 | stmfd sp!, {r0, r2, r4 - r7, lr} | ||
380 | cmp r2, #4 | ||
381 | blt .cfu_not_enough | ||
382 | ands ip, r0, #3 | ||
383 | bne .cfu_dest_not_aligned | ||
384 | .cfu_dest_aligned: | ||
385 | ands ip, r1, #3 | ||
386 | bne .cfu_src_not_aligned | ||
387 | /* | ||
388 | * Seeing as there has to be at least 8 bytes to copy, we can | ||
389 | * copy one word, and force a user-mode page fault... | ||
390 | */ | ||
391 | |||
392 | .cfu_0fupi: subs r2, r2, #4 | ||
393 | addmi ip, r2, #4 | ||
394 | bmi .cfu_0nowords | ||
395 | USER( ldrt r3, [r1], #4) | ||
396 | str r3, [r0], #4 | ||
397 | mov ip, r1, lsl #32 - PAGE_SHIFT @ On each page, use a ld/st??t instruction | ||
398 | rsb ip, ip, #0 | ||
399 | movs ip, ip, lsr #32 - PAGE_SHIFT | ||
400 | beq .cfu_0fupi | ||
401 | /* | ||
402 | * ip = max no. of bytes to copy before needing another "strt" insn | ||
403 | */ | ||
404 | cmp r2, ip | ||
405 | movlt ip, r2 | ||
406 | sub r2, r2, ip | ||
407 | subs ip, ip, #32 | ||
408 | blt .cfu_0rem8lp | ||
409 | |||
410 | .cfu_0cpy8lp: ldmia r1!, {r3 - r6} @ Shouldnt fault | ||
411 | stmia r0!, {r3 - r6} | ||
412 | ldmia r1!, {r3 - r6} @ Shouldnt fault | ||
413 | stmia r0!, {r3 - r6} | ||
414 | subs ip, ip, #32 | ||
415 | bpl .cfu_0cpy8lp | ||
416 | .cfu_0rem8lp: cmn ip, #16 | ||
417 | ldmgeia r1!, {r3 - r6} @ Shouldnt fault | ||
418 | stmgeia r0!, {r3 - r6} | ||
419 | tst ip, #8 | ||
420 | ldmneia r1!, {r3 - r4} @ Shouldnt fault | ||
421 | stmneia r0!, {r3 - r4} | ||
422 | tst ip, #4 | ||
423 | ldrnet r3, [r1], #4 @ Shouldnt fault | ||
424 | strne r3, [r0], #4 | ||
425 | ands ip, ip, #3 | ||
426 | beq .cfu_0fupi | ||
427 | .cfu_0nowords: teq ip, #0 | ||
428 | beq .cfu_finished | ||
429 | .cfu_nowords: cmp ip, #2 | ||
430 | USER( ldrbt r3, [r1], #1) @ May fault | ||
431 | strb r3, [r0], #1 | ||
432 | USER( ldrgebt r3, [r1], #1) @ May fault | ||
433 | strgeb r3, [r0], #1 | ||
434 | USER( ldrgtbt r3, [r1], #1) @ May fault | ||
435 | strgtb r3, [r0], #1 | ||
436 | b .cfu_finished | ||
437 | |||
438 | .cfu_not_enough: | ||
439 | movs ip, r2 | ||
440 | bne .cfu_nowords | ||
441 | .cfu_finished: mov r0, #0 | ||
442 | add sp, sp, #8 | ||
443 | LOADREGS(fd,sp!,{r4 - r7, pc}) | ||
444 | |||
445 | .cfu_src_not_aligned: | ||
446 | bic r1, r1, #3 | ||
447 | USER( ldrt r7, [r1], #4) @ May fault | ||
448 | cmp ip, #2 | ||
449 | bgt .cfu_3fupi | ||
450 | beq .cfu_2fupi | ||
451 | .cfu_1fupi: subs r2, r2, #4 | ||
452 | addmi ip, r2, #4 | ||
453 | bmi .cfu_1nowords | ||
454 | mov r3, r7, pull #8 | ||
455 | USER( ldrt r7, [r1], #4) @ May fault | ||
456 | orr r3, r3, r7, push #24 | ||
457 | str r3, [r0], #4 | ||
458 | mov ip, r1, lsl #32 - PAGE_SHIFT | ||
459 | rsb ip, ip, #0 | ||
460 | movs ip, ip, lsr #32 - PAGE_SHIFT | ||
461 | beq .cfu_1fupi | ||
462 | cmp r2, ip | ||
463 | movlt ip, r2 | ||
464 | sub r2, r2, ip | ||
465 | subs ip, ip, #16 | ||
466 | blt .cfu_1rem8lp | ||
467 | |||
468 | .cfu_1cpy8lp: mov r3, r7, pull #8 | ||
469 | ldmia r1!, {r4 - r7} @ Shouldnt fault | ||
470 | orr r3, r3, r4, push #24 | ||
471 | mov r4, r4, pull #8 | ||
472 | orr r4, r4, r5, push #24 | ||
473 | mov r5, r5, pull #8 | ||
474 | orr r5, r5, r6, push #24 | ||
475 | mov r6, r6, pull #8 | ||
476 | orr r6, r6, r7, push #24 | ||
477 | stmia r0!, {r3 - r6} | ||
478 | subs ip, ip, #16 | ||
479 | bpl .cfu_1cpy8lp | ||
480 | .cfu_1rem8lp: tst ip, #8 | ||
481 | movne r3, r7, pull #8 | ||
482 | ldmneia r1!, {r4, r7} @ Shouldnt fault | ||
483 | orrne r3, r3, r4, push #24 | ||
484 | movne r4, r4, pull #8 | ||
485 | orrne r4, r4, r7, push #24 | ||
486 | stmneia r0!, {r3 - r4} | ||
487 | tst ip, #4 | ||
488 | movne r3, r7, pull #8 | ||
489 | USER( ldrnet r7, [r1], #4) @ May fault | ||
490 | orrne r3, r3, r7, push #24 | ||
491 | strne r3, [r0], #4 | ||
492 | ands ip, ip, #3 | ||
493 | beq .cfu_1fupi | ||
494 | .cfu_1nowords: mov r3, r7, lsr #byte(1) | ||
495 | teq ip, #0 | ||
496 | beq .cfu_finished | ||
497 | cmp ip, #2 | ||
498 | strb r3, [r0], #1 | ||
499 | movge r3, r7, lsr #byte(2) | ||
500 | strgeb r3, [r0], #1 | ||
501 | movgt r3, r7, lsr #byte(3) | ||
502 | strgtb r3, [r0], #1 | ||
503 | b .cfu_finished | ||
504 | |||
505 | .cfu_2fupi: subs r2, r2, #4 | ||
506 | addmi ip, r2, #4 | ||
507 | bmi .cfu_2nowords | ||
508 | mov r3, r7, pull #16 | ||
509 | USER( ldrt r7, [r1], #4) @ May fault | ||
510 | orr r3, r3, r7, push #16 | ||
511 | str r3, [r0], #4 | ||
512 | mov ip, r1, lsl #32 - PAGE_SHIFT | ||
513 | rsb ip, ip, #0 | ||
514 | movs ip, ip, lsr #32 - PAGE_SHIFT | ||
515 | beq .cfu_2fupi | ||
516 | cmp r2, ip | ||
517 | movlt ip, r2 | ||
518 | sub r2, r2, ip | ||
519 | subs ip, ip, #16 | ||
520 | blt .cfu_2rem8lp | ||
521 | |||
522 | .cfu_2cpy8lp: mov r3, r7, pull #16 | ||
523 | ldmia r1!, {r4 - r7} @ Shouldnt fault | ||
524 | orr r3, r3, r4, push #16 | ||
525 | mov r4, r4, pull #16 | ||
526 | orr r4, r4, r5, push #16 | ||
527 | mov r5, r5, pull #16 | ||
528 | orr r5, r5, r6, push #16 | ||
529 | mov r6, r6, pull #16 | ||
530 | orr r6, r6, r7, push #16 | ||
531 | stmia r0!, {r3 - r6} | ||
532 | subs ip, ip, #16 | ||
533 | bpl .cfu_2cpy8lp | ||
534 | .cfu_2rem8lp: tst ip, #8 | ||
535 | movne r3, r7, pull #16 | ||
536 | ldmneia r1!, {r4, r7} @ Shouldnt fault | ||
537 | orrne r3, r3, r4, push #16 | ||
538 | movne r4, r4, pull #16 | ||
539 | orrne r4, r4, r7, push #16 | ||
540 | stmneia r0!, {r3 - r4} | ||
541 | tst ip, #4 | ||
542 | movne r3, r7, pull #16 | ||
543 | USER( ldrnet r7, [r1], #4) @ May fault | ||
544 | orrne r3, r3, r7, push #16 | ||
545 | strne r3, [r0], #4 | ||
546 | ands ip, ip, #3 | ||
547 | beq .cfu_2fupi | ||
548 | .cfu_2nowords: mov r3, r7, lsr #byte(2) | ||
549 | teq ip, #0 | ||
550 | beq .cfu_finished | ||
551 | cmp ip, #2 | ||
552 | strb r3, [r0], #1 | ||
553 | movge r3, r7, lsr #byte(3) | ||
554 | strgeb r3, [r0], #1 | ||
555 | USER( ldrgtbt r3, [r1], #0) @ May fault | ||
556 | strgtb r3, [r0], #1 | ||
557 | b .cfu_finished | ||
558 | |||
559 | .cfu_3fupi: subs r2, r2, #4 | ||
560 | addmi ip, r2, #4 | ||
561 | bmi .cfu_3nowords | ||
562 | mov r3, r7, pull #24 | ||
563 | USER( ldrt r7, [r1], #4) @ May fault | ||
564 | orr r3, r3, r7, push #8 | ||
565 | str r3, [r0], #4 | ||
566 | mov ip, r1, lsl #32 - PAGE_SHIFT | ||
567 | rsb ip, ip, #0 | ||
568 | movs ip, ip, lsr #32 - PAGE_SHIFT | ||
569 | beq .cfu_3fupi | ||
570 | cmp r2, ip | ||
571 | movlt ip, r2 | ||
572 | sub r2, r2, ip | ||
573 | subs ip, ip, #16 | ||
574 | blt .cfu_3rem8lp | ||
575 | |||
576 | .cfu_3cpy8lp: mov r3, r7, pull #24 | ||
577 | ldmia r1!, {r4 - r7} @ Shouldnt fault | ||
578 | orr r3, r3, r4, push #8 | ||
579 | mov r4, r4, pull #24 | ||
580 | orr r4, r4, r5, push #8 | ||
581 | mov r5, r5, pull #24 | ||
582 | orr r5, r5, r6, push #8 | ||
583 | mov r6, r6, pull #24 | ||
584 | orr r6, r6, r7, push #8 | ||
585 | stmia r0!, {r3 - r6} | ||
586 | subs ip, ip, #16 | ||
587 | bpl .cfu_3cpy8lp | ||
588 | .cfu_3rem8lp: tst ip, #8 | ||
589 | movne r3, r7, pull #24 | ||
590 | ldmneia r1!, {r4, r7} @ Shouldnt fault | ||
591 | orrne r3, r3, r4, push #8 | ||
592 | movne r4, r4, pull #24 | ||
593 | orrne r4, r4, r7, push #8 | ||
594 | stmneia r0!, {r3 - r4} | ||
595 | tst ip, #4 | ||
596 | movne r3, r7, pull #24 | ||
597 | USER( ldrnet r7, [r1], #4) @ May fault | ||
598 | orrne r3, r3, r7, push #8 | ||
599 | strne r3, [r0], #4 | ||
600 | ands ip, ip, #3 | ||
601 | beq .cfu_3fupi | ||
602 | .cfu_3nowords: mov r3, r7, lsr #byte(3) | ||
603 | teq ip, #0 | ||
604 | beq .cfu_finished | ||
605 | cmp ip, #2 | ||
606 | strb r3, [r0], #1 | ||
607 | USER( ldrgebt r3, [r1], #1) @ May fault | ||
608 | strgeb r3, [r0], #1 | ||
609 | USER( ldrgtbt r3, [r1], #1) @ May fault | ||
610 | strgtb r3, [r0], #1 | ||
611 | b .cfu_finished | ||
612 | |||
613 | .section .fixup,"ax" | ||
614 | .align 0 | ||
615 | /* | ||
616 | * We took an exception. r0 contains a pointer to | ||
617 | * the byte not copied. | ||
618 | */ | ||
619 | 9001: ldr r2, [sp], #4 @ void *to | ||
620 | sub r2, r0, r2 @ bytes copied | ||
621 | ldr r1, [sp], #4 @ unsigned long count | ||
622 | subs r4, r1, r2 @ bytes left to copy | ||
623 | movne r1, r4 | ||
624 | blne __memzero | ||
625 | mov r0, r4 | ||
626 | LOADREGS(fd,sp!, {r4 - r7, pc}) | ||
627 | .previous | ||
628 | |||
629 | /* Prototype: int uaccess_user_clear_user(void *addr, size_t sz) | ||
630 | * Purpose : clear some user memory | ||
631 | * Params : addr - user memory address to clear | ||
632 | * : sz - number of bytes to clear | ||
633 | * Returns : number of bytes NOT cleared | ||
634 | */ | ||
635 | ENTRY(uaccess_user_clear_user) | ||
636 | stmfd sp!, {r1, lr} | ||
637 | mov r2, #0 | ||
638 | cmp r1, #4 | ||
639 | blt 2f | ||
640 | ands ip, r0, #3 | ||
641 | beq 1f | ||
642 | cmp ip, #2 | ||
643 | USER( strbt r2, [r0], #1) | ||
644 | USER( strlebt r2, [r0], #1) | ||
645 | USER( strltbt r2, [r0], #1) | ||
646 | rsb ip, ip, #4 | ||
647 | sub r1, r1, ip @ 7 6 5 4 3 2 1 | ||
648 | 1: subs r1, r1, #8 @ -1 -2 -3 -4 -5 -6 -7 | ||
649 | USER( strplt r2, [r0], #4) | ||
650 | USER( strplt r2, [r0], #4) | ||
651 | bpl 1b | ||
652 | adds r1, r1, #4 @ 3 2 1 0 -1 -2 -3 | ||
653 | USER( strplt r2, [r0], #4) | ||
654 | 2: tst r1, #2 @ 1x 1x 0x 0x 1x 1x 0x | ||
655 | USER( strnebt r2, [r0], #1) | ||
656 | USER( strnebt r2, [r0], #1) | ||
657 | tst r1, #1 @ x1 x0 x1 x0 x1 x0 x1 | ||
658 | USER( strnebt r2, [r0], #1) | ||
659 | mov r0, #0 | ||
660 | LOADREGS(fd,sp!, {r1, pc}) | ||
661 | |||
662 | .section .fixup,"ax" | ||
663 | .align 0 | ||
664 | 9001: LOADREGS(fd,sp!, {r0, pc}) | ||
665 | .previous | ||
666 | |||
667 | /* | ||
668 | * Copy a string from user space to kernel space. | ||
669 | * r0 = dst, r1 = src, r2 = byte length | ||
670 | * returns the number of characters copied (strlen of copied string), | ||
671 | * -EFAULT on exception, or "len" if we fill the whole buffer | ||
672 | */ | ||
673 | ENTRY(uaccess_user_strncpy_from_user) | ||
674 | save_lr | ||
675 | mov ip, r1 | ||
676 | 1: subs r2, r2, #1 | ||
677 | USER( ldrplbt r3, [r1], #1) | ||
678 | bmi 2f | ||
679 | strb r3, [r0], #1 | ||
680 | teq r3, #0 | ||
681 | bne 1b | ||
682 | sub r1, r1, #1 @ take NUL character out of count | ||
683 | 2: sub r0, r1, ip | ||
684 | restore_pc | ||
685 | |||
686 | .section .fixup,"ax" | ||
687 | .align 0 | ||
688 | 9001: mov r3, #0 | ||
689 | strb r3, [r0, #0] @ null terminate | ||
690 | mov r0, #-EFAULT | ||
691 | restore_pc | ||
692 | .previous | ||
693 | |||
694 | /* Prototype: unsigned long uaccess_user_strnlen_user(const char *str, long n) | ||
695 | * Purpose : get length of a string in user memory | ||
696 | * Params : str - address of string in user memory | ||
697 | * Returns : length of string *including terminator* | ||
698 | * or zero on exception, or n + 1 if too long | ||
699 | */ | ||
700 | ENTRY(uaccess_user_strnlen_user) | ||
701 | save_lr | ||
702 | mov r2, r0 | ||
703 | 1: | ||
704 | USER( ldrbt r3, [r0], #1) | ||
705 | teq r3, #0 | ||
706 | beq 2f | ||
707 | subs r1, r1, #1 | ||
708 | bne 1b | ||
709 | add r0, r0, #1 | ||
710 | 2: sub r0, r0, r2 | ||
711 | restore_pc | ||
712 | |||
713 | .section .fixup,"ax" | ||
714 | .align 0 | ||
715 | 9001: mov r0, #0 | ||
716 | restore_pc | ||
717 | .previous | ||
718 | |||