1 /*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 1996, 1997, 1998, 1999, 2000 by Ralf Baechle
7 * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
8 */
9 #ifndef _ASM_UACCESS_H
10 #define _ASM_UACCESS_H
11
12 #include <linux/errno.h>
13 #include <linux/sched.h>
14
15 #define STR(x) __STR(x)
16 #define __STR(x) #x
17
18 /*
19 * The fs value determines whether argument validity checking should be
20 * performed or not. If get_fs() == USER_DS, checking is performed, with
21 * get_fs() == KERNEL_DS, checking is bypassed.
22 *
23 * For historical reasons, these macros are grossly misnamed.
24 */
25 #define KERNEL_DS ((mm_segment_t) { (unsigned long) 0L })
26 #define USER_DS ((mm_segment_t) { (unsigned long) -1L })
27
28 #define VERIFY_READ 0
29 #define VERIFY_WRITE 1
30
31 #define get_fs() (current->thread.current_ds)
32 #define get_ds() (KERNEL_DS)
33 #define set_fs(x) (current->thread.current_ds=(x))
34
35 #define segment_eq(a,b) ((a).seg == (b).seg)
36
37
38 /*
39 * Is a address valid? This does a straighforward calculation rather
40 * than tests.
41 *
42 * Address valid if:
43 * - "addr" doesn't have any high-bits set
44 * - AND "size" doesn't have any high-bits set
45 * - AND "addr+size" doesn't have any high-bits set
46 * - OR we are in kernel mode.
47 */
48 #define __access_ok(addr,size,mask) \
49 (((__signed__ long)((mask)&(addr | size | (addr+size)))) >= 0)
50 #define __access_mask ((long)(get_fs().seg))
51
52 #define access_ok(type,addr,size) \
53 __access_ok(((unsigned long)(addr)),(size),__access_mask)
54
55 extern inline int verify_area(int type, const void * addr, unsigned long size)
56 {
57 return access_ok(type,addr,size) ? 0 : -EFAULT;
58 }
59
60 /*
61 * Uh, these should become the main single-value transfer routines ...
62 * They automatically use the right size if we just have the right
63 * pointer type ...
64 *
65 * As MIPS uses the same address space for kernel and user data, we
66 * can just do these as direct assignments.
67 *
68 * Careful to not
69 * (a) re-use the arguments for side effects (sizeof is ok)
70 * (b) require any knowledge of processes at this stage
71 */
72 #define put_user(x,ptr) \
73 __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
74 #define get_user(x,ptr) \
75 __get_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
76
77 /*
78 * The "__xxx" versions do not do address space checking, useful when
79 * doing multiple accesses to the same area (the user has to do the
80 * checks by hand with "access_ok()")
81 */
82 #define __put_user(x,ptr) \
83 __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
84 #define __get_user(x,ptr) \
85 __get_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
86
87 struct __large_struct { unsigned long buf[100]; };
88 #define __m(x) (*(struct __large_struct *)(x))
89
90 #define __get_user_nocheck(x,ptr,size) ({ \
91 long __gu_err; \
92 __typeof(*(ptr)) __gu_val; \
93 long __gu_addr; \
94 __asm__("":"=r" (__gu_val)); \
95 __gu_addr = (long) (ptr); \
96 __asm__("":"=r" (__gu_err)); \
97 switch (size) { \
98 case 1: __get_user_asm("lb"); break; \
99 case 2: __get_user_asm("lh"); break; \
100 case 4: __get_user_asm("lw"); break; \
101 case 8: __get_user_asm("ld"); break; \
102 default: __get_user_unknown(); break; \
103 } x = (__typeof__(*(ptr))) __gu_val; __gu_err; })
104
105 #define __get_user_check(x,ptr,size) ({ \
106 long __gu_err; \
107 __typeof__(*(ptr)) __gu_val; \
108 long __gu_addr; \
109 __asm__("":"=r" (__gu_val)); \
110 __gu_addr = (long) (ptr); \
111 __asm__("":"=r" (__gu_err)); \
112 if (__access_ok(__gu_addr,size,__access_mask)) { \
113 switch (size) { \
114 case 1: __get_user_asm("lb"); break; \
115 case 2: __get_user_asm("lh"); break; \
116 case 4: __get_user_asm("lw"); break; \
117 case 8: __get_user_asm("ld"); break; \
118 default: __get_user_unknown(); break; \
119 } } x = (__typeof__(*(ptr))) __gu_val; __gu_err; })
120
121 #define __get_user_asm(insn) \
122 ({ \
123 __asm__ __volatile__( \
124 "1:\t" insn "\t%1,%2\n\t" \
125 "move\t%0,$0\n" \
126 "2:\n\t" \
127 ".section\t.fixup,\"ax\"\n" \
128 "3:\tli\t%0,%3\n\t" \
129 "move\t%1,$0\n\t" \
130 "j\t2b\n\t" \
131 ".previous\n\t" \
132 ".section\t__ex_table,\"a\"\n\t" \
133 ".dword\t1b,3b\n\t" \
134 ".previous" \
135 :"=r" (__gu_err), "=r" (__gu_val) \
136 :"o" (__m(__gu_addr)), "i" (-EFAULT)); })
137
138 extern void __get_user_unknown(void);
139
140 #define __put_user_nocheck(x,ptr,size) ({ \
141 long __pu_err; \
142 __typeof__(*(ptr)) __pu_val; \
143 long __pu_addr; \
144 __pu_val = (x); \
145 __pu_addr = (long) (ptr); \
146 __asm__("":"=r" (__pu_err)); \
147 switch (size) { \
148 case 1: __put_user_asm("sb"); break; \
149 case 2: __put_user_asm("sh"); break; \
150 case 4: __put_user_asm("sw"); break; \
151 case 8: __put_user_asm("sd"); break; \
152 default: __put_user_unknown(); break; \
153 } __pu_err; })
154
155 #define __put_user_check(x,ptr,size) ({ \
156 long __pu_err; \
157 __typeof__(*(ptr)) __pu_val; \
158 long __pu_addr; \
159 __pu_val = (x); \
160 __pu_addr = (long) (ptr); \
161 __asm__("":"=r" (__pu_err)); \
162 if (__access_ok(__pu_addr,size,__access_mask)) { \
163 switch (size) { \
164 case 1: __put_user_asm("sb"); break; \
165 case 2: __put_user_asm("sh"); break; \
166 case 4: __put_user_asm("sw"); break; \
167 case 8: __put_user_asm("sd"); break; \
168 default: __put_user_unknown(); break; \
169 } } __pu_err; })
170
171 #define __put_user_asm(insn) \
172 ({ \
173 __asm__ __volatile__( \
174 "1:\t" insn "\t%1,%2\n\t" \
175 "move\t%0,$0\n" \
176 "2:\n\t" \
177 ".section\t.fixup,\"ax\"\n" \
178 "3:\tli\t%0,%3\n\t" \
179 "j\t2b\n\t" \
180 ".previous\n\t" \
181 ".section\t__ex_table,\"a\"\n\t" \
182 ".dword\t1b,3b\n\t" \
183 ".previous" \
184 :"=r" (__pu_err) \
185 :"r" (__pu_val), "o" (__m(__pu_addr)), "i" (-EFAULT)); })
186
187 extern void __put_user_unknown(void);
188
189 /*
190 * We're generating jump to subroutines which will be outside the range of
191 * jump instructions
192 */
193 #ifdef MODULE
194 #define __MODULE_JAL(destination) \
195 ".set\tnoat\n\t" \
196 "la\t$1, " #destination "\n\t" \
197 "jalr\t$1\n\t" \
198 ".set\tat\n\t"
199 #else
200 #define __MODULE_JAL(destination) \
201 "jal\t" #destination "\n\t"
202 #endif
203
204 extern size_t __copy_user(void *__to, const void *__from, size_t __n);
205
206 #define __copy_to_user(to,from,n) ({ \
207 void *__cu_to; \
208 const void *__cu_from; \
209 long __cu_len; \
210 \
211 __cu_to = (to); \
212 __cu_from = (from); \
213 __cu_len = (n); \
214 __asm__ __volatile__( \
215 "move\t$4, %1\n\t" \
216 "move\t$5, %2\n\t" \
217 "move\t$6, %3\n\t" \
218 __MODULE_JAL(__copy_user) \
219 "move\t%0, $6" \
220 : "=r" (__cu_len) \
221 : "r" (__cu_to), "r" (__cu_from), "r" (__cu_len) \
222 : "$4", "$5", "$6", "$8", "$9", "$10", "$11", "$12", "$15", \
223 "$24", "$31","memory"); \
224 __cu_len; \
225 })
226
227 #define __copy_from_user(to,from,n) ({ \
228 void *__cu_to; \
229 const void *__cu_from; \
230 long __cu_len; \
231 \
232 __cu_to = (to); \
233 __cu_from = (from); \
234 __cu_len = (n); \
235 __asm__ __volatile__( \
236 "move\t$4, %1\n\t" \
237 "move\t$5, %2\n\t" \
238 "move\t$6, %3\n\t" \
239 ".set\tnoreorder\n\t" \
240 __MODULE_JAL(__copy_user) \
241 ".set\tnoat\n\t" \
242 "daddu\t$1, %2, %3\n\t" \
243 ".set\tat\n\t" \
244 ".set\treorder\n\t" \
245 "move\t%0, $6" \
246 : "=r" (__cu_len) \
247 : "r" (__cu_to), "r" (__cu_from), "r" (__cu_len) \
248 : "$4", "$5", "$6", "$8", "$9", "$10", "$11", "$12", "$15", \
249 "$24", "$31","memory"); \
250 __cu_len; \
251 })
252
253 #define copy_to_user(to,from,n) ({ \
254 void *__cu_to; \
255 const void *__cu_from; \
256 long __cu_len; \
257 \
258 __cu_to = (to); \
259 __cu_from = (from); \
260 __cu_len = (n); \
261 if (access_ok(VERIFY_WRITE, __cu_to, __cu_len)) \
262 __asm__ __volatile__( \
263 "move\t$4, %1\n\t" \
264 "move\t$5, %2\n\t" \
265 "move\t$6, %3\n\t" \
266 __MODULE_JAL(__copy_user) \
267 "move\t%0, $6" \
268 : "=r" (__cu_len) \
269 : "r" (__cu_to), "r" (__cu_from), "r" (__cu_len) \
270 : "$4", "$5", "$6", "$8", "$9", "$10", "$11", "$12", \
271 "$15", "$24", "$31","memory"); \
272 __cu_len; \
273 })
274
275 #define copy_from_user(to,from,n) ({ \
276 void *__cu_to; \
277 const void *__cu_from; \
278 long __cu_len; \
279 \
280 __cu_to = (to); \
281 __cu_from = (from); \
282 __cu_len = (n); \
283 if (access_ok(VERIFY_READ, __cu_from, __cu_len)) \
284 __asm__ __volatile__( \
285 "move\t$4, %1\n\t" \
286 "move\t$5, %2\n\t" \
287 "move\t$6, %3\n\t" \
288 ".set\tnoreorder\n\t" \
289 __MODULE_JAL(__copy_user) \
290 ".set\tnoat\n\t" \
291 "daddu\t$1, %2, %3\n\t" \
292 ".set\tat\n\t" \
293 ".set\treorder\n\t" \
294 "move\t%0, $6" \
295 : "=r" (__cu_len) \
296 : "r" (__cu_to), "r" (__cu_from), "r" (__cu_len) \
297 : "$4", "$5", "$6", "$8", "$9", "$10", "$11", "$12", \
298 "$15", "$24", "$31","memory"); \
299 __cu_len; \
300 })
301
302 extern inline __kernel_size_t
303 __clear_user(void *addr, __kernel_size_t size)
304 {
305 __kernel_size_t res;
306
307 __asm__ __volatile__(
308 "move\t$4, %1\n\t"
309 "move\t$5, $0\n\t"
310 "move\t$6, %2\n\t"
311 __MODULE_JAL(__bzero)
312 "move\t%0, $6"
313 : "=r" (res)
314 : "r" (addr), "r" (size)
315 : "$4", "$5", "$6", "$8", "$9", "$31");
316
317 return res;
318 }
319
320 #define clear_user(addr,n) ({ \
321 void * __cl_addr = (addr); \
322 unsigned long __cl_size = (n); \
323 if (__cl_size && __access_ok(VERIFY_WRITE, ((unsigned long)(__cl_addr)), __cl_size)) \
324 __cl_size = __clear_user(__cl_addr, __cl_size); \
325 __cl_size; })
326
327 /*
328 * Returns: -EFAULT if exception before terminator, N if the entire
329 * buffer filled, else strlen.
330 */
331 extern inline long
332 __strncpy_from_user(char *__to, const char *__from, long __len)
333 {
334 long res;
335
336 __asm__ __volatile__(
337 "move\t$4, %1\n\t"
338 "move\t$5, %2\n\t"
339 "move\t$6, %3\n\t"
340 __MODULE_JAL(__strncpy_from_user_nocheck_asm)
341 "move\t%0, $2"
342 : "=r" (res)
343 : "r" (__to), "r" (__from), "r" (__len)
344 : "$2", "$3", "$4", "$5", "$6", "$8", "$31", "memory");
345
346 return res;
347 }
348
349 extern inline long
350 strncpy_from_user(char *__to, const char *__from, long __len)
351 {
352 long res;
353
354 __asm__ __volatile__(
355 "move\t$4, %1\n\t"
356 "move\t$5, %2\n\t"
357 "move\t$6, %3\n\t"
358 __MODULE_JAL(__strncpy_from_user_asm)
359 "move\t%0, $2"
360 : "=r" (res)
361 : "r" (__to), "r" (__from), "r" (__len)
362 : "$2", "$3", "$4", "$5", "$6", "$8", "$31", "memory");
363
364 return res;
365 }
366
367 /* Returns: 0 if bad, string length+1 (memory size) of string if ok */
368 extern inline long __strlen_user(const char *s)
369 {
370 long res;
371
372 __asm__ __volatile__(
373 "move\t$4, %1\n\t"
374 __MODULE_JAL(__strlen_user_nocheck_asm)
375 "move\t%0, $2"
376 : "=r" (res)
377 : "r" (s)
378 : "$2", "$4", "$8", "$31");
379
380 return res;
381 }
382
383 extern inline long strlen_user(const char *s)
384 {
385 long res;
386
387 __asm__ __volatile__(
388 "move\t$4, %1\n\t"
389 __MODULE_JAL(__strlen_user_asm)
390 "move\t%0, $2"
391 : "=r" (res)
392 : "r" (s)
393 : "$2", "$4", "$8", "$31");
394
395 return res;
396 }
397
398 /* Returns: 0 if bad, string length+1 (memory size) of string if ok */
399 extern inline long __strnlen_user(const char *s, long n)
400 {
401 long res;
402
403 __asm__ __volatile__(
404 "move\t$4, %1\n\t"
405 "move\t$5, %2\n\t"
406 __MODULE_JAL(__strlen_user_nocheck_asm)
407 "move\t%0, $2"
408 : "=r" (res)
409 : "r" (s), "r" (n)
410 : "$2", "$4", "$5", "$8", "$31");
411
412 return res;
413 }
414
415 extern inline long strnlen_user(const char *s, long n)
416 {
417 long res;
418
419 __asm__ __volatile__(
420 "move\t$4, %1\n\t"
421 "move\t$5, %2\n\t"
422 __MODULE_JAL(__strlen_user_asm)
423 "move\t%0, $2"
424 : "=r" (res)
425 : "r" (s), "r" (n)
426 : "$2", "$4", "$5", "$8", "$31");
427
428 return res;
429 }
430
431 struct exception_table_entry
432 {
433 unsigned long insn;
434 unsigned long nextinsn;
435 };
436
437 /* Returns 0 if exception not found and fixup.unit otherwise. */
438 extern unsigned long search_exception_table(unsigned long addr);
439
440 /* Returns the new pc */
441 #define fixup_exception(map_reg, fixup_unit, pc) \
442 ({ \
443 fixup_unit; \
444 })
445
446 #endif /* _ASM_UACCESS_H */
447
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.