diff options
author | Ville Syrjälä <ville.syrjala@linux.intel.com> | 2012-12-12 15:34:03 +0400 |
---|---|---|
committer | H. Peter Anvin <hpa@linux.intel.com> | 2013-02-08 03:07:28 +0400 |
commit | 96477b4cd705c5416346aef262b0a1116cfcdd80 (patch) | |
tree | fcc031d7eb37e0eeef361e65102c260c8b62490b /arch/x86/include/asm/uaccess.h | |
parent | 07f4207a305c834f528d08428df4531744e25678 (diff) | |
download | linux-96477b4cd705c5416346aef262b0a1116cfcdd80.tar.xz |
x86-32: Add support for 64bit get_user()
Implement __get_user_8() for x86-32. It will return the
64-bit result in edx:eax register pair, and ecx is used
to pass in the address and return the error value.
For consistency, change the register assignment for all
other __get_user_x() variants, so that address is passed in
ecx/rcx, the error value is returned in ecx/rcx, and eax/rax
contains the actual value.
[ hpa: I modified the patch so that it does NOT change the calling
conventions for the existing callsites, this also means that the code
is completely unchanged for 64 bits.
Instead, continue to use eax for address input/error output and use
the ecx:edx register pair for the output. ]
This is a partial refresh of a patch [1] by Jamie Lokier from
2004. Only the minimal changes to implement 64bit get_user()
were picked from the original patch.
[1] http://article.gmane.org/gmane.linux.kernel/198823
Originally-by: Jamie Lokier <jamie@shareable.org>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link:
http://lkml.kernel.org/r/1355312043-11467-1-git-send-email-ville.syrjala@linux.intel.com
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'arch/x86/include/asm/uaccess.h')
-rw-r--r-- | arch/x86/include/asm/uaccess.h | 19 |
1 files changed, 15 insertions, 4 deletions
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h index 1709801d18ec..1e963267d44e 100644 --- a/arch/x86/include/asm/uaccess.h +++ b/arch/x86/include/asm/uaccess.h @@ -151,8 +151,15 @@ extern int __get_user_bad(void); * On error, the variable @x is set to zero. */ #ifdef CONFIG_X86_32 -#define __get_user_8(__ret_gu, __val_gu, ptr) \ - __get_user_x(X, __ret_gu, __val_gu, ptr) +#define __get_user_8(ret, x, ptr) \ +do { \ + register unsigned long long __xx asm("%edx"); \ + asm volatile("call __get_user_8" \ + : "=a" (ret), "=r" (__xx) \ + : "0" (ptr)); \ + (x) = __xx; \ +} while (0) + #else #define __get_user_8(__ret_gu, __val_gu, ptr) \ __get_user_x(8, __ret_gu, __val_gu, ptr) @@ -162,6 +169,7 @@ extern int __get_user_bad(void); ({ \ int __ret_gu; \ unsigned long __val_gu; \ + unsigned long long __val_gu8; \ __chk_user_ptr(ptr); \ might_fault(); \ switch (sizeof(*(ptr))) { \ @@ -175,13 +183,16 @@ extern int __get_user_bad(void); __get_user_x(4, __ret_gu, __val_gu, ptr); \ break; \ case 8: \ - __get_user_8(__ret_gu, __val_gu, ptr); \ + __get_user_8(__ret_gu, __val_gu8, ptr); \ break; \ default: \ __get_user_x(X, __ret_gu, __val_gu, ptr); \ break; \ } \ - (x) = (__typeof__(*(ptr)))__val_gu; \ + if (sizeof(*(ptr)) == 8) \ + (x) = (__typeof__(*(ptr)))__val_gu8; \ + else \ + (x) = (__typeof__(*(ptr)))__val_gu; \ __ret_gu; \ }) |