diff options
-rw-r--r-- | arch/arm64/include/asm/asm-uaccess.h | 12 | ||||
-rw-r--r-- | arch/arm64/include/asm/efi.h | 12 | ||||
-rw-r--r-- | arch/arm64/include/asm/mmu_context.h | 3 | ||||
-rw-r--r-- | arch/arm64/include/asm/uaccess.h | 9 | ||||
-rw-r--r-- | arch/arm64/kernel/entry.S | 2 | ||||
-rw-r--r-- | arch/arm64/lib/clear_user.S | 2 | ||||
-rw-r--r-- | arch/arm64/lib/copy_from_user.S | 2 | ||||
-rw-r--r-- | arch/arm64/lib/copy_in_user.S | 2 | ||||
-rw-r--r-- | arch/arm64/lib/copy_to_user.S | 2 | ||||
-rw-r--r-- | arch/arm64/mm/cache.S | 2 | ||||
-rw-r--r-- | arch/arm64/mm/proc.S | 3 | ||||
-rw-r--r-- | arch/arm64/xen/hypercall.S | 2 |
12 files changed, 32 insertions, 21 deletions
diff --git a/arch/arm64/include/asm/asm-uaccess.h b/arch/arm64/include/asm/asm-uaccess.h index 8719ce122a38..4128bec033f6 100644 --- a/arch/arm64/include/asm/asm-uaccess.h +++ b/arch/arm64/include/asm/asm-uaccess.h | |||
@@ -14,11 +14,11 @@ | |||
14 | #ifdef CONFIG_ARM64_SW_TTBR0_PAN | 14 | #ifdef CONFIG_ARM64_SW_TTBR0_PAN |
15 | .macro __uaccess_ttbr0_disable, tmp1 | 15 | .macro __uaccess_ttbr0_disable, tmp1 |
16 | mrs \tmp1, ttbr1_el1 // swapper_pg_dir | 16 | mrs \tmp1, ttbr1_el1 // swapper_pg_dir |
17 | bic \tmp1, \tmp1, #TTBR_ASID_MASK | ||
17 | sub \tmp1, \tmp1, #RESERVED_TTBR0_SIZE // reserved_ttbr0 just before swapper_pg_dir | 18 | sub \tmp1, \tmp1, #RESERVED_TTBR0_SIZE // reserved_ttbr0 just before swapper_pg_dir |
18 | msr ttbr0_el1, \tmp1 // set reserved TTBR0_EL1 | 19 | msr ttbr0_el1, \tmp1 // set reserved TTBR0_EL1 |
19 | isb | 20 | isb |
20 | add \tmp1, \tmp1, #RESERVED_TTBR0_SIZE | 21 | add \tmp1, \tmp1, #RESERVED_TTBR0_SIZE |
21 | bic \tmp1, \tmp1, #TTBR_ASID_MASK | ||
22 | msr ttbr1_el1, \tmp1 // set reserved ASID | 22 | msr ttbr1_el1, \tmp1 // set reserved ASID |
23 | isb | 23 | isb |
24 | .endm | 24 | .endm |
@@ -35,9 +35,11 @@ | |||
35 | isb | 35 | isb |
36 | .endm | 36 | .endm |
37 | 37 | ||
38 | .macro uaccess_ttbr0_disable, tmp1 | 38 | .macro uaccess_ttbr0_disable, tmp1, tmp2 |
39 | alternative_if_not ARM64_HAS_PAN | 39 | alternative_if_not ARM64_HAS_PAN |
40 | save_and_disable_irq \tmp2 // avoid preemption | ||
40 | __uaccess_ttbr0_disable \tmp1 | 41 | __uaccess_ttbr0_disable \tmp1 |
42 | restore_irq \tmp2 | ||
41 | alternative_else_nop_endif | 43 | alternative_else_nop_endif |
42 | .endm | 44 | .endm |
43 | 45 | ||
@@ -49,7 +51,7 @@ alternative_if_not ARM64_HAS_PAN | |||
49 | alternative_else_nop_endif | 51 | alternative_else_nop_endif |
50 | .endm | 52 | .endm |
51 | #else | 53 | #else |
52 | .macro uaccess_ttbr0_disable, tmp1 | 54 | .macro uaccess_ttbr0_disable, tmp1, tmp2 |
53 | .endm | 55 | .endm |
54 | 56 | ||
55 | .macro uaccess_ttbr0_enable, tmp1, tmp2, tmp3 | 57 | .macro uaccess_ttbr0_enable, tmp1, tmp2, tmp3 |
@@ -59,8 +61,8 @@ alternative_else_nop_endif | |||
59 | /* | 61 | /* |
60 | * These macros are no-ops when UAO is present. | 62 | * These macros are no-ops when UAO is present. |
61 | */ | 63 | */ |
62 | .macro uaccess_disable_not_uao, tmp1 | 64 | .macro uaccess_disable_not_uao, tmp1, tmp2 |
63 | uaccess_ttbr0_disable \tmp1 | 65 | uaccess_ttbr0_disable \tmp1, \tmp2 |
64 | alternative_if ARM64_ALT_PAN_NOT_UAO | 66 | alternative_if ARM64_ALT_PAN_NOT_UAO |
65 | SET_PSTATE_PAN(1) | 67 | SET_PSTATE_PAN(1) |
66 | alternative_else_nop_endif | 68 | alternative_else_nop_endif |
diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h index c4cd5081d78b..8389050328bb 100644 --- a/arch/arm64/include/asm/efi.h +++ b/arch/arm64/include/asm/efi.h | |||
@@ -121,19 +121,21 @@ static inline void efi_set_pgd(struct mm_struct *mm) | |||
121 | if (mm != current->active_mm) { | 121 | if (mm != current->active_mm) { |
122 | /* | 122 | /* |
123 | * Update the current thread's saved ttbr0 since it is | 123 | * Update the current thread's saved ttbr0 since it is |
124 | * restored as part of a return from exception. Set | 124 | * restored as part of a return from exception. Enable |
125 | * the hardware TTBR0_EL1 using cpu_switch_mm() | 125 | * access to the valid TTBR0_EL1 and invoke the errata |
126 | * directly to enable potential errata workarounds. | 126 | * workaround directly since there is no return from |
127 | * exception when invoking the EFI run-time services. | ||
127 | */ | 128 | */ |
128 | update_saved_ttbr0(current, mm); | 129 | update_saved_ttbr0(current, mm); |
129 | cpu_switch_mm(mm->pgd, mm); | 130 | uaccess_ttbr0_enable(); |
131 | post_ttbr_update_workaround(); | ||
130 | } else { | 132 | } else { |
131 | /* | 133 | /* |
132 | * Defer the switch to the current thread's TTBR0_EL1 | 134 | * Defer the switch to the current thread's TTBR0_EL1 |
133 | * until uaccess_enable(). Restore the current | 135 | * until uaccess_enable(). Restore the current |
134 | * thread's saved ttbr0 corresponding to its active_mm | 136 | * thread's saved ttbr0 corresponding to its active_mm |
135 | */ | 137 | */ |
136 | cpu_set_reserved_ttbr0(); | 138 | uaccess_ttbr0_disable(); |
137 | update_saved_ttbr0(current, current->active_mm); | 139 | update_saved_ttbr0(current, current->active_mm); |
138 | } | 140 | } |
139 | } | 141 | } |
diff --git a/arch/arm64/include/asm/mmu_context.h b/arch/arm64/include/asm/mmu_context.h index 5aee19905556..8d3331985d2e 100644 --- a/arch/arm64/include/asm/mmu_context.h +++ b/arch/arm64/include/asm/mmu_context.h | |||
@@ -184,7 +184,7 @@ static inline void update_saved_ttbr0(struct task_struct *tsk, | |||
184 | else | 184 | else |
185 | ttbr = virt_to_phys(mm->pgd) | ASID(mm) << 48; | 185 | ttbr = virt_to_phys(mm->pgd) | ASID(mm) << 48; |
186 | 186 | ||
187 | task_thread_info(tsk)->ttbr0 = ttbr; | 187 | WRITE_ONCE(task_thread_info(tsk)->ttbr0, ttbr); |
188 | } | 188 | } |
189 | #else | 189 | #else |
190 | static inline void update_saved_ttbr0(struct task_struct *tsk, | 190 | static inline void update_saved_ttbr0(struct task_struct *tsk, |
@@ -239,6 +239,7 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next, | |||
239 | #define activate_mm(prev,next) switch_mm(prev, next, current) | 239 | #define activate_mm(prev,next) switch_mm(prev, next, current) |
240 | 240 | ||
241 | void verify_cpu_asid_bits(void); | 241 | void verify_cpu_asid_bits(void); |
242 | void post_ttbr_update_workaround(void); | ||
242 | 243 | ||
243 | #endif /* !__ASSEMBLY__ */ | 244 | #endif /* !__ASSEMBLY__ */ |
244 | 245 | ||
diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h index 01ade20d5456..59fda5292936 100644 --- a/arch/arm64/include/asm/uaccess.h +++ b/arch/arm64/include/asm/uaccess.h | |||
@@ -105,16 +105,18 @@ static inline void set_fs(mm_segment_t fs) | |||
105 | #ifdef CONFIG_ARM64_SW_TTBR0_PAN | 105 | #ifdef CONFIG_ARM64_SW_TTBR0_PAN |
106 | static inline void __uaccess_ttbr0_disable(void) | 106 | static inline void __uaccess_ttbr0_disable(void) |
107 | { | 107 | { |
108 | unsigned long ttbr; | 108 | unsigned long flags, ttbr; |
109 | 109 | ||
110 | local_irq_save(flags); | ||
110 | ttbr = read_sysreg(ttbr1_el1); | 111 | ttbr = read_sysreg(ttbr1_el1); |
112 | ttbr &= ~TTBR_ASID_MASK; | ||
111 | /* reserved_ttbr0 placed before swapper_pg_dir */ | 113 | /* reserved_ttbr0 placed before swapper_pg_dir */ |
112 | write_sysreg(ttbr - RESERVED_TTBR0_SIZE, ttbr0_el1); | 114 | write_sysreg(ttbr - RESERVED_TTBR0_SIZE, ttbr0_el1); |
113 | isb(); | 115 | isb(); |
114 | /* Set reserved ASID */ | 116 | /* Set reserved ASID */ |
115 | ttbr &= ~TTBR_ASID_MASK; | ||
116 | write_sysreg(ttbr, ttbr1_el1); | 117 | write_sysreg(ttbr, ttbr1_el1); |
117 | isb(); | 118 | isb(); |
119 | local_irq_restore(flags); | ||
118 | } | 120 | } |
119 | 121 | ||
120 | static inline void __uaccess_ttbr0_enable(void) | 122 | static inline void __uaccess_ttbr0_enable(void) |
@@ -127,10 +129,11 @@ static inline void __uaccess_ttbr0_enable(void) | |||
127 | * roll-over and an update of 'ttbr0'. | 129 | * roll-over and an update of 'ttbr0'. |
128 | */ | 130 | */ |
129 | local_irq_save(flags); | 131 | local_irq_save(flags); |
130 | ttbr0 = current_thread_info()->ttbr0; | 132 | ttbr0 = READ_ONCE(current_thread_info()->ttbr0); |
131 | 133 | ||
132 | /* Restore active ASID */ | 134 | /* Restore active ASID */ |
133 | ttbr1 = read_sysreg(ttbr1_el1); | 135 | ttbr1 = read_sysreg(ttbr1_el1); |
136 | ttbr1 &= ~TTBR_ASID_MASK; /* safety measure */ | ||
134 | ttbr1 |= ttbr0 & TTBR_ASID_MASK; | 137 | ttbr1 |= ttbr0 & TTBR_ASID_MASK; |
135 | write_sysreg(ttbr1, ttbr1_el1); | 138 | write_sysreg(ttbr1, ttbr1_el1); |
136 | isb(); | 139 | isb(); |
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 1e1d1842888d..b34e717d7597 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S | |||
@@ -204,7 +204,7 @@ alternative_if ARM64_HAS_PAN | |||
204 | alternative_else_nop_endif | 204 | alternative_else_nop_endif |
205 | 205 | ||
206 | .if \el != 0 | 206 | .if \el != 0 |
207 | mrs x21, ttbr1_el1 | 207 | mrs x21, ttbr0_el1 |
208 | tst x21, #TTBR_ASID_MASK // Check for the reserved ASID | 208 | tst x21, #TTBR_ASID_MASK // Check for the reserved ASID |
209 | orr x23, x23, #PSR_PAN_BIT // Set the emulated PAN in the saved SPSR | 209 | orr x23, x23, #PSR_PAN_BIT // Set the emulated PAN in the saved SPSR |
210 | b.eq 1f // TTBR0 access already disabled | 210 | b.eq 1f // TTBR0 access already disabled |
diff --git a/arch/arm64/lib/clear_user.S b/arch/arm64/lib/clear_user.S index 8f9c4641e706..3d69a8d41fa5 100644 --- a/arch/arm64/lib/clear_user.S +++ b/arch/arm64/lib/clear_user.S | |||
@@ -50,7 +50,7 @@ uao_user_alternative 9f, strh, sttrh, wzr, x0, 2 | |||
50 | b.mi 5f | 50 | b.mi 5f |
51 | uao_user_alternative 9f, strb, sttrb, wzr, x0, 0 | 51 | uao_user_alternative 9f, strb, sttrb, wzr, x0, 0 |
52 | 5: mov x0, #0 | 52 | 5: mov x0, #0 |
53 | uaccess_disable_not_uao x2 | 53 | uaccess_disable_not_uao x2, x3 |
54 | ret | 54 | ret |
55 | ENDPROC(__clear_user) | 55 | ENDPROC(__clear_user) |
56 | 56 | ||
diff --git a/arch/arm64/lib/copy_from_user.S b/arch/arm64/lib/copy_from_user.S index 69d86a80f3e2..20305d485046 100644 --- a/arch/arm64/lib/copy_from_user.S +++ b/arch/arm64/lib/copy_from_user.S | |||
@@ -67,7 +67,7 @@ ENTRY(__arch_copy_from_user) | |||
67 | uaccess_enable_not_uao x3, x4, x5 | 67 | uaccess_enable_not_uao x3, x4, x5 |
68 | add end, x0, x2 | 68 | add end, x0, x2 |
69 | #include "copy_template.S" | 69 | #include "copy_template.S" |
70 | uaccess_disable_not_uao x3 | 70 | uaccess_disable_not_uao x3, x4 |
71 | mov x0, #0 // Nothing to copy | 71 | mov x0, #0 // Nothing to copy |
72 | ret | 72 | ret |
73 | ENDPROC(__arch_copy_from_user) | 73 | ENDPROC(__arch_copy_from_user) |
diff --git a/arch/arm64/lib/copy_in_user.S b/arch/arm64/lib/copy_in_user.S index e442b531252a..fbb090f431a5 100644 --- a/arch/arm64/lib/copy_in_user.S +++ b/arch/arm64/lib/copy_in_user.S | |||
@@ -68,7 +68,7 @@ ENTRY(raw_copy_in_user) | |||
68 | uaccess_enable_not_uao x3, x4, x5 | 68 | uaccess_enable_not_uao x3, x4, x5 |
69 | add end, x0, x2 | 69 | add end, x0, x2 |
70 | #include "copy_template.S" | 70 | #include "copy_template.S" |
71 | uaccess_disable_not_uao x3 | 71 | uaccess_disable_not_uao x3, x4 |
72 | mov x0, #0 | 72 | mov x0, #0 |
73 | ret | 73 | ret |
74 | ENDPROC(raw_copy_in_user) | 74 | ENDPROC(raw_copy_in_user) |
diff --git a/arch/arm64/lib/copy_to_user.S b/arch/arm64/lib/copy_to_user.S index 318f15d5c336..fda6172d6b88 100644 --- a/arch/arm64/lib/copy_to_user.S +++ b/arch/arm64/lib/copy_to_user.S | |||
@@ -66,7 +66,7 @@ ENTRY(__arch_copy_to_user) | |||
66 | uaccess_enable_not_uao x3, x4, x5 | 66 | uaccess_enable_not_uao x3, x4, x5 |
67 | add end, x0, x2 | 67 | add end, x0, x2 |
68 | #include "copy_template.S" | 68 | #include "copy_template.S" |
69 | uaccess_disable_not_uao x3 | 69 | uaccess_disable_not_uao x3, x4 |
70 | mov x0, #0 | 70 | mov x0, #0 |
71 | ret | 71 | ret |
72 | ENDPROC(__arch_copy_to_user) | 72 | ENDPROC(__arch_copy_to_user) |
diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S index 6cd20a8c0952..91464e7f77cc 100644 --- a/arch/arm64/mm/cache.S +++ b/arch/arm64/mm/cache.S | |||
@@ -72,7 +72,7 @@ USER(9f, ic ivau, x4 ) // invalidate I line PoU | |||
72 | isb | 72 | isb |
73 | mov x0, #0 | 73 | mov x0, #0 |
74 | 1: | 74 | 1: |
75 | uaccess_ttbr0_disable x1 | 75 | uaccess_ttbr0_disable x1, x2 |
76 | ret | 76 | ret |
77 | 9: | 77 | 9: |
78 | mov x0, #-EFAULT | 78 | mov x0, #-EFAULT |
diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S index 05e4ae934b23..c6a12073ef46 100644 --- a/arch/arm64/mm/proc.S +++ b/arch/arm64/mm/proc.S | |||
@@ -153,6 +153,9 @@ ENDPROC(cpu_do_resume) | |||
153 | ENTRY(cpu_do_switch_mm) | 153 | ENTRY(cpu_do_switch_mm) |
154 | mrs x2, ttbr1_el1 | 154 | mrs x2, ttbr1_el1 |
155 | mmid x1, x1 // get mm->context.id | 155 | mmid x1, x1 // get mm->context.id |
156 | #ifdef CONFIG_ARM64_SW_TTBR0_PAN | ||
157 | bfi x0, x1, #48, #16 // set the ASID field in TTBR0 | ||
158 | #endif | ||
156 | bfi x2, x1, #48, #16 // set the ASID | 159 | bfi x2, x1, #48, #16 // set the ASID |
157 | msr ttbr1_el1, x2 // in TTBR1 (since TCR.A1 is set) | 160 | msr ttbr1_el1, x2 // in TTBR1 (since TCR.A1 is set) |
158 | isb | 161 | isb |
diff --git a/arch/arm64/xen/hypercall.S b/arch/arm64/xen/hypercall.S index acdbd2c9e899..c5f05c4a4d00 100644 --- a/arch/arm64/xen/hypercall.S +++ b/arch/arm64/xen/hypercall.S | |||
@@ -107,6 +107,6 @@ ENTRY(privcmd_call) | |||
107 | /* | 107 | /* |
108 | * Disable userspace access from kernel once the hyp call completed. | 108 | * Disable userspace access from kernel once the hyp call completed. |
109 | */ | 109 | */ |
110 | uaccess_ttbr0_disable x6 | 110 | uaccess_ttbr0_disable x6, x7 |
111 | ret | 111 | ret |
112 | ENDPROC(privcmd_call); | 112 | ENDPROC(privcmd_call); |