File: /usr/src/linux/include/asm-mips64/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 #define __get_user_nocheck(x,ptr,size) \
95 ({ \
96 long __gu_err; \
97 __typeof(*(ptr)) __gu_val; \
98 long __gu_addr; \
99 __asm__("":"=r" (__gu_val)); \
100 __gu_addr = (long) (ptr); \
101 __asm__("":"=r" (__gu_err)); \
102 switch (size) { \
103 case 1: __get_user_asm("lb"); break; \
104 case 2: __get_user_asm("lh"); break; \
105 case 4: __get_user_asm("lw"); break; \
106 case 8: __get_user_asm("ld"); break; \
107 default: __get_user_unknown(); break; \
108 } x = (__typeof__(*(ptr))) __gu_val; __gu_err; \
109 })
110
111 #define __get_user_check(x,ptr,size) \
112 ({ \
113 long __gu_err; \
114 __typeof__(*(ptr)) __gu_val; \
115 long __gu_addr; \
116 __asm__("":"=r" (__gu_val)); \
117 __gu_addr = (long) (ptr); \
118 __asm__("":"=r" (__gu_err)); \
119 if (__access_ok(__gu_addr,size,__access_mask)) { \
120 switch (size) { \
121 case 1: __get_user_asm("lb"); break; \
122 case 2: __get_user_asm("lh"); break; \
123 case 4: __get_user_asm("lw"); break; \
124 case 8: __get_user_asm("ld"); break; \
125 default: __get_user_unknown(); break; \
126 } \
127 } x = (__typeof__(*(ptr))) __gu_val; __gu_err; \
128 })
129
130 #define __get_user_asm(insn) \
131 ({ \
132 __asm__ __volatile__( \
133 "1:\t" insn "\t%1,%2\n\t" \
134 "move\t%0,$0\n" \
135 "2:\n\t" \
136 ".section\t.fixup,\"ax\"\n" \
137 "3:\tli\t%0,%3\n\t" \
138 "move\t%1,$0\n\t" \
139 "j\t2b\n\t" \
140 ".previous\n\t" \
141 ".section\t__ex_table,\"a\"\n\t" \
142 ".dword\t1b,3b\n\t" \
143 ".previous" \
144 :"=r" (__gu_err), "=r" (__gu_val) \
145 :"o" (__m(__gu_addr)), "i" (-EFAULT)); \
146 })
147
148 extern void __get_user_unknown(void);
149
150 #define __put_user_nocheck(x,ptr,size) \
151 ({ \
152 long __pu_err; \
153 __typeof__(*(ptr)) __pu_val; \
154 long __pu_addr; \
155 __pu_val = (x); \
156 __pu_addr = (long) (ptr); \
157 __asm__("":"=r" (__pu_err)); \
158 switch (size) { \
159 case 1: __put_user_asm("sb"); break; \
160 case 2: __put_user_asm("sh"); break; \
161 case 4: __put_user_asm("sw"); break; \
162 case 8: __put_user_asm("sd"); break; \
163 default: __put_user_unknown(); break; \
164 } __pu_err; \
165 })
166
167 #define __put_user_check(x,ptr,size) \
168 ({ \
169 long __pu_err; \
170 __typeof__(*(ptr)) __pu_val; \
171 long __pu_addr; \
172 __pu_val = (x); \
173 __pu_addr = (long) (ptr); \
174 __asm__("":"=r" (__pu_err)); \
175 if (__access_ok(__pu_addr,size,__access_mask)) { \
176 switch (size) { \
177 case 1: __put_user_asm("sb"); break; \
178 case 2: __put_user_asm("sh"); break; \
179 case 4: __put_user_asm("sw"); break; \
180 case 8: __put_user_asm("sd"); break; \
181 default: __put_user_unknown(); break; \
182 } \
183 } __pu_err; \
184 })
185
186 #define __put_user_asm(insn) \
187 ({ \
188 __asm__ __volatile__( \
189 "1:\t" insn "\t%z1, %2\t\t\t# __put_user_asm\n\t" \
190 "move\t%0,$0\n" \
191 "2:\n\t" \
192 ".section\t.fixup,\"ax\"\n" \
193 "3:\tli\t%0,%3\n\t" \
194 "j\t2b\n\t" \
195 ".previous\n\t" \
196 ".section\t__ex_table,\"a\"\n\t" \
197 ".dword\t1b,3b\n\t" \
198 ".previous" \
199 :"=r" (__pu_err) \
200 :"Jr" (__pu_val), "o" (__m(__pu_addr)), "i" (-EFAULT)); \
201 })
202
203 extern void __put_user_unknown(void);
204
205 /*
206 * We're generating jump to subroutines which will be outside the range of
207 * jump instructions
208 */
209 #ifdef MODULE
210 #define __MODULE_JAL(destination) \
211 ".set\tnoat\n\t" \
212 "dla\t$1, " #destination "\n\t" \
213 "jalr\t$1\n\t" \
214 ".set\tat\n\t"
215 #else
216 #define __MODULE_JAL(destination) \
217 "jal\t" #destination "\n\t"
218 #endif
219
220 extern size_t __copy_user(void *__to, const void *__from, size_t __n);
221
222 #define __copy_to_user(to,from,n) \
223 ({ \
224 void *__cu_to; \
225 const void *__cu_from; \
226 long __cu_len; \
227 \
228 __cu_to = (to); \
229 __cu_from = (from); \
230 __cu_len = (n); \
231 __asm__ __volatile__( \
232 "move\t$4, %1\n\t" \
233 "move\t$5, %2\n\t" \
234 "move\t$6, %3\n\t" \
235 __MODULE_JAL(__copy_user) \
236 "move\t%0, $6" \
237 : "=r" (__cu_len) \
238 : "r" (__cu_to), "r" (__cu_from), "r" (__cu_len) \
239 : "$4", "$5", "$6", "$8", "$9", "$10", "$11", "$12", \
240 "$15", "$24", "$31","memory"); \
241 __cu_len; \
242 })
243
244 #define __copy_from_user(to,from,n) \
245 ({ \
246 void *__cu_to; \
247 const void *__cu_from; \
248 long __cu_len; \
249 \
250 __cu_to = (to); \
251 __cu_from = (from); \
252 __cu_len = (n); \
253 __asm__ __volatile__( \
254 "move\t$4, %1\n\t" \
255 "move\t$5, %2\n\t" \
256 "move\t$6, %3\n\t" \
257 ".set\tnoreorder\n\t" \
258 __MODULE_JAL(__copy_user) \
259 ".set\tnoat\n\t" \
260 "daddu\t$1, %2, %3\n\t" \
261 ".set\tat\n\t" \
262 ".set\treorder\n\t" \
263 "move\t%0, $6" \
264 : "=r" (__cu_len) \
265 : "r" (__cu_to), "r" (__cu_from), "r" (__cu_len) \
266 : "$4", "$5", "$6", "$8", "$9", "$10", "$11", "$12", \
267 "$15", "$24", "$31","memory"); \
268 __cu_len; \
269 })
270
271 #define copy_to_user(to,from,n) \
272 ({ \
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 if (access_ok(VERIFY_WRITE, __cu_to, __cu_len)) \
281 __asm__ __volatile__( \
282 "move\t$4, %1\n\t" \
283 "move\t$5, %2\n\t" \
284 "move\t$6, %3\n\t" \
285 __MODULE_JAL(__copy_user) \
286 "move\t%0, $6" \
287 : "=r" (__cu_len) \
288 : "r" (__cu_to), "r" (__cu_from), "r" (__cu_len) \
289 : "$4", "$5", "$6", "$8", "$9", "$10", "$11", \
290 "$12", "$15", "$24", "$31","memory"); \
291 __cu_len; \
292 })
293
294 #define copy_from_user(to,from,n) \
295 ({ \
296 void *__cu_to; \
297 const void *__cu_from; \
298 long __cu_len; \
299 \
300 __cu_to = (to); \
301 __cu_from = (from); \
302 __cu_len = (n); \
303 if (access_ok(VERIFY_READ, __cu_from, __cu_len)) \
304 __asm__ __volatile__( \
305 "move\t$4, %1\n\t" \
306 "move\t$5, %2\n\t" \
307 "move\t$6, %3\n\t" \
308 ".set\tnoreorder\n\t" \
309 __MODULE_JAL(__copy_user) \
310 ".set\tnoat\n\t" \
311 "daddu\t$1, %2, %3\n\t" \
312 ".set\tat\n\t" \
313 ".set\treorder\n\t" \
314 "move\t%0, $6" \
315 : "=r" (__cu_len) \
316 : "r" (__cu_to), "r" (__cu_from), "r" (__cu_len) \
317 : "$4", "$5", "$6", "$8", "$9", "$10", "$11", \
318 "$12", "$15", "$24", "$31","memory"); \
319 __cu_len; \
320 })
321
322 extern inline __kernel_size_t
323 __clear_user(void *addr, __kernel_size_t size)
324 {
325 __kernel_size_t res;
326
327 __asm__ __volatile__(
328 "move\t$4, %1\n\t"
329 "move\t$5, $0\n\t"
330 "move\t$6, %2\n\t"
331 __MODULE_JAL(__bzero)
332 "move\t%0, $6"
333 : "=r" (res)
334 : "r" (addr), "r" (size)
335 : "$4", "$5", "$6", "$8", "$9", "$31");
336
337 return res;
338 }
339
340 #define clear_user(addr,n) \
341 ({ \
342 void * __cl_addr = (addr); \
343 unsigned long __cl_size = (n); \
344 if (__cl_size && __access_ok(VERIFY_WRITE, \
345 ((unsigned long)(__cl_addr)), __cl_size)) \
346 __cl_size = __clear_user(__cl_addr, __cl_size); \
347 __cl_size; \
348 })
349
350 /*
351 * Returns: -EFAULT if exception before terminator, N if the entire
352 * buffer filled, else strlen.
353 */
354 extern inline long
355 __strncpy_from_user(char *__to, const char *__from, long __len)
356 {
357 long res;
358
359 __asm__ __volatile__(
360 "move\t$4, %1\n\t"
361 "move\t$5, %2\n\t"
362 "move\t$6, %3\n\t"
363 __MODULE_JAL(__strncpy_from_user_nocheck_asm)
364 "move\t%0, $2"
365 : "=r" (res)
366 : "r" (__to), "r" (__from), "r" (__len)
367 : "$2", "$3", "$4", "$5", "$6", "$8", "$31", "memory");
368
369 return res;
370 }
371
372 extern inline long
373 strncpy_from_user(char *__to, const char *__from, long __len)
374 {
375 long res;
376
377 __asm__ __volatile__(
378 "move\t$4, %1\n\t"
379 "move\t$5, %2\n\t"
380 "move\t$6, %3\n\t"
381 __MODULE_JAL(__strncpy_from_user_asm)
382 "move\t%0, $2"
383 : "=r" (res)
384 : "r" (__to), "r" (__from), "r" (__len)
385 : "$2", "$3", "$4", "$5", "$6", "$8", "$31", "memory");
386
387 return res;
388 }
389
390 /* Returns: 0 if bad, string length+1 (memory size) of string if ok */
391 extern inline long __strlen_user(const char *s)
392 {
393 long res;
394
395 __asm__ __volatile__(
396 "move\t$4, %1\n\t"
397 __MODULE_JAL(__strlen_user_nocheck_asm)
398 "move\t%0, $2"
399 : "=r" (res)
400 : "r" (s)
401 : "$2", "$4", "$8", "$31");
402
403 return res;
404 }
405
406 extern inline long strlen_user(const char *s)
407 {
408 long res;
409
410 __asm__ __volatile__(
411 "move\t$4, %1\n\t"
412 __MODULE_JAL(__strlen_user_asm)
413 "move\t%0, $2"
414 : "=r" (res)
415 : "r" (s)
416 : "$2", "$4", "$8", "$31");
417
418 return res;
419 }
420
421 /* Returns: 0 if bad, string length+1 (memory size) of string if ok */
422 extern inline long __strnlen_user(const char *s, long n)
423 {
424 long res;
425
426 __asm__ __volatile__(
427 "move\t$4, %1\n\t"
428 "move\t$5, %2\n\t"
429 __MODULE_JAL(__strlen_user_nocheck_asm)
430 "move\t%0, $2"
431 : "=r" (res)
432 : "r" (s), "r" (n)
433 : "$2", "$4", "$5", "$8", "$31");
434
435 return res;
436 }
437
438 extern inline long strnlen_user(const char *s, long n)
439 {
440 long res;
441
442 __asm__ __volatile__(
443 "move\t$4, %1\n\t"
444 "move\t$5, %2\n\t"
445 __MODULE_JAL(__strlen_user_asm)
446 "move\t%0, $2"
447 : "=r" (res)
448 : "r" (s), "r" (n)
449 : "$2", "$4", "$5", "$8", "$31");
450
451 return res;
452 }
453
454 struct exception_table_entry
455 {
456 unsigned long insn;
457 unsigned long nextinsn;
458 };
459
460 /* Returns 0 if exception not found and fixup.unit otherwise. */
461 extern unsigned long search_exception_table(unsigned long addr);
462
463 /* Returns the new pc */
464 #define fixup_exception(map_reg, fixup_unit, pc) \
465 ({ \
466 fixup_unit; \
467 })
468
469 #endif /* _ASM_UACCESS_H */
470