Linux-libre 4.15.7-gnu
[librecmc/linux-libre.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