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>
This commit is contained in:
Anton Blanchard 2014-09-19 09:40:19 +10:00 committed by Michael Ellerman
parent 6d31c2fa0e
commit de5946c035
1 changed files with 40 additions and 0 deletions

View File

@ -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 */