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 #  define KERNEL_DS	MAKE_MM_SEG(0xFFFFFFFF)
34 #  define USER_DS	MAKE_MM_SEG(TASK_SIZE - 1)
35 
36 # define get_fs()	(current_thread_info()->addr_limit)
37 # define set_fs(val)	(current_thread_info()->addr_limit = (val))
38 # define user_addr_max() get_fs().seg
39 
40 # define uaccess_kernel()	(get_fs().seg == KERNEL_DS.seg)
41 
42 static inline int access_ok(const void __user *addr, unsigned long size)
43 {
44 	if (!size)
45 		goto ok;
46 
47 	if ((get_fs().seg < ((unsigned long)addr)) ||
48 			(get_fs().seg < ((unsigned long)addr + size - 1))) {
49 		pr_devel("ACCESS fail at 0x%08x (size 0x%x), seg 0x%08x\n",
50 			(__force u32)addr, (u32)size,
51 			(u32)get_fs().seg);
52 		return 0;
53 	}
54 ok:
55 	pr_devel("ACCESS OK at 0x%08x (size 0x%x), seg 0x%08x\n",
56 			(__force u32)addr, (u32)size,
57 			(u32)get_fs().seg);
58 	return 1;
59 }
60 
61 # define __FIXUP_SECTION	".section .fixup,\"ax\"\n"
62 # define __EX_TABLE_SECTION	".section __ex_table,\"a\"\n"
63 
64 extern unsigned long __copy_tofrom_user(void __user *to,
65 		const void __user *from, unsigned long size);
66 
67 /* Return: number of not copied bytes, i.e. 0 if OK or non-zero if fail. */
68 static inline unsigned long __must_check __clear_user(void __user *to,
69 							unsigned long n)
70 {
71 	/* normal memset with two words to __ex_table */
72 	__asm__ __volatile__ (				\
73 			"1:	sb	r0, %1, r0;"	\
74 			"	addik	%0, %0, -1;"	\
75 			"	bneid	%0, 1b;"	\
76 			"	addik	%1, %1, 1;"	\
77 			"2:			"	\
78 			__EX_TABLE_SECTION		\
79 			".word	1b,2b;"			\
80 			".previous;"			\
81 		: "=r"(n), "=r"(to)			\
82 		: "0"(n), "1"(to)
83 	);
84 	return n;
85 }
86 
87 static inline unsigned long __must_check clear_user(void __user *to,
88 							unsigned long n)
89 {
90 	might_fault();
91 	if (unlikely(!access_ok(to, n)))
92 		return n;
93 
94 	return __clear_user(to, n);
95 }
96 
97 /* put_user and get_user macros */
98 extern long __user_bad(void);
99 
100 #define __get_user_asm(insn, __gu_ptr, __gu_val, __gu_err)	\
101 ({								\
102 	__asm__ __volatile__ (					\
103 			"1:"	insn	" %1, %2, r0;"		\
104 			"	addk	%0, r0, r0;"		\
105 			"2:			"		\
106 			__FIXUP_SECTION				\
107 			"3:	brid	2b;"			\
108 			"	addik	%0, r0, %3;"		\
109 			".previous;"				\
110 			__EX_TABLE_SECTION			\
111 			".word	1b,3b;"				\
112 			".previous;"				\
113 		: "=&r"(__gu_err), "=r"(__gu_val)		\
114 		: "r"(__gu_ptr), "i"(-EFAULT)			\
115 	);							\
116 })
117 
118 /**
119  * get_user: - Get a simple variable from user space.
120  * @x:   Variable to store result.
121  * @ptr: Source address, in user space.
122  *
123  * Context: User context only. This function may sleep if pagefaults are
124  *          enabled.
125  *
126  * This macro copies a single simple variable from user space to kernel
127  * space.  It supports simple types like char and int, but not larger
128  * data types like structures or arrays.
129  *
130  * @ptr must have pointer-to-simple-variable type, and the result of
131  * dereferencing @ptr must be assignable to @x without a cast.
132  *
133  * Returns zero on success, or -EFAULT on error.
134  * On error, the variable @x is set to zero.
135  */
136 #define get_user(x, ptr) ({				\
137 	const typeof(*(ptr)) __user *__gu_ptr = (ptr);	\
138 	access_ok(__gu_ptr, sizeof(*__gu_ptr)) ?	\
139 		__get_user(x, __gu_ptr) : -EFAULT;	\
140 })
141 
142 #define __get_user(x, ptr)						\
143 ({									\
144 	unsigned long __gu_val = 0;					\
145 	long __gu_err;							\
146 	switch (sizeof(*(ptr))) {					\
147 	case 1:								\
148 		__get_user_asm("lbu", (ptr), __gu_val, __gu_err);	\
149 		break;							\
150 	case 2:								\
151 		__get_user_asm("lhu", (ptr), __gu_val, __gu_err);	\
152 		break;							\
153 	case 4:								\
154 		__get_user_asm("lw", (ptr), __gu_val, __gu_err);	\
155 		break;							\
156 	case 8:								\
157 		__gu_err = __copy_from_user(&__gu_val, ptr, 8);		\
158 		if (__gu_err)						\
159 			__gu_err = -EFAULT;				\
160 		break;							\
161 	default:							\
162 		/* __gu_val = 0; __gu_err = -EINVAL;*/ __gu_err = __user_bad();\
163 	}								\
164 	x = (__force __typeof__(*(ptr))) __gu_val;			\
165 	__gu_err;							\
166 })
167 
168 
169 #define __put_user_asm(insn, __gu_ptr, __gu_val, __gu_err)	\
170 ({								\
171 	__asm__ __volatile__ (					\
172 			"1:"	insn	" %1, %2, r0;"		\
173 			"	addk	%0, r0, r0;"		\
174 			"2:			"		\
175 			__FIXUP_SECTION				\
176 			"3:	brid	2b;"			\
177 			"	addik	%0, r0, %3;"		\
178 			".previous;"				\
179 			__EX_TABLE_SECTION			\
180 			".word	1b,3b;"				\
181 			".previous;"				\
182 		: "=&r"(__gu_err)				\
183 		: "r"(__gu_val), "r"(__gu_ptr), "i"(-EFAULT)	\
184 	);							\
185 })
186 
187 #define __put_user_asm_8(__gu_ptr, __gu_val, __gu_err)		\
188 ({								\
189 	__asm__ __volatile__ ("	lwi	%0, %1, 0;"		\
190 			"1:	swi	%0, %2, 0;"		\
191 			"	lwi	%0, %1, 4;"		\
192 			"2:	swi	%0, %2, 4;"		\
193 			"	addk	%0, r0, r0;"		\
194 			"3:			"		\
195 			__FIXUP_SECTION				\
196 			"4:	brid	3b;"			\
197 			"	addik	%0, r0, %3;"		\
198 			".previous;"				\
199 			__EX_TABLE_SECTION			\
200 			".word	1b,4b,2b,4b;"			\
201 			".previous;"				\
202 		: "=&r"(__gu_err)				\
203 		: "r"(&__gu_val), "r"(__gu_ptr), "i"(-EFAULT)	\
204 		);						\
205 })
206 
207 /**
208  * put_user: - Write a simple value into user space.
209  * @x:   Value to copy to user space.
210  * @ptr: Destination address, in user space.
211  *
212  * Context: User context only. This function may sleep if pagefaults are
213  *          enabled.
214  *
215  * This macro copies a single simple value from kernel space to user
216  * space.  It supports simple types like char and int, but not larger
217  * data types like structures or arrays.
218  *
219  * @ptr must have pointer-to-simple-variable type, and @x must be assignable
220  * to the result of dereferencing @ptr.
221  *
222  * Returns zero on success, or -EFAULT on error.
223  */
224 #define put_user(x, ptr)						\
225 	__put_user_check((x), (ptr), sizeof(*(ptr)))
226 
227 #define __put_user_check(x, ptr, size)					\
228 ({									\
229 	typeof(*(ptr)) volatile __pu_val = x;				\
230 	typeof(*(ptr)) __user *__pu_addr = (ptr);			\
231 	int __pu_err = 0;						\
232 									\
233 	if (access_ok(__pu_addr, size)) {			\
234 		switch (size) {						\
235 		case 1:							\
236 			__put_user_asm("sb", __pu_addr, __pu_val,	\
237 				       __pu_err);			\
238 			break;						\
239 		case 2:							\
240 			__put_user_asm("sh", __pu_addr, __pu_val,	\
241 				       __pu_err);			\
242 			break;						\
243 		case 4:							\
244 			__put_user_asm("sw", __pu_addr, __pu_val,	\
245 				       __pu_err);			\
246 			break;						\
247 		case 8:							\
248 			__put_user_asm_8(__pu_addr, __pu_val, __pu_err);\
249 			break;						\
250 		default:						\
251 			__pu_err = __user_bad();			\
252 			break;						\
253 		}							\
254 	} else {							\
255 		__pu_err = -EFAULT;					\
256 	}								\
257 	__pu_err;							\
258 })
259 
260 #define __put_user(x, ptr)						\
261 ({									\
262 	__typeof__(*(ptr)) volatile __gu_val = (x);			\
263 	long __gu_err = 0;						\
264 	switch (sizeof(__gu_val)) {					\
265 	case 1:								\
266 		__put_user_asm("sb", (ptr), __gu_val, __gu_err);	\
267 		break;							\
268 	case 2:								\
269 		__put_user_asm("sh", (ptr), __gu_val, __gu_err);	\
270 		break;							\
271 	case 4:								\
272 		__put_user_asm("sw", (ptr), __gu_val, __gu_err);	\
273 		break;							\
274 	case 8:								\
275 		__put_user_asm_8((ptr), __gu_val, __gu_err);		\
276 		break;							\
277 	default:							\
278 		/*__gu_err = -EINVAL;*/	__gu_err = __user_bad();	\
279 	}								\
280 	__gu_err;							\
281 })
282 
283 static inline unsigned long
284 raw_copy_from_user(void *to, const void __user *from, unsigned long n)
285 {
286 	return __copy_tofrom_user((__force void __user *)to, from, n);
287 }
288 
289 static inline unsigned long
290 raw_copy_to_user(void __user *to, const void *from, unsigned long n)
291 {
292 	return __copy_tofrom_user(to, (__force const void __user *)from, n);
293 }
294 #define INLINE_COPY_FROM_USER
295 #define INLINE_COPY_TO_USER
296 
297 /*
298  * Copy a null terminated string from userspace.
299  */
300 __must_check long strncpy_from_user(char *dst, const char __user *src,
301 				    long count);
302 
303 /*
304  * Return the size of a string (including the ending 0)
305  *
306  * Return 0 on exception, a value greater than N if too long
307  */
308 __must_check long strnlen_user(const char __user *sstr, long len);
309 
310 #endif /* _ASM_MICROBLAZE_UACCESS_H */
311