linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / include / asm-i386 / uaccess.h
index 9e31639..3f1337c 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/thread_info.h>
 #include <linux/prefetch.h>
 #include <linux/string.h>
-#include <linux/compiler.h>
 #include <asm/page.h>
 
 #define VERIFY_READ 0
@@ -27,7 +26,7 @@
 
 
 #define KERNEL_DS      MAKE_MM_SEG(0xFFFFFFFFUL)
-#define USER_DS                MAKE_MM_SEG(TASK_SIZE)
+#define USER_DS                MAKE_MM_SEG(PAGE_OFFSET)
 
 #define get_ds()       (KERNEL_DS)
 #define get_fs()       (current_thread_info()->addr_limit)
 
 #define segment_eq(a,b)        ((a).seg == (b).seg)
 
-extern long not_a_user_address;
-#define check_user_ptr(x) \
-       (void) ({ void __user * __userptr = (__typeof__(*(x)) *)&not_a_user_address; __userptr; })
-
 /*
  * movsl can be slow when source and dest are not both 8-byte aligned
  */
@@ -61,7 +56,7 @@ extern struct movsl_mask {
  */
 #define __range_ok(addr,size) ({ \
        unsigned long flag,sum; \
-       check_user_ptr(addr); \
+       __chk_user_ptr(addr); \
        asm("addl %3,%1 ; sbbl %0,%0; cmpl %1,%4; sbbl $0,%0" \
                :"=&r" (flag), "=r" (sum) \
                :"1" (addr),"g" ((int)(size)),"g" (current_thread_info()->addr_limit.seg)); \
@@ -88,29 +83,6 @@ extern struct movsl_mask {
  */
 #define access_ok(type,addr,size) (likely(__range_ok(addr,size) == 0))
 
-/**
- * verify_area: - Obsolete, use access_ok()
- * @type: Type of access: %VERIFY_READ or %VERIFY_WRITE
- * @addr: User space pointer to start of block to check
- * @size: Size of block to check
- *
- * Context: User context only.  This function may sleep.
- *
- * This function has been replaced by access_ok().
- *
- * Checks if a pointer to a block of memory in user space is valid.
- *
- * Returns zero if the memory block may be valid, -EFAULT
- * if it is definitely invalid.
- *
- * See access_ok() for more details.
- */
-static inline int verify_area(int type, const void __user * addr, unsigned long size)
-{
-       return access_ok(type,addr,size) ? 0 : -EFAULT;
-}
-
-
 /*
  * The exception table consists of pairs of addresses: the first is the
  * address of an instruction that is allowed to fault, and the second is
@@ -155,45 +127,6 @@ extern void __get_user_4(void);
                :"=a" (ret),"=d" (x) \
                :"0" (ptr))
 
-extern int get_user_size(unsigned int size, void *val, const void *ptr);
-extern int put_user_size(unsigned int size, const void *val, void *ptr);
-extern int zero_user_size(unsigned int size, void *ptr);
-extern int copy_str_fromuser_size(unsigned int size, void *val, const void *ptr);
-extern int strlen_fromuser_size(unsigned int size, const void *ptr);
-
-
-# define indirect_get_user(x,ptr)                                      \
-({     int __ret_gu,__val_gu;                                          \
-       __typeof__(ptr) __ptr_gu = (ptr);                               \
-       __ret_gu = get_user_size(sizeof(*__ptr_gu), &__val_gu,__ptr_gu) ? -EFAULT : 0;\
-       (x) = (__typeof__(*__ptr_gu))__val_gu;                          \
-       __ret_gu;                                                       \
-})
-#define indirect_put_user(x,ptr)                                       \
-({                                                                     \
-       __typeof__(*(ptr)) *__ptr_pu = (ptr), __x_pu = (x);             \
-       put_user_size(sizeof(*__ptr_pu), &__x_pu, __ptr_pu) ? -EFAULT : 0; \
-})
-#define __indirect_put_user indirect_put_user
-#define __indirect_get_user indirect_get_user
-
-#define indirect_copy_from_user(to,from,n) get_user_size(n,to,from)
-#define indirect_copy_to_user(to,from,n) put_user_size(n,from,to)
-
-#define __indirect_copy_from_user indirect_copy_from_user
-#define __indirect_copy_to_user indirect_copy_to_user
-
-#define indirect_strncpy_from_user(dst, src, count) \
-               copy_str_fromuser_size(count, dst, src)
-
-extern int strlen_fromuser_size(unsigned int size, const void *ptr);
-#define indirect_strnlen_user(str, n) strlen_fromuser_size(n, str)
-#define indirect_strlen_user(str) indirect_strnlen_user(str, ~0UL >> 1)
-
-extern int zero_user_size(unsigned int size, void *ptr);
-
-#define indirect_clear_user(mem, len) zero_user_size(len, mem)
-#define __indirect_clear_user clear_user
 
 /* Careful: we have to cast the result to the type of the pointer for sign reasons */
 /**
@@ -213,9 +146,10 @@ extern int zero_user_size(unsigned int size, void *ptr);
  * Returns zero on success, or -EFAULT on error.
  * On error, the variable @x is set to zero.
  */
-#define direct_get_user(x,ptr)                                         \
-({     int __ret_gu,__val_gu;                                          \
-       check_user_ptr(ptr);                                            \
+#define get_user(x,ptr)                                                        \
+({     int __ret_gu;                                                   \
+       unsigned long __val_gu;                                         \
+       __chk_user_ptr(ptr);                                            \
        switch(sizeof (*(ptr))) {                                       \
        case 1:  __get_user_x(1,__ret_gu,__val_gu,ptr); break;          \
        case 2:  __get_user_x(2,__ret_gu,__val_gu,ptr); break;          \
@@ -228,6 +162,21 @@ extern int zero_user_size(unsigned int size, void *ptr);
 
 extern void __put_user_bad(void);
 
+/*
+ * Strange magic calling convention: pointer in %ecx,
+ * value in %eax(:%edx), return value in %eax, no clobbers.
+ */
+extern void __put_user_1(void);
+extern void __put_user_2(void);
+extern void __put_user_4(void);
+extern void __put_user_8(void);
+
+#define __put_user_1(x, ptr) __asm__ __volatile__("call __put_user_1":"=a" (__ret_pu):"0" ((typeof(*(ptr)))(x)), "c" (ptr))
+#define __put_user_2(x, ptr) __asm__ __volatile__("call __put_user_2":"=a" (__ret_pu):"0" ((typeof(*(ptr)))(x)), "c" (ptr))
+#define __put_user_4(x, ptr) __asm__ __volatile__("call __put_user_4":"=a" (__ret_pu):"0" ((typeof(*(ptr)))(x)), "c" (ptr))
+#define __put_user_8(x, ptr) __asm__ __volatile__("call __put_user_8":"=a" (__ret_pu):"A" ((typeof(*(ptr)))(x)), "c" (ptr))
+#define __put_user_X(x, ptr) __asm__ __volatile__("call __put_user_X":"=a" (__ret_pu):"c" (ptr))
+
 /**
  * put_user: - Write a simple value into user space.
  * @x:   Value to copy to user space.
@@ -244,9 +193,35 @@ extern void __put_user_bad(void);
  *
  * Returns zero on success, or -EFAULT on error.
  */
-#define direct_put_user(x,ptr)                                         \
-  __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
+#ifdef CONFIG_X86_WP_WORKS_OK
+
+#define put_user(x,ptr)                                                \
+({     int __ret_pu;                                           \
+       __chk_user_ptr(ptr);                                    \
+       switch(sizeof(*(ptr))) {                                \
+       case 1: __put_user_1(x, ptr); break;                    \
+       case 2: __put_user_2(x, ptr); break;                    \
+       case 4: __put_user_4(x, ptr); break;                    \
+       case 8: __put_user_8(x, ptr); break;                    \
+       default:__put_user_X(x, ptr); break;                    \
+       }                                                       \
+       __ret_pu;                                               \
+})
+
+#else
+#define put_user(x,ptr)                                                \
+({                                                             \
+       int __ret_pu;                                           \
+       __typeof__(*(ptr)) __pus_tmp = x;                       \
+       __ret_pu=0;                                             \
+       if(unlikely(__copy_to_user_ll(ptr, &__pus_tmp,          \
+                               sizeof(*(ptr))) != 0))          \
+               __ret_pu=-EFAULT;                               \
+       __ret_pu;                                               \
+ })
+
 
+#endif
 
 /**
  * __get_user: - Get a simple variable from user space, with less checking.
@@ -268,7 +243,7 @@ extern void __put_user_bad(void);
  * Returns zero on success, or -EFAULT on error.
  * On error, the variable @x is set to zero.
  */
-#define __direct_get_user(x,ptr) \
+#define __get_user(x,ptr) \
   __get_user_nocheck((x),(ptr),sizeof(*(ptr)))
 
 
@@ -291,7 +266,7 @@ extern void __put_user_bad(void);
  *
  * Returns zero on success, or -EFAULT on error.
  */
-#define __direct_put_user(x,ptr) \
+#define __put_user(x,ptr) \
   __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
 
 #define __put_user_nocheck(x,ptr,size)                         \
@@ -302,16 +277,6 @@ extern void __put_user_bad(void);
 })
 
 
-#define __put_user_check(x,ptr,size)                                   \
-({                                                                     \
-       long __pu_err = -EFAULT;                                        \
-       __typeof__(*(ptr)) *__pu_addr = (ptr);                          \
-       might_sleep();                                          \
-       if (access_ok(VERIFY_WRITE,__pu_addr,size))                     \
-               __put_user_size((x),__pu_addr,(size),__pu_err,-EFAULT); \
-       __pu_err;                                                       \
-})                                                     
-
 #define __put_user_u64(x, addr, err)                           \
        __asm__ __volatile__(                                   \
                "1:     movl %%eax,0(%2)\n"                     \
@@ -334,7 +299,7 @@ extern void __put_user_bad(void);
 #define __put_user_size(x,ptr,size,retval,errret)                      \
 do {                                                                   \
        retval = 0;                                                     \
-       check_user_ptr(ptr);                                            \
+       __chk_user_ptr(ptr);                                            \
        switch (size) {                                                 \
        case 1: __put_user_asm(x,ptr,retval,"b","b","iq",errret);break; \
        case 2: __put_user_asm(x,ptr,retval,"w","w","ir",errret);break; \
@@ -357,7 +322,7 @@ do {                                                                        \
 
 #endif
 struct __large_struct { unsigned long buf[100]; };
-#define __m(x) (*(struct __large_struct *)(x))
+#define __m(x) (*(struct __large_struct __user *)(x))
 
 /*
  * Tell gcc we read from memory instead of writing: this is because
@@ -382,7 +347,8 @@ struct __large_struct { unsigned long buf[100]; };
 
 #define __get_user_nocheck(x,ptr,size)                         \
 ({                                                             \
-       long __gu_err, __gu_val;                                \
+       long __gu_err;                                          \
+       unsigned long __gu_val;                                 \
        __get_user_size(__gu_val,(ptr),(size),__gu_err,-EFAULT);\
        (x) = (__typeof__(*(ptr)))__gu_val;                     \
        __gu_err;                                               \
@@ -393,7 +359,7 @@ extern long __get_user_bad(void);
 #define __get_user_size(x,ptr,size,retval,errret)                      \
 do {                                                                   \
        retval = 0;                                                     \
-       check_user_ptr(ptr);                                            \
+       __chk_user_ptr(ptr);                                            \
        switch (size) {                                                 \
        case 1: __get_user_asm(x,ptr,retval,"b","b","=q",errret);break; \
        case 2: __get_user_asm(x,ptr,retval,"w","w","=r",errret);break; \
@@ -419,8 +385,10 @@ do {                                                                       \
                : "m"(__m(addr)), "i"(errret), "0"(err))
 
 
-unsigned long __must_check __copy_to_user_ll(void __user *to, const void *from, unsigned long n);
-unsigned long __must_check __copy_from_user_ll(void *to, const void __user *from, unsigned long n);
+unsigned long __must_check __copy_to_user_ll(void __user *to,
+                               const void *from, unsigned long n);
+unsigned long __must_check __copy_from_user_ll(void *to,
+                               const void __user *from, unsigned long n);
 
 /*
  * Here we special-case 1, 2 and 4-byte copy_*_user invocations.  On a fault
@@ -443,8 +411,8 @@ unsigned long __must_check __copy_from_user_ll(void *to, const void __user *from
  * Returns number of bytes that could not be copied.
  * On success, this will be zero.
  */
-static inline unsigned long __must_check
-__direct_copy_to_user(void __user *to, const void *from, unsigned long n)
+static __always_inline unsigned long __must_check
+__copy_to_user_inatomic(void __user *to, const void *from, unsigned long n)
 {
        if (__builtin_constant_p(n)) {
                unsigned long ret;
@@ -464,6 +432,13 @@ __direct_copy_to_user(void __user *to, const void *from, unsigned long n)
        return __copy_to_user_ll(to, from, n);
 }
 
+static __always_inline unsigned long __must_check
+__copy_to_user(void __user *to, const void *from, unsigned long n)
+{
+       might_sleep();
+       return __copy_to_user_inatomic(to, from, n);
+}
+
 /**
  * __copy_from_user: - Copy a block of data from user space, with less checking.
  * @to:   Destination address, in kernel space.
@@ -481,8 +456,8 @@ __direct_copy_to_user(void __user *to, const void *from, unsigned long n)
  * If some data could not be copied, this function will pad the copied
  * data to the requested size using zero bytes.
  */
-static inline unsigned long __must_check
-__direct_copy_from_user(void *to, const void __user *from, unsigned long n)
+static __always_inline unsigned long
+__copy_from_user_inatomic(void *to, const void __user *from, unsigned long n)
 {
        if (__builtin_constant_p(n)) {
                unsigned long ret;
@@ -502,57 +477,20 @@ __direct_copy_from_user(void *to, const void __user *from, unsigned long n)
        return __copy_from_user_ll(to, from, n);
 }
 
-/**
- * copy_to_user: - Copy a block of data into user space.
- * @to:   Destination address, in user space.
- * @from: Source address, in kernel space.
- * @n:    Number of bytes to copy.
- *
- * Context: User context only.  This function may sleep.
- *
- * Copy data from kernel space to user space.
- *
- * Returns number of bytes that could not be copied.
- * On success, this will be zero.
- */
-static inline unsigned long __must_check
-direct_copy_to_user(void __user *to, const void *from, unsigned long n)
+static __always_inline unsigned long
+__copy_from_user(void *to, const void __user *from, unsigned long n)
 {
-       might_sleep();
-       if (access_ok(VERIFY_WRITE, to, n))
-               n = __direct_copy_to_user(to, from, n);
-       return n;
+       might_sleep();
+       return __copy_from_user_inatomic(to, from, n);
 }
-
-/**
- * copy_from_user: - Copy a block of data from user space.
- * @to:   Destination address, in kernel space.
- * @from: Source address, in user space.
- * @n:    Number of bytes to copy.
- *
- * Context: User context only.  This function may sleep.
- *
- * Copy data from user space to kernel space.
- *
- * Returns number of bytes that could not be copied.
- * On success, this will be zero.
- *
- * If some data could not be copied, this function will pad the copied
- * data to the requested size using zero bytes.
- */
-static inline unsigned long __must_check
-direct_copy_from_user(void *to, const void __user *from, unsigned long n)
-{
-       might_sleep();
-       if (access_ok(VERIFY_READ, from, n))
-               n = __direct_copy_from_user(to, from, n);
-       else
-               memset(to, 0, n);
-       return n;
-}
-
-long strncpy_from_user(char *dst, const char __user *src, long count);
-long __strncpy_from_user(char *dst, const char __user *src, long count);
+unsigned long __must_check copy_to_user(void __user *to,
+                               const void *from, unsigned long n);
+unsigned long __must_check copy_from_user(void *to,
+                               const void __user *from, unsigned long n);
+long __must_check strncpy_from_user(char *dst, const char __user *src,
+                               long count);
+long __must_check __strncpy_from_user(char *dst,
+                               const char __user *src, long count);
 
 /**
  * strlen_user: - Get the size of a string in user space.
@@ -568,68 +506,10 @@ long __strncpy_from_user(char *dst, const char __user *src, long count);
  * If there is a limit on the length of a valid string, you may wish to
  * consider using strnlen_user() instead.
  */
+#define strlen_user(str) strnlen_user(str, ~0UL >> 1)
 
-long direct_strncpy_from_user(char *dst, const char *src, long count);
-long __direct_strncpy_from_user(char *dst, const char *src, long count);
-#define direct_strlen_user(str) direct_strnlen_user(str, ~0UL >> 1)
-long direct_strnlen_user(const char *str, long n);
-unsigned long direct_clear_user(void *mem, unsigned long len);
-unsigned long __direct_clear_user(void *mem, unsigned long len);
-
-extern int indirect_uaccess;
-
-#ifdef CONFIG_X86_UACCESS_INDIRECT
-
-/*
- * Return code and zeroing semantics:
-
- __clear_user          0                      <-> bytes not done
- clear_user            0                      <-> bytes not done
- __copy_to_user        0                      <-> bytes not done
- copy_to_user          0                      <-> bytes not done
- __copy_from_user      0                      <-> bytes not done, zero rest
- copy_from_user        0                      <-> bytes not done, zero rest
- __get_user            0                      <-> -EFAULT
- get_user              0                      <-> -EFAULT
- __put_user            0                      <-> -EFAULT
- put_user              0                      <-> -EFAULT
- strlen_user           strlen + 1             <-> 0
- strnlen_user          strlen + 1 (or n+1)    <-> 0
- strncpy_from_user     strlen (or n)          <-> -EFAULT
-
- */
-
-#define __clear_user(mem,len) __indirect_clear_user(mem,len)
-#define clear_user(mem,len) indirect_clear_user(mem,len)
-#define __copy_to_user(to,from,n) __indirect_copy_to_user(to,from,n)
-#define copy_to_user(to,from,n) indirect_copy_to_user(to,from,n)
-#define __copy_from_user(to,from,n) __indirect_copy_from_user(to,from,n)
-#define copy_from_user(to,from,n) indirect_copy_from_user(to,from,n)
-#define __get_user(val,ptr) __indirect_get_user(val,ptr)
-#define get_user(val,ptr) indirect_get_user(val,ptr)
-#define __put_user(val,ptr) __indirect_put_user(val,ptr)
-#define put_user(val,ptr) indirect_put_user(val,ptr)
-#define strlen_user(str) indirect_strlen_user(str)
-#define strnlen_user(src,count) indirect_strnlen_user(src,count)
-#define strncpy_from_user(dst,src,count) \
-                       indirect_strncpy_from_user(dst,src,count)
-
-#else
-
-#define __clear_user __direct_clear_user
-#define clear_user direct_clear_user
-#define __copy_to_user __direct_copy_to_user
-#define copy_to_user direct_copy_to_user
-#define __copy_from_user __direct_copy_from_user
-#define copy_from_user direct_copy_from_user
-#define __get_user __direct_get_user
-#define get_user direct_get_user
-#define __put_user __direct_put_user
-#define put_user direct_put_user
-#define strlen_user direct_strlen_user
-#define strnlen_user direct_strnlen_user
-#define strncpy_from_user direct_strncpy_from_user
-
-#endif /* CONFIG_X86_UACCESS_INDIRECT */
+long strnlen_user(const char __user *str, long n);
+unsigned long __must_check clear_user(void __user *mem, unsigned long len);
+unsigned long __must_check __clear_user(void __user *mem, unsigned long len);
 
 #endif /* __i386_UACCESS_H */