mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-10-29 11:54:38 +01:00
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
This commit is contained in:
1 parent
9204a315a7
commit
4bc68fa98f
7 files changed
+73
-19
No files matched your search
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in new issue
Block a user