diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/m32r/lib/usercopy.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/m32r/lib/usercopy.c')
-rw-r--r-- | arch/m32r/lib/usercopy.c | 391 |
1 files changed, 391 insertions, 0 deletions
diff --git a/arch/m32r/lib/usercopy.c b/arch/m32r/lib/usercopy.c new file mode 100644 index 000000000000..6c6855f1aa05 --- /dev/null +++ b/arch/m32r/lib/usercopy.c | |||
@@ -0,0 +1,391 @@ | |||
1 | /* | ||
2 | * User address space access functions. | ||
3 | * The non inlined parts of asm-m32r/uaccess.h are here. | ||
4 | * | ||
5 | * Copyright 1997 Andi Kleen <ak@muc.de> | ||
6 | * Copyright 1997 Linus Torvalds | ||
7 | * Copyright 2001, 2002, 2004 Hirokazu Takata | ||
8 | */ | ||
9 | #include <linux/config.h> | ||
10 | #include <linux/prefetch.h> | ||
11 | #include <linux/string.h> | ||
12 | #include <linux/thread_info.h> | ||
13 | #include <asm/uaccess.h> | ||
14 | |||
15 | unsigned long | ||
16 | __generic_copy_to_user(void *to, const void *from, unsigned long n) | ||
17 | { | ||
18 | prefetch(from); | ||
19 | if (access_ok(VERIFY_WRITE, to, n)) | ||
20 | __copy_user(to,from,n); | ||
21 | return n; | ||
22 | } | ||
23 | |||
24 | unsigned long | ||
25 | __generic_copy_from_user(void *to, const void *from, unsigned long n) | ||
26 | { | ||
27 | prefetchw(to); | ||
28 | if (access_ok(VERIFY_READ, from, n)) | ||
29 | __copy_user_zeroing(to,from,n); | ||
30 | else | ||
31 | memset(to, 0, n); | ||
32 | return n; | ||
33 | } | ||
34 | |||
35 | |||
36 | /* | ||
37 | * Copy a null terminated string from userspace. | ||
38 | */ | ||
39 | |||
40 | #ifdef CONFIG_ISA_DUAL_ISSUE | ||
41 | |||
42 | #define __do_strncpy_from_user(dst,src,count,res) \ | ||
43 | do { \ | ||
44 | int __d0, __d1, __d2; \ | ||
45 | __asm__ __volatile__( \ | ||
46 | " beqz %1, 2f\n" \ | ||
47 | " .fillinsn\n" \ | ||
48 | "0: ldb r14, @%3 || addi %3, #1\n" \ | ||
49 | " stb r14, @%4 || addi %4, #1\n" \ | ||
50 | " beqz r14, 1f\n" \ | ||
51 | " addi %1, #-1\n" \ | ||
52 | " bnez %1, 0b\n" \ | ||
53 | " .fillinsn\n" \ | ||
54 | "1: sub %0, %1\n" \ | ||
55 | " .fillinsn\n" \ | ||
56 | "2:\n" \ | ||
57 | ".section .fixup,\"ax\"\n" \ | ||
58 | " .balign 4\n" \ | ||
59 | "3: seth r14, #high(2b)\n" \ | ||
60 | " or3 r14, r14, #low(2b)\n" \ | ||
61 | " jmp r14 || ldi %0, #%5\n" \ | ||
62 | ".previous\n" \ | ||
63 | ".section __ex_table,\"a\"\n" \ | ||
64 | " .balign 4\n" \ | ||
65 | " .long 0b,3b\n" \ | ||
66 | ".previous" \ | ||
67 | : "=r"(res), "=r"(count), "=&r" (__d0), "=&r" (__d1), \ | ||
68 | "=&r" (__d2) \ | ||
69 | : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), \ | ||
70 | "4"(dst) \ | ||
71 | : "r14", "cbit", "memory"); \ | ||
72 | } while (0) | ||
73 | |||
74 | #else /* not CONFIG_ISA_DUAL_ISSUE */ | ||
75 | |||
76 | #define __do_strncpy_from_user(dst,src,count,res) \ | ||
77 | do { \ | ||
78 | int __d0, __d1, __d2; \ | ||
79 | __asm__ __volatile__( \ | ||
80 | " beqz %1, 2f\n" \ | ||
81 | " .fillinsn\n" \ | ||
82 | "0: ldb r14, @%3\n" \ | ||
83 | " stb r14, @%4\n" \ | ||
84 | " addi %3, #1\n" \ | ||
85 | " addi %4, #1\n" \ | ||
86 | " beqz r14, 1f\n" \ | ||
87 | " addi %1, #-1\n" \ | ||
88 | " bnez %1, 0b\n" \ | ||
89 | " .fillinsn\n" \ | ||
90 | "1: sub %0, %1\n" \ | ||
91 | " .fillinsn\n" \ | ||
92 | "2:\n" \ | ||
93 | ".section .fixup,\"ax\"\n" \ | ||
94 | " .balign 4\n" \ | ||
95 | "3: ldi %0, #%5\n" \ | ||
96 | " seth r14, #high(2b)\n" \ | ||
97 | " or3 r14, r14, #low(2b)\n" \ | ||
98 | " jmp r14\n" \ | ||
99 | ".previous\n" \ | ||
100 | ".section __ex_table,\"a\"\n" \ | ||
101 | " .balign 4\n" \ | ||
102 | " .long 0b,3b\n" \ | ||
103 | ".previous" \ | ||
104 | : "=r"(res), "=r"(count), "=&r" (__d0), "=&r" (__d1), \ | ||
105 | "=&r" (__d2) \ | ||
106 | : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), \ | ||
107 | "4"(dst) \ | ||
108 | : "r14", "cbit", "memory"); \ | ||
109 | } while (0) | ||
110 | |||
111 | #endif /* CONFIG_ISA_DUAL_ISSUE */ | ||
112 | |||
113 | long | ||
114 | __strncpy_from_user(char *dst, const char *src, long count) | ||
115 | { | ||
116 | long res; | ||
117 | __do_strncpy_from_user(dst, src, count, res); | ||
118 | return res; | ||
119 | } | ||
120 | |||
121 | long | ||
122 | strncpy_from_user(char *dst, const char *src, long count) | ||
123 | { | ||
124 | long res = -EFAULT; | ||
125 | if (access_ok(VERIFY_READ, src, 1)) | ||
126 | __do_strncpy_from_user(dst, src, count, res); | ||
127 | return res; | ||
128 | } | ||
129 | |||
130 | |||
131 | /* | ||
132 | * Zero Userspace | ||
133 | */ | ||
134 | |||
135 | #ifdef CONFIG_ISA_DUAL_ISSUE | ||
136 | |||
137 | #define __do_clear_user(addr,size) \ | ||
138 | do { \ | ||
139 | int __dst, __c; \ | ||
140 | __asm__ __volatile__( \ | ||
141 | " beqz %1, 9f\n" \ | ||
142 | " and3 r14, %0, #3\n" \ | ||
143 | " bnez r14, 2f\n" \ | ||
144 | " and3 r14, %1, #3\n" \ | ||
145 | " bnez r14, 2f\n" \ | ||
146 | " and3 %1, %1, #3\n" \ | ||
147 | " beqz %2, 2f\n" \ | ||
148 | " addi %0, #-4\n" \ | ||
149 | " .fillinsn\n" \ | ||
150 | "0: ; word clear \n" \ | ||
151 | " st %6, @+%0 || addi %2, #-1\n" \ | ||
152 | " bnez %2, 0b\n" \ | ||
153 | " beqz %1, 9f\n" \ | ||
154 | " .fillinsn\n" \ | ||
155 | "2: ; byte clear \n" \ | ||
156 | " stb %6, @%0 || addi %1, #-1\n" \ | ||
157 | " addi %0, #1\n" \ | ||
158 | " bnez %1, 2b\n" \ | ||
159 | " .fillinsn\n" \ | ||
160 | "9:\n" \ | ||
161 | ".section .fixup,\"ax\"\n" \ | ||
162 | " .balign 4\n" \ | ||
163 | "4: slli %2, #2\n" \ | ||
164 | " seth r14, #high(9b)\n" \ | ||
165 | " or3 r14, r14, #low(9b)\n" \ | ||
166 | " jmp r14 || add %1, %2\n" \ | ||
167 | ".previous\n" \ | ||
168 | ".section __ex_table,\"a\"\n" \ | ||
169 | " .balign 4\n" \ | ||
170 | " .long 0b,4b\n" \ | ||
171 | " .long 2b,9b\n" \ | ||
172 | ".previous\n" \ | ||
173 | : "=&r"(__dst), "=&r"(size), "=&r"(__c) \ | ||
174 | : "0"(addr), "1"(size), "2"(size / 4), "r"(0) \ | ||
175 | : "r14", "cbit", "memory"); \ | ||
176 | } while (0) | ||
177 | |||
178 | #else /* not CONFIG_ISA_DUAL_ISSUE */ | ||
179 | |||
180 | #define __do_clear_user(addr,size) \ | ||
181 | do { \ | ||
182 | int __dst, __c; \ | ||
183 | __asm__ __volatile__( \ | ||
184 | " beqz %1, 9f\n" \ | ||
185 | " and3 r14, %0, #3\n" \ | ||
186 | " bnez r14, 2f\n" \ | ||
187 | " and3 r14, %1, #3\n" \ | ||
188 | " bnez r14, 2f\n" \ | ||
189 | " and3 %1, %1, #3\n" \ | ||
190 | " beqz %2, 2f\n" \ | ||
191 | " addi %0, #-4\n" \ | ||
192 | " .fillinsn\n" \ | ||
193 | "0: st %6, @+%0 ; word clear \n" \ | ||
194 | " addi %2, #-1\n" \ | ||
195 | " bnez %2, 0b\n" \ | ||
196 | " beqz %1, 9f\n" \ | ||
197 | " .fillinsn\n" \ | ||
198 | "2: stb %6, @%0 ; byte clear \n" \ | ||
199 | " addi %1, #-1\n" \ | ||
200 | " addi %0, #1\n" \ | ||
201 | " bnez %1, 2b\n" \ | ||
202 | " .fillinsn\n" \ | ||
203 | "9:\n" \ | ||
204 | ".section .fixup,\"ax\"\n" \ | ||
205 | " .balign 4\n" \ | ||
206 | "4: slli %2, #2\n" \ | ||
207 | " add %1, %2\n" \ | ||
208 | " seth r14, #high(9b)\n" \ | ||
209 | " or3 r14, r14, #low(9b)\n" \ | ||
210 | " jmp r14\n" \ | ||
211 | ".previous\n" \ | ||
212 | ".section __ex_table,\"a\"\n" \ | ||
213 | " .balign 4\n" \ | ||
214 | " .long 0b,4b\n" \ | ||
215 | " .long 2b,9b\n" \ | ||
216 | ".previous\n" \ | ||
217 | : "=&r"(__dst), "=&r"(size), "=&r"(__c) \ | ||
218 | : "0"(addr), "1"(size), "2"(size / 4), "r"(0) \ | ||
219 | : "r14", "cbit", "memory"); \ | ||
220 | } while (0) | ||
221 | |||
222 | #endif /* not CONFIG_ISA_DUAL_ISSUE */ | ||
223 | |||
224 | unsigned long | ||
225 | clear_user(void *to, unsigned long n) | ||
226 | { | ||
227 | if (access_ok(VERIFY_WRITE, to, n)) | ||
228 | __do_clear_user(to, n); | ||
229 | return n; | ||
230 | } | ||
231 | |||
232 | unsigned long | ||
233 | __clear_user(void *to, unsigned long n) | ||
234 | { | ||
235 | __do_clear_user(to, n); | ||
236 | return n; | ||
237 | } | ||
238 | |||
239 | /* | ||
240 | * Return the size of a string (including the ending 0) | ||
241 | * | ||
242 | * Return 0 on exception, a value greater than N if too long | ||
243 | */ | ||
244 | |||
245 | #ifdef CONFIG_ISA_DUAL_ISSUE | ||
246 | |||
247 | long strnlen_user(const char *s, long n) | ||
248 | { | ||
249 | unsigned long mask = -__addr_ok(s); | ||
250 | unsigned long res; | ||
251 | |||
252 | __asm__ __volatile__( | ||
253 | " and %0, %5 || mv r1, %1\n" | ||
254 | " beqz %0, strnlen_exit\n" | ||
255 | " and3 r0, %1, #3\n" | ||
256 | " bnez r0, strnlen_byte_loop\n" | ||
257 | " cmpui %0, #4\n" | ||
258 | " bc strnlen_byte_loop\n" | ||
259 | "strnlen_word_loop:\n" | ||
260 | "0: ld r0, @%1+\n" | ||
261 | " pcmpbz r0\n" | ||
262 | " bc strnlen_last_bytes_fixup\n" | ||
263 | " addi %0, #-4\n" | ||
264 | " beqz %0, strnlen_exit\n" | ||
265 | " bgtz %0, strnlen_word_loop\n" | ||
266 | "strnlen_last_bytes:\n" | ||
267 | " mv %0, %4\n" | ||
268 | "strnlen_last_bytes_fixup:\n" | ||
269 | " addi %1, #-4\n" | ||
270 | "strnlen_byte_loop:\n" | ||
271 | "1: ldb r0, @%1 || addi %0, #-1\n" | ||
272 | " beqz r0, strnlen_exit\n" | ||
273 | " addi %1, #1\n" | ||
274 | " bnez %0, strnlen_byte_loop\n" | ||
275 | "strnlen_exit:\n" | ||
276 | " sub %1, r1\n" | ||
277 | " add3 %0, %1, #1\n" | ||
278 | " .fillinsn\n" | ||
279 | "9:\n" | ||
280 | ".section .fixup,\"ax\"\n" | ||
281 | " .balign 4\n" | ||
282 | "4: addi %1, #-4\n" | ||
283 | " .fillinsn\n" | ||
284 | "5: seth r1, #high(9b)\n" | ||
285 | " or3 r1, r1, #low(9b)\n" | ||
286 | " jmp r1 || ldi %0, #0\n" | ||
287 | ".previous\n" | ||
288 | ".section __ex_table,\"a\"\n" | ||
289 | " .balign 4\n" | ||
290 | " .long 0b,4b\n" | ||
291 | " .long 1b,5b\n" | ||
292 | ".previous" | ||
293 | : "=&r" (res), "=r" (s) | ||
294 | : "0" (n), "1" (s), "r" (n & 3), "r" (mask), "r"(0x01010101) | ||
295 | : "r0", "r1", "cbit"); | ||
296 | |||
297 | /* NOTE: strnlen_user() algorism: | ||
298 | * { | ||
299 | * char *p; | ||
300 | * for (p = s; n-- && *p != '\0'; ++p) | ||
301 | * ; | ||
302 | * return p - s + 1; | ||
303 | * } | ||
304 | */ | ||
305 | |||
306 | /* NOTE: If a null char. exists, return 0. | ||
307 | * if ((x - 0x01010101) & ~x & 0x80808080)\n" | ||
308 | * return 0;\n" | ||
309 | */ | ||
310 | |||
311 | return res & mask; | ||
312 | } | ||
313 | |||
314 | #else /* not CONFIG_ISA_DUAL_ISSUE */ | ||
315 | |||
316 | long strnlen_user(const char *s, long n) | ||
317 | { | ||
318 | unsigned long mask = -__addr_ok(s); | ||
319 | unsigned long res; | ||
320 | |||
321 | __asm__ __volatile__( | ||
322 | " and %0, %5\n" | ||
323 | " mv r1, %1\n" | ||
324 | " beqz %0, strnlen_exit\n" | ||
325 | " and3 r0, %1, #3\n" | ||
326 | " bnez r0, strnlen_byte_loop\n" | ||
327 | " cmpui %0, #4\n" | ||
328 | " bc strnlen_byte_loop\n" | ||
329 | " sll3 r3, %6, #7\n" | ||
330 | "strnlen_word_loop:\n" | ||
331 | "0: ld r0, @%1+\n" | ||
332 | " not r2, r0\n" | ||
333 | " sub r0, %6\n" | ||
334 | " and r2, r3\n" | ||
335 | " and r2, r0\n" | ||
336 | " bnez r2, strnlen_last_bytes_fixup\n" | ||
337 | " addi %0, #-4\n" | ||
338 | " beqz %0, strnlen_exit\n" | ||
339 | " bgtz %0, strnlen_word_loop\n" | ||
340 | "strnlen_last_bytes:\n" | ||
341 | " mv %0, %4\n" | ||
342 | "strnlen_last_bytes_fixup:\n" | ||
343 | " addi %1, #-4\n" | ||
344 | "strnlen_byte_loop:\n" | ||
345 | "1: ldb r0, @%1\n" | ||
346 | " addi %0, #-1\n" | ||
347 | " beqz r0, strnlen_exit\n" | ||
348 | " addi %1, #1\n" | ||
349 | " bnez %0, strnlen_byte_loop\n" | ||
350 | "strnlen_exit:\n" | ||
351 | " sub %1, r1\n" | ||
352 | " add3 %0, %1, #1\n" | ||
353 | " .fillinsn\n" | ||
354 | "9:\n" | ||
355 | ".section .fixup,\"ax\"\n" | ||
356 | " .balign 4\n" | ||
357 | "4: addi %1, #-4\n" | ||
358 | " .fillinsn\n" | ||
359 | "5: ldi %0, #0\n" | ||
360 | " seth r1, #high(9b)\n" | ||
361 | " or3 r1, r1, #low(9b)\n" | ||
362 | " jmp r1\n" | ||
363 | ".previous\n" | ||
364 | ".section __ex_table,\"a\"\n" | ||
365 | " .balign 4\n" | ||
366 | " .long 0b,4b\n" | ||
367 | " .long 1b,5b\n" | ||
368 | ".previous" | ||
369 | : "=&r" (res), "=r" (s) | ||
370 | : "0" (n), "1" (s), "r" (n & 3), "r" (mask), "r"(0x01010101) | ||
371 | : "r0", "r1", "r2", "r3", "cbit"); | ||
372 | |||
373 | /* NOTE: strnlen_user() algorism: | ||
374 | * { | ||
375 | * char *p; | ||
376 | * for (p = s; n-- && *p != '\0'; ++p) | ||
377 | * ; | ||
378 | * return p - s + 1; | ||
379 | * } | ||
380 | */ | ||
381 | |||
382 | /* NOTE: If a null char. exists, return 0. | ||
383 | * if ((x - 0x01010101) & ~x & 0x80808080)\n" | ||
384 | * return 0;\n" | ||
385 | */ | ||
386 | |||
387 | return res & mask; | ||
388 | } | ||
389 | |||
390 | #endif /* CONFIG_ISA_DUAL_ISSUE */ | ||
391 | |||