@@ -22,6 +22,7 @@
void __dummy__(void)
{
OFFSET(UREGS_X0, struct cpu_user_regs, x0);
+ OFFSET(UREGS_X1, struct cpu_user_regs, x1);
OFFSET(UREGS_LR, struct cpu_user_regs, lr);
OFFSET(UREGS_SP, struct cpu_user_regs, sp);
@@ -45,6 +46,7 @@ void __dummy__(void)
BLANK();
DEFINE(CPUINFO_sizeof, sizeof(struct cpu_info));
+ OFFSET(CPUINFO_flags, struct cpu_info, flags);
OFFSET(VCPU_arch_saved_context, struct vcpu, arch.saved_context);
@@ -1,4 +1,6 @@
#include <asm/asm_defns.h>
+#include <asm/current.h>
+#include <asm/macros.h>
#include <asm/regs.h>
#include <asm/alternative.h>
#include <asm/smccc.h>
@@ -241,7 +243,7 @@ guest_sync:
* be encoded as an immediate for cmp.
*/
eor w0, w0, #ARM_SMCCC_ARCH_WORKAROUND_1_FID
- cbnz w0, guest_sync_slowpath
+ cbnz w0, check_wa2
/*
* Clobber both x0 and x1 to prevent leakage. Note that thanks
@@ -250,6 +252,44 @@ guest_sync:
mov x1, xzr
eret
+check_wa2:
+ /* ARM_SMCCC_ARCH_WORKAROUND_2 handling */
+ eor w0, w0, #(ARM_SMCCC_ARCH_WORKAROUND_1_FID ^ ARM_SMCCC_ARCH_WORKAROUND_2_FID)
+ cbnz w0, guest_sync_slowpath
+#ifdef CONFIG_ARM_SSBD
+alternative_cb arm_enable_wa2_handling
+ b wa2_end
+alternative_cb_end
+ /* Sanitize the argument */
+ mov x0, #-(UREGS_kernel_sizeof - UREGS_X1) /* x0 := offset of guest's x1 on the stack */
+ ldr x1, [sp, x0] /* Load guest's x1 */
+ cmp w1, wzr
+ cset x1, ne
+
+ /*
+ * Update the guest flag. At this stage sp point after the field
+ * guest_cpu_user_regs in cpu_info.
+ */
+ adr_cpu_info x2
+ ldr x0, [x2, #CPUINFO_flags]
+ bfi x0, x1, #CPUINFO_WORKAROUND_2_FLAG_SHIFT, #1
+ str x0, [x2, #CPUINFO_flags]
+
+ /* Check that we actually need to perform the call */
+ ldr_this_cpu x0, ssbd_callback_required, x2
+ cbz x0, wa2_end
+
+ mov w0, #ARM_SMCCC_ARCH_WORKAROUND_2_FID
+ smc #0
+
+wa2_end:
+ /* Don't leak data from the SMC call */
+ mov x1, xzr
+ mov x2, xzr
+ mov x3, xzr
+#endif /* !CONFIG_ARM_SSBD */
+ mov x0, xzr
+ eret
guest_sync_slowpath:
/*
* x0/x1 may have been scratch by the fast path above, so avoid
@@ -7,6 +7,7 @@
#include <xen/warning.h>
#include <asm/cpufeature.h>
#include <asm/cpuerrata.h>
+#include <asm/insn.h>
#include <asm/psci.h>
/* Override macros from asm/page.h to make them work with mfn_t */
@@ -272,6 +273,23 @@ static int __init parse_spec_ctrl(const char *s)
}
custom_param("spec-ctrl", parse_spec_ctrl);
+/* Arm64 only for now as for Arm32 the workaround is currently handled in C. */
+#ifdef CONFIG_ARM_64
+void __init arm_enable_wa2_handling(const struct alt_instr *alt,
+ const uint32_t *origptr,
+ uint32_t *updptr, int nr_inst)
+{
+ BUG_ON(nr_inst != 1);
+
+ /*
+ * Only allow mitigation on guest ARCH_WORKAROUND_2 if the SSBD
+ * state allow it to be flipped.
+ */
+ if ( get_ssbd_state() == ARM_SSBD_RUNTIME )
+ *updptr = aarch64_insn_gen_nop();
+}
+#endif
+
/*
* Assembly code may use the variable directly, so we need to make sure
* it fits in a register.