aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm64/include/asm/asm-uaccess.h12
-rw-r--r--arch/arm64/include/asm/efi.h12
-rw-r--r--arch/arm64/include/asm/mmu_context.h3
-rw-r--r--arch/arm64/include/asm/uaccess.h9
-rw-r--r--arch/arm64/kernel/entry.S2
-rw-r--r--arch/arm64/lib/clear_user.S2
-rw-r--r--arch/arm64/lib/copy_from_user.S2
-rw-r--r--arch/arm64/lib/copy_in_user.S2
-rw-r--r--arch/arm64/lib/copy_to_user.S2
-rw-r--r--arch/arm64/mm/cache.S2
-rw-r--r--arch/arm64/mm/proc.S3
-rw-r--r--arch/arm64/xen/hypercall.S2
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
39alternative_if_not ARM64_HAS_PAN 39alternative_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
41alternative_else_nop_endif 43alternative_else_nop_endif
42 .endm 44 .endm
43 45
@@ -49,7 +51,7 @@ alternative_if_not ARM64_HAS_PAN
49alternative_else_nop_endif 51alternative_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
64alternative_if ARM64_ALT_PAN_NOT_UAO 66alternative_if ARM64_ALT_PAN_NOT_UAO
65 SET_PSTATE_PAN(1) 67 SET_PSTATE_PAN(1)
66alternative_else_nop_endif 68alternative_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
190static inline void update_saved_ttbr0(struct task_struct *tsk, 190static 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
241void verify_cpu_asid_bits(void); 241void verify_cpu_asid_bits(void);
242void 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
106static inline void __uaccess_ttbr0_disable(void) 106static 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
120static inline void __uaccess_ttbr0_enable(void) 122static 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
204alternative_else_nop_endif 204alternative_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
51uao_user_alternative 9f, strb, sttrb, wzr, x0, 0 51uao_user_alternative 9f, strb, sttrb, wzr, x0, 0
525: mov x0, #0 525: mov x0, #0
53 uaccess_disable_not_uao x2 53 uaccess_disable_not_uao x2, x3
54 ret 54 ret
55ENDPROC(__clear_user) 55ENDPROC(__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
73ENDPROC(__arch_copy_from_user) 73ENDPROC(__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
74ENDPROC(raw_copy_in_user) 74ENDPROC(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
72ENDPROC(__arch_copy_to_user) 72ENDPROC(__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
741: 741:
75 uaccess_ttbr0_disable x1 75 uaccess_ttbr0_disable x1, x2
76 ret 76 ret
779: 779:
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)
153ENTRY(cpu_do_switch_mm) 153ENTRY(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
112ENDPROC(privcmd_call); 112ENDPROC(privcmd_call);