diff options
-rw-r--r-- | arch/arm/mm/alignment.c | 42 |
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. */ | ||
99 | static bool cpu_is_v6_unaligned(void) | ||
100 | { | ||
101 | return cpu_architecture() >= CPU_ARCH_ARMv6 && (cr_alignment & CR_U); | ||
102 | } | ||
103 | |||
104 | static 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 | |||
98 | static int alignment_proc_show(struct seq_file *m, void *v) | 125 | static 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, |