x86: merge put_user.
Move both versions, which are highly similar, to uaccess.h. Note that, for x86_64, X86_WP_WORKS_OK is always defined. Signed-off-by: Glauber Costa <gcosta@redhat.com> Signed-off-by: H. Peter Anvin <hpa@zytor.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
committed by
Ingo Molnar
parent
ec840956d2
commit
e30a44fdbf
@@ -178,6 +178,12 @@ extern int __get_user_bad(void);
|
|||||||
__ret_gu; \
|
__ret_gu; \
|
||||||
})
|
})
|
||||||
|
|
||||||
|
#define __put_user_x(size, x, ptr, __ret_pu) \
|
||||||
|
asm volatile("call __put_user_" #size : "=a" (__ret_pu) \
|
||||||
|
:"0" ((typeof(*(ptr)))(x)), "c" (ptr) : "ebx")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_X86_32
|
#ifdef CONFIG_X86_32
|
||||||
#define __put_user_u64(x, addr, err) \
|
#define __put_user_u64(x, addr, err) \
|
||||||
asm volatile("1: movl %%eax,0(%2)\n" \
|
asm volatile("1: movl %%eax,0(%2)\n" \
|
||||||
@@ -191,13 +197,71 @@ extern int __get_user_bad(void);
|
|||||||
_ASM_EXTABLE(2b, 4b) \
|
_ASM_EXTABLE(2b, 4b) \
|
||||||
: "=r" (err) \
|
: "=r" (err) \
|
||||||
: "A" (x), "r" (addr), "i" (-EFAULT), "0" (err))
|
: "A" (x), "r" (addr), "i" (-EFAULT), "0" (err))
|
||||||
|
|
||||||
|
#define __put_user_x8(x, ptr, __ret_pu) \
|
||||||
|
asm volatile("call __put_user_8" : "=a" (__ret_pu) \
|
||||||
|
: "A" ((typeof(*(ptr)))(x)), "c" (ptr) : "ebx")
|
||||||
#else
|
#else
|
||||||
#define __put_user_u64(x, ptr, retval) \
|
#define __put_user_u64(x, ptr, retval) \
|
||||||
__put_user_asm(x, ptr, retval, "q", "", "Zr", -EFAULT)
|
__put_user_asm(x, ptr, retval, "q", "", "Zr", -EFAULT)
|
||||||
|
#define __put_user_x8(x, ptr, __ret_pu) __put_user_x(8, x, ptr, __ret_pu)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
extern void __put_user_bad(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Strange magic calling convention: pointer in %ecx,
|
||||||
|
* value in %eax(:%edx), return value in %eax. clobbers %rbx
|
||||||
|
*/
|
||||||
|
extern void __put_user_1(void);
|
||||||
|
extern void __put_user_2(void);
|
||||||
|
extern void __put_user_4(void);
|
||||||
|
extern void __put_user_8(void);
|
||||||
|
|
||||||
#ifdef CONFIG_X86_WP_WORKS_OK
|
#ifdef CONFIG_X86_WP_WORKS_OK
|
||||||
|
|
||||||
|
/**
|
||||||
|
* put_user: - Write a simple value into user space.
|
||||||
|
* @x: Value to copy to user space.
|
||||||
|
* @ptr: Destination address, in user space.
|
||||||
|
*
|
||||||
|
* Context: User context only. This function may sleep.
|
||||||
|
*
|
||||||
|
* This macro copies a single simple value from kernel space to user
|
||||||
|
* space. It supports simple types like char and int, but not larger
|
||||||
|
* data types like structures or arrays.
|
||||||
|
*
|
||||||
|
* @ptr must have pointer-to-simple-variable type, and @x must be assignable
|
||||||
|
* to the result of dereferencing @ptr.
|
||||||
|
*
|
||||||
|
* Returns zero on success, or -EFAULT on error.
|
||||||
|
*/
|
||||||
|
#define put_user(x, ptr) \
|
||||||
|
({ \
|
||||||
|
int __ret_pu; \
|
||||||
|
__typeof__(*(ptr)) __pu_val; \
|
||||||
|
__chk_user_ptr(ptr); \
|
||||||
|
__pu_val = x; \
|
||||||
|
switch (sizeof(*(ptr))) { \
|
||||||
|
case 1: \
|
||||||
|
__put_user_x(1, __pu_val, ptr, __ret_pu); \
|
||||||
|
break; \
|
||||||
|
case 2: \
|
||||||
|
__put_user_x(2, __pu_val, ptr, __ret_pu); \
|
||||||
|
break; \
|
||||||
|
case 4: \
|
||||||
|
__put_user_x(4, __pu_val, ptr, __ret_pu); \
|
||||||
|
break; \
|
||||||
|
case 8: \
|
||||||
|
__put_user_x8(__pu_val, ptr, __ret_pu); \
|
||||||
|
break; \
|
||||||
|
default: \
|
||||||
|
__put_user_x(X, __pu_val, ptr, __ret_pu); \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
__ret_pu; \
|
||||||
|
})
|
||||||
|
|
||||||
#define __put_user_size(x, ptr, size, retval, errret) \
|
#define __put_user_size(x, ptr, size, retval, errret) \
|
||||||
do { \
|
do { \
|
||||||
retval = 0; \
|
retval = 0; \
|
||||||
@@ -231,6 +295,16 @@ do { \
|
|||||||
retval = errret; \
|
retval = errret; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
#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
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_X86_32
|
#ifdef CONFIG_X86_32
|
||||||
|
@@ -20,85 +20,6 @@ extern struct movsl_mask {
|
|||||||
} ____cacheline_aligned_in_smp movsl_mask;
|
} ____cacheline_aligned_in_smp movsl_mask;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
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_x(size, x, ptr, __ret_pu) \
|
|
||||||
asm volatile("call __put_user_" #size : "=a" (__ret_pu) \
|
|
||||||
:"0" ((typeof(*(ptr)))(x)), "c" (ptr) : "ebx")
|
|
||||||
|
|
||||||
#define __put_user_8(x, ptr, __ret_pu) \
|
|
||||||
asm volatile("call __put_user_8" : "=a" (__ret_pu) \
|
|
||||||
: "A" ((typeof(*(ptr)))(x)), "c" (ptr) : "ebx")
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* put_user: - Write a simple value into user space.
|
|
||||||
* @x: Value to copy to user space.
|
|
||||||
* @ptr: Destination address, in user space.
|
|
||||||
*
|
|
||||||
* Context: User context only. This function may sleep.
|
|
||||||
*
|
|
||||||
* This macro copies a single simple value from kernel space to user
|
|
||||||
* space. It supports simple types like char and int, but not larger
|
|
||||||
* data types like structures or arrays.
|
|
||||||
*
|
|
||||||
* @ptr must have pointer-to-simple-variable type, and @x must be assignable
|
|
||||||
* to the result of dereferencing @ptr.
|
|
||||||
*
|
|
||||||
* Returns zero on success, or -EFAULT on error.
|
|
||||||
*/
|
|
||||||
#ifdef CONFIG_X86_WP_WORKS_OK
|
|
||||||
|
|
||||||
#define put_user(x, ptr) \
|
|
||||||
({ \
|
|
||||||
int __ret_pu; \
|
|
||||||
__typeof__(*(ptr)) __pu_val; \
|
|
||||||
__chk_user_ptr(ptr); \
|
|
||||||
__pu_val = x; \
|
|
||||||
switch (sizeof(*(ptr))) { \
|
|
||||||
case 1: \
|
|
||||||
__put_user_x(1, __pu_val, ptr, __ret_pu); \
|
|
||||||
break; \
|
|
||||||
case 2: \
|
|
||||||
__put_user_x(2, __pu_val, ptr, __ret_pu); \
|
|
||||||
break; \
|
|
||||||
case 4: \
|
|
||||||
__put_user_x(4, __pu_val, ptr, __ret_pu); \
|
|
||||||
break; \
|
|
||||||
case 8: \
|
|
||||||
__put_user_8(__pu_val, ptr, __ret_pu); \
|
|
||||||
break; \
|
|
||||||
default: \
|
|
||||||
__put_user_x(X, __pu_val, ptr, __ret_pu); \
|
|
||||||
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.
|
* __get_user: - Get a simple variable from user space, with less checking.
|
||||||
* @x: Variable to store result.
|
* @x: Variable to store result.
|
||||||
|
@@ -11,18 +11,6 @@
|
|||||||
|
|
||||||
#define ARCH_HAS_SEARCH_EXTABLE
|
#define ARCH_HAS_SEARCH_EXTABLE
|
||||||
|
|
||||||
extern void __put_user_1(void);
|
|
||||||
extern void __put_user_2(void);
|
|
||||||
extern void __put_user_4(void);
|
|
||||||
extern void __put_user_8(void);
|
|
||||||
extern void __put_user_bad(void);
|
|
||||||
|
|
||||||
#define __put_user_x(size, ret, x, ptr) \
|
|
||||||
asm volatile("call __put_user_" #size \
|
|
||||||
:"=a" (ret) \
|
|
||||||
:"c" (ptr),"a" (x) \
|
|
||||||
:"ebx")
|
|
||||||
|
|
||||||
#define __get_user(x, ptr) \
|
#define __get_user(x, ptr) \
|
||||||
__get_user_nocheck((x), (ptr), sizeof(*(ptr)))
|
__get_user_nocheck((x), (ptr), sizeof(*(ptr)))
|
||||||
#define __put_user(x, ptr) \
|
#define __put_user(x, ptr) \
|
||||||
@@ -31,30 +19,6 @@ extern void __put_user_bad(void);
|
|||||||
#define __get_user_unaligned __get_user
|
#define __get_user_unaligned __get_user
|
||||||
#define __put_user_unaligned __put_user
|
#define __put_user_unaligned __put_user
|
||||||
|
|
||||||
#define put_user(x, ptr) \
|
|
||||||
({ \
|
|
||||||
int __pu_err; \
|
|
||||||
typeof(*(ptr)) __user *__pu_addr = (ptr); \
|
|
||||||
__chk_user_ptr(ptr); \
|
|
||||||
switch (sizeof(*(ptr))) { \
|
|
||||||
case 1: \
|
|
||||||
__put_user_x(1, __pu_err, x, __pu_addr); \
|
|
||||||
break; \
|
|
||||||
case 2: \
|
|
||||||
__put_user_x(2, __pu_err, x, __pu_addr); \
|
|
||||||
break; \
|
|
||||||
case 4: \
|
|
||||||
__put_user_x(4, __pu_err, x, __pu_addr); \
|
|
||||||
break; \
|
|
||||||
case 8: \
|
|
||||||
__put_user_x(8, __pu_err, x, __pu_addr); \
|
|
||||||
break; \
|
|
||||||
default: \
|
|
||||||
__put_user_bad(); \
|
|
||||||
} \
|
|
||||||
__pu_err; \
|
|
||||||
})
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copy To/From Userspace
|
* Copy To/From Userspace
|
||||||
*/
|
*/
|
||||||
|
Reference in New Issue
Block a user