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, |
