From: Anton Blanchard Date: Thu, 18 Sep 2014 23:40:19 +0000 (+1000) Subject: powerpc: Implement load_unaligned_zeropad X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=de5946c03575fb8c222610a6ac6726a5deabad46;p=GitHub%2Fmoto-9609%2Fandroid_kernel_motorola_exynos9610.git 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 Signed-off-by: Michael Ellerman --- diff --git a/arch/powerpc/include/asm/word-at-a-time.h b/arch/powerpc/include/asm/word-at-a-time.h index 9a5c928bb3c6..07cc121e8a79 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 */