]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - arch/m68k/include/asm/uaccess.h
Merge tag 'efi-urgent-for-v5.15' of git://git.kernel.org/pub/scm/linux/kernel/git...
[mirror_ubuntu-jammy-kernel.git] / arch / m68k / include / asm / uaccess.h
CommitLineData
b2441318 1/* SPDX-License-Identifier: GPL-2.0 */
a27bc11f
GU
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>
a27bc11f
GU
12#include <asm/extable.h>
13
14/* We let the MMU do all checking */
15static inline int access_ok(const void __user *addr,
16 unsigned long size)
17{
1dc4027b
CH
18 /*
19 * XXX: for !CONFIG_CPU_HAS_ADDRESS_SPACES this really needs to check
20 * for TASK_SIZE!
21 */
a27bc11f
GU
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"
49148020 37#else
a27bc11f 38#define MOVES "move"
49148020 39#endif
a27bc11f 40
8ade8339 41#define __put_user_asm(inst, res, x, ptr, bwl, reg, err) \
a27bc11f 42asm volatile ("\n" \
8ade8339 43 "1: "inst"."#bwl" %2,%1\n" \
a27bc11f
GU
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
8ade8339 59#define __put_user_asm8(inst, res, x, ptr) \
01eec1af
CH
60do { \
61 const void *__pu_ptr = (const void __force *)(ptr); \
62 \
63 asm volatile ("\n" \
8ade8339
CH
64 "1: "inst".l %2,(%1)+\n" \
65 "2: "inst".l %R2,(%1)\n" \
01eec1af
CH
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
a27bc11f
GU
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: \
8ade8339 96 __put_user_asm(MOVES, __pu_err, __pu_val, ptr, b, d, -EFAULT); \
a27bc11f
GU
97 break; \
98 case 2: \
8ade8339 99 __put_user_asm(MOVES, __pu_err, __pu_val, ptr, w, r, -EFAULT); \
a27bc11f
GU
100 break; \
101 case 4: \
8ade8339 102 __put_user_asm(MOVES, __pu_err, __pu_val, ptr, l, r, -EFAULT); \
a27bc11f
GU
103 break; \
104 case 8: \
8ade8339 105 __put_user_asm8(MOVES, __pu_err, __pu_val, ptr); \
a27bc11f 106 break; \
a27bc11f 107 default: \
25d2cae4 108 BUILD_BUG(); \
a27bc11f
GU
109 } \
110 __pu_err; \
111})
112#define put_user(x, ptr) __put_user(x, ptr)
113
114
8ade8339 115#define __get_user_asm(inst, res, x, ptr, type, bwl, reg, err) ({ \
a27bc11f
GU
116 type __gu_val; \
117 asm volatile ("\n" \
8ade8339 118 "1: "inst"."#bwl" %2,%1\n" \
a27bc11f
GU
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
8ade8339 136#define __get_user_asm8(inst, res, x, ptr) \
01eec1af
CH
137do { \
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" \
8ade8339
CH
145 "1: "inst".l (%2)+,%1\n" \
146 "2: "inst".l (%2),%R1\n" \
01eec1af
CH
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
a27bc11f
GU
168#define __get_user(x, ptr) \
169({ \
170 int __gu_err = 0; \
171 __chk_user_ptr(ptr); \
172 switch (sizeof(*(ptr))) { \
173 case 1: \
8ade8339 174 __get_user_asm(MOVES, __gu_err, x, ptr, u8, b, d, -EFAULT); \
a27bc11f
GU
175 break; \
176 case 2: \
8ade8339 177 __get_user_asm(MOVES, __gu_err, x, ptr, u16, w, r, -EFAULT); \
a27bc11f
GU
178 break; \
179 case 4: \
8ade8339 180 __get_user_asm(MOVES, __gu_err, x, ptr, u32, l, r, -EFAULT); \
a27bc11f 181 break; \
01eec1af 182 case 8: \
8ade8339 183 __get_user_asm8(MOVES, __gu_err, x, ptr); \
a27bc11f 184 break; \
a27bc11f 185 default: \
25d2cae4 186 BUILD_BUG(); \
a27bc11f
GU
187 } \
188 __gu_err; \
189})
190#define get_user(x, ptr) __get_user(x, ptr)
191
192unsigned long __generic_copy_from_user(void *to, const void __user *from, unsigned long n);
193unsigned 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
244static __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
325static __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:
8ade8339
CH
332 __put_user_asm(MOVES, res, *(u8 *)from, (u8 __user *)to,
333 b, d, 1);
a27bc11f
GU
334 break;
335 case 2:
8ade8339
CH
336 __put_user_asm(MOVES, res, *(u16 *)from, (u16 __user *)to,
337 w, r, 2);
a27bc11f
GU
338 break;
339 case 3:
340 __constant_copy_to_user_asm(res, to, from, tmp, 3, w, b,);
341 break;
342 case 4:
8ade8339
CH
343 __put_user_asm(MOVES, res, *(u32 *)from, (u32 __user *)to,
344 l, r, 4);
a27bc11f
GU
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
375static inline unsigned long
376raw_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
383static inline unsigned long
384raw_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
8ade8339
CH
393#define HAVE_GET_KERNEL_NOFAULT
394
395#define __get_kernel_nofault(dst, src, type, err_label) \
396do { \
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) \
425do { \
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
a27bc11f
GU
453extern long strncpy_from_user(char *dst, const char __user *src, long count);
454extern __must_check long strnlen_user(const char __user *str, long n);
455
456unsigned 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 */