File: /usr/src/linux/include/asm-mips/uaccess.h
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 __ua_size(size) \
49 (__builtin_constant_p(size) && (signed long) (size) > 0 ? 0 : (size))
50
51 #define __access_ok(addr,size,mask) \
52 (((signed long)((mask)&(addr | (addr + size) | __ua_size(size)))) >= 0)
53
54 #define __access_mask ((long)(get_fs().seg))
55
56 #define access_ok(type,addr,size) \
57 __access_ok(((unsigned long)(addr)),(size),__access_mask)
58
59 extern inline int verify_area(int type, const void * addr, unsigned long size)
60 {
61 return access_ok(type,addr,size) ? 0 : -EFAULT;
62 }
63
64 /*
65 * Uh, these should become the main single-value transfer routines ...
66 * They automatically use the right size if we just have the right
67 * pointer type ...
68 *
69 * As MIPS uses the same address space for kernel and user data, we
70 * can just do these as direct assignments.
71 *
72 * Careful to not
73 * (a) re-use the arguments for side effects (sizeof is ok)
74 * (b) require any knowledge of processes at this stage
75 */
76 #define put_user(x,ptr) \
77 __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
78 #define get_user(x,ptr) \
79 __get_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
80
81 /*
82 * The "__xxx" versions do not do address space checking, useful when
83 * doing multiple accesses to the same area (the user has to do the
84 * checks by hand with "access_ok()")
85 */
86 #define __put_user(x,ptr) \
87 __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
88 #define __get_user(x,ptr) \
89 __get_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
90
91 struct __large_struct { unsigned long buf[100]; };
92 #define __m(x) (*(struct __large_struct *)(x))
93
94 /*
95 * Yuck. We need two variants, one for 64bit operation and one
96 * for 32 bit mode and old iron.
97 */
98 #ifdef __mips64
99 #define __GET_USER_DW __get_user_asm("ld")
100 #else
101 #define __GET_USER_DW __get_user_asm_ll32
102 #endif
103
104 #define __get_user_nocheck(x,ptr,size) ({ \
105 long __gu_err; \
106 __typeof(*(ptr)) __gu_val; \
107 long __gu_addr; \
108 __asm__("":"=r" (__gu_val)); \
109 __gu_addr = (long) (ptr); \
110 __asm__("":"=r" (__gu_err)); \
111 switch (size) { \
112 case 1: __get_user_asm("lb"); break; \
113 case 2: __get_user_asm("lh"); break; \
114 case 4: __get_user_asm("lw"); break; \
115 case 8: __GET_USER_DW; break; \
116 default: __get_user_unknown(); break; \
117 } x = (__typeof__(*(ptr))) __gu_val; __gu_err; })
118
119 #define __get_user_check(x,ptr,size) ({ \
120 long __gu_err; \
121 __typeof__(*(ptr)) __gu_val; \
122 long __gu_addr; \
123 __asm__("":"=r" (__gu_val)); \
124 __gu_addr = (long) (ptr); \
125 __asm__("":"=r" (__gu_err)); \
126 if (__access_ok(__gu_addr,size,__access_mask)) { \
127 switch (size) { \
128 case 1: __get_user_asm("lb"); break; \
129 case 2: __get_user_asm("lh"); break; \
130 case 4: __get_user_asm("lw"); break; \
131 case 8: __GET_USER_DW; break; \
132 default: __get_user_unknown(); break; \
133 } } x = (__typeof__(*(ptr))) __gu_val; __gu_err; })
134
135 #define __get_user_asm(insn) \
136 ({ \
137 __asm__ __volatile__( \
138 "1:\t" insn "\t%1,%2\n\t" \
139 "move\t%0,$0\n" \
140 "2:\n\t" \
141 ".section\t.fixup,\"ax\"\n" \
142 "3:\tli\t%0,%3\n\t" \
143 "move\t%1,$0\n\t" \
144 "j\t2b\n\t" \
145 ".previous\n\t" \
146 ".section\t__ex_table,\"a\"\n\t" \
147 ".word\t1b,3b\n\t" \
148 ".previous" \
149 :"=r" (__gu_err), "=r" (__gu_val) \
150 :"o" (__m(__gu_addr)), "i" (-EFAULT)); })
151
152 /*
153 * Get a long long 64 using 32 bit registers.
154 */
155 #define __get_user_asm_ll32 \
156 ({ \
157 __asm__ __volatile__( \
158 "1:\tlw\t%1,%2\n" \
159 "2:\tlw\t%D1,%3\n\t" \
160 "move\t%0,$0\n" \
161 "3:\t.section\t.fixup,\"ax\"\n" \
162 "4:\tli\t%0,%4\n\t" \
163 "move\t%1,$0\n\t" \
164 "move\t%D1,$0\n\t" \
165 "j\t3b\n\t" \
166 ".previous\n\t" \
167 ".section\t__ex_table,\"a\"\n\t" \
168 ".word\t1b,4b\n\t" \
169 ".word\t2b,4b\n\t" \
170 ".previous" \
171 :"=r" (__gu_err), "=&r" (__gu_val) \
172 :"o" (__m(__gu_addr)), "o" (__m(__gu_addr + 4)), \
173 "i" (-EFAULT)); })
174
175 extern void __get_user_unknown(void);
176
177 /*
178 * Yuck. We need two variants, one for 64bit operation and one
179 * for 32 bit mode and old iron.
180 */
181 #ifdef __mips64
182 #define __PUT_USER_DW __put_user_asm("sd")
183 #else
184 #define __PUT_USER_DW __put_user_asm_ll32
185 #endif
186
187 #define __put_user_nocheck(x,ptr,size) ({ \
188 long __pu_err; \
189 __typeof__(*(ptr)) __pu_val; \
190 long __pu_addr; \
191 __pu_val = (x); \
192 __pu_addr = (long) (ptr); \
193 __asm__("":"=r" (__pu_err)); \
194 switch (size) { \
195 case 1: __put_user_asm("sb"); break; \
196 case 2: __put_user_asm("sh"); break; \
197 case 4: __put_user_asm("sw"); break; \
198 case 8: __PUT_USER_DW; break; \
199 default: __put_user_unknown(); break; \
200 } __pu_err; })
201
202 #define __put_user_check(x,ptr,size) ({ \
203 long __pu_err; \
204 __typeof__(*(ptr)) __pu_val; \
205 long __pu_addr; \
206 __pu_val = (x); \
207 __pu_addr = (long) (ptr); \
208 __asm__("":"=r" (__pu_err)); \
209 if (__access_ok(__pu_addr,size,__access_mask)) { \
210 switch (size) { \
211 case 1: __put_user_asm("sb"); break; \
212 case 2: __put_user_asm("sh"); break; \
213 case 4: __put_user_asm("sw"); break; \
214 case 8: __PUT_USER_DW; break; \
215 default: __put_user_unknown(); break; \
216 } } __pu_err; })
217
218 #define __put_user_asm(insn) \
219 ({ \
220 __asm__ __volatile__( \
221 "1:\t" insn "\t%z1, %2\t\t\t# __put_user_asm\n\t" \
222 "move\t%0, $0\n" \
223 "2:\n\t" \
224 ".section\t.fixup,\"ax\"\n" \
225 "3:\tli\t%0,%3\n\t" \
226 "j\t2b\n\t" \
227 ".previous\n\t" \
228 ".section\t__ex_table,\"a\"\n\t" \
229 ".word\t1b,3b\n\t" \
230 ".previous" \
231 :"=r" (__pu_err) \
232 :"Jr" (__pu_val), "o" (__m(__pu_addr)), "i" (-EFAULT)); })
233
234 #define __put_user_asm_ll32 \
235 ({ \
236 __asm__ __volatile__( \
237 "1:\tsw\t%1, %2\t\t\t# __put_user_asm_ll32\n\t" \
238 "2:\tsw\t%D1, %3\n" \
239 "move\t%0, $0\n" \
240 "3:\n\t" \
241 ".section\t.fixup,\"ax\"\n" \
242 "4:\tli\t%0,%4\n\t" \
243 "j\t3b\n\t" \
244 ".previous\n\t" \
245 ".section\t__ex_table,\"a\"\n\t" \
246 ".word\t1b,4b\n\t" \
247 ".word\t2b,4b\n\t" \
248 ".previous" \
249 :"=r" (__pu_err) \
250 :"r" (__pu_val), "o" (__m(__pu_addr)), "o" (__m(__pu_addr + 4)), \
251 "i" (-EFAULT)); })
252
253 extern void __put_user_unknown(void);
254
255 /*
256 * We're generating jump to subroutines which will be outside the range of
257 * jump instructions
258 */
259 #ifdef MODULE
260 #define __MODULE_JAL(destination) \
261 ".set\tnoat\n\t" \
262 "la\t$1, " #destination "\n\t" \
263 "jalr\t$1\n\t" \
264 ".set\tat\n\t"
265 #else
266 #define __MODULE_JAL(destination) \
267 "jal\t" #destination "\n\t"
268 #endif
269
270 extern size_t __copy_user(void *__to, const void *__from, size_t __n);
271
272 #define __copy_to_user(to,from,n) ({ \
273 void *__cu_to; \
274 const void *__cu_from; \
275 long __cu_len; \
276 \
277 __cu_to = (to); \
278 __cu_from = (from); \
279 __cu_len = (n); \
280 __asm__ __volatile__( \
281 "move\t$4, %1\n\t" \
282 "move\t$5, %2\n\t" \
283 "move\t$6, %3\n\t" \
284 __MODULE_JAL(__copy_user) \
285 "move\t%0, $6" \
286 : "=r" (__cu_len) \
287 : "r" (__cu_to), "r" (__cu_from), "r" (__cu_len) \
288 : "$4", "$5", "$6", "$8", "$9", "$10", "$11", "$12", "$15", \
289 "$24", "$31","memory"); \
290 __cu_len; \
291 })
292
293 #define __copy_from_user(to,from,n) ({ \
294 void *__cu_to; \
295 const void *__cu_from; \
296 long __cu_len; \
297 \
298 __cu_to = (to); \
299 __cu_from = (from); \
300 __cu_len = (n); \
301 __asm__ __volatile__( \
302 "move\t$4, %1\n\t" \
303 "move\t$5, %2\n\t" \
304 "move\t$6, %3\n\t" \
305 ".set\tnoreorder\n\t" \
306 __MODULE_JAL(__copy_user) \
307 ".set\tnoat\n\t" \
308 "addu\t$1, %2, %3\n\t" \
309 ".set\tat\n\t" \
310 ".set\treorder\n\t" \
311 "move\t%0, $6" \
312 : "=r" (__cu_len) \
313 : "r" (__cu_to), "r" (__cu_from), "r" (__cu_len) \
314 : "$4", "$5", "$6", "$8", "$9", "$10", "$11", "$12", "$15", \
315 "$24", "$31","memory"); \
316 __cu_len; \
317 })
318
319 #define copy_to_user(to,from,n) ({ \
320 void *__cu_to; \
321 const void *__cu_from; \
322 long __cu_len; \
323 \
324 __cu_to = (to); \
325 __cu_from = (from); \
326 __cu_len = (n); \
327 if (access_ok(VERIFY_WRITE, __cu_to, __cu_len)) \
328 __asm__ __volatile__( \
329 "move\t$4, %1\n\t" \
330 "move\t$5, %2\n\t" \
331 "move\t$6, %3\n\t" \
332 __MODULE_JAL(__copy_user) \
333 "move\t%0, $6" \
334 : "=r" (__cu_len) \
335 : "r" (__cu_to), "r" (__cu_from), "r" (__cu_len) \
336 : "$4", "$5", "$6", "$8", "$9", "$10", "$11", "$12", \
337 "$15", "$24", "$31","memory"); \
338 __cu_len; \
339 })
340
341 #define copy_from_user(to,from,n) ({ \
342 void *__cu_to; \
343 const void *__cu_from; \
344 long __cu_len; \
345 \
346 __cu_to = (to); \
347 __cu_from = (from); \
348 __cu_len = (n); \
349 if (access_ok(VERIFY_READ, __cu_from, __cu_len)) \
350 __asm__ __volatile__( \
351 "move\t$4, %1\n\t" \
352 "move\t$5, %2\n\t" \
353 "move\t$6, %3\n\t" \
354 ".set\tnoreorder\n\t" \
355 __MODULE_JAL(__copy_user) \
356 ".set\tnoat\n\t" \
357 "addu\t$1, %2, %3\n\t" \
358 ".set\tat\n\t" \
359 ".set\treorder\n\t" \
360 "move\t%0, $6" \
361 : "=r" (__cu_len) \
362 : "r" (__cu_to), "r" (__cu_from), "r" (__cu_len) \
363 : "$4", "$5", "$6", "$8", "$9", "$10", "$11", "$12", \
364 "$15", "$24", "$31","memory"); \
365 __cu_len; \
366 })
367
368 extern inline __kernel_size_t
369 __clear_user(void *addr, __kernel_size_t size)
370 {
371 __kernel_size_t res;
372
373 __asm__ __volatile__(
374 "move\t$4, %1\n\t"
375 "move\t$5, $0\n\t"
376 "move\t$6, %2\n\t"
377 __MODULE_JAL(__bzero)
378 "move\t%0, $6"
379 : "=r" (res)
380 : "r" (addr), "r" (size)
381 : "$4", "$5", "$6", "$8", "$9", "$31");
382
383 return res;
384 }
385
386 #define clear_user(addr,n) ({ \
387 void * __cl_addr = (addr); \
388 unsigned long __cl_size = (n); \
389 if (__cl_size && access_ok(VERIFY_WRITE, ((unsigned long)(__cl_addr)), __cl_size)) \
390 __cl_size = __clear_user(__cl_addr, __cl_size); \
391 __cl_size; })
392
393 /*
394 * Returns: -EFAULT if exception before terminator, N if the entire
395 * buffer filled, else strlen.
396 */
397 extern inline long
398 __strncpy_from_user(char *__to, const char *__from, long __len)
399 {
400 long res;
401
402 __asm__ __volatile__(
403 "move\t$4, %1\n\t"
404 "move\t$5, %2\n\t"
405 "move\t$6, %3\n\t"
406 __MODULE_JAL(__strncpy_from_user_nocheck_asm)
407 "move\t%0, $2"
408 : "=r" (res)
409 : "r" (__to), "r" (__from), "r" (__len)
410 : "$2", "$3", "$4", "$5", "$6", "$8", "$31", "memory");
411
412 return res;
413 }
414
415 extern inline long
416 strncpy_from_user(char *__to, const char *__from, long __len)
417 {
418 long res;
419
420 __asm__ __volatile__(
421 "move\t$4, %1\n\t"
422 "move\t$5, %2\n\t"
423 "move\t$6, %3\n\t"
424 __MODULE_JAL(__strncpy_from_user_asm)
425 "move\t%0, $2"
426 : "=r" (res)
427 : "r" (__to), "r" (__from), "r" (__len)
428 : "$2", "$3", "$4", "$5", "$6", "$8", "$31", "memory");
429
430 return res;
431 }
432
433 /* Returns: 0 if bad, string length+1 (memory size) of string if ok */
434 extern inline long __strlen_user(const char *s)
435 {
436 long res;
437
438 __asm__ __volatile__(
439 "move\t$4, %1\n\t"
440 __MODULE_JAL(__strlen_user_nocheck_asm)
441 "move\t%0, $2"
442 : "=r" (res)
443 : "r" (s)
444 : "$2", "$4", "$8", "$31");
445
446 return res;
447 }
448
449 extern inline long strlen_user(const char *s)
450 {
451 long res;
452
453 __asm__ __volatile__(
454 "move\t$4, %1\n\t"
455 __MODULE_JAL(__strlen_user_asm)
456 "move\t%0, $2"
457 : "=r" (res)
458 : "r" (s)
459 : "$2", "$4", "$8", "$31");
460
461 return res;
462 }
463
464 /* Returns: 0 if bad, string length+1 (memory size) of string if ok */
465 extern inline long __strnlen_user(const char *s, long n)
466 {
467 long res;
468
469 __asm__ __volatile__(
470 "move\t$4, %1\n\t"
471 "move\t$5, %2\n\t"
472 __MODULE_JAL(__strnlen_user_nocheck_asm)
473 "move\t%0, $2"
474 : "=r" (res)
475 : "r" (s), "r" (n)
476 : "$2", "$4", "$5", "$8", "$31");
477
478 return res;
479 }
480
481 extern inline long strnlen_user(const char *s, long n)
482 {
483 long res;
484
485 __asm__ __volatile__(
486 "move\t$4, %1\n\t"
487 "move\t$5, %2\n\t"
488 __MODULE_JAL(__strnlen_user_asm)
489 "move\t%0, $2"
490 : "=r" (res)
491 : "r" (s), "r" (n)
492 : "$2", "$4", "$5", "$8", "$31");
493
494 return res;
495 }
496
497 struct exception_table_entry
498 {
499 unsigned long insn;
500 unsigned long nextinsn;
501 };
502
503 /* Returns 0 if exception not found and fixup.unit otherwise. */
504 extern unsigned long search_exception_table(unsigned long addr);
505
506 /* Returns the new pc */
507 #define fixup_exception(map_reg, fixup_unit, pc) \
508 ({ \
509 fixup_unit; \
510 })
511
512 #endif /* _ASM_UACCESS_H */
513