On Mon, Sep 16, 2024 at 06:12:04PM +0100, Conor Dooley wrote: > On Wed, Sep 11, 2024 at 10:55:22PM -0700, Charlie Jenkins wrote: > > Follow the patterns of the other architectures that use > > GENERIC_CPU_VULNERABILITIES for riscv to introduce the ghostwrite > > vulnerability and mitigation. The mitigation is to disable all vector > > which is accomplished by clearing the bit from the cpufeature field. > > > > Ghostwrite only affects thead c9xx CPUs that impelment xtheadvector, so > > the vulerability will only be mitigated on these CPUs. > > > > Signed-off-by: Charlie Jenkins <charlie@xxxxxxxxxxxx> > > --- > > arch/riscv/Kconfig.errata | 11 ++++++++ > > arch/riscv/errata/thead/errata.c | 28 ++++++++++++++++++ > > arch/riscv/include/asm/bugs.h | 22 +++++++++++++++ > > arch/riscv/include/asm/errata_list.h | 3 +- > > arch/riscv/kernel/Makefile | 2 ++ > > arch/riscv/kernel/bugs.c | 55 ++++++++++++++++++++++++++++++++++++ > > arch/riscv/kernel/cpufeature.c | 9 +++++- > > drivers/base/cpu.c | 3 ++ > > include/linux/cpu.h | 1 + > > 9 files changed, 132 insertions(+), 2 deletions(-) > > > > diff --git a/arch/riscv/Kconfig.errata b/arch/riscv/Kconfig.errata > > index 2acc7d876e1f..e318119d570d 100644 > > --- a/arch/riscv/Kconfig.errata > > +++ b/arch/riscv/Kconfig.errata > > @@ -119,4 +119,15 @@ config ERRATA_THEAD_PMU > > > > If you don't know what to do here, say "Y". > > > > +config ERRATA_THEAD_GHOSTWRITE > > + bool "Apply T-Head Ghostwrite errata" > > + depends on ERRATA_THEAD && RISCV_ISA_XTHEADVECTOR > > + default y > > + help > > + The T-Head C9xx cores have a vulnerability in the xtheadvector > > + instruction set. When this errata is enabled, the CPUs will be probed > > + to determine if they are vulnerable and disable xtheadvector. > > + > > + If you don't know what to do here, say "Y". > > + > > endmenu # "CPU errata selection" > > diff --git a/arch/riscv/errata/thead/errata.c b/arch/riscv/errata/thead/errata.c > > index f5120e07c318..5cc008ab41a8 100644 > > --- a/arch/riscv/errata/thead/errata.c > > +++ b/arch/riscv/errata/thead/errata.c > > @@ -10,6 +10,7 @@ > > #include <linux/string.h> > > #include <linux/uaccess.h> > > #include <asm/alternative.h> > > +#include <asm/bugs.h> > > #include <asm/cacheflush.h> > > #include <asm/cpufeature.h> > > #include <asm/dma-noncoherent.h> > > @@ -142,6 +143,31 @@ static bool errata_probe_pmu(unsigned int stage, > > return true; > > } > > > > +static bool errata_probe_ghostwrite(unsigned int stage, > > + unsigned long arch_id, unsigned long impid) > > +{ > > + if (!IS_ENABLED(CONFIG_ERRATA_THEAD_GHOSTWRITE)) > > + return false; > > + > > + /* > > + * target-c9xx cores report arch_id and impid as 0 > > + * > > + * While ghostwrite may not affect all c9xx cores that implement > > + * xtheadvector, there is no futher granularity than c9xx. Assume > > + * vulnerable for this entire class of processors when xtheadvector is > > + * enabled. > > + */ > > Is it not possible to use the cpu compatible string for this? Given that > we only know if xtheadvector is enabled once we are already parsing the > cpu node devicetree, it seems, to me, as if it should be possible to be > more granular. AFAIU, some T-Head c900 series devices are not venerable. Sure we can do that. I figured that since T-Head didn't feel it was valuable to change the archid/implid between cores that Linux shouldn't go out of its way to fix the granularity issue. Since you think it is worthwhile though, I can try to work around this hardware issue. - Charlie > > Cheers, > Conor. > > > + if (arch_id != 0 || impid != 0) > > + return false; > > + > > + if (stage != RISCV_ALTERNATIVES_EARLY_BOOT) > > + return false; > > + > > + ghostwrite_set_vulnerable(); > > + > > + return true; > > +} > > + > > static u32 thead_errata_probe(unsigned int stage, > > unsigned long archid, unsigned long impid) > > { > > @@ -155,6 +181,8 @@ static u32 thead_errata_probe(unsigned int stage, > > if (errata_probe_pmu(stage, archid, impid)) > > cpu_req_errata |= BIT(ERRATA_THEAD_PMU); > > > > + errata_probe_ghostwrite(stage, archid, impid); > > + > > return cpu_req_errata; > > } > > > > diff --git a/arch/riscv/include/asm/bugs.h b/arch/riscv/include/asm/bugs.h > > new file mode 100644 > > index 000000000000..e294b15bf78e > > --- /dev/null > > +++ b/arch/riscv/include/asm/bugs.h > > @@ -0,0 +1,22 @@ > > +/* SPDX-License-Identifier: GPL-2.0-only */ > > +/* > > + * Interface for managing mitigations for riscv vulnerabilities. > > + * > > + * Copyright (C) 2024 Rivos Inc. > > + */ > > + > > +#ifndef __ASM_BUGS_H > > +#define __ASM_BUGS_H > > + > > +/* Watch out, ordering is important here. */ > > +enum mitigation_state { > > + UNAFFECTED, > > + MITIGATED, > > + VULNERABLE, > > +}; > > + > > +void ghostwrite_set_vulnerable(void); > > +void ghostwrite_enable_mitigation(void); > > +enum mitigation_state ghostwrite_get_state(void); > > + > > +#endif /* __ASM_BUGS_H */ > > diff --git a/arch/riscv/include/asm/errata_list.h b/arch/riscv/include/asm/errata_list.h > > index 7c8a71a526a3..6e426ed7919a 100644 > > --- a/arch/riscv/include/asm/errata_list.h > > +++ b/arch/riscv/include/asm/errata_list.h > > @@ -25,7 +25,8 @@ > > #ifdef CONFIG_ERRATA_THEAD > > #define ERRATA_THEAD_MAE 0 > > #define ERRATA_THEAD_PMU 1 > > -#define ERRATA_THEAD_NUMBER 2 > > +#define ERRATA_THEAD_GHOSTWRITE 2 > > +#define ERRATA_THEAD_NUMBER 3 > > #endif > > > > #ifdef __ASSEMBLY__ > > diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile > > index 06d407f1b30b..d7a54e34178e 100644 > > --- a/arch/riscv/kernel/Makefile > > +++ b/arch/riscv/kernel/Makefile > > @@ -113,3 +113,5 @@ obj-$(CONFIG_COMPAT) += compat_vdso/ > > obj-$(CONFIG_64BIT) += pi/ > > obj-$(CONFIG_ACPI) += acpi.o > > obj-$(CONFIG_ACPI_NUMA) += acpi_numa.o > > + > > +obj-$(CONFIG_GENERIC_CPU_VULNERABILITIES) += bugs.o > > diff --git a/arch/riscv/kernel/bugs.c b/arch/riscv/kernel/bugs.c > > new file mode 100644 > > index 000000000000..0c19691b4cd5 > > --- /dev/null > > +++ b/arch/riscv/kernel/bugs.c > > @@ -0,0 +1,55 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* > > + * Copyright (C) 2024 Rivos Inc. > > + */ > > + > > +#include <linux/cpu.h> > > +#include <linux/device.h> > > +#include <linux/sprintf.h> > > + > > +#include <asm/bugs.h> > > +#include <asm/vendor_extensions/thead.h> > > + > > +static enum mitigation_state ghostwrite_state; > > + > > +void ghostwrite_set_vulnerable(void) > > +{ > > + ghostwrite_state = VULNERABLE; > > +} > > + > > +/* > > + * Vendor extension alternatives will use the value set at the time of boot > > + * alternative patching, thus this must be called before boot alternatives are > > + * patched (and after extension probing) to be effective. > > + */ > > +void ghostwrite_enable_mitigation(void) > > +{ > > + if (IS_ENABLED(CONFIG_RISCV_ISA_XTHEADVECTOR) && > > + ghostwrite_state == VULNERABLE && !cpu_mitigations_off()) { > > + disable_xtheadvector(); > > + ghostwrite_state = MITIGATED; > > + } > > +} > > + > > +enum mitigation_state ghostwrite_get_state(void) > > +{ > > + return ghostwrite_state; > > +} > > + > > +ssize_t cpu_show_ghostwrite(struct device *dev, struct device_attribute *attr, char *buf) > > +{ > > + if (IS_ENABLED(CONFIG_RISCV_ISA_XTHEADVECTOR)) { > > + switch (ghostwrite_state) { > > + case UNAFFECTED: > > + return sprintf(buf, "Not affected\n"); > > + case MITIGATED: > > + return sprintf(buf, "Mitigation: xtheadvector disabled\n"); > > + case VULNERABLE: > > + fallthrough; > > + default: > > + return sprintf(buf, "Vulnerable\n"); > > + } > > + } else { > > + return sprintf(buf, "Not affected\n"); > > + } > > +} > > diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c > > index 56b5054b8f86..1f4329bb8a9d 100644 > > --- a/arch/riscv/kernel/cpufeature.c > > +++ b/arch/riscv/kernel/cpufeature.c > > @@ -17,6 +17,7 @@ > > #include <linux/of.h> > > #include <asm/acpi.h> > > #include <asm/alternative.h> > > +#include <asm/bugs.h> > > #include <asm/cacheflush.h> > > #include <asm/cpufeature.h> > > #include <asm/hwcap.h> > > @@ -867,7 +868,13 @@ static int __init riscv_fill_hwcap_from_ext_list(unsigned long *isa2hwcap) > > riscv_fill_vendor_ext_list(cpu); > > } > > > > - if (has_xtheadvector_no_alternatives() && has_thead_homogeneous_vlenb() < 0) { > > + /* > > + * Execute ghostwrite mitigation immediately after detecting extensions > > + * to disable xtheadvector if necessary. > > + */ > > + if (ghostwrite_get_state() == VULNERABLE) { > > + ghostwrite_enable_mitigation(); > > + } else if (has_xtheadvector_no_alternatives() && has_thead_homogeneous_vlenb() < 0) { > > pr_warn("Unsupported heterogeneous vlenb detected, vector extension disabled.\n"); > > disable_xtheadvector(); > > } > > diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c > > index fdaa24bb641a..a7e511849875 100644 > > --- a/drivers/base/cpu.c > > +++ b/drivers/base/cpu.c > > @@ -599,6 +599,7 @@ CPU_SHOW_VULN_FALLBACK(retbleed); > > CPU_SHOW_VULN_FALLBACK(spec_rstack_overflow); > > CPU_SHOW_VULN_FALLBACK(gds); > > CPU_SHOW_VULN_FALLBACK(reg_file_data_sampling); > > +CPU_SHOW_VULN_FALLBACK(ghostwrite); > > > > static DEVICE_ATTR(meltdown, 0444, cpu_show_meltdown, NULL); > > static DEVICE_ATTR(spectre_v1, 0444, cpu_show_spectre_v1, NULL); > > @@ -614,6 +615,7 @@ static DEVICE_ATTR(retbleed, 0444, cpu_show_retbleed, NULL); > > static DEVICE_ATTR(spec_rstack_overflow, 0444, cpu_show_spec_rstack_overflow, NULL); > > static DEVICE_ATTR(gather_data_sampling, 0444, cpu_show_gds, NULL); > > static DEVICE_ATTR(reg_file_data_sampling, 0444, cpu_show_reg_file_data_sampling, NULL); > > +static DEVICE_ATTR(ghostwrite, 0444, cpu_show_ghostwrite, NULL); > > > > static struct attribute *cpu_root_vulnerabilities_attrs[] = { > > &dev_attr_meltdown.attr, > > @@ -630,6 +632,7 @@ static struct attribute *cpu_root_vulnerabilities_attrs[] = { > > &dev_attr_spec_rstack_overflow.attr, > > &dev_attr_gather_data_sampling.attr, > > &dev_attr_reg_file_data_sampling.attr, > > + &dev_attr_ghostwrite.attr, > > NULL > > }; > > > > diff --git a/include/linux/cpu.h b/include/linux/cpu.h > > index bdcec1732445..6a0a8f1c7c90 100644 > > --- a/include/linux/cpu.h > > +++ b/include/linux/cpu.h > > @@ -77,6 +77,7 @@ extern ssize_t cpu_show_gds(struct device *dev, > > struct device_attribute *attr, char *buf); > > extern ssize_t cpu_show_reg_file_data_sampling(struct device *dev, > > struct device_attribute *attr, char *buf); > > +extern ssize_t cpu_show_ghostwrite(struct device *dev, struct device_attribute *attr, char *buf); > > > > extern __printf(4, 5) > > struct device *cpu_device_create(struct device *parent, void *drvdata, > > > > -- > > 2.45.0 > >