Commit baa745a3 authored by Russell King's avatar Russell King Committed by Russell King

[ARM] Fix alignment fault handling for ARMv6 and later CPUs

On ARMv6 and later CPUs, it is possible for userspace processes to
get stuck on a misaligned load or store due to the "ignore fault"
setting; unlike previous CPUs, retrying the instruction without
the 'A' bit set does not always cause the load to succeed.

We have no real option but to default to fixing up alignment faults
on these CPUs, and having the CPU fix up those misaligned accesses
which it can.
Reported-by: default avatarWolfgang Grandegger <wg@grandegger.com>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 794baba6
...@@ -70,6 +70,10 @@ static unsigned long ai_dword; ...@@ -70,6 +70,10 @@ static unsigned long ai_dword;
static unsigned long ai_multi; static unsigned long ai_multi;
static int ai_usermode; static int ai_usermode;
#define UM_WARN (1 << 0)
#define UM_FIXUP (1 << 1)
#define UM_SIGNAL (1 << 2)
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
static const char *usermode_action[] = { static const char *usermode_action[] = {
"ignored", "ignored",
...@@ -754,7 +758,7 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs) ...@@ -754,7 +758,7 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
user: user:
ai_user += 1; ai_user += 1;
if (ai_usermode & 1) if (ai_usermode & UM_WARN)
printk("Alignment trap: %s (%d) PC=0x%08lx Instr=0x%0*lx " printk("Alignment trap: %s (%d) PC=0x%08lx Instr=0x%0*lx "
"Address=0x%08lx FSR 0x%03x\n", current->comm, "Address=0x%08lx FSR 0x%03x\n", current->comm,
task_pid_nr(current), instrptr, task_pid_nr(current), instrptr,
...@@ -762,10 +766,10 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs) ...@@ -762,10 +766,10 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
thumb_mode(regs) ? tinstr : instr, thumb_mode(regs) ? tinstr : instr,
addr, fsr); addr, fsr);
if (ai_usermode & 2) if (ai_usermode & UM_FIXUP)
goto fixup; goto fixup;
if (ai_usermode & 4) if (ai_usermode & UM_SIGNAL)
force_sig(SIGBUS, current); force_sig(SIGBUS, current);
else else
set_cr(cr_no_alignment); set_cr(cr_no_alignment);
...@@ -796,6 +800,22 @@ static int __init alignment_init(void) ...@@ -796,6 +800,22 @@ static int __init alignment_init(void)
res->write_proc = proc_alignment_write; res->write_proc = proc_alignment_write;
#endif #endif
/*
* ARMv6 and later CPUs can perform unaligned accesses for
* most single load and store instructions up to word size.
* LDM, STM, LDRD and STRD still need to be handled.
*
* Ignoring the alignment fault is not an option on these
* CPUs since we spin re-faulting the instruction without
* making any progress.
*/
if (cpu_architecture() >= CPU_ARCH_ARMv6 && (cr_alignment & CR_U)) {
cr_alignment &= ~CR_A;
cr_no_alignment &= ~CR_A;
set_cr(cr_alignment);
ai_usermode = UM_FIXUP;
}
hook_fault_code(1, do_alignment, SIGILL, "alignment exception"); hook_fault_code(1, do_alignment, SIGILL, "alignment exception");
hook_fault_code(3, do_alignment, SIGILL, "alignment exception"); hook_fault_code(3, do_alignment, SIGILL, "alignment exception");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment