diff options
author | Anton Blanchard <anton@samba.org> | 2014-09-19 09:40:19 +1000 |
---|---|---|
committer | Michael Ellerman <mpe@ellerman.id.au> | 2014-09-30 14:59:12 +1000 |
commit | de5946c03575fb8c222610a6ac6726a5deabad46 (patch) | |
tree | 9df28ec080f641f05aa2440b66284a2cbf18ccf2 /arch/powerpc/include | |
parent | 6d31c2fa0eee89e31ca48a66ccfaf71ef545c474 (diff) | |
download | op-kernel-dev-de5946c03575fb8c222610a6ac6726a5deabad46.zip op-kernel-dev-de5946c03575fb8c222610a6ac6726a5deabad46.tar.gz |
powerpc: Implement load_unaligned_zeropad
Implement a bi-arch and bi-endian version of load_unaligned_zeropad.
Since the fallback case is so rare, a userspace test harness was used
to test this on ppc64le, ppc64 and ppc32:
http://ozlabs.org/~anton/junkcode/test_load_unaligned_zeropad.c
It uses mprotect to force a SEGV across a page boundary, and a SEGV
handler to lookup the exception tables and run the fixup routine.
It also compares the result against a normal load.
Signed-off-by: Anton Blanchard <anton@samba.org>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Diffstat (limited to 'arch/powerpc/include')
-rw-r--r-- | arch/powerpc/include/asm/word-at-a-time.h | 40 |
1 files changed, 40 insertions, 0 deletions
diff --git a/arch/powerpc/include/asm/word-at-a-time.h b/arch/powerpc/include/asm/word-at-a-time.h index 9a5c928..07cc121 100644 --- a/arch/powerpc/include/asm/word-at-a-time.h +++ b/arch/powerpc/include/asm/word-at-a-time.h @@ -116,4 +116,44 @@ static inline unsigned long prep_zero_mask(unsigned long a, unsigned long bits, #endif +static inline unsigned long load_unaligned_zeropad(const void *addr) +{ + unsigned long ret, offset, tmp; + + asm( + "1: " PPC_LL "%[ret], 0(%[addr])\n" + "2:\n" + ".section .fixup,\"ax\"\n" + "3: " +#ifdef __powerpc64__ + "clrrdi %[tmp], %[addr], 3\n\t" + "clrlsldi %[offset], %[addr], 61, 3\n\t" + "ld %[ret], 0(%[tmp])\n\t" +#ifdef __BIG_ENDIAN__ + "sld %[ret], %[ret], %[offset]\n\t" +#else + "srd %[ret], %[ret], %[offset]\n\t" +#endif +#else + "clrrwi %[tmp], %[addr], 2\n\t" + "clrlslwi %[offset], %[addr], 30, 3\n\t" + "lwz %[ret], 0(%[tmp])\n\t" +#ifdef __BIG_ENDIAN__ + "slw %[ret], %[ret], %[offset]\n\t" +#else + "srw %[ret], %[ret], %[offset]\n\t" +#endif +#endif + "b 2b\n" + ".previous\n" + ".section __ex_table,\"a\"\n\t" + PPC_LONG_ALIGN "\n\t" + PPC_LONG "1b,3b\n" + ".previous" + : [tmp] "=&b" (tmp), [offset] "=&r" (offset), [ret] "=&r" (ret) + : [addr] "b" (addr), "m" (*(unsigned long *)addr)); + + return ret; +} + #endif /* _ASM_WORD_AT_A_TIME_H */ |