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