feat(cpufeat): do feature detection on secondary cores too
Feature detection currently only happens on the boot core, however, it
is possible to have asymmetry between cores. TF-A supports limited such
configurations so it should check secondary cores too.
Change-Id: Iee4955714685be9ae6a017af4a6c284e835ff299
Signed-off-by: Boyan Karatotev <boyan.karatotev@arm.com>
diff --git a/common/feat_detect.c b/common/feat_detect.c
index d7adae6..694d616 100644
--- a/common/feat_detect.c
+++ b/common/feat_detect.c
@@ -7,8 +7,9 @@
#include <arch_features.h>
#include <common/debug.h>
#include <common/feat_detect.h>
+#include <plat/common/platform.h>
-static bool tainted;
+static bool detection_done[PLATFORM_CORE_COUNT] = { false };
/*******************************************************************************
* This section lists the wrapper modules for each feature to evaluate the
@@ -45,19 +46,21 @@
* We force inlining here to let the compiler optimise away the whole check
* if the feature is disabled at build time (FEAT_STATE_DISABLED).
******************************************************************************/
-static inline void __attribute((__always_inline__))
+static inline bool __attribute((__always_inline__))
check_feature(int state, unsigned long field, const char *feat_name,
unsigned int min, unsigned int max)
{
if (state == FEAT_STATE_ALWAYS && field < min) {
ERROR("FEAT_%s not supported by the PE\n", feat_name);
- tainted = true;
+ return true;
}
if (state >= FEAT_STATE_ALWAYS && field > max) {
ERROR("FEAT_%s is version %ld, but is only known up to version %d\n",
feat_name, field, max);
- tainted = true;
+ return true;
}
+
+ return false;
}
/************************************************
@@ -326,127 +329,150 @@
* { FEAT_STATE_DISABLED, FEAT_STATE_ALWAYS, FEAT_STATE_CHECK }, taking values
* { 0, 1, 2 }, respectively, as their naming.
**********************************************************************************/
-void detect_arch_features(void)
+void detect_arch_features(unsigned int core_pos)
{
- tainted = false;
+ /* No need to keep checking after the first time for each core. */
+ if (detection_done[core_pos]) {
+ return;
+ }
+
+ bool tainted = false;
/* v8.0 features */
- check_feature(ENABLE_FEAT_SB, read_feat_sb_id_field(), "SB", 1, 1);
- check_feature(ENABLE_FEAT_CSV2_2, read_feat_csv2_id_field(),
- "CSV2_2", 2, 3);
+ tainted |= check_feature(ENABLE_FEAT_SB, read_feat_sb_id_field(),
+ "SB", 1, 1);
+ tainted |= check_feature(ENABLE_FEAT_CSV2_2, read_feat_csv2_id_field(),
+ "CSV2_2", 2, 3);
/*
* Even though the PMUv3 is an OPTIONAL feature, it is always
* implemented and Arm prescribes so. So assume it will be there and do
* away with a flag for it. This is used to check minor PMUv3px
* revisions so that we catch them as they come along
*/
- check_feature(FEAT_STATE_ALWAYS, read_feat_pmuv3_id_field(),
- "PMUv3", 1, ID_AA64DFR0_PMUVER_PMUV3P9);
+ tainted |= check_feature(FEAT_STATE_ALWAYS, read_feat_pmuv3_id_field(),
+ "PMUv3", 1, ID_AA64DFR0_PMUVER_PMUV3P9);
/* v8.1 features */
- check_feature(ENABLE_FEAT_PAN, read_feat_pan_id_field(), "PAN", 1, 3);
- check_feature(ENABLE_FEAT_VHE, read_feat_vhe_id_field(), "VHE", 1, 1);
+ tainted |= check_feature(ENABLE_FEAT_PAN, read_feat_pan_id_field(),
+ "PAN", 1, 3);
+ tainted |= check_feature(ENABLE_FEAT_VHE, read_feat_vhe_id_field(),
+ "VHE", 1, 1);
/* v8.2 features */
- check_feature(ENABLE_SVE_FOR_NS, read_feat_sve_id_field(),
- "SVE", 1, 1);
- check_feature(ENABLE_FEAT_RAS, read_feat_ras_id_field(), "RAS", 1, 2);
+ tainted |= check_feature(ENABLE_SVE_FOR_NS, read_feat_sve_id_field(),
+ "SVE", 1, 1);
+ tainted |= check_feature(ENABLE_FEAT_RAS, read_feat_ras_id_field(),
+ "RAS", 1, 2);
/* v8.3 features */
/* TODO: Pauth yet to convert to tri-state feat detect logic */
read_feat_pauth();
/* v8.4 features */
- check_feature(ENABLE_FEAT_DIT, read_feat_dit_id_field(), "DIT", 1, 1);
- check_feature(ENABLE_FEAT_AMU, read_feat_amu_id_field(),
- "AMUv1", 1, 2);
- check_feature(ENABLE_FEAT_MOPS, read_feat_mops_id_field(),
- "MOPS", 1, 1);
- check_feature(ENABLE_FEAT_MPAM, read_feat_mpam_version(),
- "MPAM", 1, 17);
- check_feature(CTX_INCLUDE_NEVE_REGS, read_feat_nv_id_field(),
- "NV2", 2, 2);
- check_feature(ENABLE_FEAT_SEL2, read_feat_sel2_id_field(),
- "SEL2", 1, 1);
- check_feature(ENABLE_TRF_FOR_NS, read_feat_trf_id_field(),
- "TRF", 1, 1);
+ tainted |= check_feature(ENABLE_FEAT_DIT, read_feat_dit_id_field(),
+ "DIT", 1, 1);
+ tainted |= check_feature(ENABLE_FEAT_AMU, read_feat_amu_id_field(),
+ "AMUv1", 1, 2);
+ tainted |= check_feature(ENABLE_FEAT_MOPS, read_feat_mops_id_field(),
+ "MOPS", 1, 1);
+ tainted |= check_feature(ENABLE_FEAT_MPAM, read_feat_mpam_version(),
+ "MPAM", 1, 17);
+ tainted |= check_feature(CTX_INCLUDE_NEVE_REGS, read_feat_nv_id_field(),
+ "NV2", 2, 2);
+ tainted |= check_feature(ENABLE_FEAT_SEL2, read_feat_sel2_id_field(),
+ "SEL2", 1, 1);
+ tainted |= check_feature(ENABLE_TRF_FOR_NS, read_feat_trf_id_field(),
+ "TRF", 1, 1);
/* v8.5 features */
- check_feature(ENABLE_FEAT_MTE2, get_armv8_5_mte_support(), "MTE2",
- MTE_IMPLEMENTED_ELX, MTE_IMPLEMENTED_ASY);
- check_feature(ENABLE_FEAT_RNG, read_feat_rng_id_field(), "RNG", 1, 1);
- check_feature(ENABLE_BTI, read_feat_bti_id_field(), "BTI", 1, 1);
- check_feature(ENABLE_FEAT_RNG_TRAP, read_feat_rng_trap_id_field(),
- "RNG_TRAP", 1, 1);
+ tainted |= check_feature(ENABLE_FEAT_MTE2, get_armv8_5_mte_support(),
+ "MTE2", MTE_IMPLEMENTED_ELX, MTE_IMPLEMENTED_ASY);
+ tainted |= check_feature(ENABLE_FEAT_RNG, read_feat_rng_id_field(),
+ "RNG", 1, 1);
+ tainted |= check_feature(ENABLE_BTI, read_feat_bti_id_field(),
+ "BTI", 1, 1);
+ tainted |= check_feature(ENABLE_FEAT_RNG_TRAP, read_feat_rng_trap_id_field(),
+ "RNG_TRAP", 1, 1);
/* v8.6 features */
- check_feature(ENABLE_FEAT_AMUv1p1, read_feat_amu_id_field(),
- "AMUv1p1", 2, 2);
- check_feature(ENABLE_FEAT_FGT, read_feat_fgt_id_field(), "FGT", 1, 2);
- check_feature(ENABLE_FEAT_FGT2, read_feat_fgt_id_field(), "FGT2", 2, 2);
- check_feature(ENABLE_FEAT_ECV, read_feat_ecv_id_field(), "ECV", 1, 2);
- check_feature(ENABLE_FEAT_TWED, read_feat_twed_id_field(),
- "TWED", 1, 1);
+ tainted |= check_feature(ENABLE_FEAT_AMUv1p1, read_feat_amu_id_field(),
+ "AMUv1p1", 2, 2);
+ tainted |= check_feature(ENABLE_FEAT_FGT, read_feat_fgt_id_field(),
+ "FGT", 1, 2);
+ tainted |= check_feature(ENABLE_FEAT_FGT2, read_feat_fgt_id_field(),
+ "FGT2", 2, 2);
+ tainted |= check_feature(ENABLE_FEAT_ECV, read_feat_ecv_id_field(),
+ "ECV", 1, 2);
+ tainted |= check_feature(ENABLE_FEAT_TWED, read_feat_twed_id_field(),
+ "TWED", 1, 1);
/*
* even though this is a "DISABLE" it does confusingly perform feature
* enablement duties like all other flags here. Check it against the HW
* feature when we intend to diverge from the default behaviour
*/
- check_feature(DISABLE_MTPMU, read_feat_mtpmu_id_field(), "MTPMU", 1, 1);
+ tainted |= check_feature(DISABLE_MTPMU, read_feat_mtpmu_id_field(),
+ "MTPMU", 1, 1);
/* v8.7 features */
- check_feature(ENABLE_FEAT_HCX, read_feat_hcx_id_field(), "HCX", 1, 1);
- check_feature(ENABLE_FEAT_LS64_ACCDATA, read_feat_ls64_id_field(), "LS64", 1, 3);
+ tainted |= check_feature(ENABLE_FEAT_HCX, read_feat_hcx_id_field(),
+ "HCX", 1, 1);
+ tainted |= check_feature(ENABLE_FEAT_LS64_ACCDATA, read_feat_ls64_id_field(),
+ "LS64", 1, 3);
/* v8.9 features */
- check_feature(ENABLE_FEAT_TCR2, read_feat_tcr2_id_field(),
- "TCR2", 1, 1);
- check_feature(ENABLE_FEAT_S2PIE, read_feat_s2pie_id_field(),
- "S2PIE", 1, 1);
- check_feature(ENABLE_FEAT_S1PIE, read_feat_s1pie_id_field(),
- "S1PIE", 1, 1);
- check_feature(ENABLE_FEAT_S2POE, read_feat_s2poe_id_field(),
- "S2POE", 1, 1);
- check_feature(ENABLE_FEAT_S1POE, read_feat_s1poe_id_field(),
- "S1POE", 1, 1);
- check_feature(ENABLE_FEAT_CSV2_3, read_feat_csv2_id_field(),
- "CSV2_3", 3, 3);
- check_feature(ENABLE_FEAT_DEBUGV8P9, read_feat_debugv8p9_id_field(),
- "DEBUGV8P9", 11, 11);
- check_feature(ENABLE_FEAT_THE, read_feat_the_id_field(),
- "THE", 1, 1);
- check_feature(ENABLE_FEAT_SCTLR2, read_feat_sctlr2_id_field(),
- "SCTLR2", 1, 1);
+ tainted |= check_feature(ENABLE_FEAT_TCR2, read_feat_tcr2_id_field(),
+ "TCR2", 1, 1);
+ tainted |= check_feature(ENABLE_FEAT_S2PIE, read_feat_s2pie_id_field(),
+ "S2PIE", 1, 1);
+ tainted |= check_feature(ENABLE_FEAT_S1PIE, read_feat_s1pie_id_field(),
+ "S1PIE", 1, 1);
+ tainted |= check_feature(ENABLE_FEAT_S2POE, read_feat_s2poe_id_field(),
+ "S2POE", 1, 1);
+ tainted |= check_feature(ENABLE_FEAT_S1POE, read_feat_s1poe_id_field(),
+ "S1POE", 1, 1);
+ tainted |= check_feature(ENABLE_FEAT_CSV2_3, read_feat_csv2_id_field(),
+ "CSV2_3", 3, 3);
+ tainted |= check_feature(ENABLE_FEAT_DEBUGV8P9, read_feat_debugv8p9_id_field(),
+ "DEBUGV8P9", 11, 11);
+ tainted |= check_feature(ENABLE_FEAT_THE, read_feat_the_id_field(),
+ "THE", 1, 1);
+ tainted |= check_feature(ENABLE_FEAT_SCTLR2, read_feat_sctlr2_id_field(),
+ "SCTLR2", 1, 1);
/* v9.0 features */
- check_feature(ENABLE_BRBE_FOR_NS, read_feat_brbe_id_field(),
- "BRBE", 1, 2);
- check_feature(ENABLE_TRBE_FOR_NS, read_feat_trbe_id_field(),
- "TRBE", 1, 1);
+ tainted |= check_feature(ENABLE_BRBE_FOR_NS, read_feat_brbe_id_field(),
+ "BRBE", 1, 2);
+ tainted |= check_feature(ENABLE_TRBE_FOR_NS, read_feat_trbe_id_field(),
+ "TRBE", 1, 1);
/* v9.2 features */
- check_feature(ENABLE_SME_FOR_NS, read_feat_sme_id_field(),
- "SME", 1, 2);
- check_feature(ENABLE_SME2_FOR_NS, read_feat_sme_id_field(),
- "SME2", 2, 2);
- check_feature(ENABLE_FEAT_FPMR, read_feat_fpmr_id_field(),
- "FPMR", 1, 1);
+ tainted |= check_feature(ENABLE_SME_FOR_NS, read_feat_sme_id_field(),
+ "SME", 1, 2);
+ tainted |= check_feature(ENABLE_SME2_FOR_NS, read_feat_sme_id_field(),
+ "SME2", 2, 2);
+ tainted |= check_feature(ENABLE_FEAT_FPMR, read_feat_fpmr_id_field(),
+ "FPMR", 1, 1);
/* v9.3 features */
- check_feature(ENABLE_FEAT_D128, read_feat_d128_id_field(),
- "D128", 1, 1);
- check_feature(ENABLE_FEAT_GCIE, read_feat_gcie_id_field(),
- "GCIE", 1, 1);
+ tainted |= check_feature(ENABLE_FEAT_D128, read_feat_d128_id_field(),
+ "D128", 1, 1);
+ tainted |= check_feature(ENABLE_FEAT_GCIE, read_feat_gcie_id_field(),
+ "GCIE", 1, 1);
/* v9.4 features */
- check_feature(ENABLE_FEAT_GCS, read_feat_gcs_id_field(), "GCS", 1, 1);
- check_feature(ENABLE_RME, read_feat_rme_id_field(), "RME", 1, 1);
- check_feature(ENABLE_FEAT_PAUTH_LR, is_feat_pauth_lr_present(), "PAUTH_LR", 1, 1);
- check_feature(ENABLE_FEAT_FGWTE3, read_feat_fgwte3_id_field(),
- "FGWTE3", 1, 1);
+ tainted |= check_feature(ENABLE_FEAT_GCS, read_feat_gcs_id_field(),
+ "GCS", 1, 1);
+ tainted |= check_feature(ENABLE_RME, read_feat_rme_id_field(),
+ "RME", 1, 1);
+ tainted |= check_feature(ENABLE_FEAT_PAUTH_LR, is_feat_pauth_lr_present(),
+ "PAUTH_LR", 1, 1);
+ tainted |= check_feature(ENABLE_FEAT_FGWTE3, read_feat_fgwte3_id_field(),
+ "FGWTE3", 1, 1);
if (tainted) {
panic();
}
+
+ detection_done[core_pos] = true;
}