forked from Minki/linux
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:
parent
6d31c2fa0e
commit
de5946c035
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user