uaccess.h
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:11k
- /* $Id: uaccess.h,v 1.13 2001/10/01 02:22:01 gniibe Exp $
- *
- * User space memory access functions
- *
- * Copyright (C) 1999 Niibe Yutaka
- *
- * Based on:
- * MIPS implementation version 1.15 by
- * Copyright (C) 1996, 1997, 1998 by Ralf Baechle
- * and i386 version.
- */
- #ifndef __ASM_SH_UACCESS_H
- #define __ASM_SH_UACCESS_H
- #include <linux/errno.h>
- #include <linux/sched.h>
- #define VERIFY_READ 0
- #define VERIFY_WRITE 1
- /*
- * The fs value determines whether argument validity checking should be
- * performed or not. If get_fs() == USER_DS, checking is performed, with
- * get_fs() == KERNEL_DS, checking is bypassed.
- *
- * For historical reasons (Data Segment Register?), these macros are misnamed.
- */
- #define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
- #define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFF)
- #define USER_DS MAKE_MM_SEG(0x80000000)
- #define get_ds() (KERNEL_DS)
- #define get_fs() (current->addr_limit)
- #define set_fs(x) (current->addr_limit=(x))
- #define segment_eq(a,b) ((a).seg == (b).seg)
- #define __addr_ok(addr) ((unsigned long)(addr) < (current->addr_limit.seg))
- /*
- * Uhhuh, this needs 33-bit arithmetic. We have a carry..
- *
- * sum := addr + size; carry? --> flag = true;
- * if (sum >= addr_limit) flag = true;
- */
- #define __range_ok(addr,size) ({
- unsigned long flag,sum;
- __asm__("clrt; addc %3, %1; movt %0; cmp/hi %4, %1; rotcl %0"
- :"=&r" (flag), "=r" (sum)
- :"1" (addr), "r" ((int)(size)), "r" (current->addr_limit.seg)
- :"t");
- flag; })
- #define access_ok(type,addr,size) (__range_ok(addr,size) == 0)
- #define __access_ok(addr,size) (__range_ok(addr,size) == 0)
- static inline int verify_area(int type, const void * addr, unsigned long size)
- {
- return access_ok(type,addr,size) ? 0 : -EFAULT;
- }
- /*
- * Uh, these should become the main single-value transfer routines ...
- * They automatically use the right size if we just have the right
- * pointer type ...
- *
- * As SuperH uses the same address space for kernel and user data, we
- * can just do these as direct assignments.
- *
- * Careful to not
- * (a) re-use the arguments for side effects (sizeof is ok)
- * (b) require any knowledge of processes at this stage
- */
- #define put_user(x,ptr) __put_user_check((x),(ptr),sizeof(*(ptr)))
- #define get_user(x,ptr) __get_user_check((x),(ptr),sizeof(*(ptr)))
- /*
- * The "__xxx" versions do not do address space checking, useful when
- * doing multiple accesses to the same area (the user has to do the
- * checks by hand with "access_ok()")
- */
- #define __put_user(x,ptr) __put_user_nocheck((x),(ptr),sizeof(*(ptr)))
- #define __get_user(x,ptr) __get_user_nocheck((x),(ptr),sizeof(*(ptr)))
- struct __large_struct { unsigned long buf[100]; };
- #define __m(x) (*(struct __large_struct *)(x))
- #define __get_user_nocheck(x,ptr,size) ({
- long __gu_err;
- __typeof(*(ptr)) __gu_val;
- long __gu_addr;
- __asm__("":"=r" (__gu_val));
- __gu_addr = (long) (ptr);
- __asm__("":"=r" (__gu_err));
- switch (size) {
- case 1: __get_user_asm("b"); break;
- case 2: __get_user_asm("w"); break;
- case 4: __get_user_asm("l"); break;
- default: __get_user_unknown(); break;
- } x = (__typeof__(*(ptr))) __gu_val; __gu_err; })
- #define __get_user_check(x,ptr,size) ({
- long __gu_err;
- __typeof__(*(ptr)) __gu_val;
- long __gu_addr;
- __asm__("":"=r" (__gu_val));
- __gu_addr = (long) (ptr);
- __asm__("":"=r" (__gu_err));
- if (__access_ok(__gu_addr,size)) {
- switch (size) {
- case 1: __get_user_asm("b"); break;
- case 2: __get_user_asm("w"); break;
- case 4: __get_user_asm("l"); break;
- default: __get_user_unknown(); break;
- } } x = (__typeof__(*(ptr))) __gu_val; __gu_err; })
- #define __get_user_asm(insn)
- ({
- __asm__ __volatile__(
- "1:nt"
- "mov." insn " %2, %1nt"
- "mov #0, %0n"
- "2:n"
- ".section .fixup,"ax"n"
- "3:nt"
- "mov #0, %1nt"
- "mov.l 4f, %0nt"
- "jmp @%0nt"
- " mov %3, %0n"
- "4: .long 2bnt"
- ".previousn"
- ".section __ex_table,"a"nt"
- ".long 1b, 3bnt"
- ".previous"
- :"=&r" (__gu_err), "=&r" (__gu_val)
- :"m" (__m(__gu_addr)), "i" (-EFAULT)); })
- extern void __get_user_unknown(void);
- #define __put_user_nocheck(x,ptr,size) ({
- long __pu_err;
- __typeof__(*(ptr)) __pu_val;
- long __pu_addr;
- __pu_val = (x);
- __pu_addr = (long) (ptr);
- __asm__("":"=r" (__pu_err));
- switch (size) {
- case 1: __put_user_asm("b"); break;
- case 2: __put_user_asm("w"); break;
- case 4: __put_user_asm("l"); break;
- case 8: __put_user_u64(__pu_val,__pu_addr,__pu_err); break;
- default: __put_user_unknown(); break;
- } __pu_err; })
- #define __put_user_check(x,ptr,size) ({
- long __pu_err;
- __typeof__(*(ptr)) __pu_val;
- long __pu_addr;
- __pu_val = (x);
- __pu_addr = (long) (ptr);
- __asm__("":"=r" (__pu_err));
- if (__access_ok(__pu_addr,size)) {
- switch (size) {
- case 1: __put_user_asm("b"); break;
- case 2: __put_user_asm("w"); break;
- case 4: __put_user_asm("l"); break;
- case 8: __put_user_u64(__pu_val,__pu_addr,__pu_err); break;
- default: __put_user_unknown(); break;
- } } __pu_err; })
- #define __put_user_asm(insn)
- ({
- __asm__ __volatile__(
- "1:nt"
- "mov." insn " %1, %2nt"
- "mov #0, %0n"
- "2:n"
- ".section .fixup,"ax"n"
- "3:nt"
- "nopnt"
- "mov.l 4f, %0nt"
- "jmp @%0nt"
- "mov %3, %0n"
- "4: .long 2bnt"
- ".previousn"
- ".section __ex_table,"a"nt"
- ".long 1b, 3bnt"
- ".previous"
- :"=&r" (__pu_err)
- :"r" (__pu_val), "m" (__m(__pu_addr)), "i" (-EFAULT)
- :"memory"); })
- #if defined(__LITTLE_ENDIAN__)
- #define __put_user_u64(val,addr,retval)
- ({
- __asm__ __volatile__(
- "1:nt"
- "mov.l %R1,%2nt"
- "mov.l %S1,%T2nt"
- "mov #0,%0n"
- "2:n"
- ".section .fixup,"ax"n"
- "3:nt"
- "nopnt"
- "mov.l 4f,%0nt"
- "jmp @%0nt"
- " mov %3,%0n"
- "4: .long 2bnt"
- ".previousn"
- ".section __ex_table,"a"nt"
- ".long 1b, 3bnt"
- ".previous"
- : "=r" (retval)
- : "r" (val), "m" (__m(addr)), "i" (-EFAULT)
- : "memory"); })
- #else
- #define __put_user_u64(val,addr,retval)
- ({
- __asm__ __volatile__(
- "1:nt"
- "mov.l %S1,%2nt"
- "mov.l %R1,%T2nt"
- "mov #0,%0n"
- "2:n"
- ".section .fixup,"ax"n"
- "3:nt"
- "nopnt"
- "mov.l 4f,%0nt"
- "jmp @%0nt"
- " mov %3,%0n"
- "4: .long 2bnt"
- ".previousn"
- ".section __ex_table,"a"nt"
- ".long 1b, 3bnt"
- ".previous"
- : "=r" (retval)
- : "r" (val), "m" (__m(addr)), "i" (-EFAULT)
- : "memory"); })
- #endif
- extern void __put_user_unknown(void);
- /* Generic arbitrary sized copy. */
- /* Return the number of bytes NOT copied */
- /* XXX: should be such that: 4byte and the rest. */
- static __inline__ __kernel_size_t
- __copy_user(void *__to, const void *__from, __kernel_size_t __n)
- {
- unsigned long __dummy, _f, _t;
- __kernel_size_t res;
- if ((res = __n))
- __asm__ __volatile__(
- "9:nt"
- "mov.b @%2+, %1nt"
- "dt %0n"
- "1:nt"
- "mov.b %1, @%3nt"
- "bf/s 9bnt"
- " add #1, %3n"
- "2:n"
- ".section .fixup,"ax"n"
- "3:nt"
- "mov.l 5f, %1nt"
- "jmp @%1nt"
- " add #1, %0nt"
- ".balign 4n"
- "5: .long 2bn"
- ".previousn"
- ".section __ex_table,"a"n"
- " .balign 4n"
- " .long 9b,2bn"
- " .long 1b,3bn"
- ".previous"
- : "=r" (res), "=&z" (__dummy), "=r" (_f), "=r" (_t)
- : "2" (__from), "3" (__to), "0" (res)
- : "memory", "t");
- return res;
- }
- #define copy_to_user(to,from,n) ({
- void *__copy_to = (void *) (to);
- __kernel_size_t __copy_size = (__kernel_size_t) (n);
- __kernel_size_t __copy_res;
- if(__copy_size && __access_ok((unsigned long)__copy_to, __copy_size)) {
- __copy_res = __copy_user(__copy_to, (void *) (from), __copy_size);
- } else __copy_res = __copy_size;
- __copy_res; })
- #define __copy_to_user(to,from,n)
- __copy_user((void *)(to),
- (void *)(from), n)
- #define copy_from_user(to,from,n) ({
- void *__copy_to = (void *) (to);
- void *__copy_from = (void *) (from);
- __kernel_size_t __copy_size = (__kernel_size_t) (n);
- __kernel_size_t __copy_res;
- if(__copy_size && __access_ok((unsigned long)__copy_from, __copy_size)) {
- __copy_res = __copy_user(__copy_to, __copy_from, __copy_size);
- } else __copy_res = __copy_size;
- __copy_res; })
- #define __copy_from_user(to,from,n)
- __copy_user((void *)(to),
- (void *)(from), n)
- /* XXX: Not sure it works well..
- should be such that: 4byte clear and the rest. */
- static __inline__ __kernel_size_t
- __clear_user(void *addr, __kernel_size_t size)
- {
- unsigned long __a;
- __asm__ __volatile__(
- "9:nt"
- "dt %0n"
- "1:nt"
- "mov.b %4, @%1nt"
- "bf/s 9bnt"
- " add #1, %1n"
- "2:n"
- ".section .fixup,"ax"n"
- "3:nt"
- "mov.l 4f, %1nt"
- "jmp @%1nt"
- " nopn"
- ".balign 4n"
- "4: .long 2bn"
- ".previousn"
- ".section __ex_table,"a"n"
- " .balign 4n"
- " .long 1b,3bn"
- ".previous"
- : "=r" (size), "=r" (__a)
- : "0" (size), "1" (addr), "r" (0)
- : "memory", "t");
- return size;
- }
- #define clear_user(addr,n) ({
- void * __cl_addr = (addr);
- unsigned long __cl_size = (n);
- if (__cl_size && __access_ok(((unsigned long)(__cl_addr)), __cl_size))
- __cl_size = __clear_user(__cl_addr, __cl_size);
- __cl_size; })
- static __inline__ int
- __strncpy_from_user(unsigned long __dest, unsigned long __src, int __count)
- {
- __kernel_size_t res;
- unsigned long __dummy, _d, _s;
- __asm__ __volatile__(
- "9:n"
- "mov.b @%2+, %1nt"
- "cmp/eq #0, %1nt"
- "bt/s 2fn"
- "1:n"
- "mov.b %1, @%3nt"
- "dt %7nt"
- "bf/s 9bnt"
- " add #1, %3nt"
- "2:nt"
- "sub %7, %0n"
- "3:n"
- ".section .fixup,"ax"n"
- "4:nt"
- "mov.l 5f, %1nt"
- "jmp @%1nt"
- " mov %8, %0nt"
- ".balign 4n"
- "5: .long 3bn"
- ".previousn"
- ".section __ex_table,"a"n"
- " .balign 4n"
- " .long 9b,4bn"
- ".previous"
- : "=r" (res), "=&z" (__dummy), "=r" (_s), "=r" (_d)
- : "0" (__count), "2" (__src), "3" (__dest), "r" (__count),
- "i" (-EFAULT)
- : "memory", "t");
- return res;
- }
- #define strncpy_from_user(dest,src,count) ({
- unsigned long __sfu_src = (unsigned long) (src);
- int __sfu_count = (int) (count);
- long __sfu_res = -EFAULT;
- if(__access_ok(__sfu_src, __sfu_count)) {
- __sfu_res = __strncpy_from_user((unsigned long) (dest), __sfu_src, __sfu_count);
- } __sfu_res; })
- #define strlen_user(str) strnlen_user(str, ~0UL >> 1)
- /*
- * Return the size of a string (including the ending 0!)
- */
- static __inline__ long __strnlen_user(const char *__s, long __n)
- {
- unsigned long res;
- unsigned long __dummy;
- __asm__ __volatile__(
- "9:n"
- "cmp/eq %4, %0nt"
- "bt 2fn"
- "1:t"
- "mov.b @(%0,%3), %1nt"
- "tst %1, %1nt"
- "bf/s 9bnt"
- " add #1, %0n"
- "2:n"
- ".section .fixup,"ax"n"
- "3:nt"
- "mov.l 4f, %1nt"
- "jmp @%1nt"
- " mov %5, %0n"
- ".balign 4n"
- "4: .long 2bn"
- ".previousn"
- ".section __ex_table,"a"n"
- " .balign 4n"
- " .long 1b,3bn"
- ".previous"
- : "=z" (res), "=&r" (__dummy)
- : "0" (0), "r" (__s), "r" (__n), "i" (-EFAULT)
- : "t");
- return res;
- }
- static __inline__ long strnlen_user(const char *s, long n)
- {
- if (!__addr_ok(s))
- return 0;
- else
- return __strnlen_user(s, n);
- }
- struct exception_table_entry
- {
- unsigned long insn, fixup;
- };
- /* Returns 0 if exception not found and fixup.unit otherwise. */
- extern unsigned long search_exception_table(unsigned long addr);
- /* Returns the new pc */
- #define fixup_exception(map_reg, fixup_unit, pc)
- ({
- fixup_unit;
- })
- #endif /* __ASM_SH_UACCESS_H */