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