Linux Audio

Check our new training course

Embedded Linux training

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