aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2018-02-06 12:56:20 -0500
committerCatalin Marinas <catalin.marinas@arm.com>2018-02-06 17:54:17 -0500
commitb092201e0020614127f495c092e0a12d26a2116e (patch)
tree687459c8073a8331c25f592552e926e886cceec3
parentf2d3b2e8759a5833df6f022e42df2d581e6d843c (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.S20
-rw-r--r--arch/arm64/kernel/cpu_errata.c68
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
87ENTRY(__qcom_hyp_sanitize_link_stack_end) 88ENTRY(__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
101ENTRY(__smccc_workaround_1_smc_start)
102 smccc_workaround_1 smc
103ENTRY(__smccc_workaround_1_smc_end)
104
105ENTRY(__smccc_workaround_1_hvc_start)
106 smccc_workaround_1 hvc
107ENTRY(__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);
70extern char __psci_hyp_bp_inval_start[], __psci_hyp_bp_inval_end[]; 70extern char __psci_hyp_bp_inval_start[], __psci_hyp_bp_inval_end[];
71extern char __qcom_hyp_sanitize_link_stack_start[]; 71extern char __qcom_hyp_sanitize_link_stack_start[];
72extern char __qcom_hyp_sanitize_link_stack_end[]; 72extern char __qcom_hyp_sanitize_link_stack_end[];
73extern char __smccc_workaround_1_smc_start[];
74extern char __smccc_workaround_1_smc_end[];
75extern char __smccc_workaround_1_hvc_start[];
76extern char __smccc_workaround_1_hvc_end[];
73 77
74static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start, 78static 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
120static void __install_bp_hardening_cb(bp_hardening_cb_t fn, 128static 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
157static void call_smc_arch_workaround_1(void)
158{
159 arm_smccc_1_1_smc(ARM_SMCCC_ARCH_WORKAROUND_1, NULL);
160}
161
162static void call_hvc_arch_workaround_1(void)
163{
164 arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_WORKAROUND_1, NULL);
165}
166
167static 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
147static int enable_psci_bp_hardening(void *data) 209static 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}