Commit | Line | Data |
---|---|---|
b2441318 | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
eed417dd AB |
2 | #ifndef __ASM_GENERIC_UACCESS_H |
3 | #define __ASM_GENERIC_UACCESS_H | |
4 | ||
5 | /* | |
6 | * User space memory access functions, these should work | |
0a4a6647 | 7 | * on any machine that has kernel and user data in the same |
eed417dd AB |
8 | * address space, e.g. all NOMMU machines. |
9 | */ | |
eed417dd | 10 | #include <linux/string.h> |
967747bb | 11 | #include <asm-generic/access_ok.h> |
eed417dd | 12 | |
bd79f947 | 13 | #ifdef CONFIG_UACCESS_MEMCPY |
931de11f CH |
14 | #include <asm/unaligned.h> |
15 | ||
0bcd0a2b CH |
16 | static __always_inline int |
17 | __get_user_fn(size_t size, const void __user *from, void *to) | |
bd79f947 | 18 | { |
931de11f CH |
19 | BUILD_BUG_ON(!__builtin_constant_p(size)); |
20 | ||
21 | switch (size) { | |
22 | case 1: | |
d40d8179 | 23 | *(u8 *)to = *((u8 __force *)from); |
931de11f CH |
24 | return 0; |
25 | case 2: | |
26 | *(u16 *)to = get_unaligned((u16 __force *)from); | |
27 | return 0; | |
28 | case 4: | |
29 | *(u32 *)to = get_unaligned((u32 __force *)from); | |
30 | return 0; | |
31 | case 8: | |
32 | *(u64 *)to = get_unaligned((u64 __force *)from); | |
33 | return 0; | |
34 | default: | |
35 | BUILD_BUG(); | |
36 | return 0; | |
37 | } | |
38 | ||
39 | } | |
40 | #define __get_user_fn(sz, u, k) __get_user_fn(sz, u, k) | |
41 | ||
0bcd0a2b CH |
42 | static __always_inline int |
43 | __put_user_fn(size_t size, void __user *to, void *from) | |
931de11f CH |
44 | { |
45 | BUILD_BUG_ON(!__builtin_constant_p(size)); | |
46 | ||
47 | switch (size) { | |
48 | case 1: | |
d40d8179 | 49 | *(u8 __force *)to = *(u8 *)from; |
931de11f CH |
50 | return 0; |
51 | case 2: | |
52 | put_unaligned(*(u16 *)from, (u16 __force *)to); | |
53 | return 0; | |
54 | case 4: | |
55 | put_unaligned(*(u32 *)from, (u32 __force *)to); | |
56 | return 0; | |
57 | case 8: | |
58 | put_unaligned(*(u64 *)from, (u64 __force *)to); | |
59 | return 0; | |
60 | default: | |
61 | BUILD_BUG(); | |
62 | return 0; | |
bd79f947 | 63 | } |
931de11f CH |
64 | } |
65 | #define __put_user_fn(sz, u, k) __put_user_fn(sz, u, k) | |
bd79f947 | 66 | |
2d2d2554 CH |
67 | #define __get_kernel_nofault(dst, src, type, err_label) \ |
68 | do { \ | |
69 | *((type *)dst) = get_unaligned((type *)(src)); \ | |
70 | if (0) /* make sure the label looks used to the compiler */ \ | |
71 | goto err_label; \ | |
72 | } while (0) | |
73 | ||
74 | #define __put_kernel_nofault(dst, src, type, err_label) \ | |
75 | do { \ | |
76 | put_unaligned(*((type *)src), (type *)(dst)); \ | |
77 | if (0) /* make sure the label looks used to the compiler */ \ | |
78 | goto err_label; \ | |
79 | } while (0) | |
80 | ||
931de11f CH |
81 | static inline __must_check unsigned long |
82 | raw_copy_from_user(void *to, const void __user * from, unsigned long n) | |
83 | { | |
bd79f947 CH |
84 | memcpy(to, (const void __force *)from, n); |
85 | return 0; | |
86 | } | |
87 | ||
88 | static inline __must_check unsigned long | |
89 | raw_copy_to_user(void __user *to, const void *from, unsigned long n) | |
90 | { | |
bd79f947 CH |
91 | memcpy((void __force *)to, from, n); |
92 | return 0; | |
93 | } | |
94 | #define INLINE_COPY_FROM_USER | |
95 | #define INLINE_COPY_TO_USER | |
96 | #endif /* CONFIG_UACCESS_MEMCPY */ | |
97 | ||
eed417dd AB |
98 | /* |
99 | * These are the main single-value transfer routines. They automatically | |
100 | * use the right size if we just have the right pointer type. | |
101 | * This version just falls back to copy_{from,to}_user, which should | |
102 | * provide a fast-path for small values. | |
103 | */ | |
104 | #define __put_user(x, ptr) \ | |
105 | ({ \ | |
106 | __typeof__(*(ptr)) __x = (x); \ | |
107 | int __pu_err = -EFAULT; \ | |
108 | __chk_user_ptr(ptr); \ | |
109 | switch (sizeof (*(ptr))) { \ | |
110 | case 1: \ | |
111 | case 2: \ | |
112 | case 4: \ | |
113 | case 8: \ | |
114 | __pu_err = __put_user_fn(sizeof (*(ptr)), \ | |
115 | ptr, &__x); \ | |
116 | break; \ | |
117 | default: \ | |
118 | __put_user_bad(); \ | |
119 | break; \ | |
120 | } \ | |
121 | __pu_err; \ | |
122 | }) | |
123 | ||
124 | #define put_user(x, ptr) \ | |
125 | ({ \ | |
1985296a | 126 | void __user *__p = (ptr); \ |
e0acd0bd | 127 | might_fault(); \ |
96d4f267 | 128 | access_ok(__p, sizeof(*ptr)) ? \ |
1985296a | 129 | __put_user((x), ((__typeof__(*(ptr)) __user *)__p)) : \ |
eed417dd AB |
130 | -EFAULT; \ |
131 | }) | |
132 | ||
05d88a49 VG |
133 | #ifndef __put_user_fn |
134 | ||
eed417dd AB |
135 | static inline int __put_user_fn(size_t size, void __user *ptr, void *x) |
136 | { | |
d597580d | 137 | return unlikely(raw_copy_to_user(ptr, x, size)) ? -EFAULT : 0; |
eed417dd AB |
138 | } |
139 | ||
05d88a49 VG |
140 | #define __put_user_fn(sz, u, k) __put_user_fn(sz, u, k) |
141 | ||
142 | #endif | |
143 | ||
eed417dd AB |
144 | extern int __put_user_bad(void) __attribute__((noreturn)); |
145 | ||
146 | #define __get_user(x, ptr) \ | |
147 | ({ \ | |
148 | int __gu_err = -EFAULT; \ | |
149 | __chk_user_ptr(ptr); \ | |
150 | switch (sizeof(*(ptr))) { \ | |
151 | case 1: { \ | |
c1aad8dc | 152 | unsigned char __x = 0; \ |
eed417dd AB |
153 | __gu_err = __get_user_fn(sizeof (*(ptr)), \ |
154 | ptr, &__x); \ | |
155 | (x) = *(__force __typeof__(*(ptr)) *) &__x; \ | |
156 | break; \ | |
157 | }; \ | |
158 | case 2: { \ | |
c1aad8dc | 159 | unsigned short __x = 0; \ |
eed417dd AB |
160 | __gu_err = __get_user_fn(sizeof (*(ptr)), \ |
161 | ptr, &__x); \ | |
162 | (x) = *(__force __typeof__(*(ptr)) *) &__x; \ | |
163 | break; \ | |
164 | }; \ | |
165 | case 4: { \ | |
c1aad8dc | 166 | unsigned int __x = 0; \ |
eed417dd AB |
167 | __gu_err = __get_user_fn(sizeof (*(ptr)), \ |
168 | ptr, &__x); \ | |
169 | (x) = *(__force __typeof__(*(ptr)) *) &__x; \ | |
170 | break; \ | |
171 | }; \ | |
172 | case 8: { \ | |
c1aad8dc | 173 | unsigned long long __x = 0; \ |
eed417dd AB |
174 | __gu_err = __get_user_fn(sizeof (*(ptr)), \ |
175 | ptr, &__x); \ | |
176 | (x) = *(__force __typeof__(*(ptr)) *) &__x; \ | |
177 | break; \ | |
178 | }; \ | |
179 | default: \ | |
180 | __get_user_bad(); \ | |
181 | break; \ | |
182 | } \ | |
183 | __gu_err; \ | |
184 | }) | |
185 | ||
186 | #define get_user(x, ptr) \ | |
187 | ({ \ | |
1985296a | 188 | const void __user *__p = (ptr); \ |
e0acd0bd | 189 | might_fault(); \ |
96d4f267 | 190 | access_ok(__p, sizeof(*ptr)) ? \ |
1985296a | 191 | __get_user((x), (__typeof__(*(ptr)) __user *)__p) :\ |
9ad18b75 | 192 | ((x) = (__typeof__(*(ptr)))0,-EFAULT); \ |
eed417dd AB |
193 | }) |
194 | ||
05d88a49 | 195 | #ifndef __get_user_fn |
eed417dd AB |
196 | static inline int __get_user_fn(size_t size, const void __user *ptr, void *x) |
197 | { | |
d597580d | 198 | return unlikely(raw_copy_from_user(x, ptr, size)) ? -EFAULT : 0; |
eed417dd AB |
199 | } |
200 | ||
05d88a49 VG |
201 | #define __get_user_fn(sz, u, k) __get_user_fn(sz, u, k) |
202 | ||
203 | #endif | |
204 | ||
eed417dd AB |
205 | extern int __get_user_bad(void) __attribute__((noreturn)); |
206 | ||
eed417dd AB |
207 | /* |
208 | * Zero Userspace | |
209 | */ | |
210 | #ifndef __clear_user | |
211 | static inline __must_check unsigned long | |
212 | __clear_user(void __user *to, unsigned long n) | |
213 | { | |
214 | memset((void __force *)to, 0, n); | |
215 | return 0; | |
216 | } | |
217 | #endif | |
218 | ||
219 | static inline __must_check unsigned long | |
220 | clear_user(void __user *to, unsigned long n) | |
221 | { | |
e0acd0bd | 222 | might_fault(); |
96d4f267 | 223 | if (!access_ok(to, n)) |
eed417dd AB |
224 | return n; |
225 | ||
226 | return __clear_user(to, n); | |
227 | } | |
228 | ||
aaa2e7ac AV |
229 | #include <asm/extable.h> |
230 | ||
98b861a3 AB |
231 | __must_check long strncpy_from_user(char *dst, const char __user *src, |
232 | long count); | |
233 | __must_check long strnlen_user(const char __user *src, long n); | |
234 | ||
eed417dd | 235 | #endif /* __ASM_GENERIC_UACCESS_H */ |