Changeset View
Changeset View
Standalone View
Standalone View
sys/arm/arm/cpuinfo.c
Show All 25 Lines | |||||
*/ | */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/pcpu.h> | |||||
#include <sys/smp.h> | |||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <machine/cpu.h> | #include <machine/cpu.h> | ||||
#include <machine/cpuinfo.h> | #include <machine/cpuinfo.h> | ||||
#include <machine/elf.h> | #include <machine/elf.h> | ||||
#include <machine/md_var.h> | #include <machine/md_var.h> | ||||
#if __ARM_ARCH >= 6 | #if __ARM_ARCH >= 6 | ||||
void reinit_mmu(uint32_t ttb, uint32_t aux_clr, uint32_t aux_set); | void reinit_mmu(uint32_t ttb, uint32_t aux_clr, uint32_t aux_set); | ||||
int disable_bp_hardening; | |||||
int spectre_v2_safe = 1; | |||||
#endif | #endif | ||||
struct cpuinfo cpuinfo = | struct cpuinfo cpuinfo = | ||||
{ | { | ||||
/* Use safe defaults for start */ | /* Use safe defaults for start */ | ||||
.dcache_line_size = 32, | .dcache_line_size = 32, | ||||
.dcache_line_mask = 31, | .dcache_line_mask = 31, | ||||
.icache_line_size = 32, | .icache_line_size = 32, | ||||
▲ Show 20 Lines • Show All 199 Lines • ▼ Show 20 Lines | |||||
cpuinfo_get_actlr_modifier(uint32_t *actlr_mask, uint32_t *actlr_set) | cpuinfo_get_actlr_modifier(uint32_t *actlr_mask, uint32_t *actlr_set) | ||||
{ | { | ||||
*actlr_mask = 0; | *actlr_mask = 0; | ||||
*actlr_set = 0; | *actlr_set = 0; | ||||
if (cpuinfo.implementer == CPU_IMPLEMENTER_ARM) { | if (cpuinfo.implementer == CPU_IMPLEMENTER_ARM) { | ||||
switch (cpuinfo.part_number) { | switch (cpuinfo.part_number) { | ||||
case CPU_ARCH_CORTEX_A75: | |||||
case CPU_ARCH_CORTEX_A73: | case CPU_ARCH_CORTEX_A73: | ||||
case CPU_ARCH_CORTEX_A72: | case CPU_ARCH_CORTEX_A72: | ||||
case CPU_ARCH_CORTEX_A57: | case CPU_ARCH_CORTEX_A57: | ||||
case CPU_ARCH_CORTEX_A53: | case CPU_ARCH_CORTEX_A53: | ||||
/* Nothing to do for AArch32 */ | /* Nothing to do for AArch32 */ | ||||
break; | break; | ||||
case CPU_ARCH_CORTEX_A17: | case CPU_ARCH_CORTEX_A17: | ||||
case CPU_ARCH_CORTEX_A12: /* A12 is merged to A17 */ | case CPU_ARCH_CORTEX_A12: /* A12 is merged to A17 */ | ||||
▲ Show 20 Lines • Show All 66 Lines • ▼ Show 20 Lines | cpuinfo_reinit_mmu(uint32_t ttb) | ||||
uint32_t actlr_mask; | uint32_t actlr_mask; | ||||
uint32_t actlr_set; | uint32_t actlr_set; | ||||
cpuinfo_get_actlr_modifier(&actlr_mask, &actlr_set); | cpuinfo_get_actlr_modifier(&actlr_mask, &actlr_set); | ||||
actlr_mask |= cpu_quirks_actlr_mask; | actlr_mask |= cpu_quirks_actlr_mask; | ||||
actlr_set |= cpu_quirks_actlr_set; | actlr_set |= cpu_quirks_actlr_set; | ||||
reinit_mmu(ttb, actlr_mask, actlr_set); | reinit_mmu(ttb, actlr_mask, actlr_set); | ||||
} | } | ||||
static bool | |||||
modify_actlr(uint32_t clear, uint32_t set) | |||||
{ | |||||
uint32_t reg, newreg; | |||||
reg = cp15_actlr_get(); | |||||
newreg = reg; | |||||
newreg &= ~clear; | |||||
newreg |= set; | |||||
if (reg == newreg) | |||||
return (true); | |||||
cp15_actlr_set(newreg); | |||||
reg = cp15_actlr_get(); | |||||
if (reg == newreg) | |||||
return (true); | |||||
return (false); | |||||
} | |||||
static void | |||||
handle_bp_hardening(bool enable) | |||||
{ | |||||
/* | |||||
* Note: Access to ACTRL is locked to secure world on most boards. | |||||
* This means that full BP hardening depends on updated u-boot/firmware | |||||
* or is impossible at all (if secure monitor is in on-chip ROM). | |||||
*/ | |||||
if (cpuinfo.implementer == CPU_IMPLEMENTER_ARM) { | |||||
imp: What about !ARM implementors? Do we know of any that FreeBSD runs on? Or are all the armv7 CPUs… | |||||
Not Done Inline ActionsImho, we supports Marvell PJ4B cores and Qualcomm Krait cores. mmel: Imho, we supports Marvell PJ4B cores and Qualcomm Krait cores.
Krait cores are known to be… | |||||
Not Done Inline ActionsDo we need to print warnings for those cores? Eg "Qualcomm Krait cores are known (or believed) to be vulnerable to speculative branch attacks, no mitigation exists yet." ? imp: Do we need to print warnings for those cores? Eg "Qualcomm Krait cores are known (or believed)… | |||||
switch (cpuinfo.part_number) { | |||||
case CPU_ARCH_CORTEX_A8: | |||||
/* | |||||
* For Cortex-A8, IBE bit must be set otherwise | |||||
* BPIALL is effectively NOP. | |||||
* Unfortunately, Cortex-A is also affected by | |||||
* ARM erratum 687067 which causes non-working | |||||
* BPIALL if IBE bit is set and 'Instruction L1 System | |||||
* Array Debug Register 0' is not 0. | |||||
* This register is not reset on power-up and is | |||||
* accessible only from secure world, so we cannot do | |||||
* nothing (nor detect) to fix this issue. | |||||
* I afraid that on chip ROM based secure monitor on | |||||
* AM335x (BeagleBone) doesn't reset this debug | |||||
* register. | |||||
*/ | |||||
if (enable) { | |||||
if (!modify_actlr(0, 1 << 6)) | |||||
goto actlr_err; | |||||
PCPU_SET(bp_harden_kind, | |||||
PCPU_BP_HARDEN_KIND_BPIALL); | |||||
} else { | |||||
PCPU_SET(bp_harden_kind, | |||||
PCPU_BP_HARDEN_KIND_NONE); | |||||
modify_actlr(~0, PCPU_GET(original_actlr)); | |||||
spectre_v2_safe = 0; | |||||
} | |||||
break; | |||||
break; | |||||
case CPU_ARCH_CORTEX_A9: | |||||
case CPU_ARCH_CORTEX_A12: /* A12 is merged to A17 */ | |||||
case CPU_ARCH_CORTEX_A17: | |||||
case CPU_ARCH_CORTEX_A57: | |||||
case CPU_ARCH_CORTEX_A72: | |||||
case CPU_ARCH_CORTEX_A73: | |||||
case CPU_ARCH_CORTEX_A75: | |||||
if (enable) { | |||||
PCPU_SET(bp_harden_kind, | |||||
PCPU_BP_HARDEN_KIND_BPIALL); | |||||
} else { | |||||
spectre_v2_safe = 0; | |||||
PCPU_SET(bp_harden_kind, | |||||
PCPU_BP_HARDEN_KIND_NONE); | |||||
} | |||||
break; | |||||
break; | |||||
case CPU_ARCH_CORTEX_A15: | |||||
/* | |||||
* For Cortex-A15, set 'Enable invalidates of BTB' bit. | |||||
* Despite this, the BPIALL is still effectively NOP, | |||||
* but with this bit set, the ICIALLU also flushes | |||||
* branch predictor as side effect. | |||||
*/ | |||||
if (enable) { | |||||
if (!modify_actlr(0 , 1 << 0)) | |||||
goto actlr_err; | |||||
PCPU_SET(bp_harden_kind, | |||||
PCPU_BP_HARDEN_KIND_ICIALLU); | |||||
} else { | |||||
PCPU_SET(bp_harden_kind, | |||||
PCPU_BP_HARDEN_KIND_NONE); | |||||
modify_actlr(0xFFFFFFFF, | |||||
PCPU_GET(original_actlr)); | |||||
spectre_v2_safe = 0; | |||||
} | |||||
break; | |||||
default: | |||||
break; | |||||
} | |||||
} else if (cpuinfo.implementer == CPU_IMPLEMENTER_QCOM) { | |||||
spectre_v2_safe = 0; | |||||
printf("!!!WARNING!!! CPU(%d) is vulnerable to speculative " | |||||
"branch attacks. !!!\n" | |||||
"Qualcomm Krait cores are known (or believed) to be " | |||||
"vulnerable to \n" | |||||
"speculative branch attacks, no mitigation exists yet.\n", | |||||
Not Done Inline Actions"Would it make sense to add "It is vulnerable to speculative branch attacks." after "unsecure" (which I think should be "insecure" since that reads better to my ear)? imp: "Would it make sense to add "It is vulnerable to speculative branch attacks." after "unsecure"… | |||||
PCPU_GET(cpuid)); | |||||
} | |||||
return; | |||||
actlr_err: | |||||
PCPU_SET(bp_harden_kind, PCPU_BP_HARDEN_KIND_NONE); | |||||
spectre_v2_safe = 0; | |||||
printf("!!!WARNING!!! CPU(%d) is vulnerable to speculative branch " | |||||
"attacks. !!!\n" | |||||
"We cannot enable required bit(s) in ACTRL register\n" | |||||
"because it's locked by secure monitor and/or firmware.\n", | |||||
PCPU_GET(cpuid)); | |||||
} | |||||
void | |||||
cpuinfo_init_bp_hardening(void) | |||||
{ | |||||
/* | |||||
* Store original unmodified ACTRL, so we can restore it when | |||||
* BP hardening is disabled by sysctl. | |||||
*/ | |||||
PCPU_SET(original_actlr, cp15_actlr_get()); | |||||
handle_bp_hardening(true); | |||||
} | |||||
static void | |||||
bp_hardening_action(void *arg) | |||||
{ | |||||
handle_bp_hardening(disable_bp_hardening == 0); | |||||
} | |||||
static int | |||||
sysctl_disable_bp_hardening(SYSCTL_HANDLER_ARGS) | |||||
{ | |||||
int rv; | |||||
rv = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req); | |||||
Not Done Inline ActionsIt's a shame that smp_rendezvous_cpus doesn't work on single core case... But fixing that is beyond the scope of this code review... imp: It's a shame that smp_rendezvous_cpus doesn't work on single core case... But fixing that is… | |||||
if (!rv && req->newptr) { | |||||
spectre_v2_safe = 1; | |||||
dmb(); | |||||
#ifdef SMP | |||||
smp_rendezvous_cpus(all_cpus, smp_no_rendezvous_barrier, | |||||
bp_hardening_action, NULL, NULL); | |||||
#else | |||||
bp_hardening_action(NULL); | |||||
#endif | |||||
} | |||||
return (rv); | |||||
} | |||||
SYSCTL_PROC(_machdep, OID_AUTO, disable_bp_hardening, | |||||
CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, | |||||
&disable_bp_hardening, 0, sysctl_disable_bp_hardening, "I", | |||||
"Disable BP hardening mitigation."); | |||||
SYSCTL_INT(_machdep, OID_AUTO, spectre_v2_safe, CTLFLAG_RD, | |||||
&spectre_v2_safe, 0, "System is safe to Spectre Version 2 attacks"); | |||||
#endif /* __ARM_ARCH >= 6 */ | #endif /* __ARM_ARCH >= 6 */ |
What about !ARM implementors? Do we know of any that FreeBSD runs on? Or are all the armv7 CPUs that we have Cortex Ax?