diff options
| -rw-r--r-- | sys/arm64/arm64/cpu_errata.c | 47 | ||||
| -rw-r--r-- | sys/arm64/arm64/exception.S | 16 | ||||
| -rw-r--r-- | sys/arm64/arm64/genassym.c | 1 | ||||
| -rw-r--r-- | sys/arm64/include/pcpu.h | 4 | ||||
| -rw-r--r-- | sys/dev/psci/smccc.c | 9 | ||||
| -rw-r--r-- | sys/dev/psci/smccc.h | 3 |
6 files changed, 79 insertions, 1 deletions
diff --git a/sys/arm64/arm64/cpu_errata.c b/sys/arm64/arm64/cpu_errata.c index c54fb085e378..c41f9169cf4f 100644 --- a/sys/arm64/arm64/cpu_errata.c +++ b/sys/arm64/arm64/cpu_errata.c @@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/kernel.h> #include <sys/pcpu.h> +#include <sys/systm.h> #include <machine/cpu.h> @@ -50,7 +51,14 @@ struct cpu_quirks { u_int midr_value; }; +static enum { + SSBD_FORCE_ON, + SSBD_FORCE_OFF, + SSBD_KERNEL, +} ssbd_method = SSBD_KERNEL; + static cpu_quirk_install install_psci_bp_hardening; +static cpu_quirk_install install_ssbd_workaround; static struct cpu_quirks cpu_quirks[] = { { @@ -79,6 +87,11 @@ static struct cpu_quirks cpu_quirks[] = { CPU_ID_RAW(CPU_IMPL_CAVIUM, CPU_PART_THUNDERX2, 0,0), .quirk_install = install_psci_bp_hardening, }, + { + .midr_mask = 0, + .midr_value = 0, + .quirk_install = install_ssbd_workaround, + }, }; static void @@ -91,6 +104,40 @@ install_psci_bp_hardening(void) PCPU_SET(bp_harden, smccc_arch_workaround_1); } +static void +install_ssbd_workaround(void) +{ + char *env; + + if (PCPU_GET(cpuid) == 0) { + env = kern_getenv("kern.cfg.ssbd"); + if (env != NULL) { + if (strcmp(env, "force-on") == 0) { + ssbd_method = SSBD_FORCE_ON; + } else if (strcmp(env, "force-off") == 0) { + ssbd_method = SSBD_FORCE_OFF; + } + } + } + + /* Enable the workaround on this CPU if it's enabled in the firmware */ + if (smccc_arch_features(SMCCC_ARCH_WORKAROUND_2) != SMCCC_RET_SUCCESS) + return; + + switch(ssbd_method) { + case SSBD_FORCE_ON: + smccc_arch_workaround_2(true); + break; + case SSBD_FORCE_OFF: + smccc_arch_workaround_2(false); + break; + case SSBD_KERNEL: + default: + PCPU_SET(ssbd, smccc_arch_workaround_2); + break; + } +} + void install_cpu_errata(void) { diff --git a/sys/arm64/arm64/exception.S b/sys/arm64/arm64/exception.S index 6cda7a265e75..d3242f4ac0b7 100644 --- a/sys/arm64/arm64/exception.S +++ b/sys/arm64/arm64/exception.S @@ -66,6 +66,14 @@ __FBSDID("$FreeBSD$"); stp x18, lr, [sp, #(TF_SP)] mrs x18, tpidr_el1 add x29, sp, #(TF_SIZE) +.if \el == 0 + /* Apply the SSBD (CVE-2018-3639) workaround if needed */ + ldr x1, [x18, #PC_SSBD] + cbz x1, 1f + mov w0, #1 + blr x1 +1: +.endif .endm .macro restore_registers el @@ -76,6 +84,14 @@ __FBSDID("$FreeBSD$"); * handler. For EL0 exceptions, do_ast already did this. */ .endif +.if \el == 0 + /* Remove the SSBD (CVE-2018-3639) workaround if needed */ + ldr x1, [x18, #PC_SSBD] + cbz x1, 1f + mov w0, #0 + blr x1 +1: +.endif ldp x18, lr, [sp, #(TF_SP)] ldp x10, x11, [sp, #(TF_ELR)] .if \el == 0 diff --git a/sys/arm64/arm64/genassym.c b/sys/arm64/arm64/genassym.c index 00b77a435867..debe63c62659 100644 --- a/sys/arm64/arm64/genassym.c +++ b/sys/arm64/arm64/genassym.c @@ -43,6 +43,7 @@ ASSYM(TDF_NEEDRESCHED, TDF_NEEDRESCHED); ASSYM(PCPU_SIZE, sizeof(struct pcpu)); ASSYM(PC_CURPCB, offsetof(struct pcpu, pc_curpcb)); ASSYM(PC_CURTHREAD, offsetof(struct pcpu, pc_curthread)); +ASSYM(PC_SSBD, offsetof(struct pcpu, pc_ssbd)); /* Size of pcb, rounded to keep stack alignment */ ASSYM(PCB_SIZE, roundup2(sizeof(struct pcb), STACKALIGNBYTES + 1)); diff --git a/sys/arm64/include/pcpu.h b/sys/arm64/include/pcpu.h index 48935c151072..fbe4310da2af 100644 --- a/sys/arm64/include/pcpu.h +++ b/sys/arm64/include/pcpu.h @@ -36,13 +36,15 @@ #define ALT_STACK_SIZE 128 typedef int (*pcpu_bp_harden)(void); +typedef int (*pcpu_ssbd)(bool); #define PCPU_MD_FIELDS \ u_int pc_acpi_id; /* ACPI CPU id */ \ u_int pc_midr; /* stored MIDR value */ \ uint64_t pc_clock; \ pcpu_bp_harden pc_bp_harden; \ - char __pad[233] + pcpu_ssbd pc_ssbd; \ + char __pad[225] #ifdef _KERNEL diff --git a/sys/dev/psci/smccc.c b/sys/dev/psci/smccc.c index 9641a49e34ff..b59bf659eec5 100644 --- a/sys/dev/psci/smccc.c +++ b/sys/dev/psci/smccc.c @@ -91,3 +91,12 @@ smccc_arch_workaround_1(void) ("SMCCC arch workaround 1 called with an invalid SMCCC interface")); return (psci_call(SMCCC_ARCH_WORKAROUND_1, 0, 0, 0)); } + +int +smccc_arch_workaround_2(bool enable) +{ + + KASSERT(smccc_version != SMCCC_VERSION_1_0, + ("SMCCC arch workaround 2 called with an invalid SMCCC interface")); + return (psci_call(SMCCC_ARCH_WORKAROUND_2, enable ? 1 : 0, 0, 0)); +} diff --git a/sys/dev/psci/smccc.h b/sys/dev/psci/smccc.h index 1047ba86055c..223f688fa80e 100644 --- a/sys/dev/psci/smccc.h +++ b/sys/dev/psci/smccc.h @@ -59,6 +59,8 @@ SMCCC_FUNC_ID(SMCCC_FAST_CALL, SMCCC_32BIT_CALL, 0, 1) #define SMCCC_ARCH_WORKAROUND_1 \ SMCCC_FUNC_ID(SMCCC_FAST_CALL, SMCCC_32BIT_CALL, 0, 0x8000) +#define SMCCC_ARCH_WORKAROUND_2 \ + SMCCC_FUNC_ID(SMCCC_FAST_CALL, SMCCC_32BIT_CALL, 0, 0x7fff) /* The return values from ARM DEN 0070A. */ #define SMCCC_RET_SUCCESS 0 @@ -67,6 +69,7 @@ int32_t smccc_arch_features(uint32_t); int smccc_arch_workaround_1(void); +int smccc_arch_workaround_2(bool); #endif /* _PSCI_SMCCC_H_ */ |
