xref: /openbmc/linux/arch/csky/include/asm/uaccess.h (revision 3213486f)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 // Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
3 
4 #ifndef __ASM_CSKY_UACCESS_H
5 #define __ASM_CSKY_UACCESS_H
6 
7 /*
8  * User space memory access functions
9  */
10 #include <linux/compiler.h>
11 #include <linux/errno.h>
12 #include <linux/types.h>
13 #include <linux/sched.h>
14 #include <linux/mm.h>
15 #include <linux/string.h>
16 #include <linux/version.h>
17 #include <asm/segment.h>
18 
19 static inline int access_ok(const void *addr, unsigned long size)
20 {
21 	unsigned long limit = current_thread_info()->addr_limit.seg;
22 
23 	return (((unsigned long)addr < limit) &&
24 		((unsigned long)(addr + size) < limit));
25 }
26 
27 #define __addr_ok(addr) (access_ok(addr, 0))
28 
29 extern int __put_user_bad(void);
30 
31 /*
32  * Tell gcc we read from memory instead of writing: this is because
33  * we do not write to any memory gcc knows about, so there are no
34  * aliasing issues.
35  */
36 
37 /*
38  * These are the main single-value transfer routines.  They automatically
39  * use the right size if we just have the right pointer type.
40  *
41  * This gets kind of ugly. We want to return _two_ values in "get_user()"
42  * and yet we don't want to do any pointers, because that is too much
43  * of a performance impact. Thus we have a few rather ugly macros here,
44  * and hide all the ugliness from the user.
45  *
46  * The "__xxx" versions of the user access functions are versions that
47  * do not verify the address space, that must have been done previously
48  * with a separate "access_ok()" call (this is used when we do multiple
49  * accesses to the same area of user memory).
50  *
51  * As we use the same address space for kernel and user data on
52  * Ckcore, we can just do these as direct assignments.  (Of course, the
53  * exception handling means that it's no longer "just"...)
54  */
55 
56 #define put_user(x, ptr) \
57 	__put_user_check((x), (ptr), sizeof(*(ptr)))
58 
59 #define __put_user(x, ptr) \
60 	__put_user_nocheck((x), (ptr), sizeof(*(ptr)))
61 
62 #define __ptr(x) ((unsigned long *)(x))
63 
64 #define get_user(x, ptr) \
65 	__get_user_check((x), (ptr), sizeof(*(ptr)))
66 
67 #define __get_user(x, ptr) \
68 	__get_user_nocheck((x), (ptr), sizeof(*(ptr)))
69 
70 #define __put_user_nocheck(x, ptr, size)				\
71 ({									\
72 	long __pu_err = 0;						\
73 	typeof(*(ptr)) *__pu_addr = (ptr);				\
74 	typeof(*(ptr)) __pu_val = (typeof(*(ptr)))(x);			\
75 	if (__pu_addr)							\
76 		__put_user_size(__pu_val, (__pu_addr), (size),		\
77 				__pu_err);				\
78 	__pu_err;							\
79 })
80 
81 #define __put_user_check(x, ptr, size)					\
82 ({									\
83 	long __pu_err = -EFAULT;					\
84 	typeof(*(ptr)) *__pu_addr = (ptr);				\
85 	typeof(*(ptr)) __pu_val = (typeof(*(ptr)))(x);			\
86 	if (access_ok(__pu_addr, size) && __pu_addr)	\
87 		__put_user_size(__pu_val, __pu_addr, (size), __pu_err);	\
88 	__pu_err;							\
89 })
90 
91 #define __put_user_size(x, ptr, size, retval)		\
92 do {							\
93 	retval = 0;					\
94 	switch (size) {                                 \
95 	case 1:						\
96 		__put_user_asm_b(x, ptr, retval);	\
97 		break;					\
98 	case 2:						\
99 		__put_user_asm_h(x, ptr, retval);	\
100 		break;					\
101 	case 4:						\
102 		__put_user_asm_w(x, ptr, retval);	\
103 		break;					\
104 	case 8:						\
105 		__put_user_asm_64(x, ptr, retval);	\
106 		break;					\
107 	default:					\
108 		__put_user_bad();			\
109 	}	                                        \
110 } while (0)
111 
112 /*
113  * We don't tell gcc that we are accessing memory, but this is OK
114  * because we do not write to any memory gcc knows about, so there
115  * are no aliasing issues.
116  *
117  * Note that PC at a fault is the address *after* the faulting
118  * instruction.
119  */
120 #define __put_user_asm_b(x, ptr, err)			\
121 do {							\
122 	int errcode;					\
123 	asm volatile(					\
124 	"1:     stb   %1, (%2,0)	\n"		\
125 	"       br    3f		\n"		\
126 	"2:     mov   %0, %3		\n"		\
127 	"       br    3f		\n"		\
128 	".section __ex_table, \"a\"	\n"		\
129 	".align   2			\n"		\
130 	".long    1b,2b			\n"		\
131 	".previous			\n"		\
132 	"3:				\n"		\
133 	: "=r"(err), "=r"(x), "=r"(ptr), "=r"(errcode)	\
134 	: "0"(err), "1"(x), "2"(ptr), "3"(-EFAULT)	\
135 	: "memory");					\
136 } while (0)
137 
138 #define __put_user_asm_h(x, ptr, err)			\
139 do {							\
140 	int errcode;					\
141 	asm volatile(					\
142 	"1:     sth   %1, (%2,0)	\n"		\
143 	"       br    3f		\n"		\
144 	"2:     mov   %0, %3		\n"		\
145 	"       br    3f		\n"		\
146 	".section __ex_table, \"a\"	\n"		\
147 	".align   2			\n"		\
148 	".long    1b,2b			\n"		\
149 	".previous			\n"		\
150 	"3:				\n"		\
151 	: "=r"(err), "=r"(x), "=r"(ptr), "=r"(errcode)	\
152 	: "0"(err), "1"(x), "2"(ptr), "3"(-EFAULT)	\
153 	: "memory");					\
154 } while (0)
155 
156 #define __put_user_asm_w(x, ptr, err)			\
157 do {							\
158 	int errcode;					\
159 	asm volatile(					\
160 	"1:     stw   %1, (%2,0)	\n"		\
161 	"       br    3f		\n"		\
162 	"2:     mov   %0, %3		\n"		\
163 	"       br    3f		\n"		\
164 	".section __ex_table,\"a\"	\n"		\
165 	".align   2			\n"		\
166 	".long    1b, 2b		\n"		\
167 	".previous			\n"		\
168 	"3:				\n"		\
169 	: "=r"(err), "=r"(x), "=r"(ptr), "=r"(errcode)	\
170 	: "0"(err), "1"(x), "2"(ptr), "3"(-EFAULT)	\
171 	: "memory");					\
172 } while (0)
173 
174 #define __put_user_asm_64(x, ptr, err)				\
175 do {								\
176 	int tmp;						\
177 	int errcode;						\
178 	typeof(*(ptr))src = (typeof(*(ptr)))x;			\
179 	typeof(*(ptr))*psrc = &src;				\
180 								\
181 	asm volatile(						\
182 	"     ldw     %3, (%1, 0)     \n"			\
183 	"1:   stw     %3, (%2, 0)     \n"			\
184 	"     ldw     %3, (%1, 4)     \n"			\
185 	"2:   stw     %3, (%2, 4)     \n"			\
186 	"     br      4f              \n"			\
187 	"3:   mov     %0, %4          \n"			\
188 	"     br      4f              \n"			\
189 	".section __ex_table, \"a\"   \n"			\
190 	".align   2                   \n"			\
191 	".long    1b, 3b              \n"			\
192 	".long    2b, 3b              \n"			\
193 	".previous                    \n"			\
194 	"4:                           \n"			\
195 	: "=r"(err), "=r"(psrc), "=r"(ptr),			\
196 	  "=r"(tmp), "=r"(errcode)				\
197 	: "0"(err), "1"(psrc), "2"(ptr), "3"(0), "4"(-EFAULT)	\
198 	: "memory");						\
199 } while (0)
200 
201 #define __get_user_nocheck(x, ptr, size)			\
202 ({								\
203 	long  __gu_err;						\
204 	__get_user_size(x, (ptr), (size), __gu_err);		\
205 	__gu_err;						\
206 })
207 
208 #define __get_user_check(x, ptr, size)				\
209 ({								\
210 	int __gu_err = -EFAULT;					\
211 	const __typeof__(*(ptr)) __user *__gu_ptr = (ptr);	\
212 	if (access_ok(__gu_ptr, size) && __gu_ptr)	\
213 		__get_user_size(x, __gu_ptr, size, __gu_err);	\
214 	__gu_err;						\
215 })
216 
217 #define __get_user_size(x, ptr, size, retval)			\
218 do {								\
219 	switch (size) {						\
220 	case 1:							\
221 		__get_user_asm_common((x), ptr, "ldb", retval);	\
222 		break;						\
223 	case 2:							\
224 		__get_user_asm_common((x), ptr, "ldh", retval);	\
225 		break;						\
226 	case 4:							\
227 		__get_user_asm_common((x), ptr, "ldw", retval);	\
228 		break;						\
229 	default:						\
230 		x = 0;						\
231 		(retval) = __get_user_bad();			\
232 	}							\
233 } while (0)
234 
235 #define __get_user_asm_common(x, ptr, ins, err)			\
236 do {								\
237 	int errcode;						\
238 	asm volatile(						\
239 	"1:   " ins " %1, (%4,0)	\n"			\
240 	"       br    3f		\n"			\
241 	/* Fix up codes */					\
242 	"2:     mov   %0, %2		\n"			\
243 	"       movi  %1, 0		\n"			\
244 	"       br    3f		\n"			\
245 	".section __ex_table,\"a\"      \n"			\
246 	".align   2			\n"			\
247 	".long    1b, 2b		\n"			\
248 	".previous			\n"			\
249 	"3:				\n" 			\
250 	: "=r"(err), "=r"(x), "=r"(errcode)			\
251 	: "0"(0), "r"(ptr), "2"(-EFAULT)			\
252 	: "memory");						\
253 } while (0)
254 
255 extern int __get_user_bad(void);
256 
257 #define __copy_user(to, from, n)			\
258 do {							\
259 	int w0, w1, w2, w3;				\
260 	asm volatile(					\
261 	"0:     cmpnei  %1, 0           \n"		\
262 	"       bf      8f              \n"		\
263 	"       mov     %3, %1          \n"		\
264 	"       or      %3, %2          \n"		\
265 	"       andi    %3, 3           \n"		\
266 	"       cmpnei  %3, 0           \n"		\
267 	"       bf      1f              \n"		\
268 	"       br      5f              \n"		\
269 	"1:     cmplti  %0, 16          \n" /* 4W */	\
270 	"       bt      3f              \n"		\
271 	"       ldw     %3, (%2, 0)     \n"		\
272 	"       ldw     %4, (%2, 4)     \n"		\
273 	"       ldw     %5, (%2, 8)     \n"		\
274 	"       ldw     %6, (%2, 12)    \n"		\
275 	"2:     stw     %3, (%1, 0)     \n"		\
276 	"9:     stw     %4, (%1, 4)     \n"		\
277 	"10:    stw     %5, (%1, 8)     \n"		\
278 	"11:    stw     %6, (%1, 12)    \n"		\
279 	"       addi    %2, 16          \n"		\
280 	"       addi    %1, 16          \n"		\
281 	"       subi    %0, 16          \n"		\
282 	"       br      1b              \n"		\
283 	"3:     cmplti  %0, 4           \n" /* 1W */	\
284 	"       bt      5f              \n"		\
285 	"       ldw     %3, (%2, 0)     \n"		\
286 	"4:     stw     %3, (%1, 0)     \n"		\
287 	"       addi    %2, 4           \n"		\
288 	"       addi    %1, 4           \n"		\
289 	"       subi    %0, 4           \n"		\
290 	"       br      3b              \n"		\
291 	"5:     cmpnei  %0, 0           \n"  /* 1B */   \
292 	"       bf      8f              \n"		\
293 	"       ldb     %3, (%2, 0)     \n"		\
294 	"6:     stb     %3, (%1, 0)     \n"		\
295 	"       addi    %2,  1          \n"		\
296 	"       addi    %1,  1          \n"		\
297 	"       subi    %0,  1          \n"		\
298 	"       br      5b              \n"		\
299 	"7:     br      8f              \n"		\
300 	".section __ex_table, \"a\"     \n"		\
301 	".align   2                     \n"		\
302 	".long    2b, 7b                \n"		\
303 	".long    9b, 7b                \n"		\
304 	".long   10b, 7b                \n"		\
305 	".long   11b, 7b                \n"		\
306 	".long    4b, 7b                \n"		\
307 	".long    6b, 7b                \n"		\
308 	".previous                      \n"		\
309 	"8:                             \n"		\
310 	: "=r"(n), "=r"(to), "=r"(from), "=r"(w0),	\
311 	  "=r"(w1), "=r"(w2), "=r"(w3)			\
312 	: "0"(n), "1"(to), "2"(from)			\
313 	: "memory");					\
314 } while (0)
315 
316 #define __copy_user_zeroing(to, from, n)		\
317 do {							\
318 	int tmp;					\
319 	int nsave;					\
320 	asm volatile(					\
321 	"0:     cmpnei  %1, 0           \n"		\
322 	"       bf      7f              \n"		\
323 	"       mov     %3, %1          \n"		\
324 	"       or      %3, %2          \n"		\
325 	"       andi    %3, 3           \n"		\
326 	"       cmpnei  %3, 0           \n"		\
327 	"       bf      1f              \n"		\
328 	"       br      5f              \n"		\
329 	"1:     cmplti  %0, 16          \n"		\
330 	"       bt      3f              \n"		\
331 	"2:     ldw     %3, (%2, 0)     \n"		\
332 	"10:    ldw     %4, (%2, 4)     \n"		\
333 	"       stw     %3, (%1, 0)     \n"		\
334 	"       stw     %4, (%1, 4)     \n"		\
335 	"11:    ldw     %3, (%2, 8)     \n"		\
336 	"12:    ldw     %4, (%2, 12)    \n"		\
337 	"       stw     %3, (%1, 8)     \n"		\
338 	"       stw     %4, (%1, 12)    \n"		\
339 	"       addi    %2, 16          \n"		\
340 	"       addi    %1, 16          \n"		\
341 	"       subi    %0, 16          \n"		\
342 	"       br      1b              \n"		\
343 	"3:     cmplti  %0, 4           \n"		\
344 	"       bt      5f              \n"		\
345 	"4:     ldw     %3, (%2, 0)     \n"		\
346 	"       stw     %3, (%1, 0)     \n"		\
347 	"       addi    %2, 4           \n"		\
348 	"       addi    %1, 4           \n"		\
349 	"       subi    %0, 4           \n"		\
350 	"       br      3b              \n"		\
351 	"5:     cmpnei  %0, 0           \n"		\
352 	"       bf      7f              \n"		\
353 	"6:     ldb     %3, (%2, 0)     \n"		\
354 	"       stb     %3, (%1, 0)     \n"		\
355 	"       addi    %2,  1          \n"		\
356 	"       addi    %1,  1          \n"		\
357 	"       subi    %0,  1          \n"		\
358 	"       br      5b              \n"		\
359 	"8:     mov     %3, %0          \n"		\
360 	"       movi    %4, 0           \n"		\
361 	"9:     stb     %4, (%1, 0)     \n"		\
362 	"       addi    %1, 1           \n"		\
363 	"       subi    %3, 1           \n"		\
364 	"       cmpnei  %3, 0           \n"		\
365 	"       bt      9b              \n"		\
366 	"       br      7f              \n"		\
367 	".section __ex_table, \"a\"     \n"		\
368 	".align   2                     \n"		\
369 	".long    2b, 8b                \n"		\
370 	".long   10b, 8b                \n"		\
371 	".long   11b, 8b                \n"		\
372 	".long   12b, 8b                \n"		\
373 	".long    4b, 8b                \n"		\
374 	".long    6b, 8b                \n"		\
375 	".previous                      \n"		\
376 	"7:                             \n"		\
377 	: "=r"(n), "=r"(to), "=r"(from), "=r"(nsave),	\
378 	  "=r"(tmp)					\
379 	: "0"(n), "1"(to), "2"(from)			\
380 	: "memory");					\
381 } while (0)
382 
383 unsigned long raw_copy_from_user(void *to, const void *from, unsigned long n);
384 unsigned long raw_copy_to_user(void *to, const void *from, unsigned long n);
385 
386 unsigned long clear_user(void *to, unsigned long n);
387 unsigned long __clear_user(void __user *to, unsigned long n);
388 
389 long strncpy_from_user(char *dst, const char *src, long count);
390 long __strncpy_from_user(char *dst, const char *src, long count);
391 
392 /*
393  * Return the size of a string (including the ending 0)
394  *
395  * Return 0 on exception, a value greater than N if too long
396  */
397 long strnlen_user(const char *src, long n);
398 
399 #define strlen_user(str) strnlen_user(str, 32767)
400 
401 struct exception_table_entry {
402 	unsigned long insn;
403 	unsigned long nextinsn;
404 };
405 
406 extern int fixup_exception(struct pt_regs *regs);
407 
408 #endif /* __ASM_CSKY_UACCESS_H */
409