diff options
author | Will Deacon <will.deacon@arm.com> | 2014-02-07 13:12:27 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2014-02-10 06:48:13 -0500 |
commit | b6ccb9803e90c16b212cf4ed62913a7591e79a39 (patch) | |
tree | e077cbf203e4b7fbaaa0e0b4807b01c0f028405a | |
parent | afdd3bba3ca18e6b0515b2e60101a932f5fa9afa (diff) |
ARM: 7954/1: mm: remove remaining domain support from ARMv6
CPU_32v6 currently selects CPU_USE_DOMAINS if CPU_V6 and MMU. This is
because ARM 1136 r0pX CPUs lack the v6k extensions, and therefore do
not have hardware thread registers. The lack of these registers requires
the kernel to update the vectors page at each context switch in order to
write a new TLS pointer. This write must be done via the userspace
mapping, since aliasing caches can lead to expensive flushing when using
kmap. Finally, this requires the vectors page to be mapped r/w for
kernel and r/o for user, which has implications for things like put_user
which must trigger CoW appropriately when targetting user pages.
The upshot of all this is that a v6/v7 kernel makes use of domains to
segregate kernel and user memory accesses. This has the nasty
side-effect of making device mappings executable, which has been
observed to cause subtle bugs on recent cores (e.g. Cortex-A15
performing a speculative instruction fetch from the GIC and acking an
interrupt in the process).
This patch solves this problem by removing the remaining domain support
from ARMv6. A new memory type is added specifically for the vectors page
which allows that page (and only that page) to be mapped as user r/o,
kernel r/w. All other user r/o pages are mapped also as kernel r/o.
Patch co-developed with Russell King.
Cc: <stable@vger.kernel.org>
Signed-off-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r-- | arch/arm/include/asm/futex.h | 6 | ||||
-rw-r--r-- | arch/arm/include/asm/pgtable-2level.h | 1 | ||||
-rw-r--r-- | arch/arm/mm/Kconfig | 3 | ||||
-rw-r--r-- | arch/arm/mm/mmu.c | 10 | ||||
-rw-r--r-- | arch/arm/mm/proc-macros.S | 19 | ||||
-rw-r--r-- | arch/arm/mm/proc-v7-2level.S | 7 |
6 files changed, 18 insertions, 28 deletions
diff --git a/arch/arm/include/asm/futex.h b/arch/arm/include/asm/futex.h index e42cf597f6e6..2aff798fbef4 100644 --- a/arch/arm/include/asm/futex.h +++ b/arch/arm/include/asm/futex.h | |||
@@ -3,11 +3,6 @@ | |||
3 | 3 | ||
4 | #ifdef __KERNEL__ | 4 | #ifdef __KERNEL__ |
5 | 5 | ||
6 | #if defined(CONFIG_CPU_USE_DOMAINS) && defined(CONFIG_SMP) | ||
7 | /* ARM doesn't provide unprivileged exclusive memory accessors */ | ||
8 | #include <asm-generic/futex.h> | ||
9 | #else | ||
10 | |||
11 | #include <linux/futex.h> | 6 | #include <linux/futex.h> |
12 | #include <linux/uaccess.h> | 7 | #include <linux/uaccess.h> |
13 | #include <asm/errno.h> | 8 | #include <asm/errno.h> |
@@ -164,6 +159,5 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr) | |||
164 | return ret; | 159 | return ret; |
165 | } | 160 | } |
166 | 161 | ||
167 | #endif /* !(CPU_USE_DOMAINS && SMP) */ | ||
168 | #endif /* __KERNEL__ */ | 162 | #endif /* __KERNEL__ */ |
169 | #endif /* _ASM_ARM_FUTEX_H */ | 163 | #endif /* _ASM_ARM_FUTEX_H */ |
diff --git a/arch/arm/include/asm/pgtable-2level.h b/arch/arm/include/asm/pgtable-2level.h index dfff709fda3c..219ac88a9542 100644 --- a/arch/arm/include/asm/pgtable-2level.h +++ b/arch/arm/include/asm/pgtable-2level.h | |||
@@ -140,6 +140,7 @@ | |||
140 | #define L_PTE_MT_DEV_NONSHARED (_AT(pteval_t, 0x0c) << 2) /* 1100 */ | 140 | #define L_PTE_MT_DEV_NONSHARED (_AT(pteval_t, 0x0c) << 2) /* 1100 */ |
141 | #define L_PTE_MT_DEV_WC (_AT(pteval_t, 0x09) << 2) /* 1001 */ | 141 | #define L_PTE_MT_DEV_WC (_AT(pteval_t, 0x09) << 2) /* 1001 */ |
142 | #define L_PTE_MT_DEV_CACHED (_AT(pteval_t, 0x0b) << 2) /* 1011 */ | 142 | #define L_PTE_MT_DEV_CACHED (_AT(pteval_t, 0x0b) << 2) /* 1011 */ |
143 | #define L_PTE_MT_VECTORS (_AT(pteval_t, 0x0f) << 2) /* 1111 */ | ||
143 | #define L_PTE_MT_MASK (_AT(pteval_t, 0x0f) << 2) | 144 | #define L_PTE_MT_MASK (_AT(pteval_t, 0x0f) << 2) |
144 | 145 | ||
145 | #ifndef __ASSEMBLY__ | 146 | #ifndef __ASSEMBLY__ |
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 1f8fed94c2a4..ca8ecdee47d8 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig | |||
@@ -446,7 +446,6 @@ config CPU_32v5 | |||
446 | 446 | ||
447 | config CPU_32v6 | 447 | config CPU_32v6 |
448 | bool | 448 | bool |
449 | select CPU_USE_DOMAINS if CPU_V6 && MMU | ||
450 | select TLS_REG_EMUL if !CPU_32v6K && !MMU | 449 | select TLS_REG_EMUL if !CPU_32v6K && !MMU |
451 | 450 | ||
452 | config CPU_32v6K | 451 | config CPU_32v6K |
@@ -671,7 +670,7 @@ config ARM_VIRT_EXT | |||
671 | 670 | ||
672 | config SWP_EMULATE | 671 | config SWP_EMULATE |
673 | bool "Emulate SWP/SWPB instructions" | 672 | bool "Emulate SWP/SWPB instructions" |
674 | depends on !CPU_USE_DOMAINS && CPU_V7 | 673 | depends on CPU_V7 |
675 | default y if SMP | 674 | default y if SMP |
676 | select HAVE_PROC_CPU if PROC_FS | 675 | select HAVE_PROC_CPU if PROC_FS |
677 | help | 676 | help |
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index 4f08c133cc25..6ec07a84f759 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c | |||
@@ -511,6 +511,16 @@ static void __init build_mem_type_table(void) | |||
511 | hyp_device_pgprot = s2_device_pgprot = mem_types[MT_DEVICE].prot_pte; | 511 | hyp_device_pgprot = s2_device_pgprot = mem_types[MT_DEVICE].prot_pte; |
512 | 512 | ||
513 | /* | 513 | /* |
514 | * We don't use domains on ARMv6 (since this causes problems with | ||
515 | * v6/v7 kernels), so we must use a separate memory type for user | ||
516 | * r/o, kernel r/w to map the vectors page. | ||
517 | */ | ||
518 | #ifndef CONFIG_ARM_LPAE | ||
519 | if (cpu_arch == CPU_ARCH_ARMv6) | ||
520 | vecs_pgprot |= L_PTE_MT_VECTORS; | ||
521 | #endif | ||
522 | |||
523 | /* | ||
514 | * ARMv6 and above have extended page tables. | 524 | * ARMv6 and above have extended page tables. |
515 | */ | 525 | */ |
516 | if (cpu_arch >= CPU_ARCH_ARMv6 && (cr & CR_XP)) { | 526 | if (cpu_arch >= CPU_ARCH_ARMv6 && (cr & CR_XP)) { |
diff --git a/arch/arm/mm/proc-macros.S b/arch/arm/mm/proc-macros.S index e3c48a3fe063..ee1d80593958 100644 --- a/arch/arm/mm/proc-macros.S +++ b/arch/arm/mm/proc-macros.S | |||
@@ -112,13 +112,9 @@ | |||
112 | * 100x 1 0 1 r/o no acc | 112 | * 100x 1 0 1 r/o no acc |
113 | * 10x0 1 0 1 r/o no acc | 113 | * 10x0 1 0 1 r/o no acc |
114 | * 1011 0 0 1 r/w no acc | 114 | * 1011 0 0 1 r/w no acc |
115 | * 110x 0 1 0 r/w r/o | ||
116 | * 11x0 0 1 0 r/w r/o | ||
117 | * 1111 0 1 1 r/w r/w | ||
118 | * | ||
119 | * If !CONFIG_CPU_USE_DOMAINS, the following permissions are changed: | ||
120 | * 110x 1 1 1 r/o r/o | 115 | * 110x 1 1 1 r/o r/o |
121 | * 11x0 1 1 1 r/o r/o | 116 | * 11x0 1 1 1 r/o r/o |
117 | * 1111 0 1 1 r/w r/w | ||
122 | */ | 118 | */ |
123 | .macro armv6_mt_table pfx | 119 | .macro armv6_mt_table pfx |
124 | \pfx\()_mt_table: | 120 | \pfx\()_mt_table: |
@@ -137,7 +133,7 @@ | |||
137 | .long PTE_EXT_TEX(2) @ L_PTE_MT_DEV_NONSHARED | 133 | .long PTE_EXT_TEX(2) @ L_PTE_MT_DEV_NONSHARED |
138 | .long 0x00 @ unused | 134 | .long 0x00 @ unused |
139 | .long 0x00 @ unused | 135 | .long 0x00 @ unused |
140 | .long 0x00 @ unused | 136 | .long PTE_CACHEABLE | PTE_BUFFERABLE | PTE_EXT_APX @ L_PTE_MT_VECTORS |
141 | .endm | 137 | .endm |
142 | 138 | ||
143 | .macro armv6_set_pte_ext pfx | 139 | .macro armv6_set_pte_ext pfx |
@@ -158,24 +154,21 @@ | |||
158 | 154 | ||
159 | tst r1, #L_PTE_USER | 155 | tst r1, #L_PTE_USER |
160 | orrne r3, r3, #PTE_EXT_AP1 | 156 | orrne r3, r3, #PTE_EXT_AP1 |
161 | #ifdef CONFIG_CPU_USE_DOMAINS | ||
162 | @ allow kernel read/write access to read-only user pages | ||
163 | tstne r3, #PTE_EXT_APX | 157 | tstne r3, #PTE_EXT_APX |
164 | bicne r3, r3, #PTE_EXT_APX | PTE_EXT_AP0 | 158 | |
165 | #endif | 159 | @ user read-only -> kernel read-only |
160 | bicne r3, r3, #PTE_EXT_AP0 | ||
166 | 161 | ||
167 | tst r1, #L_PTE_XN | 162 | tst r1, #L_PTE_XN |
168 | orrne r3, r3, #PTE_EXT_XN | 163 | orrne r3, r3, #PTE_EXT_XN |
169 | 164 | ||
170 | orr r3, r3, r2 | 165 | eor r3, r3, r2 |
171 | 166 | ||
172 | tst r1, #L_PTE_YOUNG | 167 | tst r1, #L_PTE_YOUNG |
173 | tstne r1, #L_PTE_PRESENT | 168 | tstne r1, #L_PTE_PRESENT |
174 | moveq r3, #0 | 169 | moveq r3, #0 |
175 | #ifndef CONFIG_CPU_USE_DOMAINS | ||
176 | tstne r1, #L_PTE_NONE | 170 | tstne r1, #L_PTE_NONE |
177 | movne r3, #0 | 171 | movne r3, #0 |
178 | #endif | ||
179 | 172 | ||
180 | str r3, [r0] | 173 | str r3, [r0] |
181 | mcr p15, 0, r0, c7, c10, 1 @ flush_pte | 174 | mcr p15, 0, r0, c7, c10, 1 @ flush_pte |
diff --git a/arch/arm/mm/proc-v7-2level.S b/arch/arm/mm/proc-v7-2level.S index bdd3be4be77a..1f52915f2b28 100644 --- a/arch/arm/mm/proc-v7-2level.S +++ b/arch/arm/mm/proc-v7-2level.S | |||
@@ -90,21 +90,14 @@ ENTRY(cpu_v7_set_pte_ext) | |||
90 | 90 | ||
91 | tst r1, #L_PTE_USER | 91 | tst r1, #L_PTE_USER |
92 | orrne r3, r3, #PTE_EXT_AP1 | 92 | orrne r3, r3, #PTE_EXT_AP1 |
93 | #ifdef CONFIG_CPU_USE_DOMAINS | ||
94 | @ allow kernel read/write access to read-only user pages | ||
95 | tstne r3, #PTE_EXT_APX | ||
96 | bicne r3, r3, #PTE_EXT_APX | PTE_EXT_AP0 | ||
97 | #endif | ||
98 | 93 | ||
99 | tst r1, #L_PTE_XN | 94 | tst r1, #L_PTE_XN |
100 | orrne r3, r3, #PTE_EXT_XN | 95 | orrne r3, r3, #PTE_EXT_XN |
101 | 96 | ||
102 | tst r1, #L_PTE_YOUNG | 97 | tst r1, #L_PTE_YOUNG |
103 | tstne r1, #L_PTE_VALID | 98 | tstne r1, #L_PTE_VALID |
104 | #ifndef CONFIG_CPU_USE_DOMAINS | ||
105 | eorne r1, r1, #L_PTE_NONE | 99 | eorne r1, r1, #L_PTE_NONE |
106 | tstne r1, #L_PTE_NONE | 100 | tstne r1, #L_PTE_NONE |
107 | #endif | ||
108 | moveq r3, #0 | 101 | moveq r3, #0 |
109 | 102 | ||
110 | ARM( str r3, [r0, #2048]! ) | 103 | ARM( str r3, [r0, #2048]! ) |