GNU Linux-libre 5.19-rc6-gnu
[releases.git] / arch / microblaze / include / asm / uaccess.h
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. */
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
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
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
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 */