Re: [PATCH v4 12/21] arm64: cpufeature: Add an early command-line cpufeature override facility
From: David Brazdil <hidden>
Date: 2021-01-18 13:09:08
Also in:
linux-arm-kernel, lkml
On Mon, Jan 18, 2021 at 09:45:24AM +0000, Marc Zyngier wrote:
In order to be able to override CPU features at boot time, let's add a command line parser that matches options of the form "cpureg.feature=value", and store the corresponding value into the override val/mask pair. No features are currently defined, so no expected change in functionality. Signed-off-by: Marc Zyngier <maz@kernel.org>
Acked-by: David Brazdil <redacted>
quoted hunk ↗ jump to hunk
--- arch/arm64/kernel/Makefile | 2 +- arch/arm64/kernel/head.S | 1 + arch/arm64/kernel/idreg-override.c | 119 +++++++++++++++++++++++++++++ 3 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 arch/arm64/kernel/idreg-override.cdiff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 86364ab6f13f..2262f0392857 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile@@ -17,7 +17,7 @@ obj-y := debug-monitors.o entry.o irq.o fpsimd.o \ return_address.o cpuinfo.o cpu_errata.o \ cpufeature.o alternative.o cacheinfo.o \ smp.o smp_spin_table.o topology.o smccc-call.o \ - syscall.o proton-pack.o + syscall.o proton-pack.o idreg-override.o targets += efi-entry.odiff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S index d74e5f84042e..b3c4dd04f74b 100644 --- a/arch/arm64/kernel/head.S +++ b/arch/arm64/kernel/head.S@@ -435,6 +435,7 @@ SYM_FUNC_START_LOCAL(__primary_switched) mov x0, x21 // pass FDT address in x0 bl early_fdt_map // Try mapping the FDT early + bl init_shadow_regs bl switch_to_vhe #if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS) bl kasan_early_initdiff --git a/arch/arm64/kernel/idreg-override.c b/arch/arm64/kernel/idreg-override.c new file mode 100644 index 000000000000..392f93b67103 --- /dev/null +++ b/arch/arm64/kernel/idreg-override.c@@ -0,0 +1,119 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Early cpufeature override framework + * + * Copyright (C) 2020 Google LLC + * Author: Marc Zyngier <maz@kernel.org> + */ + +#include <linux/kernel.h> +#include <linux/libfdt.h> + +#include <asm/cacheflush.h> +#include <asm/setup.h> + +struct reg_desc { + const char * const name; + u64 * const val; + u64 * const mask; + struct { + const char * const name; + u8 shift;
nit: There's an extra space before `shift`.
+ } fields[];
+};
+
+static const struct reg_desc * const regs[] __initdata = {
+};
+
+static int __init find_field(const char *cmdline, const struct reg_desc *reg,
+ int f, u64 *v)
+{
+ char buf[256], *str;
+ size_t len;
+
+ snprintf(buf, ARRAY_SIZE(buf), "%s.%s=", reg->name, reg->fields[f].name);
+
+ str = strstr(cmdline, buf);
+ if (!(str == cmdline || (str > cmdline && *(str - 1) == ' ')))
+ return -1;
+
+ str += strlen(buf);
+ len = strcspn(str, " ");
+ len = min(len, ARRAY_SIZE(buf) - 1);
+ strncpy(buf, str, len);
+ buf[len] = 0;
+
+ return kstrtou64(buf, 0, v);
+}
+
+static void __init match_options(const char *cmdline)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(regs); i++) {
+ int f;
+
+ if (!regs[i]->val || !regs[i]->mask)
+ continue;
+
+ for (f = 0; regs[i]->fields[f].name; f++) {
+ u64 v;
+
+ if (find_field(cmdline, regs[i], f, &v))
+ continue;
+
+ *regs[i]->val |= (v & 0xf) << regs[i]->fields[f].shift;
+ *regs[i]->mask |= 0xfUL << regs[i]->fields[f].shift;
+ }
+ }
+}
+
+static __init void parse_cmdline(void)
+{
+ if (!IS_ENABLED(CONFIG_CMDLINE_FORCE)) {
+ const u8 *prop;
+ void *fdt;
+ int node;
+
+ fdt = get_early_fdt_ptr();
+ if (!fdt)
+ goto out;
+
+ node = fdt_path_offset(fdt, "/chosen");
+ if (node < 0)
+ goto out;
+
+ prop = fdt_getprop(fdt, node, "bootargs", NULL);
+ if (!prop)
+ goto out;
+
+ match_options(prop);
+
+ if (!IS_ENABLED(CONFIG_CMDLINE_EXTEND))
+ return;
+ }
+
+out:
+ match_options(CONFIG_CMDLINE);
+}
+
+void __init init_shadow_regs(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(regs); i++) {
+ if (regs[i]->val)
+ *regs[i]->val = 0;
+ if (regs[i]->mask)
+ *regs[i]->mask = 0;
+ }
+
+ parse_cmdline();
+
+ for (i = 0; i < ARRAY_SIZE(regs); i++) {
+ if (regs[i]->val)
+ __flush_dcache_area(regs[i]->val, sizeof(*regs[i]->val));
+ if (regs[i]->mask)
+ __flush_dcache_area(regs[i]->mask, sizeof(*regs[i]->mask));
+ }
+}
--
2.29.2_______________________________________________ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm