arm64: Call ARCH_WORKAROUND_2 on transitions between EL0 and EL1
authorMarc Zyngier <marc.zyngier@arm.com>
Fri, 20 Jul 2018 09:53:00 +0000 (10:53 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 22 Jul 2018 12:28:50 +0000 (14:28 +0200)
commit 8e2906245f1e3b0d027169d9f2e55ce0548cb96e upstream.

In order for the kernel to protect itself, let's call the SSBD mitigation
implemented by the higher exception level (either hypervisor or firmware)
on each transition between userspace and kernel.

We must take the PSCI conduit into account in order to target the
right exception level, hence the introduction of a runtime patching
callback.

Reviewed-by: Mark Rutland <mark.rutland@arm.com>
Reviewed-by: Julien Grall <julien.grall@arm.com>
Acked-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/arm64/kernel/cpu_errata.c
arch/arm64/kernel/entry.S
include/linux/arm-smccc.h

index b5a28336c07712af8d10aa62f1669b8a798065d8..44798a700f6cb0bde4ecc5f11fc2b906c59497d3 100644 (file)
@@ -228,6 +228,30 @@ static int qcom_enable_link_stack_sanitization(void *data)
 }
 #endif /* CONFIG_HARDEN_BRANCH_PREDICTOR */
 
+#ifdef CONFIG_ARM64_SSBD
+void __init arm64_update_smccc_conduit(struct alt_instr *alt,
+                                      __le32 *origptr, __le32 *updptr,
+                                      int nr_inst)
+{
+       u32 insn;
+
+       BUG_ON(nr_inst != 1);
+
+       switch (psci_ops.conduit) {
+       case PSCI_CONDUIT_HVC:
+               insn = aarch64_insn_get_hvc_value();
+               break;
+       case PSCI_CONDUIT_SMC:
+               insn = aarch64_insn_get_smc_value();
+               break;
+       default:
+               return;
+       }
+
+       *updptr = cpu_to_le32(insn);
+}
+#endif /* CONFIG_ARM64_SSBD */
+
 #define MIDR_RANGE(model, min, max) \
        .def_scope = SCOPE_LOCAL_CPU, \
        .matches = is_affected_midr_range, \
index 93958d1341bbd7f2f54f970acf0a3465a3d8d7f0..f9473efee9c5984222ccbd9963febd2f5480dea8 100644 (file)
@@ -18,6 +18,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/arm-smccc.h>
 #include <linux/init.h>
 #include <linux/linkage.h>
 
@@ -137,6 +138,18 @@ alternative_else_nop_endif
        add     \dst, \dst, #(\sym - .entry.tramp.text)
        .endm
 
+       // This macro corrupts x0-x3. It is the caller's duty
+       // to save/restore them if required.
+       .macro  apply_ssbd, state
+#ifdef CONFIG_ARM64_SSBD
+       mov     w0, #ARM_SMCCC_ARCH_WORKAROUND_2
+       mov     w1, #\state
+alternative_cb arm64_update_smccc_conduit
+       nop                                     // Patched to SMC/HVC #0
+alternative_cb_end
+#endif
+       .endm
+
        .macro  kernel_entry, el, regsize = 64
        .if     \regsize == 32
        mov     w0, w0                          // zero upper 32 bits of x0
@@ -163,6 +176,13 @@ alternative_else_nop_endif
        ldr     x19, [tsk, #TSK_TI_FLAGS]       // since we can unmask debug
        disable_step_tsk x19, x20               // exceptions when scheduling.
 
+       apply_ssbd 1
+
+#ifdef CONFIG_ARM64_SSBD
+       ldp     x0, x1, [sp, #16 * 0]
+       ldp     x2, x3, [sp, #16 * 1]
+#endif
+
        mov     x29, xzr                        // fp pointed to user-space
        .else
        add     x21, sp, #S_FRAME_SIZE
@@ -301,6 +321,8 @@ alternative_if ARM64_WORKAROUND_845719
 alternative_else_nop_endif
 #endif
 3:
+       apply_ssbd 0
+
        .endif
 
        msr     elr_el1, x21                    // set up the return data
index c89da86de99fb7ac050819f66d4b2cef1525ca74..ca1d2cc2cdfa09a8a760693b6b3c10e9c3f6a704 100644 (file)
                           ARM_SMCCC_SMC_32,                            \
                           0, 0x8000)
 
+#define ARM_SMCCC_ARCH_WORKAROUND_2                                    \
+       ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,                         \
+                          ARM_SMCCC_SMC_32,                            \
+                          0, 0x7fff)
+
 #ifndef __ASSEMBLY__
 
 #include <linux/linkage.h>