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