Commit 322b8a8b authored by Russell King's avatar Russell King

[ARM] __put_user, __get_user cleanups and fixups

This fixes the ARM __put_user implementation.  The gcc folk have
agreed that the %Qn and %Rn register notation in asm() statements
should become official, and have been in all compilers which can
be used to build the ARM kernel.

In addition, we remove some historical gunk from when put_user()
and get_user() was inlined on ARM.
parent 9804476c
......@@ -12,7 +12,7 @@
* Note that this is actually 0x1,0000,0000
*/
#define KERNEL_DS 0x00000000
#define USER_DS PAGE_OFFSET
#define USER_DS TASK_SIZE
static inline void set_fs (mm_segment_t fs)
{
......@@ -50,8 +50,8 @@ static inline void set_fs (mm_segment_t fs)
" .align 3\n" \
" .long 1b, 3b\n" \
" .previous" \
: "=r" (err) \
: "r" (x), "r" (__pu_addr), "i" (-EFAULT), "0" (err) \
: "+r" (err) \
: "r" (x), "r" (__pu_addr), "i" (-EFAULT) \
: "cc")
#ifndef __ARMEB__
......@@ -83,19 +83,18 @@ static inline void set_fs (mm_segment_t fs)
" .align 3\n" \
" .long 1b, 3b\n" \
" .previous" \
: "=r" (err) \
: "r" (x), "r" (__pu_addr), "i" (-EFAULT), "0" (err))
: "+r" (err) \
: "r" (x), "r" (__pu_addr), "i" (-EFAULT) \
: "cc")
#define __put_user_asm_dword(x,__pu_addr,err) \
({ \
unsigned long long __temp = (unsigned long long)x; \
__asm__ __volatile__( \
"1: strt %1, [%2], #0\n" \
"2: strt %3, [%4], #0\n" \
"1: strt %Q2, [%1], #4\n" \
"2: strt %R2, [%1], #0\n" \
"3:\n" \
" .section .fixup,\"ax\"\n" \
" .align 2\n" \
"4: mov %0, %5\n" \
"4: mov %0, %3\n" \
" b 3b\n" \
" .previous\n" \
" .section __ex_table,\"a\"\n" \
......@@ -103,12 +102,9 @@ static inline void set_fs (mm_segment_t fs)
" .long 1b, 4b\n" \
" .long 2b, 4b\n" \
" .previous" \
: "=r" (err) \
: "r" (__temp), "r" (__pu_addr), \
"r" (__temp >> 32), "r" (__pu_addr + 4), \
"i" (-EFAULT), "0" (err) \
: "cc"); \
})
: "+r" (err), "+r" (__pu_addr) \
: "r" (x), "i" (-EFAULT) \
: "cc")
#define __get_user_asm_byte(x,addr,err) \
__asm__ __volatile__( \
......@@ -124,23 +120,24 @@ static inline void set_fs (mm_segment_t fs)
" .align 3\n" \
" .long 1b, 3b\n" \
" .previous" \
: "=r" (err), "=&r" (x) \
: "r" (addr), "i" (-EFAULT), "0" (err))
: "+r" (err), "=&r" (x) \
: "r" (addr), "i" (-EFAULT) \
: "cc")
#ifndef __ARMEB__
#define __get_user_asm_half(x,addr,err) \
#define __get_user_asm_half(x,__gu_addr,err) \
({ \
unsigned long __b1, __b2, __ptr = (unsigned long)addr; \
__get_user_asm_byte(__b1, __ptr, err); \
__get_user_asm_byte(__b2, __ptr + 1, err); \
unsigned long __b1, __b2; \
__get_user_asm_byte(__b1, __gu_addr, err); \
__get_user_asm_byte(__b2, __gu_addr + 1, err); \
(x) = __b1 | (__b2 << 8); \
})
#else
#define __get_user_asm_half(x,addr,err) \
#define __get_user_asm_half(x,__gu_addr,err) \
({ \
unsigned long __b1, __b2; \
__get_user_asm_byte(__b1, addr, err); \
__get_user_asm_byte(__b2, (int)(addr) + 1, err); \
__get_user_asm_byte(__b1, __gu_addr, err); \
__get_user_asm_byte(__b2, __gu_addr + 1, err); \
(x) = (__b1 << 8) | __b2; \
})
#endif
......@@ -159,8 +156,9 @@ static inline void set_fs (mm_segment_t fs)
" .align 3\n" \
" .long 1b, 3b\n" \
" .previous" \
: "=r" (err), "=&r" (x) \
: "r" (addr), "i" (-EFAULT), "0" (err))
: "+r" (err), "=&r" (x) \
: "r" (addr), "i" (-EFAULT) \
: "cc")
extern unsigned long __arch_copy_from_user(void *to, const void *from, unsigned long n);
#define __do_copy_from_user(to,from,n) \
......
......@@ -74,7 +74,7 @@ extern int __get_user_bad(void);
__asm__ __volatile__ ("bl __get_user_" #__s \
: "=&r" (__e), "=r" (__r1) \
: "0" (__p) \
: __i)
: __i, "cc")
#define get_user(x,p) \
({ \
......@@ -100,8 +100,31 @@ extern int __get_user_bad(void);
__e; \
})
#define __get_user(x,p) __get_user_nocheck((x),(p),sizeof(*(p)))
#define __get_user_error(x,p,e) __get_user_nocheck_error((x),(p),sizeof(*(p)),(e))
#define __get_user(x,ptr) \
({ \
long __gu_err = 0; \
__get_user_err((x),(ptr),__gu_err); \
__gu_err; \
})
#define __get_user_error(x,ptr,err) \
({ \
__get_user_err((x),(ptr),err); \
(void) 0; \
})
#define __get_user_err(x,ptr,err) \
do { \
unsigned long __gu_addr = (unsigned long)(ptr); \
unsigned long __gu_val; \
switch (sizeof(*(ptr))) { \
case 1: __get_user_asm_byte(__gu_val,__gu_addr,err); break; \
case 2: __get_user_asm_half(__gu_val,__gu_addr,err); break; \
case 4: __get_user_asm_word(__gu_val,__gu_addr,err); break; \
default: (__gu_val) = __get_user_bad(); \
} \
(x) = (__typeof__(*(ptr)))__gu_val; \
} while (0)
extern int __put_user_1(void *, unsigned int);
extern int __put_user_2(void *, unsigned int);
......@@ -113,7 +136,7 @@ extern int __put_user_bad(void);
__asm__ __volatile__ ("bl __put_user_" #__s \
: "=&r" (__e) \
: "0" (__p), "r" (__r1) \
: __i)
: __i, "cc")
#define put_user(x,p) \
({ \
......@@ -138,8 +161,31 @@ extern int __put_user_bad(void);
__e; \
})
#define __put_user(x,p) __put_user_nocheck((__typeof(*(p)))(x),(p),sizeof(*(p)))
#define __put_user_error(x,p,e) __put_user_nocheck_error((x),(p),sizeof(*(p)),(e))
#define __put_user(x,ptr) \
({ \
long __pu_err = 0; \
__put_user_err((x),(ptr),__pu_err); \
__pu_err; \
})
#define __put_user_error(x,ptr,err) \
({ \
__put_user_err((x),(ptr),err); \
(void) 0; \
})
#define __put_user_err(x,ptr,err) \
do { \
unsigned long __pu_addr = (unsigned long)(ptr); \
__typeof__(*(ptr)) __pu_val = (x); \
switch (sizeof(*(ptr))) { \
case 1: __put_user_asm_byte(__pu_val,__pu_addr,err); break; \
case 2: __put_user_asm_half(__pu_val,__pu_addr,err); break; \
case 4: __put_user_asm_word(__pu_val,__pu_addr,err); break; \
case 8: __put_user_asm_dword(__pu_val,__pu_addr,err); break; \
default: __put_user_bad(); \
} \
} while (0)
static __inline__ unsigned long copy_from_user(void *to, const void *from, unsigned long n)
{
......@@ -209,85 +255,4 @@ static inline long strnlen_user(const char *s, long n)
return res;
}
/*
* These are the work horses of the get/put_user functions
*/
#if 0
#define __get_user_check(x,ptr,size) \
({ \
long __gu_err = -EFAULT, __gu_val = 0; \
const __typeof__(*(ptr)) *__gu_addr = (ptr); \
if (access_ok(VERIFY_READ,__gu_addr,size)) { \
__gu_err = 0; \
__get_user_size(__gu_val,__gu_addr,(size),__gu_err); \
} \
(x) = (__typeof__(*(ptr)))__gu_val; \
__gu_err; \
})
#endif
#define __get_user_nocheck(x,ptr,size) \
({ \
long __gu_err = 0, __gu_val; \
__get_user_size(__gu_val,(ptr),(size),__gu_err); \
(x) = (__typeof__(*(ptr)))__gu_val; \
__gu_err; \
})
#define __get_user_nocheck_error(x,ptr,size,err) \
({ \
long __gu_val; \
__get_user_size(__gu_val,(ptr),(size),(err)); \
(x) = (__typeof__(*(ptr)))__gu_val; \
(void) 0; \
})
#define __put_user_check(x,ptr,size) \
({ \
long __pu_err = -EFAULT; \
__typeof__(*(ptr)) *__pu_addr = (ptr); \
if (access_ok(VERIFY_WRITE,__pu_addr,size)) { \
__pu_err = 0; \
__put_user_size((x),__pu_addr,(size),__pu_err); \
} \
__pu_err; \
})
#define __put_user_nocheck(x,ptr,size) \
({ \
long __pu_err = 0; \
unsigned long __pu_addr = (unsigned long)(ptr); \
__put_user_size((x),__pu_addr,(size),__pu_err); \
__pu_err; \
})
#define __put_user_nocheck_error(x,ptr,size,err) \
({ \
unsigned long __pu_addr = (unsigned long)(ptr); \
__put_user_size((x),__pu_addr,(size),err); \
(void) 0; \
})
#define __get_user_size(x,ptr,size,retval) \
do { \
switch (size) { \
case 1: __get_user_asm_byte(x,ptr,retval); break; \
case 2: __get_user_asm_half(x,ptr,retval); break; \
case 4: __get_user_asm_word(x,ptr,retval); break; \
case 8: __get_user_asm_dword(x,ptr,retval); break; \
default: (x) = __get_user_bad(); \
} \
} while (0)
#define __put_user_size(x,ptr,size,retval) \
do { \
switch (size) { \
case 1: __put_user_asm_byte(x,ptr,retval); break; \
case 2: __put_user_asm_half(x,ptr,retval); break; \
case 4: __put_user_asm_word(x,ptr,retval); break; \
case 8: __put_user_asm_dword(x,ptr,retval); break; \
default: __put_user_bad(); \
} \
} while (0)
#endif /* _ASMARM_UACCESS_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment