So after adding a quick hack to mitigate Spectre variant 2 to ARM
Trusted Firmware (ATF), ARM actually designed a proper solution that
minimizes the performance loss and makes the presence of the
workaround detectable.  This is all documented in an update of the SMC
Calling Convention (SMCCC) standard.

The diff below implements support for this solution while keeping
support for the hack.  While ARM strongly suggests vendors to update
to a version of ATF that implements SMCCC 1.1 the current ATF for the
Marvell ARMADA 8040 hasn't been updated yet (but does include the
initial hack).

Unfortunately the SMCCC 1.1 implementation in ATF doesn't quite
implement the spec.  As a result we have to check whether the
workaround is implemented by issuing the relevant calls on each of the
CPUs that might be affected.  This is important for big.LITTLE designs
such as the RK3399 that include both Cortex-A53 cores that aren't
vulnerable and Cortex-A72 cores that are.

ok?


Index: dev/fdt/psci.c
===================================================================
RCS file: /cvs/src/sys/dev/fdt/psci.c,v
retrieving revision 1.6
diff -u -p -r1.6 psci.c
--- dev/fdt/psci.c      23 Feb 2018 19:08:56 -0000      1.6
+++ dev/fdt/psci.c      1 May 2018 09:35:14 -0000
@@ -31,14 +31,19 @@
 extern void (*cpuresetfn)(void);
 extern void (*powerdownfn)(void);
 
-#define PSCI_VERSION   0x84000000
-#define SYSTEM_OFF     0x84000008
-#define SYSTEM_RESET   0x84000009
+#define SMCCC_VERSION          0x80000000
+#define SMCCC_ARCH_FEATURES    0x80000001
+#define SMCCC_ARCH_WORKAROUND_1        0x80008000
+
+#define PSCI_VERSION           0x84000000
 #ifdef __LP64__
-#define CPU_ON         0xc4000003
+#define CPU_ON                 0xc4000003
 #else
-#define CPU_ON         0x84000003
+#define CPU_ON                 0x84000003
 #endif
