1
2
3
4
5
6
7
8
9
10
11#ifndef _ASM_UACCESS_H
12#define _ASM_UACCESS_H
13
14
15
16
17#include <linux/kernel.h>
18#include <asm/page.h>
19
20
21
22
23
24
25
26
27#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
28
29#define KERNEL_XDS MAKE_MM_SEG(0xBFFFFFFF)
30#define KERNEL_DS MAKE_MM_SEG(0x9FFFFFFF)
31#define USER_DS MAKE_MM_SEG(TASK_SIZE)
32
33#define get_ds() (KERNEL_DS)
34#define get_fs() (current_thread_info()->addr_limit)
35#define set_fs(x) (current_thread_info()->addr_limit = (x))
36
37#define segment_eq(a, b) ((a).seg == (b).seg)
38
39#define __addr_ok(addr) \
40 ((unsigned long)(addr) < (current_thread_info()->addr_limit.seg))
41
42
43
44
45static inline int ___range_ok(unsigned long addr, unsigned int size)
46{
47 int flag = 1, tmp;
48
49 asm(" add %3,%1 \n"
50 " bcs 0f \n"
51 " cmp %4,%1 \n"
52 " bhi 0f \n"
53 " clr %0 \n"
54 "0: \n"
55 : "=r"(flag), "=&r"(tmp)
56 : "1"(addr), "ir"(size),
57 "r"(current_thread_info()->addr_limit.seg), "0"(flag)
58 : "cc"
59 );
60
61 return flag;
62}
63
64#define __range_ok(addr, size) ___range_ok((unsigned long)(addr), (u32)(size))
65
66#define access_ok(type, addr, size) (__range_ok((addr), (size)) == 0)
67#define __access_ok(addr, size) (__range_ok((addr), (size)) == 0)
68
69#include <asm/extable.h>
70
71#define put_user(x, ptr) __put_user_check((x), (ptr), sizeof(*(ptr)))
72#define get_user(x, ptr) __get_user_check((x), (ptr), sizeof(*(ptr)))
73
74
75
76
77
78
79#define __put_user(x, ptr) __put_user_nocheck((x), (ptr), sizeof(*(ptr)))
80#define __get_user(x, ptr) __get_user_nocheck((x), (ptr), sizeof(*(ptr)))
81
82struct __large_struct { unsigned long buf[100]; };
83#define __m(x) (*(struct __large_struct *)(x))
84
85#define __get_user_nocheck(x, ptr, size) \
86({ \
87 unsigned long __gu_addr; \
88 int __gu_err; \
89 __gu_addr = (unsigned long) (ptr); \
90 switch (size) { \
91 case 1: { \
92 unsigned char __gu_val; \
93 __get_user_asm("bu"); \
94 (x) = *(__force __typeof__(*(ptr))*) &__gu_val; \
95 break; \
96 } \
97 case 2: { \
98 unsigned short __gu_val; \
99 __get_user_asm("hu"); \
100 (x) = *(__force __typeof__(*(ptr))*) &__gu_val; \
101 break; \
102 } \
103 case 4: { \
104 unsigned int __gu_val; \
105 __get_user_asm(""); \
106 (x) = *(__force __typeof__(*(ptr))*) &__gu_val; \
107 break; \
108 } \
109 default: \
110 __get_user_unknown(); \
111 break; \
112 } \
113 __gu_err; \
114})
115
116#define __get_user_check(x, ptr, size) \
117({ \
118 const __typeof__(*(ptr))* __guc_ptr = (ptr); \
119 int _e; \
120 if (likely(__access_ok((unsigned long) __guc_ptr, (size)))) \
121 _e = __get_user_nocheck((x), __guc_ptr, (size)); \
122 else { \
123 _e = -EFAULT; \
124 (x) = (__typeof__(x))0; \
125 } \
126 _e; \
127})
128
129#define __get_user_asm(INSN) \
130({ \
131 asm volatile( \
132 "1:\n" \
133 " mov"INSN" %2,%1\n" \
134 " mov 0,%0\n" \
135 "2:\n" \
136 " .section .fixup,\"ax\"\n" \
137 "3:\n\t" \
138 " mov 0,%1\n" \
139 " mov %3,%0\n" \
140 " jmp 2b\n" \
141 " .previous\n" \
142 " .section __ex_table,\"a\"\n" \
143 " .balign 4\n" \
144 " .long 1b, 3b\n" \
145 " .previous" \
146 : "=&r" (__gu_err), "=&r" (__gu_val) \
147 : "m" (__m(__gu_addr)), "i" (-EFAULT)); \
148})
149
150extern int __get_user_unknown(void);
151
152#define __put_user_nocheck(x, ptr, size) \
153({ \
154 union { \
155 __typeof__(*(ptr)) val; \
156 u32 bits[2]; \
157 } __pu_val; \
158 unsigned long __pu_addr; \
159 int __pu_err; \
160 __pu_val.val = (x); \
161 __pu_addr = (unsigned long) (ptr); \
162 switch (size) { \
163 case 1: __put_user_asm("bu"); break; \
164 case 2: __put_user_asm("hu"); break; \
165 case 4: __put_user_asm("" ); break; \
166 case 8: __put_user_asm8(); break; \
167 default: __pu_err = __put_user_unknown(); break; \
168 } \
169 __pu_err; \
170})
171
172#define __put_user_check(x, ptr, size) \
173({ \
174 union { \
175 __typeof__(*(ptr)) val; \
176 u32 bits[2]; \
177 } __pu_val; \
178 unsigned long __pu_addr; \
179 int __pu_err; \
180 __pu_val.val = (x); \
181 __pu_addr = (unsigned long) (ptr); \
182 if (likely(__access_ok(__pu_addr, size))) { \
183 switch (size) { \
184 case 1: __put_user_asm("bu"); break; \
185 case 2: __put_user_asm("hu"); break; \
186 case 4: __put_user_asm("" ); break; \
187 case 8: __put_user_asm8(); break; \
188 default: __pu_err = __put_user_unknown(); break; \
189 } \
190 } \
191 else { \
192 __pu_err = -EFAULT; \
193 } \
194 __pu_err; \
195})
196
197#define __put_user_asm(INSN) \
198({ \
199 asm volatile( \
200 "1:\n" \
201 " mov"INSN" %1,%2\n" \
202 " mov 0,%0\n" \
203 "2:\n" \
204 " .section .fixup,\"ax\"\n" \
205 "3:\n" \
206 " mov %3,%0\n" \
207 " jmp 2b\n" \
208 " .previous\n" \
209 " .section __ex_table,\"a\"\n" \
210 " .balign 4\n" \
211 " .long 1b, 3b\n" \
212 " .previous" \
213 : "=&r" (__pu_err) \
214 : "r" (__pu_val.val), "m" (__m(__pu_addr)), \
215 "i" (-EFAULT) \
216 ); \
217})
218
219#define __put_user_asm8() \
220({ \
221 asm volatile( \
222 "1: mov %1,%3 \n" \
223 "2: mov %2,%4 \n" \
224 " mov 0,%0 \n" \
225 "3: \n" \
226 " .section .fixup,\"ax\" \n" \
227 "4: \n" \
228 " mov %5,%0 \n" \
229 " jmp 3b \n" \
230 " .previous \n" \
231 " .section __ex_table,\"a\"\n" \
232 " .balign 4 \n" \
233 " .long 1b, 4b \n" \
234 " .long 2b, 4b \n" \
235 " .previous \n" \
236 : "=&r" (__pu_err) \
237 : "r" (__pu_val.bits[0]), "r" (__pu_val.bits[1]), \
238 "m" (__m(__pu_addr)), "m" (__m(__pu_addr+4)), \
239 "i" (-EFAULT) \
240 ); \
241})
242
243extern int __put_user_unknown(void);
244
245
246
247
248
249
250#define __copy_user(to, from, size) \
251do { \
252 if (size) { \
253 void *__to = to; \
254 const void *__from = from; \
255 int w; \
256 asm volatile( \
257 "0: movbu (%0),%3;\n" \
258 "1: movbu %3,(%1);\n" \
259 " inc %0;\n" \
260 " inc %1;\n" \
261 " add -1,%2;\n" \
262 " bne 0b;\n" \
263 "2:\n" \
264 " .section .fixup,\"ax\"\n" \
265 "3: jmp 2b\n" \
266 " .previous\n" \
267 " .section __ex_table,\"a\"\n" \
268 " .balign 4\n" \
269 " .long 0b,3b\n" \
270 " .long 1b,3b\n" \
271 " .previous\n" \
272 : "=a"(__from), "=a"(__to), "=r"(size), "=&r"(w)\
273 : "0"(__from), "1"(__to), "2"(size) \
274 : "cc", "memory"); \
275 } \
276} while (0)
277
278static inline unsigned long
279raw_copy_from_user(void *to, const void __user *from, unsigned long n)
280{
281 __copy_user(to, from, n);
282 return n;
283}
284
285static inline unsigned long
286raw_copy_to_user(void __user *to, const void *from, unsigned long n)
287{
288 __copy_user(to, from, n);
289 return n;
290}
291
292extern long strncpy_from_user(char *dst, const char __user *src, long count);
293extern long strnlen_user(const char __user *str, long n);
294extern unsigned long clear_user(void __user *mem, unsigned long len);
295extern unsigned long __clear_user(void __user *mem, unsigned long len);
296
297#endif
298