1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
4 * Copyright (C) 2008-2009 PetaLogix
5 * Copyright (C) 2006 Atmark Techno, Inc.
6 */
7
8#ifndef _ASM_MICROBLAZE_UACCESS_H
9#define _ASM_MICROBLAZE_UACCESS_H
10
11#include <linux/kernel.h>
12
13#include <asm/mmu.h>
14#include <asm/page.h>
15#include <linux/pgtable.h>
16#include <asm/extable.h>
17#include <linux/string.h>
18
19/*
20 * On Microblaze the fs value is actually the top of the corresponding
21 * address space.
22 *
23 * The fs value determines whether argument validity checking should be
24 * performed or not. If get_fs() == USER_DS, checking is performed, with
25 * get_fs() == KERNEL_DS, checking is bypassed.
26 *
27 * For historical reasons, these macros are grossly misnamed.
28 *
29 * For non-MMU arch like Microblaze, KERNEL_DS and USER_DS is equal.
30 */
31# define MAKE_MM_SEG(s)       ((mm_segment_t) { (s) })
32
33#  ifndef CONFIG_MMU
34#  define KERNEL_DS	MAKE_MM_SEG(0)
35#  define USER_DS	KERNEL_DS
36#  else
37#  define KERNEL_DS	MAKE_MM_SEG(0xFFFFFFFF)
38#  define USER_DS	MAKE_MM_SEG(TASK_SIZE - 1)
39#  endif
40
41# define get_fs()	(current_thread_info()->addr_limit)
42# define set_fs(val)	(current_thread_info()->addr_limit = (val))
43
44# define uaccess_kernel()	(get_fs().seg == KERNEL_DS.seg)
45
46#ifndef CONFIG_MMU
47
48/* Check against bounds of physical memory */
49static inline int ___range_ok(unsigned long addr, unsigned long size)
50{
51	return ((addr < memory_start) ||
52		((addr + size - 1) > (memory_start + memory_size - 1)));
53}
54
55#define __range_ok(addr, size) \
56		___range_ok((unsigned long)(addr), (unsigned long)(size))
57
58#define access_ok(addr, size) (__range_ok((addr), (size)) == 0)
59
60#else
61
62static inline int access_ok(const void __user *addr, unsigned long size)
63{
64	if (!size)
65		goto ok;
66
67	if ((get_fs().seg < ((unsigned long)addr)) ||
68			(get_fs().seg < ((unsigned long)addr + size - 1))) {
69		pr_devel("ACCESS fail at 0x%08x (size 0x%x), seg 0x%08x\n",
70			(__force u32)addr, (u32)size,
71			(u32)get_fs().seg);
72		return 0;
73	}
74ok:
75	pr_devel("ACCESS OK at 0x%08x (size 0x%x), seg 0x%08x\n",
76			(__force u32)addr, (u32)size,
77			(u32)get_fs().seg);
78	return 1;
79}
80#endif
81
82#ifdef CONFIG_MMU
83# define __FIXUP_SECTION	".section .fixup,\"ax\"\n"
84# define __EX_TABLE_SECTION	".section __ex_table,\"a\"\n"
85#else
86# define __FIXUP_SECTION	".section .discard,\"ax\"\n"
87# define __EX_TABLE_SECTION	".section .discard,\"ax\"\n"
88#endif
89
90extern unsigned long __copy_tofrom_user(void __user *to,
91		const void __user *from, unsigned long size);
92
93/* Return: number of not copied bytes, i.e. 0 if OK or non-zero if fail. */
94static inline unsigned long __must_check __clear_user(void __user *to,
95							unsigned long n)
96{
97	/* normal memset with two words to __ex_table */
98	__asm__ __volatile__ (				\
99			"1:	sb	r0, %1, r0;"	\
100			"	addik	%0, %0, -1;"	\
101			"	bneid	%0, 1b;"	\
102			"	addik	%1, %1, 1;"	\
103			"2:			"	\
104			__EX_TABLE_SECTION		\
105			".word	1b,2b;"			\
106			".previous;"			\
107		: "=r"(n), "=r"(to)			\
108		: "0"(n), "1"(to)
109	);
110	return n;
111}
112
113static inline unsigned long __must_check clear_user(void __user *to,
114							unsigned long n)
115{
116	might_fault();
117	if (unlikely(!access_ok(to, n)))
118		return n;
119
120	return __clear_user(to, n);
121}
122
123/* put_user and get_user macros */
124extern long __user_bad(void);
125
126#define __get_user_asm(insn, __gu_ptr, __gu_val, __gu_err)	\
127({								\
128	__asm__ __volatile__ (					\
129			"1:"	insn	" %1, %2, r0;"		\
130			"	addk	%0, r0, r0;"		\
131			"2:			"		\
132			__FIXUP_SECTION				\
133			"3:	brid	2b;"			\
134			"	addik	%0, r0, %3;"		\
135			".previous;"				\
136			__EX_TABLE_SECTION			\
137			".word	1b,3b;"				\
138			".previous;"				\
139		: "=&r"(__gu_err), "=r"(__gu_val)		\
140		: "r"(__gu_ptr), "i"(-EFAULT)			\
141	);							\
142})
143
144/**
145 * get_user: - Get a simple variable from user space.
146 * @x:   Variable to store result.
147 * @ptr: Source address, in user space.
148 *
149 * Context: User context only. This function may sleep if pagefaults are
150 *          enabled.
151 *
152 * This macro copies a single simple variable from user space to kernel
153 * space.  It supports simple types like char and int, but not larger
154 * data types like structures or arrays.
155 *
156 * @ptr must have pointer-to-simple-variable type, and the result of
157 * dereferencing @ptr must be assignable to @x without a cast.
158 *
159 * Returns zero on success, or -EFAULT on error.
160 * On error, the variable @x is set to zero.
161 */
162#define get_user(x, ptr) ({				\
163	const typeof(*(ptr)) __user *__gu_ptr = (ptr);	\
164	access_ok(__gu_ptr, sizeof(*__gu_ptr)) ?	\
165		__get_user(x, __gu_ptr) : -EFAULT;	\
166})
167
168#define __get_user(x, ptr)						\
169({									\
170	long __gu_err;							\
171	switch (sizeof(*(ptr))) {					\
172	case 1:								\
173		__get_user_asm("lbu", (ptr), x, __gu_err);		\
174		break;							\
175	case 2:								\
176		__get_user_asm("lhu", (ptr), x, __gu_err);		\
177		break;							\
178	case 4:								\
179		__get_user_asm("lw", (ptr), x, __gu_err);		\
180		break;							\
181	case 8: {							\
182		__u64 __x = 0;						\
183		__gu_err = raw_copy_from_user(&__x, ptr, 8) ?		\
184							-EFAULT : 0;	\
185		(x) = (typeof(x))(typeof((x) - (x)))__x;		\
186		break;							\
187	}								\
188	default:							\
189		/* __gu_val = 0; __gu_err = -EINVAL;*/ __gu_err = __user_bad();\
190	}								\
191	__gu_err;							\
192})
193
194
195#define __put_user_asm(insn, __gu_ptr, __gu_val, __gu_err)	\
196({								\
197	__asm__ __volatile__ (					\
198			"1:"	insn	" %1, %2, r0;"		\
199			"	addk	%0, r0, r0;"		\
200			"2:			"		\
201			__FIXUP_SECTION				\
202			"3:	brid	2b;"			\
203			"	addik	%0, r0, %3;"		\
204			".previous;"				\
205			__EX_TABLE_SECTION			\
206			".word	1b,3b;"				\
207			".previous;"				\
208		: "=&r"(__gu_err)				\
209		: "r"(__gu_val), "r"(__gu_ptr), "i"(-EFAULT)	\
210	);							\
211})
212
213#define __put_user_asm_8(__gu_ptr, __gu_val, __gu_err)		\
214({								\
215	__asm__ __volatile__ ("	lwi	%0, %1, 0;"		\
216			"1:	swi	%0, %2, 0;"		\
217			"	lwi	%0, %1, 4;"		\
218			"2:	swi	%0, %2, 4;"		\
219			"	addk	%0, r0, r0;"		\
220			"3:			"		\
221			__FIXUP_SECTION				\
222			"4:	brid	3b;"			\
223			"	addik	%0, r0, %3;"		\
224			".previous;"				\
225			__EX_TABLE_SECTION			\
226			".word	1b,4b,2b,4b;"			\
227			".previous;"				\
228		: "=&r"(__gu_err)				\
229		: "r"(&__gu_val), "r"(__gu_ptr), "i"(-EFAULT)	\
230		);						\
231})
232
233/**
234 * put_user: - Write a simple value into user space.
235 * @x:   Value to copy to user space.
236 * @ptr: Destination address, in user space.
237 *
238 * Context: User context only. This function may sleep if pagefaults are
239 *          enabled.
240 *
241 * This macro copies a single simple value from kernel space to user
242 * space.  It supports simple types like char and int, but not larger
243 * data types like structures or arrays.
244 *
245 * @ptr must have pointer-to-simple-variable type, and @x must be assignable
246 * to the result of dereferencing @ptr.
247 *
248 * Returns zero on success, or -EFAULT on error.
249 */
250#define put_user(x, ptr)						\
251	__put_user_check((x), (ptr), sizeof(*(ptr)))
252
253#define __put_user_check(x, ptr, size)					\
254({									\
255	typeof(*(ptr)) volatile __pu_val = x;				\
256	typeof(*(ptr)) __user *__pu_addr = (ptr);			\
257	int __pu_err = 0;						\
258									\
259	if (access_ok(__pu_addr, size)) {			\
260		switch (size) {						\
261		case 1:							\
262			__put_user_asm("sb", __pu_addr, __pu_val,	\
263				       __pu_err);			\
264			break;						\
265		case 2:							\
266			__put_user_asm("sh", __pu_addr, __pu_val,	\
267				       __pu_err);			\
268			break;						\
269		case 4:							\
270			__put_user_asm("sw", __pu_addr, __pu_val,	\
271				       __pu_err);			\
272			break;						\
273		case 8:							\
274			__put_user_asm_8(__pu_addr, __pu_val, __pu_err);\
275			break;						\
276		default:						\
277			__pu_err = __user_bad();			\
278			break;						\
279		}							\
280	} else {							\
281		__pu_err = -EFAULT;					\
282	}								\
283	__pu_err;							\
284})
285
286#define __put_user(x, ptr)						\
287({									\
288	__typeof__(*(ptr)) volatile __gu_val = (x);			\
289	long __gu_err = 0;						\
290	switch (sizeof(__gu_val)) {					\
291	case 1:								\
292		__put_user_asm("sb", (ptr), __gu_val, __gu_err);	\
293		break;							\
294	case 2:								\
295		__put_user_asm("sh", (ptr), __gu_val, __gu_err);	\
296		break;							\
297	case 4:								\
298		__put_user_asm("sw", (ptr), __gu_val, __gu_err);	\
299		break;							\
300	case 8:								\
301		__put_user_asm_8((ptr), __gu_val, __gu_err);		\
302		break;							\
303	default:							\
304		/*__gu_err = -EINVAL;*/	__gu_err = __user_bad();	\
305	}								\
306	__gu_err;							\
307})
308
309static inline unsigned long
310raw_copy_from_user(void *to, const void __user *from, unsigned long n)
311{
312	return __copy_tofrom_user((__force void __user *)to, from, n);
313}
314
315static inline unsigned long
316raw_copy_to_user(void __user *to, const void *from, unsigned long n)
317{
318	return __copy_tofrom_user(to, (__force const void __user *)from, n);
319}
320#define INLINE_COPY_FROM_USER
321#define INLINE_COPY_TO_USER
322
323/*
324 * Copy a null terminated string from userspace.
325 */
326extern int __strncpy_user(char *to, const char __user *from, int len);
327
328static inline long
329strncpy_from_user(char *dst, const char __user *src, long count)
330{
331	if (!access_ok(src, 1))
332		return -EFAULT;
333	return __strncpy_user(dst, src, count);
334}
335
336/*
337 * Return the size of a string (including the ending 0)
338 *
339 * Return 0 on exception, a value greater than N if too long
340 */
341extern int __strnlen_user(const char __user *sstr, int len);
342
343static inline long strnlen_user(const char __user *src, long n)
344{
345	if (!access_ok(src, 1))
346		return 0;
347	return __strnlen_user(src, n);
348}
349
350#endif /* _ASM_MICROBLAZE_UACCESS_H */
351