mirror of https://gitee.com/openkylin/linux.git
ARM: 7007/1: alignment: Prevent ignoring of faults with ARMv6 unaligned access model
Currently, it's possible to set the kernel to ignore alignment faults when changing the alignment fault handling mode at runtime via /proc/sys/alignment, even though this is undesirable on ARMv6 and above, where it can result in infinite spins where an un-fixed- up instruction repeatedly faults. In addition, the kernel clobbers any alignment mode specified on the command-line if running on ARMv6 or above. This patch factors out the necessary safety check into a couple of new helper functions, and checks and modifies the fault handling mode as appropriate on boot and on writes to /proc/cpu/alignment. Prior to ARMv6, the behaviour is unchanged. For ARMv6 and above, the behaviour changes as follows: * Attempting to ignore faults on ARMv6 results in the mode being forced to UM_FIXUP instead. A warning is printed if this happened as a result of a write to /proc/cpu/alignment. The user's UM_WARN bit (if present) is still honoured. * An alignment= argument from the kernel command-line is now honoured, except that the kernel will modify the specified mode as described above. This is allows modes such as UM_SIGNAL and UM_WARN to be active immediately from boot, which is useful for debugging purposes. Signed-off-by: Dave Martin <dave.martin@linaro.org> Acked-by: Nicolas Pitre <nicolas.pitre@linaro.org> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
parent
bf912d99e9
commit
088c01f1e3
|
@ -95,6 +95,33 @@ static const char *usermode_action[] = {
|
||||||
"signal+warn"
|
"signal+warn"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Return true if and only if the ARMv6 unaligned access model is in use. */
|
||||||
|
static bool cpu_is_v6_unaligned(void)
|
||||||
|
{
|
||||||
|
return cpu_architecture() >= CPU_ARCH_ARMv6 && (cr_alignment & CR_U);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int safe_usermode(int new_usermode, bool warn)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* 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_is_v6_unaligned() && !(new_usermode & (UM_FIXUP | UM_SIGNAL))) {
|
||||||
|
new_usermode |= UM_FIXUP;
|
||||||
|
|
||||||
|
if (warn)
|
||||||
|
printk(KERN_WARNING "alignment: ignoring faults is unsafe on this CPU. Defaulting to fixup mode.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new_usermode;
|
||||||
|
}
|
||||||
|
|
||||||
static int alignment_proc_show(struct seq_file *m, void *v)
|
static int alignment_proc_show(struct seq_file *m, void *v)
|
||||||
{
|
{
|
||||||
seq_printf(m, "User:\t\t%lu\n", ai_user);
|
seq_printf(m, "User:\t\t%lu\n", ai_user);
|
||||||
|
@ -125,7 +152,7 @@ static ssize_t alignment_proc_write(struct file *file, const char __user *buffer
|
||||||
if (get_user(mode, buffer))
|
if (get_user(mode, buffer))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
if (mode >= '0' && mode <= '5')
|
if (mode >= '0' && mode <= '5')
|
||||||
ai_usermode = mode - '0';
|
ai_usermode = safe_usermode(mode - '0', true);
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
@ -926,20 +953,11 @@ static int __init alignment_init(void)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
if (cpu_is_v6_unaligned()) {
|
||||||
* 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_alignment &= ~CR_A;
|
||||||
cr_no_alignment &= ~CR_A;
|
cr_no_alignment &= ~CR_A;
|
||||||
set_cr(cr_alignment);
|
set_cr(cr_alignment);
|
||||||
ai_usermode = UM_FIXUP;
|
ai_usermode = safe_usermode(ai_usermode, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
hook_fault_code(1, do_alignment, SIGBUS, BUS_ADRALN,
|
hook_fault_code(1, do_alignment, SIGBUS, BUS_ADRALN,
|
||||||
|
|
Loading…
Reference in New Issue