xref: /openbmc/linux/arch/m68k/include/asm/uaccess.h (revision 901181b7)
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 */
465