diff options
author | Michal Simek <monstr@monstr.eu> | 2010-03-22 15:22:41 (GMT) |
---|---|---|
committer | Michal Simek <monstr@monstr.eu> | 2010-04-01 06:38:22 (GMT) |
commit | ef4e277b5d86e56db650137de0b1cd16ded32498 (patch) | |
tree | 4a8b2d6a716b9a3aad8e43c5670628e7e005f3cd /arch/microblaze/include/asm/uaccess.h | |
parent | 3a6d77245efe062993284fd1c2f7510d9a90efe1 (diff) | |
download | linux-ef4e277b5d86e56db650137de0b1cd16ded32498.tar.xz |
microblaze: uaccess: Fix put_user for noMMU
Here is small regression on dhrystone tests and I think
that on all benchmarking tests. It is due to better checking
mechanism in put_user macro
Signed-off-by: Michal Simek <monstr@monstr.eu>
Diffstat (limited to 'arch/microblaze/include/asm/uaccess.h')
-rw-r--r-- | arch/microblaze/include/asm/uaccess.h | 78 |
1 files changed, 56 insertions, 22 deletions
diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/include/asm/uaccess.h index b079ac3..4f17950 100644 --- a/arch/microblaze/include/asm/uaccess.h +++ b/arch/microblaze/include/asm/uaccess.h @@ -213,32 +213,66 @@ extern long __user_bad(void); ? __get_user((x), (ptr)) : -EFAULT; \ }) -/* Undefined function to trigger linker error */ -extern int bad_user_access_length(void); +#define __put_user_asm(insn, __gu_ptr, __gu_val, __gu_err) \ +({ \ + __asm__ __volatile__ ( \ + "1:" insn " %1, %2, r0;" \ + " addk %0, r0, r0;" \ + "2: " \ + __FIXUP_SECTION \ + "3: brid 2b;" \ + " addik %0, r0, %3;" \ + ".previous;" \ + __EX_TABLE_SECTION \ + ".word 1b,3b;" \ + ".previous;" \ + : "=&r"(__gu_err) \ + : "r"(__gu_val), "r"(__gu_ptr), "i"(-EFAULT) \ + ); \ +}) -/* FIXME is not there defined __pu_val */ -#define __put_user(var, ptr) \ +#define __put_user_asm_8(__gu_ptr, __gu_val, __gu_err) \ ({ \ - int __pu_err = 0; \ - switch (sizeof(*(ptr))) { \ - case 1: \ - case 2: \ - case 4: \ - *(ptr) = (var); \ - break; \ - case 8: { \ - typeof(*(ptr)) __pu_val = (var); \ - memcpy(ptr, &__pu_val, sizeof(__pu_val)); \ - } \ - break; \ - default: \ - __pu_err = __put_user_bad(); \ - break; \ - } \ - __pu_err; \ + __asm__ __volatile__ (" lwi %0, %1, 0;" \ + "1: swi %0, %2, 0;" \ + " lwi %0, %1, 4;" \ + "2: swi %0, %2, 4;" \ + " addk %0, r0, r0;" \ + "3: " \ + __FIXUP_SECTION \ + "4: brid 3b;" \ + " addik %0, r0, %3;" \ + ".previous;" \ + __EX_TABLE_SECTION \ + ".word 1b,4b,2b,4b;" \ + ".previous;" \ + : "=&r"(__gu_err) \ + : "r"(&__gu_val), "r"(__gu_ptr), "i"(-EFAULT) \ + ); \ }) -#define __put_user_bad() (bad_user_access_length(), (-EFAULT)) +#define __put_user(x, ptr) \ +({ \ + __typeof__(*(ptr)) volatile __gu_val = (x); \ + long __gu_err = 0; \ + switch (sizeof(__gu_val)) { \ + case 1: \ + __put_user_asm("sb", (ptr), __gu_val, __gu_err); \ + break; \ + case 2: \ + __put_user_asm("sh", (ptr), __gu_val, __gu_err); \ + break; \ + case 4: \ + __put_user_asm("sw", (ptr), __gu_val, __gu_err); \ + break; \ + case 8: \ + __put_user_asm_8((ptr), __gu_val, __gu_err); \ + break; \ + default: \ + /*__gu_err = -EINVAL;*/ __gu_err = __user_bad(); \ + } \ + __gu_err; \ +}) #define put_user(x, ptr) __put_user((x), (ptr)) |