Merge tag 'for-linus' of git://git.armlinux.org.uk/~rmk/linux-arm
[platform/kernel/linux-rpi.git] / arch / m68k / include / asm / uaccess.h
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef __M68K_UACCESS_H
3 #define __M68K_UACCESS_H
4
5 #ifdef CONFIG_MMU
6
7 /*
8  * User space memory access functions
9  */
10 #include <linux/compiler.h>
11 #include <linux/types.h>
12 #include <asm/extable.h>
13
14 /* We let the MMU do all checking */
15 static inline int access_ok(const void __user *addr,
16                             unsigned long size)
17 {
18         /*
19          * XXX: for !CONFIG_CPU_HAS_ADDRESS_SPACES this really needs to check
20          * for TASK_SIZE!
21          */
22         return 1;
23 }
24
25 /*
26  * Not all varients of the 68k family support the notion of address spaces.
27  * The traditional 680x0 parts do, and they use the sfc/dfc registers and
28  * the "moves" instruction to access user space from kernel space. Other
29  * family members like ColdFire don't support this, and only have a single
30  * address space, and use the usual "move" instruction for user space access.
31  *
32  * Outside of this difference the user space access functions are the same.
33  * So lets keep the code simple and just define in what we need to use.
34  */
35 #ifdef CONFIG_CPU_HAS_ADDRESS_SPACES
36 #define MOVES   "moves"
37 #else
38 #define MOVES   "move"
39 #endif
40
41 #define __put_user_asm(inst, res, x, ptr, bwl, reg, err) \
42 asm volatile ("\n"                                      \
43         "1:     "inst"."#bwl"   %2,%1\n"                \
44         "2:\n"                                          \
45         "       .section .fixup,\"ax\"\n"               \
46         "       .even\n"                                \
47         "10:    moveq.l %3,%0\n"                        \
48         "       jra 2b\n"                               \
49         "       .previous\n"                            \
50         "\n"                                            \
51         "       .section __ex_table,\"a\"\n"            \
52         "       .align  4\n"                            \
53         "       .long   1b,10b\n"                       \
54         "       .long   2b,10b\n"                       \
55         "       .previous"                              \
56         : "+d" (res), "=m" (*(ptr))                     \
57         : #reg (x), "i" (err))
58
59 #define __put_user_asm8(inst, res, x, ptr)                      \
60 do {                                                            \
61         const void *__pu_ptr = (const void __force *)(ptr);     \
62                                                                 \
63         asm volatile ("\n"                                      \
64                 "1:     "inst".l %2,(%1)+\n"                    \
65                 "2:     "inst".l %R2,(%1)\n"                    \
66                 "3:\n"                                          \
67                 "       .section .fixup,\"ax\"\n"               \
68                 "       .even\n"                                \
69                 "10:    movel %3,%0\n"                          \
70                 "       jra 3b\n"                               \
71                 "       .previous\n"                            \
72                 "\n"                                            \
73                 "       .section __ex_table,\"a\"\n"            \
74                 "       .align 4\n"                             \
75                 "       .long 1b,10b\n"                         \
76                 "       .long 2b,10b\n"                         \
77                 "       .long 3b,10b\n"                         \
78                 "       .previous"                              \
79                 : "+d" (res), "+a" (__pu_ptr)                   \
80                 : "r" (x), "i" (-EFAULT)                        \
81                 : "memory");                                    \
82 } while (0)
83
84 /*
85  * These are the main single-value transfer routines.  They automatically
86  * use the right size if we just have the right pointer type.
87  */
88
89 #define __put_user(x, ptr)                                              \
90 ({                                                                      \
91         typeof(*(ptr)) __pu_val = (x);                                  \
92         int __pu_err = 0;                                               \
93         __chk_user_ptr(ptr);                                            \
94         switch (sizeof (*(ptr))) {                                      \
95         case 1:                                                         \
96                 __put_user_asm(MOVES, __pu_err, __pu_val, ptr, b, d, -EFAULT); \
97                 break;                                                  \
98         case 2:                                                         \
99                 __put_user_asm(MOVES, __pu_err, __pu_val, ptr, w, r, -EFAULT); \
100                 break;                                                  \
101         case 4:                                                         \
102                 __put_user_asm(MOVES, __pu_err, __pu_val, ptr, l, r, -EFAULT); \
103                 break;                                                  \
104         case 8:                                                         \
105                 __put_user_asm8(MOVES, __pu_err, __pu_val, ptr);        \
106                 break;                                                  \
107         default:                                                        \
108                 BUILD_BUG();                                            \
109         }                                                               \
110         __pu_err;                                                       \
111 })
112 #define put_user(x, ptr)        __put_user(x, ptr)
113
114
115 #define __get_user_asm(inst, res, x, ptr, type, bwl, reg, err) ({       \
116         type __gu_val;                                                  \
117         asm volatile ("\n"                                              \
118                 "1:     "inst"."#bwl"   %2,%1\n"                        \
119                 "2:\n"                                                  \
120                 "       .section .fixup,\"ax\"\n"                       \
121                 "       .even\n"                                        \
122                 "10:    move.l  %3,%0\n"                                \
123                 "       sub.l   %1,%1\n"                                \
124                 "       jra     2b\n"                                   \
125                 "       .previous\n"                                    \
126                 "\n"                                                    \
127                 "       .section __ex_table,\"a\"\n"                    \
128                 "       .align  4\n"                                    \
129                 "       .long   1b,10b\n"                               \
130                 "       .previous"                                      \
131                 : "+d" (res), "=&" #reg (__gu_val)                      \
132                 : "m" (*(ptr)), "i" (err));                             \
133         (x) = (__force typeof(*(ptr)))(__force unsigned long)__gu_val;  \
134 })
135
136 #define __get_user_asm8(inst, res, x, ptr)                              \
137 do {                                                                    \
138         const void *__gu_ptr = (const void __force *)(ptr);             \
139         union {                                                         \
140                 u64 l;                                                  \
141                 __typeof__(*(ptr)) t;                                   \
142         } __gu_val;                                                     \
143                                                                         \
144         asm volatile ("\n"                                              \
145                 "1:     "inst".l (%2)+,%1\n"                            \
146                 "2:     "inst".l (%2),%R1\n"                            \
147                 "3:\n"                                                  \
148                 "       .section .fixup,\"ax\"\n"                       \
149                 "       .even\n"                                        \
150                 "10:    move.l  %3,%0\n"                                \
151                 "       sub.l   %1,%1\n"                                \
152                 "       sub.l   %R1,%R1\n"                              \
153                 "       jra     3b\n"                                   \
154                 "       .previous\n"                                    \
155                 "\n"                                                    \
156                 "       .section __ex_table,\"a\"\n"                    \
157                 "       .align  4\n"                                    \
158                 "       .long   1b,10b\n"                               \
159                 "       .long   2b,10b\n"                               \
160                 "       .previous"                                      \
161                 : "+d" (res), "=&r" (__gu_val.l),                       \
162                   "+a" (__gu_ptr)                                       \
163                 : "i" (-EFAULT)                                         \
164                 : "memory");                                            \
165         (x) = __gu_val.t;                                               \
166 } while (0)
167
168 #define __get_user(x, ptr)                                              \
169 ({                                                                      \
170         int __gu_err = 0;                                               \
171         __chk_user_ptr(ptr);                                            \
172         switch (sizeof(*(ptr))) {                                       \
173         case 1:                                                         \
174                 __get_user_asm(MOVES, __gu_err, x, ptr, u8, b, d, -EFAULT); \
175                 break;                                                  \
176         case 2:                                                         \
177                 __get_user_asm(MOVES, __gu_err, x, ptr, u16, w, r, -EFAULT); \
178                 break;                                                  \
179         case 4:                                                         \
180                 __get_user_asm(MOVES, __gu_err, x, ptr, u32, l, r, -EFAULT); \
181                 break;                                                  \
182         case 8:                                                         \
183                 __get_user_asm8(MOVES, __gu_err, x, ptr);               \
184                 break;                                                  \
185         default:                                                        \
186                 BUILD_BUG();                                            \
187         }                                                               \
188         __gu_err;                                                       \
189 })
190 #define get_user(x, ptr) __get_user(x, ptr)
191
192 unsigned long __generic_copy_from_user(void *to, const void __user *from, unsigned long n);
193 unsigned long __generic_copy_to_user(void __user *to, const void *from, unsigned long n);
194
195 #define __suffix0
196 #define __suffix1 b
197 #define __suffix2 w
198 #define __suffix4 l
199
200 #define ____constant_copy_from_user_asm(res, to, from, tmp, n1, n2, n3, s1, s2, s3)\
201         asm volatile ("\n"                                              \
202                 "1:     "MOVES"."#s1"   (%2)+,%3\n"                     \
203                 "       move."#s1"      %3,(%1)+\n"                     \
204                 "       .ifnc   \""#s2"\",\"\"\n"                       \
205                 "2:     "MOVES"."#s2"   (%2)+,%3\n"                     \
206                 "       move."#s2"      %3,(%1)+\n"                     \
207                 "       .ifnc   \""#s3"\",\"\"\n"                       \
208                 "3:     "MOVES"."#s3"   (%2)+,%3\n"                     \
209                 "       move."#s3"      %3,(%1)+\n"                     \
210                 "       .endif\n"                                       \
211                 "       .endif\n"                                       \
212                 "4:\n"                                                  \
213                 "       .section __ex_table,\"a\"\n"                    \
214                 "       .align  4\n"                                    \
215                 "       .long   1b,10f\n"                               \
216                 "       .ifnc   \""#s2"\",\"\"\n"                       \
217                 "       .long   2b,20f\n"                               \
218                 "       .ifnc   \""#s3"\",\"\"\n"                       \
219                 "       .long   3b,30f\n"                               \
220                 "       .endif\n"                                       \
221                 "       .endif\n"                                       \
222                 "       .previous\n"                                    \
223                 "\n"                                                    \
224                 "       .section .fixup,\"ax\"\n"                       \
225                 "       .even\n"                                        \
226                 "10:    addq.l #"#n1",%0\n"                             \
227                 "       .ifnc   \""#s2"\",\"\"\n"                       \
228                 "20:    addq.l #"#n2",%0\n"                             \
229                 "       .ifnc   \""#s3"\",\"\"\n"                       \
230                 "30:    addq.l #"#n3",%0\n"                             \
231                 "       .endif\n"                                       \
232                 "       .endif\n"                                       \
233                 "       jra     4b\n"                                   \
234                 "       .previous\n"                                    \
235                 : "+d" (res), "+&a" (to), "+a" (from), "=&d" (tmp)      \
236                 : : "memory")
237
238 #define ___constant_copy_from_user_asm(res, to, from, tmp, n1, n2, n3, s1, s2, s3)\
239         ____constant_copy_from_user_asm(res, to, from, tmp, n1, n2, n3, s1, s2, s3)
240 #define __constant_copy_from_user_asm(res, to, from, tmp, n1, n2, n3)   \
241         ___constant_copy_from_user_asm(res, to, from, tmp, n1, n2, n3,  \
242                                         __suffix##n1, __suffix##n2, __suffix##n3)
243
244 static __always_inline unsigned long
245 __constant_copy_from_user(void *to, const void __user *from, unsigned long n)
246 {
247         unsigned long res = 0, tmp;
248
249         switch (n) {
250         case 1:
251                 __constant_copy_from_user_asm(res, to, from, tmp, 1, 0, 0);
252                 break;
253         case 2:
254                 __constant_copy_from_user_asm(res, to, from, tmp, 2, 0, 0);
255                 break;
256         case 3:
257                 __constant_copy_from_user_asm(res, to, from, tmp, 2, 1, 0);
258                 break;
259         case 4:
260                 __constant_copy_from_user_asm(res, to, from, tmp, 4, 0, 0);
261                 break;
262         case 5:
263                 __constant_copy_from_user_asm(res, to, from, tmp, 4, 1, 0);
264                 break;
265         case 6:
266                 __constant_copy_from_user_asm(res, to, from, tmp, 4, 2, 0);
267                 break;
268         case 7:
269                 __constant_copy_from_user_asm(res, to, from, tmp, 4, 2, 1);
270                 break;
271         case 8:
272                 __constant_copy_from_user_asm(res, to, from, tmp, 4, 4, 0);
273                 break;
274         case 9:
275                 __constant_copy_from_user_asm(res, to, from, tmp, 4, 4, 1);
276                 break;
277         case 10:
278                 __constant_copy_from_user_asm(res, to, from, tmp, 4, 4, 2);
279                 break;
280         case 12:
281                 __constant_copy_from_user_asm(res, to, from, tmp, 4, 4, 4);
282                 break;
283         default:
284                 /* we limit the inlined version to 3 moves */
285                 return __generic_copy_from_user(to, from, n);
286         }
287
288         return res;
289 }
290
291 #define __constant_copy_to_user_asm(res, to, from, tmp, n, s1, s2, s3)  \
292         asm volatile ("\n"                                              \
293                 "       move."#s1"      (%2)+,%3\n"                     \
294                 "11:    "MOVES"."#s1"   %3,(%1)+\n"                     \
295                 "12:    move."#s2"      (%2)+,%3\n"                     \
296                 "21:    "MOVES"."#s2"   %3,(%1)+\n"                     \
297                 "22:\n"                                                 \
298                 "       .ifnc   \""#s3"\",\"\"\n"                       \
299                 "       move."#s3"      (%2)+,%3\n"                     \
300                 "31:    "MOVES"."#s3"   %3,(%1)+\n"                     \
301                 "32:\n"                                                 \
302                 "       .endif\n"                                       \
303                 "4:\n"                                                  \
304                 "\n"                                                    \
305                 "       .section __ex_table,\"a\"\n"                    \
306                 "       .align  4\n"                                    \
307                 "       .long   11b,5f\n"                               \
308                 "       .long   12b,5f\n"                               \
309                 "       .long   21b,5f\n"                               \
310                 "       .long   22b,5f\n"                               \
311                 "       .ifnc   \""#s3"\",\"\"\n"                       \
312                 "       .long   31b,5f\n"                               \
313                 "       .long   32b,5f\n"                               \
314                 "       .endif\n"                                       \
315                 "       .previous\n"                                    \
316                 "\n"                                                    \
317                 "       .section .fixup,\"ax\"\n"                       \
318                 "       .even\n"                                        \
319                 "5:     moveq.l #"#n",%0\n"                             \
320                 "       jra     4b\n"                                   \
321                 "       .previous\n"                                    \
322                 : "+d" (res), "+a" (to), "+a" (from), "=&d" (tmp)       \
323                 : : "memory")
324
325 static __always_inline unsigned long
326 __constant_copy_to_user(void __user *to, const void *from, unsigned long n)
327 {
328         unsigned long res = 0, tmp;
329
330         switch (n) {
331         case 1:
332                 __put_user_asm(MOVES, res, *(u8 *)from, (u8 __user *)to,
333                                 b, d, 1);
334                 break;
335         case 2:
336                 __put_user_asm(MOVES, res, *(u16 *)from, (u16 __user *)to,
337                                 w, r, 2);
338                 break;
339         case 3:
340                 __constant_copy_to_user_asm(res, to, from, tmp, 3, w, b,);
341                 break;
342         case 4:
343                 __put_user_asm(MOVES, res, *(u32 *)from, (u32 __user *)to,
344                                 l, r, 4);
345                 break;
346         case 5:
347                 __constant_copy_to_user_asm(res, to, from, tmp, 5, l, b,);
348                 break;
349         case 6:
350                 __constant_copy_to_user_asm(res, to, from, tmp, 6, l, w,);
351                 break;
352         case 7:
353                 __constant_copy_to_user_asm(res, to, from, tmp, 7, l, w, b);
354                 break;
355         case 8:
356                 __constant_copy_to_user_asm(res, to, from, tmp, 8, l, l,);
357                 break;
358         case 9:
359                 __constant_copy_to_user_asm(res, to, from, tmp, 9, l, l, b);
360                 break;
361         case 10:
362                 __constant_copy_to_user_asm(res, to, from, tmp, 10, l, l, w);
363                 break;
364         case 12:
365                 __constant_copy_to_user_asm(res, to, from, tmp, 12, l, l, l);
366                 break;
367         default:
368                 /* limit the inlined version to 3 moves */
369                 return __generic_copy_to_user(to, from, n);
370         }
371
372         return res;
373 }
374
375 static inline unsigned long
376 raw_copy_from_user(void *to, const void __user *from, unsigned long n)
377 {
378         if (__builtin_constant_p(n))
379                 return __constant_copy_from_user(to, from, n);
380         return __generic_copy_from_user(to, from, n);
381 }
382
383 static inline unsigned long
384 raw_copy_to_user(void __user *to, const void *from, unsigned long n)
385 {
386         if (__builtin_constant_p(n))
387                 return __constant_copy_to_user(to, from, n);
388         return __generic_copy_to_user(to, from, n);
389 }
390 #define INLINE_COPY_FROM_USER
391 #define INLINE_COPY_TO_USER
392
393 #define HAVE_GET_KERNEL_NOFAULT
394
395 #define __get_kernel_nofault(dst, src, type, err_label)                 \
396 do {                                                                    \
397         type *__gk_dst = (type *)(dst);                                 \
398         type *__gk_src = (type *)(src);                                 \
399         int __gk_err = 0;                                               \
400                                                                         \
401         switch (sizeof(type)) {                                         \
402         case 1:                                                         \
403                 __get_user_asm("move", __gk_err, *__gk_dst, __gk_src,   \
404                                 u8, b, d, -EFAULT);                     \
405                 break;                                                  \
406         case 2:                                                         \
407                 __get_user_asm("move", __gk_err, *__gk_dst, __gk_src,   \
408                                 u16, w, r, -EFAULT);                    \
409                 break;                                                  \
410         case 4:                                                         \
411                 __get_user_asm("move", __gk_err, *__gk_dst, __gk_src,   \
412                                 u32, l, r, -EFAULT);                    \
413                 break;                                                  \
414         case 8:                                                         \
415                 __get_user_asm8("move", __gk_err, *__gk_dst, __gk_src); \
416                 break;                                                  \
417         default:                                                        \
418                 BUILD_BUG();                                            \
419         }                                                               \
420         if (unlikely(__gk_err))                                         \
421                 goto err_label;                                         \
422 } while (0)
423
424 #define __put_kernel_nofault(dst, src, type, err_label)                 \
425 do {                                                                    \
426         type __pk_src = *(type *)(src);                                 \
427         type *__pk_dst = (type *)(dst);                                 \
428         int __pk_err = 0;                                               \
429                                                                         \
430         switch (sizeof(type)) {                                         \
431         case 1:                                                         \
432                 __put_user_asm("move", __pk_err, __pk_src, __pk_dst,    \
433                                 b, d, -EFAULT);                         \
434                 break;                                                  \
435         case 2:                                                         \
436                 __put_user_asm("move", __pk_err, __pk_src, __pk_dst,    \
437                                 w, r, -EFAULT);                         \
438                 break;                                                  \
439         case 4:                                                         \
440                 __put_user_asm("move", __pk_err, __pk_src, __pk_dst,    \
441                                 l, r, -EFAULT);                         \
442                 break;                                                  \
443         case 8:                                                         \
444                 __put_user_asm8("move", __pk_err, __pk_src, __pk_dst);  \
445                 break;                                                  \
446         default:                                                        \
447                 BUILD_BUG();                                            \
448         }                                                               \
449         if (unlikely(__pk_err))                                         \
450                 goto err_label;                                         \
451 } while (0)
452
453 extern long strncpy_from_user(char *dst, const char __user *src, long count);
454 extern __must_check long strnlen_user(const char __user *str, long n);
455
456 unsigned long __clear_user(void __user *to, unsigned long n);
457
458 #define clear_user      __clear_user
459
460 #else /* !CONFIG_MMU */
461 #include <asm-generic/uaccess.h>
462 #endif
463
464 #endif /* _M68K_UACCESS_H */