test(SMCCC): test SMCCC_ARCH_FEATURE_AVAILABILITY
This test calls the function with each valid argument and checks that
every bit is set if its relevant feature is present in the system. It
also fails the test if any set bit in the return value has not been
checked. This should serve as a reminder to update this test for every
new feature that is implemented.
Only feature that tfa supports are tested with the expectation that new
ones will be added in the future.
Co-developed-by: Charlie Bareham <charlie.bareham@arm.com>
Signed-off-by: Boyan Karatotev <boyan.karatotev@arm.com>
Change-Id: I801326a49810bb76bfc3b9d06780d416dcc32a40
diff --git a/include/common/test_helpers.h b/include/common/test_helpers.h
index fc557ae..124cc4e 100644
--- a/include/common/test_helpers.h
+++ b/include/common/test_helpers.h
@@ -102,6 +102,20 @@
} \
} while (0)
+#define SKIP_TEST_IF_SMCCC_FUNC_NOT_SUPPORTED(func) \
+ do { \
+ smc_ret_values ret; \
+ smc_args args = {0}; \
+ args.fid = SMCCC_ARCH_FEATURES; \
+ args.arg1 = func; \
+ ret = tftf_smc(&args); \
+ if ((int)ret.ret0 == SMC_ARCH_CALL_NOT_SUPPORTED) { \
+ tftf_testcase_printf( \
+ #func " is not implemented\n"); \
+ return TEST_RESULT_SKIPPED; \
+ } \
+ } while (0)
+
#define SKIP_TEST_IF_DIT_NOT_SUPPORTED() \
do { \
if (!is_armv8_4_dit_present()) { \
diff --git a/include/lib/aarch64/arch.h b/include/lib/aarch64/arch.h
index 62cf470..c640fc7 100644
--- a/include/lib/aarch64/arch.h
+++ b/include/lib/aarch64/arch.h
@@ -625,6 +625,7 @@
#define SCR_PFAREn_BIT (UL(1) << 53)
#define SCR_TWERR_BIT (UL(1) << 52)
#define SCR_TMEA_BIT (UL(1) << 51)
+#define SCR_EnFPM_BIT (UL(1) << 50)
#define SCR_MECEn_BIT (UL(1) << 49)
#define SCR_GPF_BIT (UL(1) << 48)
#define SCR_D128En_BIT (UL(1) << 47)
diff --git a/include/runtime_services/arm_arch_svc.h b/include/runtime_services/arm_arch_svc.h
index 0d2eb38..0b4e2ad 100644
--- a/include/runtime_services/arm_arch_svc.h
+++ b/include/runtime_services/arm_arch_svc.h
@@ -13,5 +13,6 @@
#define SMCCC_ARCH_WORKAROUND_1 0x80008000
#define SMCCC_ARCH_WORKAROUND_2 0x80007FFF
#define SMCCC_ARCH_WORKAROUND_3 0x80003FFF
+#define SMCCC_ARCH_FEATURE_AVAILABILITY U(0x80000003)
#endif /* __ARM_ARCH_SVC_H__ */
diff --git a/include/runtime_services/smccc.h b/include/runtime_services/smccc.h
index b898138..513ec8f 100644
--- a/include/runtime_services/smccc.h
+++ b/include/runtime_services/smccc.h
@@ -80,4 +80,9 @@
#define SMC_GET_SOC_VERSION 0
#define SMC_GET_SOC_REVISION 1
+#define SCR_EL3_OPCODE U(0x1E1100)
+#define CPTR_EL3_OPCODE U(0x1E1140)
+#define MDCR_EL3_OPCODE U(0x1E1320)
+#define MPAM3_EL3_OPCODE U(0x1EA500)
+
#endif /* __SMCCC_H__ */
diff --git a/tftf/tests/runtime_services/arm_arch_svc/smccc_feature_availability.c b/tftf/tests/runtime_services/arm_arch_svc/smccc_feature_availability.c
new file mode 100644
index 0000000..1418ca1
--- /dev/null
+++ b/tftf/tests/runtime_services/arm_arch_svc/smccc_feature_availability.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <tftf.h>
+
+#include <arm_arch_svc.h>
+#include <smccc.h>
+#include <test_helpers.h>
+#include <tftf_lib.h>
+
+static inline u_register_t get_feature_for_reg(u_register_t reg)
+{
+ smc_args args = {0};
+ smc_ret_values ret;
+
+ args.fid = SMCCC_ARCH_FEATURE_AVAILABILITY | (SMC_64 << FUNCID_CC_SHIFT);
+ args.arg1 = reg;
+ ret = tftf_smc(&args);
+
+ /* APi is pretty simple, support was already checked. This is simpler */
+ assert((int)ret.ret0 == SMC_ARCH_CALL_SUCCESS);
+ return ret.ret1;
+}
+
+static inline bool always_present(void)
+{
+ return true;
+}
+
+/*
+ * Checks that the bit's matches the feature's presence
+ * feat_func should be is_feat_xyz_present(), but get_feat_xyz_support() will
+ * also work.
+ */
+#define CHECK_BIT_SET(feat_func, bit) \
+ do { \
+ if (!!feat_func() != !!(reg & bit)) { \
+ tftf_testcase_printf( \
+ #feat_func " says feature is %ssupported but " \
+ #bit " was %sset!\n", feat_func() ? "" : "not ",\
+ (reg & bit) ? "" : "not "); \
+ bad = true; \
+ } \
+ reg &= ~bit; \
+ } while (0)
+
+/* when support for a new feature is added, we want this test to be
+ * updated. Fail the test so it's noticed. */
+#define CHECK_NO_BITS_SET(reg_name) \
+ do { \
+ if (reg != 0) { \
+ tftf_testcase_printf( \
+ #reg_name " still has values set: 0x%lx. " \
+ "Test needs to be updated\n", reg); \
+ bad = true; \
+ } \
+ } while (0)
+
+test_result_t test_smccc_arch_feature_availability(void)
+{
+ SKIP_TEST_IF_AARCH32();
+#ifdef __aarch64__
+
+ SKIP_TEST_IF_SMCCC_VERSION_LT(1, 1);
+ SKIP_TEST_IF_SMCCC_FUNC_NOT_SUPPORTED(SMCCC_ARCH_FEATURE_AVAILABILITY);
+
+ u_register_t reg;
+ bool bad = false;
+
+ reg = get_feature_for_reg(SCR_EL3_OPCODE);
+ CHECK_BIT_SET(is_armv8_9_fgt2_present, SCR_FGTEN2_BIT);
+ CHECK_BIT_SET(is_feat_fpmr_present, SCR_EnFPM_BIT);
+ CHECK_BIT_SET(is_feat_d128_supported, SCR_D128En_BIT);
+ CHECK_BIT_SET(is_feat_s1pie_present, SCR_PIEN_BIT);
+ CHECK_BIT_SET(is_feat_sctlr2_supported, SCR_SCTLR2En_BIT);
+ CHECK_BIT_SET(is_feat_tcr2_supported, SCR_TCR2EN_BIT);
+ CHECK_BIT_SET(is_feat_the_supported, SCR_RCWMASKEn_BIT);
+ CHECK_BIT_SET(is_feat_sme_supported, SCR_ENTP2_BIT);
+ CHECK_BIT_SET(is_feat_rng_trap_present, SCR_TRNDR_BIT);
+ CHECK_BIT_SET(is_feat_gcs_present, SCR_GCSEn_BIT);
+ CHECK_BIT_SET(get_feat_hcx_support, SCR_HXEn_BIT);
+ CHECK_BIT_SET(is_feat_ls64_accdata_present, SCR_ADEn_BIT);
+ CHECK_BIT_SET(is_feat_ls64_accdata_present, SCR_EnAS0_BIT);
+ CHECK_BIT_SET(is_feat_amuv1p1_present, SCR_AMVOFFEN_BIT);
+ CHECK_BIT_SET(get_armv8_6_ecv_support, SCR_ECVEN_BIT);
+ CHECK_BIT_SET(is_armv8_6_fgt_present, SCR_FGTEN_BIT);
+ CHECK_BIT_SET(is_feat_mte2_present, SCR_ATA_BIT);
+ CHECK_BIT_SET(is_feat_csv2_2_present, SCR_EnSCXT_BIT);
+ CHECK_BIT_SET(is_armv8_3_pauth_present, SCR_APK_BIT);
+ CHECK_BIT_SET(is_feat_ras_present, SCR_TERR_BIT);
+ CHECK_NO_BITS_SET(SCR_EL3);
+
+ reg = get_feature_for_reg(CPTR_EL3_OPCODE);
+ CHECK_BIT_SET(always_present, CPTR_EL3_TCPAC_BIT);
+ CHECK_BIT_SET(is_feat_amuv1_present, CPTR_EL3_TAM_BIT);
+ CHECK_BIT_SET(get_armv8_0_sys_reg_trace_support, CPTR_EL3_TTA_BIT);
+ CHECK_BIT_SET(is_feat_sme_supported, CPTR_EL3_ESM_BIT);
+ CHECK_BIT_SET(always_present, CPTR_EL3_TFP_BIT);
+ CHECK_BIT_SET(is_armv8_2_sve_present, CPTR_EL3_EZ_BIT);
+ CHECK_NO_BITS_SET(CPTR_EL3);
+
+ reg = get_feature_for_reg(MDCR_EL3_OPCODE);
+ CHECK_BIT_SET(get_feat_brbe_support, MDCR_SBRBE(1));
+ CHECK_BIT_SET(is_armv8_6_fgt_present, MDCR_TDCC_BIT);
+ CHECK_BIT_SET(is_feat_trbe_present, MDCR_NSTB(1));
+ CHECK_BIT_SET(get_armv8_4_trf_support, MDCR_TTRF_BIT);
+ CHECK_BIT_SET(is_feat_spe_supported, MDCR_NSPB(1));
+ CHECK_BIT_SET(is_feat_doublelock_present, MDCR_TDOSA_BIT);
+ CHECK_BIT_SET(always_present, MDCR_TDA_BIT);
+ CHECK_BIT_SET(get_feat_pmuv3_supported, MDCR_TPM_BIT);
+ CHECK_NO_BITS_SET(MDCR_EL3);
+
+ reg = get_feature_for_reg(MPAM3_EL3_OPCODE);
+ CHECK_BIT_SET(is_feat_mpam_supported, MPAM3_EL3_TRAPLOWER_BIT);
+ CHECK_NO_BITS_SET(MPAM3_EL3);
+
+ if (bad)
+ return TEST_RESULT_FAIL;
+
+ return TEST_RESULT_SUCCESS;
+#endif /* __aarch64__ */
+}
diff --git a/tftf/tests/tests-cpu-extensions.mk b/tftf/tests/tests-cpu-extensions.mk
index 39783b1..7375633 100644
--- a/tftf/tests/tests-cpu-extensions.mk
+++ b/tftf/tests/tests-cpu-extensions.mk
@@ -33,4 +33,5 @@
runtime_services/arm_arch_svc/smccc_arch_workaround_1.c \
runtime_services/arm_arch_svc/smccc_arch_workaround_2.c \
runtime_services/arm_arch_svc/smccc_arch_workaround_3.c \
+ runtime_services/arm_arch_svc/smccc_feature_availability.c \
)
diff --git a/tftf/tests/tests-cpu-extensions.xml b/tftf/tests/tests-cpu-extensions.xml
index bc09f37..51aa27c 100644
--- a/tftf/tests/tests-cpu-extensions.xml
+++ b/tftf/tests/tests-cpu-extensions.xml
@@ -50,6 +50,7 @@
<testcase name="SMCCC_ARCH_WORKAROUND_2 test" function="test_smccc_arch_workaround_2" />
<testcase name="SMCCC_ARCH_WORKAROUND_3 test" function="test_smccc_arch_workaround_3" />
<testcase name="SMCCC_ARCH_SOC_ID test" function="test_smccc_arch_soc_id" />
+ <testcase name="SMCCC_ARCH_FEATURE_AVAILABILITY test" function="test_smccc_arch_feature_availability" />
</testsuite>
</testsuites>