diff options
author | Marc Zyngier <marc.zyngier@arm.com> | 2018-02-06 12:56:20 -0500 |
---|---|---|
committer | Catalin Marinas <catalin.marinas@arm.com> | 2018-02-06 17:54:17 -0500 |
commit | b092201e0020614127f495c092e0a12d26a2116e (patch) | |
tree | 687459c8073a8331c25f592552e926e886cceec3 | |
parent | f2d3b2e8759a5833df6f022e42df2d581e6d843c (diff) |
arm64: Add ARM_SMCCC_ARCH_WORKAROUND_1 BP hardening support
Add the detection and runtime code for ARM_SMCCC_ARCH_WORKAROUND_1.
It is lovely. Really.
Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
-rw-r--r-- | arch/arm64/kernel/bpi.S | 20 | ||||
-rw-r--r-- | arch/arm64/kernel/cpu_errata.c | 68 |
2 files changed, 87 insertions, 1 deletions
diff --git a/arch/arm64/kernel/bpi.S b/arch/arm64/kernel/bpi.S index 76225c2611ea..fdeed629f2c6 100644 --- a/arch/arm64/kernel/bpi.S +++ b/arch/arm64/kernel/bpi.S | |||
@@ -17,6 +17,7 @@ | |||
17 | */ | 17 | */ |
18 | 18 | ||
19 | #include <linux/linkage.h> | 19 | #include <linux/linkage.h> |
20 | #include <linux/arm-smccc.h> | ||
20 | 21 | ||
21 | .macro ventry target | 22 | .macro ventry target |
22 | .rept 31 | 23 | .rept 31 |
@@ -85,3 +86,22 @@ ENTRY(__qcom_hyp_sanitize_link_stack_start) | |||
85 | .endr | 86 | .endr |
86 | ldp x29, x30, [sp], #16 | 87 | ldp x29, x30, [sp], #16 |
87 | ENTRY(__qcom_hyp_sanitize_link_stack_end) | 88 | ENTRY(__qcom_hyp_sanitize_link_stack_end) |
89 | |||
90 | .macro smccc_workaround_1 inst | ||
91 | sub sp, sp, #(8 * 4) | ||
92 | stp x2, x3, [sp, #(8 * 0)] | ||
93 | stp x0, x1, [sp, #(8 * 2)] | ||
94 | mov w0, #ARM_SMCCC_ARCH_WORKAROUND_1 | ||
95 | \inst #0 | ||
96 | ldp x2, x3, [sp, #(8 * 0)] | ||
97 | ldp x0, x1, [sp, #(8 * 2)] | ||
98 | add sp, sp, #(8 * 4) | ||
99 | .endm | ||
100 | |||
101 | ENTRY(__smccc_workaround_1_smc_start) | ||
102 | smccc_workaround_1 smc | ||
103 | ENTRY(__smccc_workaround_1_smc_end) | ||
104 | |||
105 | ENTRY(__smccc_workaround_1_hvc_start) | ||
106 | smccc_workaround_1 hvc | ||
107 | ENTRY(__smccc_workaround_1_hvc_end) | ||
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index ed6881882231..9e77809a3b23 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c | |||
@@ -70,6 +70,10 @@ DEFINE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data); | |||
70 | extern char __psci_hyp_bp_inval_start[], __psci_hyp_bp_inval_end[]; | 70 | extern char __psci_hyp_bp_inval_start[], __psci_hyp_bp_inval_end[]; |
71 | extern char __qcom_hyp_sanitize_link_stack_start[]; | 71 | extern char __qcom_hyp_sanitize_link_stack_start[]; |
72 | extern char __qcom_hyp_sanitize_link_stack_end[]; | 72 | extern char __qcom_hyp_sanitize_link_stack_end[]; |
73 | extern char __smccc_workaround_1_smc_start[]; | ||
74 | extern char __smccc_workaround_1_smc_end[]; | ||
75 | extern char __smccc_workaround_1_hvc_start[]; | ||
76 | extern char __smccc_workaround_1_hvc_end[]; | ||
73 | 77 | ||
74 | static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start, | 78 | static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start, |
75 | const char *hyp_vecs_end) | 79 | const char *hyp_vecs_end) |
@@ -116,6 +120,10 @@ static void __install_bp_hardening_cb(bp_hardening_cb_t fn, | |||
116 | #define __psci_hyp_bp_inval_end NULL | 120 | #define __psci_hyp_bp_inval_end NULL |
117 | #define __qcom_hyp_sanitize_link_stack_start NULL | 121 | #define __qcom_hyp_sanitize_link_stack_start NULL |
118 | #define __qcom_hyp_sanitize_link_stack_end NULL | 122 | #define __qcom_hyp_sanitize_link_stack_end NULL |
123 | #define __smccc_workaround_1_smc_start NULL | ||
124 | #define __smccc_workaround_1_smc_end NULL | ||
125 | #define __smccc_workaround_1_hvc_start NULL | ||
126 | #define __smccc_workaround_1_hvc_end NULL | ||
119 | 127 | ||
120 | static void __install_bp_hardening_cb(bp_hardening_cb_t fn, | 128 | static void __install_bp_hardening_cb(bp_hardening_cb_t fn, |
121 | const char *hyp_vecs_start, | 129 | const char *hyp_vecs_start, |
@@ -142,17 +150,75 @@ static void install_bp_hardening_cb(const struct arm64_cpu_capabilities *entry, | |||
142 | __install_bp_hardening_cb(fn, hyp_vecs_start, hyp_vecs_end); | 150 | __install_bp_hardening_cb(fn, hyp_vecs_start, hyp_vecs_end); |
143 | } | 151 | } |
144 | 152 | ||
153 | #include <uapi/linux/psci.h> | ||
154 | #include <linux/arm-smccc.h> | ||
145 | #include <linux/psci.h> | 155 | #include <linux/psci.h> |
146 | 156 | ||
157 | static void call_smc_arch_workaround_1(void) | ||
158 | { | ||
159 | arm_smccc_1_1_smc(ARM_SMCCC_ARCH_WORKAROUND_1, NULL); | ||
160 | } | ||
161 | |||
162 | static void call_hvc_arch_workaround_1(void) | ||
163 | { | ||
164 | arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_WORKAROUND_1, NULL); | ||
165 | } | ||
166 | |||
167 | static bool check_smccc_arch_workaround_1(const struct arm64_cpu_capabilities *entry) | ||
168 | { | ||
169 | bp_hardening_cb_t cb; | ||
170 | void *smccc_start, *smccc_end; | ||
171 | struct arm_smccc_res res; | ||
172 | |||
173 | if (!entry->matches(entry, SCOPE_LOCAL_CPU)) | ||
174 | return false; | ||
175 | |||
176 | if (psci_ops.smccc_version == SMCCC_VERSION_1_0) | ||
177 | return false; | ||
178 | |||
179 | switch (psci_ops.conduit) { | ||
180 | case PSCI_CONDUIT_HVC: | ||
181 | arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, | ||
182 | ARM_SMCCC_ARCH_WORKAROUND_1, &res); | ||
183 | if (res.a0) | ||
184 | return false; | ||
185 | cb = call_hvc_arch_workaround_1; | ||
186 | smccc_start = __smccc_workaround_1_hvc_start; | ||
187 | smccc_end = __smccc_workaround_1_hvc_end; | ||
188 | break; | ||
189 | |||
190 | case PSCI_CONDUIT_SMC: | ||
191 | arm_smccc_1_1_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, | ||
192 | ARM_SMCCC_ARCH_WORKAROUND_1, &res); | ||
193 | if (res.a0) | ||
194 | return false; | ||
195 | cb = call_smc_arch_workaround_1; | ||
196 | smccc_start = __smccc_workaround_1_smc_start; | ||
197 | smccc_end = __smccc_workaround_1_smc_end; | ||
198 | break; | ||
199 | |||
200 | default: | ||
201 | return false; | ||
202 | } | ||
203 | |||
204 | install_bp_hardening_cb(entry, cb, smccc_start, smccc_end); | ||
205 | |||
206 | return true; | ||
207 | } | ||
208 | |||
147 | static int enable_psci_bp_hardening(void *data) | 209 | static int enable_psci_bp_hardening(void *data) |
148 | { | 210 | { |
149 | const struct arm64_cpu_capabilities *entry = data; | 211 | const struct arm64_cpu_capabilities *entry = data; |
150 | 212 | ||
151 | if (psci_ops.get_version) | 213 | if (psci_ops.get_version) { |
214 | if (check_smccc_arch_workaround_1(entry)) | ||
215 | return 0; | ||
216 | |||
152 | install_bp_hardening_cb(entry, | 217 | install_bp_hardening_cb(entry, |
153 | (bp_hardening_cb_t)psci_ops.get_version, | 218 | (bp_hardening_cb_t)psci_ops.get_version, |
154 | __psci_hyp_bp_inval_start, | 219 | __psci_hyp_bp_inval_start, |
155 | __psci_hyp_bp_inval_end); | 220 | __psci_hyp_bp_inval_end); |
221 | } | ||
156 | 222 | ||
157 | return 0; | 223 | return 0; |
158 | } | 224 | } |