]>
Commit | Line | Data |
---|---|---|
eed417dd AB |
1 | #ifndef __ASM_GENERIC_UACCESS_H |
2 | #define __ASM_GENERIC_UACCESS_H | |
3 | ||
4 | /* | |
5 | * User space memory access functions, these should work | |
0a4a6647 | 6 | * on any machine that has kernel and user data in the same |
eed417dd AB |
7 | * address space, e.g. all NOMMU machines. |
8 | */ | |
eed417dd AB |
9 | #include <linux/string.h> |
10 | ||
11 | #include <asm/segment.h> | |
12 | ||
13 | #define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) | |
14 | ||
15 | #ifndef KERNEL_DS | |
16 | #define KERNEL_DS MAKE_MM_SEG(~0UL) | |
17 | #endif | |
18 | ||
19 | #ifndef USER_DS | |
20 | #define USER_DS MAKE_MM_SEG(TASK_SIZE - 1) | |
21 | #endif | |
22 | ||
23 | #ifndef get_fs | |
24 | #define get_ds() (KERNEL_DS) | |
25 | #define get_fs() (current_thread_info()->addr_limit) | |
26 | ||
27 | static inline void set_fs(mm_segment_t fs) | |
28 | { | |
29 | current_thread_info()->addr_limit = fs; | |
30 | } | |
31 | #endif | |
32 | ||
10a6007b | 33 | #ifndef segment_eq |
eed417dd | 34 | #define segment_eq(a, b) ((a).seg == (b).seg) |
10a6007b | 35 | #endif |
eed417dd | 36 | |
eed417dd AB |
37 | #define access_ok(type, addr, size) __access_ok((unsigned long)(addr),(size)) |
38 | ||
39 | /* | |
40 | * The architecture should really override this if possible, at least | |
41 | * doing a check on the get_fs() | |
42 | */ | |
43 | #ifndef __access_ok | |
44 | static inline int __access_ok(unsigned long addr, unsigned long size) | |
45 | { | |
46 | return 1; | |
47 | } | |
48 | #endif | |
49 | ||
eed417dd AB |
50 | /* |
51 | * These are the main single-value transfer routines. They automatically | |
52 | * use the right size if we just have the right pointer type. | |
53 | * This version just falls back to copy_{from,to}_user, which should | |
54 | * provide a fast-path for small values. | |
55 | */ | |
56 | #define __put_user(x, ptr) \ | |
57 | ({ \ | |
58 | __typeof__(*(ptr)) __x = (x); \ | |
59 | int __pu_err = -EFAULT; \ | |
60 | __chk_user_ptr(ptr); \ | |
61 | switch (sizeof (*(ptr))) { \ | |
62 | case 1: \ | |
63 | case 2: \ | |
64 | case 4: \ | |
65 | case 8: \ | |
66 | __pu_err = __put_user_fn(sizeof (*(ptr)), \ | |
67 | ptr, &__x); \ | |
68 | break; \ | |
69 | default: \ | |
70 | __put_user_bad(); \ | |
71 | break; \ | |
72 | } \ | |
73 | __pu_err; \ | |
74 | }) | |
75 | ||
76 | #define put_user(x, ptr) \ | |
77 | ({ \ | |
1985296a | 78 | void __user *__p = (ptr); \ |
e0acd0bd | 79 | might_fault(); \ |
a02613a4 | 80 | access_ok(VERIFY_WRITE, __p, sizeof(*ptr)) ? \ |
1985296a | 81 | __put_user((x), ((__typeof__(*(ptr)) __user *)__p)) : \ |
eed417dd AB |
82 | -EFAULT; \ |
83 | }) | |
84 | ||
05d88a49 VG |
85 | #ifndef __put_user_fn |
86 | ||
eed417dd AB |
87 | static inline int __put_user_fn(size_t size, void __user *ptr, void *x) |
88 | { | |
d597580d | 89 | return unlikely(raw_copy_to_user(ptr, x, size)) ? -EFAULT : 0; |
eed417dd AB |
90 | } |
91 | ||
05d88a49 VG |
92 | #define __put_user_fn(sz, u, k) __put_user_fn(sz, u, k) |
93 | ||
94 | #endif | |
95 | ||
eed417dd AB |
96 | extern int __put_user_bad(void) __attribute__((noreturn)); |
97 | ||
98 | #define __get_user(x, ptr) \ | |
99 | ({ \ | |
100 | int __gu_err = -EFAULT; \ | |
101 | __chk_user_ptr(ptr); \ | |
102 | switch (sizeof(*(ptr))) { \ | |
103 | case 1: { \ | |
c1aad8dc | 104 | unsigned char __x = 0; \ |
eed417dd AB |
105 | __gu_err = __get_user_fn(sizeof (*(ptr)), \ |
106 | ptr, &__x); \ | |
107 | (x) = *(__force __typeof__(*(ptr)) *) &__x; \ | |
108 | break; \ | |
109 | }; \ | |
110 | case 2: { \ | |
c1aad8dc | 111 | unsigned short __x = 0; \ |
eed417dd AB |
112 | __gu_err = __get_user_fn(sizeof (*(ptr)), \ |
113 | ptr, &__x); \ | |
114 | (x) = *(__force __typeof__(*(ptr)) *) &__x; \ | |
115 | break; \ | |
116 | }; \ | |
117 | case 4: { \ | |
c1aad8dc | 118 | unsigned int __x = 0; \ |
eed417dd AB |
119 | __gu_err = __get_user_fn(sizeof (*(ptr)), \ |
120 | ptr, &__x); \ | |
121 | (x) = *(__force __typeof__(*(ptr)) *) &__x; \ | |
122 | break; \ | |
123 | }; \ | |
124 | case 8: { \ | |
c1aad8dc | 125 | unsigned long long __x = 0; \ |
eed417dd AB |
126 | __gu_err = __get_user_fn(sizeof (*(ptr)), \ |
127 | ptr, &__x); \ | |
128 | (x) = *(__force __typeof__(*(ptr)) *) &__x; \ | |
129 | break; \ | |
130 | }; \ | |
131 | default: \ | |
132 | __get_user_bad(); \ | |
133 | break; \ | |
134 | } \ | |
135 | __gu_err; \ | |
136 | }) | |
137 | ||
138 | #define get_user(x, ptr) \ | |
139 | ({ \ | |
1985296a | 140 | const void __user *__p = (ptr); \ |
e0acd0bd | 141 | might_fault(); \ |
a02613a4 | 142 | access_ok(VERIFY_READ, __p, sizeof(*ptr)) ? \ |
1985296a | 143 | __get_user((x), (__typeof__(*(ptr)) __user *)__p) :\ |
9ad18b75 | 144 | ((x) = (__typeof__(*(ptr)))0,-EFAULT); \ |
eed417dd AB |
145 | }) |
146 | ||
05d88a49 | 147 | #ifndef __get_user_fn |
eed417dd AB |
148 | static inline int __get_user_fn(size_t size, const void __user *ptr, void *x) |
149 | { | |
d597580d | 150 | return unlikely(raw_copy_from_user(x, ptr, size)) ? -EFAULT : 0; |
eed417dd AB |
151 | } |
152 | ||
05d88a49 VG |
153 | #define __get_user_fn(sz, u, k) __get_user_fn(sz, u, k) |
154 | ||
155 | #endif | |
156 | ||
eed417dd AB |
157 | extern int __get_user_bad(void) __attribute__((noreturn)); |
158 | ||
eed417dd AB |
159 | /* |
160 | * Copy a null terminated string from userspace. | |
161 | */ | |
162 | #ifndef __strncpy_from_user | |
163 | static inline long | |
164 | __strncpy_from_user(char *dst, const char __user *src, long count) | |
165 | { | |
166 | char *tmp; | |
167 | strncpy(dst, (const char __force *)src, count); | |
168 | for (tmp = dst; *tmp && count > 0; tmp++, count--) | |
169 | ; | |
170 | return (tmp - dst); | |
171 | } | |
172 | #endif | |
173 | ||
174 | static inline long | |
175 | strncpy_from_user(char *dst, const char __user *src, long count) | |
176 | { | |
a9ede5b3 | 177 | if (!access_ok(VERIFY_READ, src, 1)) |
eed417dd AB |
178 | return -EFAULT; |
179 | return __strncpy_from_user(dst, src, count); | |
180 | } | |
181 | ||
182 | /* | |
183 | * Return the size of a string (including the ending 0) | |
184 | * | |
185 | * Return 0 on exception, a value greater than N if too long | |
186 | */ | |
7f509a9e | 187 | #ifndef __strnlen_user |
830f5800 | 188 | #define __strnlen_user(s, n) (strnlen((s), (n)) + 1) |
7f509a9e G |
189 | #endif |
190 | ||
830f5800 MS |
191 | /* |
192 | * Unlike strnlen, strnlen_user includes the nul terminator in | |
193 | * its returned count. Callers should check for a returned value | |
194 | * greater than N as an indication the string is too long. | |
195 | */ | |
eed417dd AB |
196 | static inline long strnlen_user(const char __user *src, long n) |
197 | { | |
9844813f MF |
198 | if (!access_ok(VERIFY_READ, src, 1)) |
199 | return 0; | |
7f509a9e | 200 | return __strnlen_user(src, n); |
eed417dd | 201 | } |
eed417dd | 202 | |
eed417dd AB |
203 | /* |
204 | * Zero Userspace | |
205 | */ | |
206 | #ifndef __clear_user | |
207 | static inline __must_check unsigned long | |
208 | __clear_user(void __user *to, unsigned long n) | |
209 | { | |
210 | memset((void __force *)to, 0, n); | |
211 | return 0; | |
212 | } | |
213 | #endif | |
214 | ||
215 | static inline __must_check unsigned long | |
216 | clear_user(void __user *to, unsigned long n) | |
217 | { | |
e0acd0bd | 218 | might_fault(); |
a9ede5b3 | 219 | if (!access_ok(VERIFY_WRITE, to, n)) |
eed417dd AB |
220 | return n; |
221 | ||
222 | return __clear_user(to, n); | |
223 | } | |
224 | ||
aaa2e7ac AV |
225 | #include <asm/extable.h> |
226 | ||
eed417dd | 227 | #endif /* __ASM_GENERIC_UACCESS_H */ |