refactor(cpufeat): check FEAT_FGT in a new way

To implement proper runtime checking of features, and to be able to
extend feat_detect.c to catch other cases, rework the FEAT_FGT check to
directly call a generic function instead of providing a trivial specific
one. The #ifdef is moved into the function, and rewritten as a proper C
if statement.
We need to force the compiler to inline that function, otherwise the
optimisation won't work, once we exceed a certain number of callers.

This starts with FEAT_FGT, but all the other features will be moved over
eventually, in separate patches.

For all features checked this way, we delay the panic() until after
every feature has been checked, to list them all during one run.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Change-Id: Ic576922ff2c4f8d3c1b87b5843b3626729fe4514
diff --git a/common/feat_detect.c b/common/feat_detect.c
index 05b2e42..21dd35d 100644
--- a/common/feat_detect.c
+++ b/common/feat_detect.c
@@ -8,6 +8,8 @@
 #include <common/debug.h>
 #include <common/feat_detect.h>
 
+static bool tainted;
+
 /*******************************************************************************
  * This section lists the wrapper modules for each feature to evaluate the
  * feature states (FEAT_STATE_ALWAYS and FEAT_STATE_CHECK) and perform
@@ -31,6 +33,24 @@
 	panic();
 }
 
+/*******************************************************************************
+ * Function : check_feature
+ * Check for a valid combination of build time flags (ENABLE_FEAT_xxx) and
+ * feature availability on the hardware.
+ * Panics if a feature is forcefully enabled, but not available on the PE.
+ *
+ * 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__))
+check_feature(int state, unsigned long field, const char *feat_name)
+{
+	if (state == FEAT_STATE_ALWAYS && field == 0U) {
+		ERROR("FEAT_%s not supported by the PE\n", feat_name);
+		tainted = true;
+	}
+}
+
 /******************************************
  * Feature : FEAT_SB (Speculation Barrier)
  *****************************************/
@@ -185,16 +205,6 @@
 #endif
 }
 
-/****************************************
- * Feature : FEAT_FGT (Fine Grain Traps)
- ***************************************/
-static void read_feat_fgt(void)
-{
-#if (ENABLE_FEAT_FGT == FEAT_STATE_ALWAYS)
-	feat_detect_panic(is_armv8_6_fgt_present(), "FGT");
-#endif
-}
-
 /***********************************************
  * Feature : FEAT_AMUv1p1 (AMU Extensions v1.1)
  **********************************************/
@@ -304,6 +314,8 @@
  **********************************************************************************/
 void detect_arch_features(void)
 {
+	tainted = false;
+
 	/* v8.0 features */
 	read_feat_sb();
 	read_feat_csv2_2();
@@ -334,7 +346,7 @@
 
 	/* v8.6 features */
 	read_feat_amuv1p1();
-	read_feat_fgt();
+	check_feature(ENABLE_FEAT_FGT, is_armv8_6_fgt_present(), "FGT");
 	read_feat_ecv();
 	read_feat_twed();
 
@@ -347,4 +359,8 @@
 
 	/* v9.2 features */
 	read_feat_rme();
+
+	if (tainted) {
+		panic();
+	}
 }