summaryrefslogtreecommitdiffstats
path: root/include/asm-x86/uaccess.h
diff options
context:
space:
mode:
authorGlauber Costa <gcosta@redhat.com>2008-06-25 18:17:43 +0200
committerIngo Molnar <mingo@elte.hu>2008-07-09 09:14:26 +0200
commite30a44fdbf11c7ca3a0096d71790f176a4a09e03 (patch)
tree21d173ba08e47cb539c965dfb5119ff9f3b28d04 /include/asm-x86/uaccess.h
parentx86: turn __put_user_check directly into put_user. (diff)
downloadlinux-e30a44fdbf11c7ca3a0096d71790f176a4a09e03.tar.xz
linux-e30a44fdbf11c7ca3a0096d71790f176a4a09e03.zip
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>
Diffstat (limited to 'include/asm-x86/uaccess.h')
-rw-r--r--include/asm-x86/uaccess.h74
1 files changed, 74 insertions, 0 deletions
diff --git a/include/asm-x86/uaccess.h b/include/asm-x86/uaccess.h
index 4353b2267a02..3a9092af5af0 100644
--- a/include/asm-x86/uaccess.h
+++ b/include/asm-x86/uaccess.h
@@ -178,6 +178,12 @@ extern int __get_user_bad(void);
__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
#define __put_user_u64(x, addr, err) \
asm volatile("1: movl %%eax,0(%2)\n" \
@@ -191,13 +197,71 @@ extern int __get_user_bad(void);
_ASM_EXTABLE(2b, 4b) \
: "=r" (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
#define __put_user_u64(x, ptr, retval) \
__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
+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
+/**
+ * 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) \
do { \
retval = 0; \
@@ -231,6 +295,16 @@ do { \
retval = errret; \
} 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
#ifdef CONFIG_X86_32