The branch main has been updated by andrew: URL: https://cgit.FreeBSD.org/src/commit/?id=055229eda697445880edd0050d0230a3f1bc85b3
commit 055229eda697445880edd0050d0230a3f1bc85b3 Author: Andrew Turner <and...@freebsd.org> AuthorDate: 2025-09-19 10:05:46 +0000 Commit: Andrew Turner <and...@freebsd.org> CommitDate: 2025-09-19 10:05:46 +0000 arm64: Add cpu_feat_disabled for disabled features When a feature is disabled we may need to run a cleanup handler, e.g. to remove a feature from the sanitized ID registers. Add support for this with a new feat_disabled handler. Sponsored by: Arm Ltd Differential Revision: https://reviews.freebsd.org/D52577 --- sys/arm/arm/generic_timer.c | 9 ++++++++- sys/arm64/arm64/cpu_feat.c | 10 +++++++--- sys/arm64/arm64/identcpu.c | 2 +- sys/arm64/arm64/machdep.c | 9 ++++++++- sys/arm64/arm64/pmap.c | 4 ++-- sys/arm64/arm64/ptrauth.c | 34 ++++++++++++++++++++-------------- sys/arm64/include/cpu_feat.h | 5 ++++- 7 files changed, 50 insertions(+), 23 deletions(-) diff --git a/sys/arm/arm/generic_timer.c b/sys/arm/arm/generic_timer.c index dacef8de2257..c4a1f44a0079 100644 --- a/sys/arm/arm/generic_timer.c +++ b/sys/arm/arm/generic_timer.c @@ -905,8 +905,15 @@ wfxt_enable(const struct cpu_feat *feat __unused, return (true); } +static void +wfxt_disabled(const struct cpu_feat *feat __unused) +{ + if (PCPU_GET(cpuid) == 0) + update_special_reg(ID_AA64ISAR2_EL1, ID_AA64ISAR2_WFxT_MASK, 0); +} + CPU_FEAT(feat_wfxt, "WFE and WFI instructions with timeout", - wfxt_check, NULL, wfxt_enable, + wfxt_check, NULL, wfxt_enable, wfxt_disabled, CPU_FEAT_AFTER_DEV | CPU_FEAT_SYSTEM); #endif diff --git a/sys/arm64/arm64/cpu_feat.c b/sys/arm64/arm64/cpu_feat.c index 986d5079e980..0ffcdf2c9ed1 100644 --- a/sys/arm64/arm64/cpu_feat.c +++ b/sys/arm64/arm64/cpu_feat.c @@ -69,18 +69,18 @@ enable_cpu_feat(uint32_t stage) check_status = feat->feat_check(feat, midr); /* Ignore features that are not present */ if (check_status == FEAT_ALWAYS_DISABLE) - continue; + goto next; snprintf(tunable, sizeof(tunable), "hw.feat.%s", feat->feat_name); if (TUNABLE_BOOL_FETCH(tunable, &val)) { /* Is the feature disabled by the tunable? */ if (!val) - continue; + goto next; /* If enabled by the tunable then enable it */ } else if (check_status == FEAT_DEFAULT_DISABLE) { /* No tunable set and disabled by default */ - continue; + goto next; } /* @@ -122,6 +122,10 @@ enable_cpu_feat(uint32_t stage) if (feat->feat_enable(feat, errata_status, errata_list, errata_count)) feat->feat_enabled = true; + +next: + if (!feat->feat_enabled && feat->feat_disabled != NULL) + feat->feat_disabled(feat); } } diff --git a/sys/arm64/arm64/identcpu.c b/sys/arm64/arm64/identcpu.c index 01b4ece59861..2d07420bcdb0 100644 --- a/sys/arm64/arm64/identcpu.c +++ b/sys/arm64/arm64/identcpu.c @@ -2353,7 +2353,7 @@ user_ctr_enable(const struct cpu_feat *feat __unused, } CPU_FEAT(trap_ctr, "Trap CTR_EL0", - user_ctr_check, user_ctr_has_errata, user_ctr_enable, + user_ctr_check, user_ctr_has_errata, user_ctr_enable, NULL, CPU_FEAT_AFTER_DEV | CPU_FEAT_PER_CPU); static bool diff --git a/sys/arm64/arm64/machdep.c b/sys/arm64/arm64/machdep.c index 29ffa5109305..322bad273a08 100644 --- a/sys/arm64/arm64/machdep.c +++ b/sys/arm64/arm64/machdep.c @@ -208,8 +208,15 @@ pan_enable(const struct cpu_feat *feat __unused, return (true); } +static void +pan_disabled(const struct cpu_feat *feat __unused) +{ + if (PCPU_GET(cpuid) == 0) + update_special_reg(ID_AA64MMFR1_EL1, ID_AA64MMFR1_PAN_MASK, 0); +} + CPU_FEAT(feat_pan, "Privileged access never", - pan_check, NULL, pan_enable, + pan_check, NULL, pan_enable, pan_disabled, CPU_FEAT_AFTER_DEV | CPU_FEAT_PER_CPU); bool diff --git a/sys/arm64/arm64/pmap.c b/sys/arm64/arm64/pmap.c index 8a4395aa1c89..dbf5c820d20b 100644 --- a/sys/arm64/arm64/pmap.c +++ b/sys/arm64/arm64/pmap.c @@ -1722,7 +1722,7 @@ pmap_dbm_enable(const struct cpu_feat *feat __unused, } CPU_FEAT(feat_hafdbs, "Hardware management of the Access flag and dirty state", - pmap_dbm_check, pmap_dbm_has_errata, pmap_dbm_enable, + pmap_dbm_check, pmap_dbm_has_errata, pmap_dbm_enable, NULL, CPU_FEAT_AFTER_DEV | CPU_FEAT_PER_CPU); static cpu_feat_en @@ -1767,7 +1767,7 @@ pmap_multiple_tlbi_enable(const struct cpu_feat *feat __unused, } CPU_FEAT(errata_multi_tlbi, "Multiple TLBI errata", - pmap_multiple_tlbi_check, NULL, pmap_multiple_tlbi_enable, + pmap_multiple_tlbi_check, NULL, pmap_multiple_tlbi_enable, NULL, CPU_FEAT_EARLY_BOOT | CPU_FEAT_PER_CPU); /* diff --git a/sys/arm64/arm64/ptrauth.c b/sys/arm64/arm64/ptrauth.c index fdab5414e24c..ab40b72887e9 100644 --- a/sys/arm64/arm64/ptrauth.c +++ b/sys/arm64/arm64/ptrauth.c @@ -97,11 +97,11 @@ ptrauth_check(const struct cpu_feat *feat __unused, u_int midr __unused) if (!pac_enable) { if (boothowto & RB_VERBOSE) printf("Pointer authentication is disabled\n"); - goto out; + return (FEAT_ALWAYS_DISABLE); } if (ptrauth_disable()) - goto out; + return (FEAT_ALWAYS_DISABLE); /* * This assumes if there is pointer authentication on the boot CPU @@ -127,17 +127,6 @@ ptrauth_check(const struct cpu_feat *feat __unused, u_int midr __unused) } } -out: - /* - * Pointer authentication may be disabled, mask out the ID fields we - * expose to userspace and the rest of the kernel so they don't try - * to use it. - */ - update_special_reg(ID_AA64ISAR1_EL1, ID_AA64ISAR1_API_MASK | - ID_AA64ISAR1_APA_MASK | ID_AA64ISAR1_GPA_MASK | - ID_AA64ISAR1_GPI_MASK, 0); - update_special_reg(ID_AA64ISAR2_EL1, ID_AA64ISAR2_APA3_MASK, 0); - return (FEAT_ALWAYS_DISABLE); } @@ -157,8 +146,25 @@ ptrauth_enable(const struct cpu_feat *feat __unused, return (true); } +static void +ptrauth_disabled(const struct cpu_feat *feat __unused) +{ + /* + * Pointer authentication may be disabled, mask out the ID fields we + * expose to userspace and the rest of the kernel so they don't try + * to use it. + */ + if (PCPU_GET(cpuid) == 0) { + update_special_reg(ID_AA64ISAR1_EL1, ID_AA64ISAR1_API_MASK | + ID_AA64ISAR1_APA_MASK | ID_AA64ISAR1_GPA_MASK | + ID_AA64ISAR1_GPI_MASK, 0); + update_special_reg(ID_AA64ISAR2_EL1, ID_AA64ISAR2_APA3_MASK, 0); + } + +} + CPU_FEAT(feat_pauth, "Pointer Authentication", - ptrauth_check, NULL, ptrauth_enable, + ptrauth_check, NULL, ptrauth_enable, ptrauth_disabled, CPU_FEAT_EARLY_BOOT | CPU_FEAT_SYSTEM); /* Copy the keys when forking a new process */ diff --git a/sys/arm64/include/cpu_feat.h b/sys/arm64/include/cpu_feat.h index 6a554b6baedf..20c743a7e507 100644 --- a/sys/arm64/include/cpu_feat.h +++ b/sys/arm64/include/cpu_feat.h @@ -80,12 +80,14 @@ typedef bool (cpu_feat_has_errata)(const struct cpu_feat *, u_int, u_int **, u_int *); typedef bool (cpu_feat_enable)(const struct cpu_feat *, cpu_feat_errata, u_int *, u_int); +typedef void (cpu_feat_disabled)(const struct cpu_feat *); struct cpu_feat { const char *feat_name; cpu_feat_check *feat_check; cpu_feat_has_errata *feat_has_errata; cpu_feat_enable *feat_enable; + cpu_feat_disabled *feat_disabled; uint32_t feat_flags; bool feat_enabled; }; @@ -93,12 +95,13 @@ SET_DECLARE(cpu_feat_set, struct cpu_feat); SYSCTL_DECL(_hw_feat); -#define CPU_FEAT(name, descr, check, has_errata, enable, flags) \ +#define CPU_FEAT(name, descr, check, has_errata, enable, disabled, flags) \ static struct cpu_feat name = { \ .feat_name = #name, \ .feat_check = check, \ .feat_has_errata = has_errata, \ .feat_enable = enable, \ + .feat_disabled = disabled, \ .feat_flags = flags, \ .feat_enabled = false, \ }; \