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
access_ok(const void __user * addr,unsigned long size)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. */
__clear_user(void __user * to,unsigned long n)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
clear_user(void __user * to,unsigned long n)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
raw_copy_from_user(void * to,const void __user * from,unsigned long n)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
raw_copy_to_user(void __user * to,const void * from,unsigned long n)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