+#define SYSTEM_OFF             0x84000008
+#define SYSTEM_RESET           0x84000009
+#define PSCI_FEATURES          0x8400000a
 
 struct psci_softc {
        struct device    sc_dev;
@@ -48,6 +53,9 @@ struct psci_softc {
        uint32_t         sc_system_off;
        uint32_t         sc_system_reset;
        uint32_t         sc_cpu_on;
+
+       uint32_t         sc_version;
+       uint32_t         sc_smccc_version;
 };
 
 struct psci_softc *psci_sc;
@@ -60,6 +68,12 @@ void psci_powerdown(void);
 extern register_t hvc_call(register_t, register_t, register_t, register_t);
 extern register_t smc_call(register_t, register_t, register_t, register_t);
 
+int32_t smccc_version(void);
+int32_t smccc_arch_features(uint32_t);
+
+uint32_t psci_version(void);
+int32_t psci_features(uint32_t);
+
 struct cfattach psci_ca = {
        sizeof(struct psci_softc), psci_match, psci_attach
 };
@@ -84,7 +98,6 @@ psci_attach(struct device *parent, struc
        struct psci_softc *sc = (struct psci_softc *)self;
        struct fdt_attach_args *faa = aux;
        char method[128];
-       uint32_t version;
 
        if (OF_getprop(faa->fa_node, "method", method, sizeof(method))) {
                if (strcmp(method, "hvc") == 0)
@@ -114,8 +127,18 @@ psci_attach(struct device *parent, struc
 
        psci_sc = sc;
 
-       version = psci_version();
-       printf(": PSCI %d.%d\n", version >> 16, version & 0xffff);
+       sc->sc_version = psci_version();
+       printf(": PSCI %d.%d", sc->sc_version >> 16, sc->sc_version & 0xffff);
+
+       if (sc->sc_version >= 0x10000) {
+               if (psci_features(SMCCC_VERSION) == PSCI_SUCCESS) {
+                       sc->sc_smccc_version = smccc_version();
+                       printf(", SMCCC %d.%d", sc->sc_smccc_version >> 16,
+                           sc->sc_smccc_version & 0xffff);
+               }
+       }
+
+       printf("\n");
 
        if (sc->sc_system_off != 0)
                powerdownfn = psci_powerdown;
@@ -123,22 +146,11 @@ psci_attach(struct device *parent, struc
                cpuresetfn = psci_reset;
 }
 
-uint32_t
-psci_version(void)
-{
-       struct psci_softc *sc = psci_sc;
-
-       if (sc && sc->sc_callfn && sc->sc_psci_version != 0)
-               return (*sc->sc_callfn)(sc->sc_psci_version, 0, 0, 0);
-
-       /* No version support; return 0.0. */
-       return 0;
-}
-
 void
 psci_reset(void)
 {
        struct psci_softc *sc = psci_sc;
+
        if (sc->sc_callfn)
                (*sc->sc_callfn)(sc->sc_system_reset, 0, 0, 0);
 }
@@ -147,10 +159,111 @@ void
 psci_powerdown(void)
 {
        struct psci_softc *sc = psci_sc;
+
        if (sc->sc_callfn)
                (*sc->sc_callfn)(sc->sc_system_off, 0, 0, 0);
 }
 
+/*
+ * Firmware-based workaround for CVE-2017-5715.  We pick the
+ * appropriate mechanism based on the PSCI and SMCCC versions.  Note
+ * that ARM Trusted Firmware violates the SMCCC 1.1 specification and
+ * only reports the presence of the appropriate workaround on CPUs
+ * that are actually vulnerable.  That's why we determine the
+ * appropriate workaround the first time around.
+ */
+
+void
+psci_flush_bp_none(void)
+{
+}
+
+void
+psci_flush_bp_psci_version(void)
+{
+       struct psci_softc *sc = psci_sc;
+
+       (*sc->sc_callfn)(PSCI_VERSION, 0, 0, 0);
+}
+
+void
+psci_flush_bp_smccc_arch_workaround_1(void)
+{
+       struct psci_softc *sc = psci_sc;
+
+       (*sc->sc_callfn)(SMCCC_ARCH_WORKAROUND_1, 0, 0, 0);
+}
+
+void
+psci_flush_bp(void)
+{
+       struct psci_softc *sc = psci_sc;
+       struct cpu_info *ci = curcpu();
+
+       /* No PSCI or an old version of PSCI; nothing we can do. */
+       if (sc == NULL || sc->sc_version < 0x10000) {
+               ci->ci_flush_bp = psci_flush_bp_none;
+               return;
+       }
+
+       /*
+        * PSCI 1.0 or later with SMCCC 1.0; invoke PSCI_VERSION and
+        * hope for the best.
+        */
+       if (sc->sc_smccc_version < 0x10001) {
+               ci->ci_flush_bp = psci_flush_bp_psci_version;
+               ci->ci_flush_bp();
+               return;
+       }
+
+       /*
+        * SMCCC 1.1 or later; we can actually detect if the
+        * workaround is implemented.
+        */
+       if (smccc_arch_features(SMCCC_ARCH_WORKAROUND_1) == PSCI_SUCCESS) {
+               /* Workaround implemented. */
+               ci->ci_flush_bp = psci_flush_bp_smccc_arch_workaround_1;
+               ci->ci_flush_bp();
+       } else {
+               /* No workaround needed. */
+               ci->ci_flush_bp = psci_flush_bp_none;
+       }
+}
+
+int32_t
+smccc_version(void)
+{
+       struct psci_softc *sc = psci_sc;
+
+       if (sc && sc->sc_callfn)
+               return (*sc->sc_callfn)(SMCCC_VERSION, 0, 0, 0);
+
+       return PSCI_NOT_SUPPORTED;
+}
+
+int32_t
+smccc_arch_features(uint32_t arch_func_id)
+{
+       struct psci_softc *sc = psci_sc;
+
+       if (sc && sc->sc_callfn)
+               return (*sc->sc_callfn)(SMCCC_ARCH_FEATURES, arch_func_id, 0, 
0);
+
+       return PSCI_NOT_SUPPORTED;
+}
+
+uint32_t
+psci_version(void)
+{
+       struct psci_softc *sc = psci_sc;
+
+       if (sc && sc->sc_callfn && sc->sc_psci_version != 0)
+               return (*sc->sc_callfn)(sc->sc_psci_version, 0, 0, 0);
+
+       /* No version support; return 0.0. */
+       return 0;
+}
+
 int32_t
 psci_cpu_on(register_t target_cpu, register_t entry_point_address,
     register_t context_id)
@@ -160,6 +273,17 @@ psci_cpu_on(register_t target_cpu, regis
        if (sc && sc->sc_callfn && sc->sc_cpu_on != 0)
                return (*sc->sc_callfn)(sc->sc_cpu_on, target_cpu,
                    entry_point_address, context_id);
+
+       return PSCI_NOT_SUPPORTED;
+}
+
+int32_t
+psci_features(uint32_t psci_func_id)
+{
+       struct psci_softc *sc = psci_sc;
+
+       if (sc && sc->sc_callfn)
+               return (*sc->sc_callfn)(PSCI_FEATURES, psci_func_id, 0, 0);
 
        return PSCI_NOT_SUPPORTED;
 }
Index: dev/fdt/pscivar.h
===================================================================
RCS file: /cvs/src/sys/dev/fdt/pscivar.h,v
retrieving revision 1.2
diff -u -p -r1.2 pscivar.h
--- dev/fdt/pscivar.h   23 Feb 2018 19:08:56 -0000      1.2
+++ dev/fdt/pscivar.h   1 May 2018 09:35:14 -0000
@@ -6,7 +6,7 @@
 #define PSCI_SUCCESS           0
 #define PSCI_NOT_SUPPORTED     -1
 
-uint32_t psci_version(void);
 int32_t psci_cpu_on(register_t, register_t, register_t);
+void   psci_flush_bp(void);
 
 #endif /* _SYS_DEV_FDT_PSCIVAR_H_ */
Index: arch/arm64/arm64/cpu.c
===================================================================
RCS file: /cvs/src/sys/arch/arm64/arm64/cpu.c,v
retrieving revision 1.17
diff -u -p -r1.17 cpu.c
--- arch/arm64/arm64/cpu.c      29 Mar 2018 19:48:14 -0000      1.17
+++ arch/arm64/arm64/cpu.c      1 May 2018 09:35:14 -0000
@@ -165,7 +165,7 @@ cpu_identify(struct cpu_info *ci)
 
        /*
         * Some ARM processors are vulnerable to branch target
-        * injection attacks.
+        * injection attacks (CVE-2017-5715).
         */
        switch (impl) {
        case CPU_IMPL_ARM:
@@ -182,7 +182,7 @@ cpu_identify(struct cpu_info *ci)
                case CPU_PART_CORTEX_A75:
                default:
                        /*
-                        * Vulnerable; call PSCI_VERSION and hope
+                        * Vulnerable; call into the firmware and hope
                         * we're running on top of Arm Trusted
                         * Firmware with a fix for Security Advisory
                         * TFV 6.
@@ -305,7 +305,7 @@ void
 cpu_flush_bp_psci(void)
 {
 #if NPSCI > 0
-       psci_version();
+       psci_flush_bp();
 #endif
 }
 

Reply via email to