aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mm
diff options
context:
space:
mode:
authorDave Martin <dave.martin@linaro.org>2011-07-28 09:28:52 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2011-08-09 03:42:39 -0400
commit088c01f1e39dbe93a13e0b00f4532ed8b79d35f4 (patch)
treebeaf9200bfd86e7250413a1c5490457bab90c8d3 /arch/arm/mm
parentbf912d99e94cd1f43a7decce2e9b79a3ca7f2418 (diff)
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>
Diffstat (limited to 'arch/arm/mm')
-rw-r--r--arch/arm/mm/alignment.c42
1 files changed, 30 insertions, 12 deletions
diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c
index be7c638b648b..1df38e833570 100644
--- a/arch/arm/mm/alignment.c
+++ b/arch/arm/mm/alignment.c
@@ -95,6 +95,33 @@ static const char *usermode_action[] = {
95 "signal+warn" 95 "signal+warn"
96}; 96};
97 97
98/* Return true if and only if the ARMv6 unaligned access model is in use. */
99static bool cpu_is_v6_unaligned(void)
100{
101 return cpu_architecture() >= CPU_ARCH_ARMv6 && (cr_alignment & CR_U);
102}
103
104static int safe_usermode(int new_usermode, bool warn)
105{
106 /*
107 * ARMv6 and later CPUs can perform unaligned accesses for
108 * most single load and store instructions up to word size.
109 * LDM, STM, LDRD and STRD still need to be handled.
110 *
111 * Ignoring the alignment fault is not an option on these
112 * CPUs since we spin re-faulting the instruction without
113 * making any progress.
114 */
115 if (cpu_is_v6_unaligned() && !(new_usermode & (UM_FIXUP | UM_SIGNAL))) {
116 new_usermode |= UM_FIXUP;
117
118 if (warn)
119 printk(KERN_WARNING "alignment: ignoring faults is unsafe on this CPU. Defaulting to fixup mode.\n");
120 }
121
122 return new_usermode;
123}
124
98static int alignment_proc_show(struct seq_file *m, void *v) 125static int alignment_proc_show(struct seq_file *m, void *v)
99{ 126{
100 seq_printf(m, "User:\t\t%lu\n", ai_user); 127 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
125 if (get_user(mode, buffer)) 152 if (get_user(mode, buffer))
126 return -EFAULT; 153 return -EFAULT;
127 if (mode >= '0' && mode <= '5') 154 if (mode >= '0' && mode <= '5')
128 ai_usermode = mode - '0'; 155 ai_usermode = safe_usermode(mode - '0', true);
129 } 156 }
130 return count; 157 return count;
131} 158}
@@ -926,20 +953,11 @@ static int __init alignment_init(void)
926 return -ENOMEM; 953 return -ENOMEM;
927#endif 954#endif
928 955
929 /* 956 if (cpu_is_v6_unaligned()) {
930 * ARMv6 and later CPUs can perform unaligned accesses for
931 * most single load and store instructions up to word size.
932 * LDM, STM, LDRD and STRD still need to be handled.
933 *
934 * Ignoring the alignment fault is not an option on these
935 * CPUs since we spin re-faulting the instruction without
936 * making any progress.
937 */
938 if (cpu_architecture() >= CPU_ARCH_ARMv6 && (cr_alignment & CR_U)) {
939 cr_alignment &= ~CR_A; 957 cr_alignment &= ~CR_A;
940 cr_no_alignment &= ~CR_A; 958 cr_no_alignment &= ~CR_A;
941 set_cr(cr_alignment); 959 set_cr(cr_alignment);
942 ai_usermode = UM_FIXUP; 960 ai_usermode = safe_usermode(ai_usermode, false);
943 } 961 }
944 962
945 hook_fault_code(1, do_alignment, SIGBUS, BUS_ADRALN, 963 hook_fault_code(1, do_alignment, SIGBUS, BUS_ADRALN,