git: 20fee5aa5053 - stable/15 - arm64: Add cpu_feat_disabled for disabled features

From: Andrew Turner <andrew_at_FreeBSD.org>
Date: Mon, 22 Sep 2025 15:20:19 UTC
The branch stable/15 has been updated by andrew:

URL: https://cgit.FreeBSD.org/src/commit/?id=20fee5aa505334f890c74a9059613ad7d61afe07

commit 20fee5aa505334f890c74a9059613ad7d61afe07
Author:     Andrew Turner <andrew@FreeBSD.org>
AuthorDate: 2025-09-19 10:05:46 +0000
Commit:     Andrew Turner <andrew@FreeBSD.org>
CommitDate: 2025-09-20 01:00:53 +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
    
    (cherry picked from commit 055229eda697445880edd0050d0230a3f1bc85b3)
---
 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,				\
 };									\