Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 4 Sep 2025 16:28:48 GMT
From:      Andrew Turner <andrew@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 4bc68fa98f68 - main - arm64: Support managing features from loader
Message-ID:  <202509041628.584GSmPL033103@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by andrew:

URL: https://cgit.FreeBSD.org/src/commit/?id=4bc68fa98f68211ee7943d77cfc91f60ccb5880d

commit 4bc68fa98f68211ee7943d77cfc91f60ccb5880d
Author:     Andrew Turner <andrew@FreeBSD.org>
AuthorDate: 2025-09-04 14:45:09 +0000
Commit:     Andrew Turner <andrew@FreeBSD.org>
CommitDate: 2025-09-04 14:45:09 +0000

    arm64: Support managing features from loader
    
    Allow the user to enable/disable supported cpu features/errata from a
    known tunable. This will allow the user to disable features, e.g. to
    work around broken firmware. It can also be used to enable workarounds
    for rare errata.
    
    Reviewed by:    imp
    Sponsored by:   Arm Ltd
    Differential Revision:  https://reviews.freebsd.org/D52358
---
 sys/arm/arm/generic_timer.c  |  9 ++++++---
 sys/arm64/arm64/cpu_feat.c   | 22 +++++++++++++++++++++-
 sys/arm64/arm64/identcpu.c   | 10 +++++-----
 sys/arm64/arm64/machdep.c    |  7 +++++--
 sys/arm64/arm64/pmap.c       |  9 ++++++---
 sys/arm64/arm64/ptrauth.c    |  8 ++++----
 sys/arm64/include/cpu_feat.h | 27 ++++++++++++++++++++++++++-
 7 files changed, 73 insertions(+), 19 deletions(-)

diff --git a/sys/arm/arm/generic_timer.c b/sys/arm/arm/generic_timer.c
index 27c985c5fcbe..97976408c943 100644
--- a/sys/arm/arm/generic_timer.c
+++ b/sys/arm/arm/generic_timer.c
@@ -882,14 +882,17 @@ DELAY(int usec)
 	TSEXIT();
 }
 
-static bool
+static cpu_feat_en
 wfxt_check(const struct cpu_feat *feat __unused, u_int midr __unused)
 {
 	uint64_t id_aa64isar2;
 
 	if (!get_kernel_reg(ID_AA64ISAR2_EL1, &id_aa64isar2))
-		return (false);
-	return (ID_AA64ISAR2_WFxT_VAL(id_aa64isar2) != ID_AA64ISAR2_WFxT_NONE);
+		return (FEAT_ALWAYS_DISABLE);
+	if (ID_AA64ISAR2_WFxT_VAL(id_aa64isar2) >= ID_AA64ISAR2_WFxT_NONE)
+		return (FEAT_DEFAULT_ENABLE);
+
+	return (FEAT_ALWAYS_DISABLE);
 }
 
 static bool
diff --git a/sys/arm64/arm64/cpu_feat.c b/sys/arm64/arm64/cpu_feat.c
index fd1b8429295f..986d5079e980 100644
--- a/sys/arm64/arm64/cpu_feat.c
+++ b/sys/arm64/arm64/cpu_feat.c
@@ -40,10 +40,13 @@ static cpu_feat_errata_check_fn cpu_feat_check_cb = NULL;
 void
 enable_cpu_feat(uint32_t stage)
 {
+	char tunable[32];
 	struct cpu_feat **featp, *feat;
 	uint32_t midr;
 	u_int errata_count, *errata_list;
 	cpu_feat_errata errata_status;
+	cpu_feat_en check_status;
+	bool val;
 
 	MPASS((stage & ~CPU_FEAT_STAGE_MASK) == 0);
 
@@ -60,9 +63,26 @@ enable_cpu_feat(uint32_t stage)
 		    PCPU_GET(cpuid) != 0)
 			continue;
 
-		if (feat->feat_check != NULL && !feat->feat_check(feat, midr))
+		if (feat->feat_check != NULL)
 			continue;
 
+		check_status = feat->feat_check(feat, midr);
+		/* Ignore features that are not present */
+		if (check_status == FEAT_ALWAYS_DISABLE)
+			continue;
+
+		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;
+			/* If enabled by the tunable then enable it */
+		} else if (check_status == FEAT_DEFAULT_DISABLE) {
+			/* No tunable set and disabled by default */
+			continue;
+		}
+
 		/*
 		 * Check if the feature has any errata that may need a
 		 * workaround applied (or it is to install the workaround for
diff --git a/sys/arm64/arm64/identcpu.c b/sys/arm64/arm64/identcpu.c
index 6d70692fdf5d..f271891f423d 100644
--- a/sys/arm64/arm64/identcpu.c
+++ b/sys/arm64/arm64/identcpu.c
@@ -2293,16 +2293,16 @@ user_ctr_has_neoverse_n1_1542419(uint32_t midr, uint64_t ctr)
 	return (false);
 }
 
-static bool
-user_ctr_check(const struct cpu_feat *feat __unused, u_int midr __unused)
+static cpu_feat_en
+user_ctr_check(const struct cpu_feat *feat __unused, u_int midr)
 {
 	if (emulate_ctr)
-		return (true);
+		return (FEAT_DEFAULT_ENABLE);
 
 	if (user_ctr_has_neoverse_n1_1542419(midr, READ_SPECIALREG(ctr_el0)))
-		return (true);
+		return (FEAT_DEFAULT_ENABLE);
 
-	return (false);
+	return (FEAT_ALWAYS_DISABLE);
 }
 
 static bool
diff --git a/sys/arm64/arm64/machdep.c b/sys/arm64/arm64/machdep.c
index c0aeae072570..627b02e82d34 100644
--- a/sys/arm64/arm64/machdep.c
+++ b/sys/arm64/arm64/machdep.c
@@ -173,13 +173,16 @@ SYSINIT(ssp_warn, SI_SUB_COPYRIGHT, SI_ORDER_ANY, print_ssp_warning, NULL);
 SYSINIT(ssp_warn2, SI_SUB_LAST, SI_ORDER_ANY, print_ssp_warning, NULL);
 #endif
 
-static bool
+static cpu_feat_en
 pan_check(const struct cpu_feat *feat __unused, u_int midr __unused)
 {
 	uint64_t id_aa64mfr1;
 
 	id_aa64mfr1 = READ_SPECIALREG(id_aa64mmfr1_el1);
-	return (ID_AA64MMFR1_PAN_VAL(id_aa64mfr1) != ID_AA64MMFR1_PAN_NONE);
+	if (ID_AA64MMFR1_PAN_VAL(id_aa64mfr1) == ID_AA64MMFR1_PAN_NONE)
+		return (FEAT_ALWAYS_DISABLE);
+
+	return (FEAT_DEFAULT_ENABLE);
 }
 
 static bool
diff --git a/sys/arm64/arm64/pmap.c b/sys/arm64/arm64/pmap.c
index 96bde42d2711..0ef23edbc0bf 100644
--- a/sys/arm64/arm64/pmap.c
+++ b/sys/arm64/arm64/pmap.c
@@ -1656,14 +1656,17 @@ pmap_init_pv_table(void)
 	}
 }
 
-static bool
+static cpu_feat_en
 pmap_dbm_check(const struct cpu_feat *feat __unused, u_int midr __unused)
 {
 	uint64_t id_aa64mmfr1;
 
 	id_aa64mmfr1 = READ_SPECIALREG(id_aa64mmfr1_el1);
-	return (ID_AA64MMFR1_HAFDBS_VAL(id_aa64mmfr1) >=
-	    ID_AA64MMFR1_HAFDBS_AF_DBS);
+	if (ID_AA64MMFR1_HAFDBS_VAL(id_aa64mmfr1) >=
+	    ID_AA64MMFR1_HAFDBS_AF_DBS)
+		return (FEAT_DEFAULT_ENABLE);
+
+	return (FEAT_ALWAYS_DISABLE);
 }
 
 static bool
diff --git a/sys/arm64/arm64/ptrauth.c b/sys/arm64/arm64/ptrauth.c
index 7f453dfa278d..fdab5414e24c 100644
--- a/sys/arm64/arm64/ptrauth.c
+++ b/sys/arm64/arm64/ptrauth.c
@@ -82,7 +82,7 @@ ptrauth_disable(void)
 	return (false);
 }
 
-static bool
+static cpu_feat_en
 ptrauth_check(const struct cpu_feat *feat __unused, u_int midr __unused)
 {
 	uint64_t isar;
@@ -116,14 +116,14 @@ ptrauth_check(const struct cpu_feat *feat __unused, u_int midr __unused)
 	if (get_kernel_reg(ID_AA64ISAR1_EL1, &isar)) {
 		if (ID_AA64ISAR1_APA_VAL(isar) > 0 ||
 		    ID_AA64ISAR1_API_VAL(isar) > 0) {
-			return (true);
+			return (FEAT_DEFAULT_ENABLE);
 		}
 	}
 
 	/* The QARMA3 algorithm is reported in ID_AA64ISAR2_EL1. */
 	if (get_kernel_reg(ID_AA64ISAR2_EL1, &isar)) {
 		if (ID_AA64ISAR2_APA3_VAL(isar) > 0) {
-			return (true);
+			return (FEAT_DEFAULT_ENABLE);
 		}
 	}
 
@@ -138,7 +138,7 @@ out:
 	    ID_AA64ISAR1_GPI_MASK, 0);
 	update_special_reg(ID_AA64ISAR2_EL1, ID_AA64ISAR2_APA3_MASK, 0);
 
-	return (false);
+	return (FEAT_ALWAYS_DISABLE);
 }
 
 static bool
diff --git a/sys/arm64/include/cpu_feat.h b/sys/arm64/include/cpu_feat.h
index f62f3e334dc1..6a554b6baedf 100644
--- a/sys/arm64/include/cpu_feat.h
+++ b/sys/arm64/include/cpu_feat.h
@@ -40,6 +40,31 @@ typedef enum {
 				/* kernel component. */
 } cpu_feat_errata;
 
+typedef enum {
+	/*
+	 * Don't implement the feature or erratum wrokarount,
+	 * e.g. the feature is not implemented or erratum is
+	 * for another CPU.
+	 */
+	FEAT_ALWAYS_DISABLE,
+
+	/*
+	 * Disable by default, but allow the user to enable,
+	 * e.g. For a rare erratum with a workaround, Arm
+	 * Category B (rare) or similar.
+	 */
+	FEAT_DEFAULT_DISABLE,
+
+	/*
+	 * Enabled by default, bit allow the user to disable,
+	 * e.g. For a common erratum with a workaround, Arm
+	 * Category A or B or similar.
+	 */
+	FEAT_DEFAULT_ENABLE,
+
+	/* We could add FEAT_ALWAYS_ENABLE if a need was found. */
+} cpu_feat_en;
+
 #define	CPU_FEAT_STAGE_MASK	0x00000001
 #define	CPU_FEAT_EARLY_BOOT	0x00000000
 #define	CPU_FEAT_AFTER_DEV	0x00000001
@@ -50,7 +75,7 @@ typedef enum {
 
 struct cpu_feat;
 
-typedef bool (cpu_feat_check)(const struct cpu_feat *, u_int);
+typedef cpu_feat_en (cpu_feat_check)(const struct cpu_feat *, u_int);
 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,



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202509041628.584GSmPL033103>