feat(rme): add tests to check NS SME ID registers and configurations
These tests checks the functionality of RMM for NS SME support.
- Create Realm and test ID registers specific to SME
- Check if Realm gets undefined abort when it accesses SME
- Check whether RMM preserves NS SMCR_EL2 register
Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
Change-Id: Ia8ffd0188297a74c095dbadfb389add50c548e10
diff --git a/include/lib/aarch64/arch.h b/include/lib/aarch64/arch.h
index 13d7063..0c64e40 100644
--- a/include/lib/aarch64/arch.h
+++ b/include/lib/aarch64/arch.h
@@ -408,6 +408,7 @@
#define ID_AA64PFR1_EL1_SME_SHIFT U(24)
#define ID_AA64PFR1_EL1_SME_MASK ULL(0xf)
+#define ID_AA64PFR1_EL1_SME_WIDTH ULL(0x4)
#define ID_AA64PFR1_EL1_SME_NOT_SUPPORTED ULL(0x0)
#define ID_AA64PFR1_EL1_SME_SUPPORTED ULL(0x1)
#define ID_AA64PFR1_EL1_SME2_SUPPORTED ULL(0x2)
@@ -477,6 +478,11 @@
#define CPACR_EL1_ZEN_TRAP_ALL U(0x2)
#define CPACR_EL1_ZEN_TRAP_NONE U(0x3)
+#define CPACR_EL1_SMEN(x) ((x) << 24)
+#define CPACR_EL1_SMEN_TRAP_EL0 U(0x1)
+#define CPACR_EL1_SMEN_TRAP_ALL U(0x2)
+#define CPACR_EL1_SMEN_TRAP_NONE U(0x3)
+
/* SCR definitions */
#define SCR_RES1_BITS ((U(1) << 4) | (U(1) << 5))
#define SCR_AMVOFFEN_BIT (UL(1) << 35)
diff --git a/include/runtime_services/host_realm_managment/host_realm_sve.h b/include/runtime_services/host_realm_managment/host_realm_simd.h
similarity index 64%
rename from include/runtime_services/host_realm_managment/host_realm_sve.h
rename to include/runtime_services/host_realm_managment/host_realm_simd.h
index 8ec4cd7..9680a96 100644
--- a/include/runtime_services/host_realm_managment/host_realm_sve.h
+++ b/include/runtime_services/host_realm_managment/host_realm_simd.h
@@ -3,8 +3,8 @@
* SPDX-License-Identifier: BSD-3-Clause
*/
-#ifndef HOST_REALM_SVE_H
-#define HOST_REALM_SVE_H
+#ifndef HOST_REALM_SIMD_H
+#define HOST_REALM_SIMD_H
#include <stdint.h>
@@ -21,4 +21,9 @@
uint32_t vl_bitmap;
};
-#endif /* HOST_REALM_SVE_H */
+struct sme_cmd_id_regs {
+ uint64_t id_aa64pfr1_el1;
+ uint64_t id_aa64smfr0_el1;
+};
+
+#endif /* HOST_REALM_SIMD_H */
diff --git a/include/runtime_services/host_realm_managment/host_shared_data.h b/include/runtime_services/host_realm_managment/host_shared_data.h
index b561fc5..0a8ab4a 100644
--- a/include/runtime_services/host_realm_managment/host_shared_data.h
+++ b/include/runtime_services/host_realm_managment/host_shared_data.h
@@ -59,7 +59,9 @@
REALM_SVE_UNDEF_ABORT,
REALM_PAUTH_SET_CMD,
REALM_PAUTH_CHECK_CMD,
- REALM_PAUTH_FAULT
+ REALM_PAUTH_FAULT,
+ REALM_SME_ID_REGISTERS,
+ REALM_SME_UNDEF_ABORT
};
/*
diff --git a/realm/aarch64/realm_entrypoint.S b/realm/aarch64/realm_entrypoint.S
index ab00989..016689f 100644
--- a/realm/aarch64/realm_entrypoint.S
+++ b/realm/aarch64/realm_entrypoint.S
@@ -111,6 +111,8 @@
orr x0, x0, x1
mov x1, CPACR_EL1_ZEN(CPACR_EL1_ZEN_TRAP_NONE)
orr x0, x0, x1
+ mov x1, CPACR_EL1_SMEN(CPACR_EL1_SMEN_TRAP_NONE)
+ orr x0, x0, x1
msr cpacr_el1, x0
isb
diff --git a/realm/include/realm_tests.h b/realm/include/realm_tests.h
index ac839ac..5caea8c 100644
--- a/realm/include/realm_tests.h
+++ b/realm/include/realm_tests.h
@@ -23,6 +23,8 @@
bool test_realm_sve_cmp_regs(void);
bool test_realm_sve_undef_abort(void);
bool test_realm_multiple_rec_psci_denied_cmd(void);
+bool test_realm_sme_read_id_registers(void);
+bool test_realm_sme_undef_abort(void);
#endif /* REALM_TESTS_H */
diff --git a/realm/realm_payload_main.c b/realm/realm_payload_main.c
index aaf7479..e1f78c5 100644
--- a/realm/realm_payload_main.c
+++ b/realm/realm_payload_main.c
@@ -143,6 +143,12 @@
case REALM_SVE_UNDEF_ABORT:
test_succeed = test_realm_sve_undef_abort();
break;
+ case REALM_SME_ID_REGISTERS:
+ test_succeed = test_realm_sme_read_id_registers();
+ break;
+ case REALM_SME_UNDEF_ABORT:
+ test_succeed = test_realm_sme_undef_abort();
+ break;
default:
realm_printf("%s() invalid cmd %u\n", __func__, cmd);
break;
diff --git a/realm/realm_simd.c b/realm/realm_simd.c
index 273696b..106a849 100644
--- a/realm/realm_simd.c
+++ b/realm/realm_simd.c
@@ -13,7 +13,7 @@
#include <lib/extensions/fpu.h>
#include <lib/extensions/sve.h>
-#include <host_realm_sve.h>
+#include <host_realm_simd.h>
#include <host_shared_data.h>
#define RL_SVE_OP_ARRAYSIZE 512U
@@ -218,3 +218,38 @@
return true;
}
+
+/* Reads and returns the ID_AA64PFR1_EL1 and ID_AA64SMFR0_EL1 registers */
+bool test_realm_sme_read_id_registers(void)
+{
+ host_shared_data_t *sd = realm_get_my_shared_structure();
+ struct sme_cmd_id_regs *output;
+
+ output = (struct sme_cmd_id_regs *)sd->realm_cmd_output_buffer;
+ memset((void *)output, 0, sizeof(struct sme_cmd_id_regs));
+
+ realm_printf("Realm: reading ID registers: ID_AA64PFR1_EL1, "
+ " ID_AA64SMFR0_EL1\n");
+
+ output->id_aa64pfr1_el1 = read_id_aa64pfr1_el1();
+ output->id_aa64smfr0_el1 = read_id_aa64smfr0_el1();
+
+ return true;
+}
+
+/* Check if Realm gets undefined abort when it access SME functionality */
+bool test_realm_sme_undef_abort(void)
+{
+ realm_got_undef_abort = 0UL;
+
+ /* install exception handler to catch undef abort */
+ register_custom_sync_exception_handler(&realm_sync_exception_handler);
+ (void)read_svcr();
+ unregister_custom_sync_exception_handler();
+
+ if (realm_got_undef_abort == 0UL) {
+ return false;
+ }
+
+ return true;
+}
diff --git a/tftf/tests/runtime_services/realm_payload/host_realm_payload_simd_tests.c b/tftf/tests/runtime_services/realm_payload/host_realm_payload_simd_tests.c
index 3fd18ba..94d81ca 100644
--- a/tftf/tests/runtime_services/realm_payload/host_realm_payload_simd_tests.c
+++ b/tftf/tests/runtime_services/realm_payload/host_realm_payload_simd_tests.c
@@ -10,11 +10,12 @@
#include <debug.h>
#include <test_helpers.h>
#include <lib/extensions/fpu.h>
+#include <lib/extensions/sme.h>
#include <lib/extensions/sve.h>
#include <host_realm_helper.h>
#include <host_realm_mem_layout.h>
-#include <host_realm_sve.h>
+#include <host_realm_simd.h>
#include <host_shared_data.h>
#define NS_SVE_OP_ARRAYSIZE 1024U
@@ -935,3 +936,189 @@
return rc;
}
+
+/*
+ * Create a Realm and check SME specific ID registers. Realm must report SME
+ * not present in ID_AA64PFR1_EL1 and no SME features present in
+ * ID_AA64SMFR0_EL1
+ */
+test_result_t host_realm_check_sme_id_registers(void)
+{
+ host_shared_data_t *sd;
+ struct sme_cmd_id_regs *r_regs;
+ test_result_t rc;
+ bool realm_rc;
+
+ SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
+
+ rc = host_create_sve_realm_payload(false, 0);
+ if (rc != TEST_RESULT_SUCCESS) {
+ return rc;
+ }
+
+ realm_rc = host_enter_realm_execute(REALM_SME_ID_REGISTERS, NULL,
+ RMI_EXIT_HOST_CALL, 0U);
+ if (!realm_rc) {
+ rc = TEST_RESULT_FAIL;
+ goto rm_realm;
+ }
+
+ sd = host_get_shared_structure(0U);
+ r_regs = (struct sme_cmd_id_regs *)sd->realm_cmd_output_buffer;
+
+ /* Check ID register SME flags */
+ rc = TEST_RESULT_SUCCESS;
+ if (EXTRACT(ID_AA64PFR1_EL1_SME, r_regs->id_aa64pfr1_el1) >=
+ ID_AA64PFR1_EL1_SME_SUPPORTED) {
+ ERROR("ID_AA64PFR1_EL1: SME enabled\n");
+ rc = TEST_RESULT_FAIL;
+ }
+ if (r_regs->id_aa64smfr0_el1 != 0UL) {
+ ERROR("ID_AA64SMFR0_EL1: Realm reported non-zero value\n");
+ rc = TEST_RESULT_FAIL;
+ }
+
+rm_realm:
+ host_destroy_realm();
+ return rc;
+}
+
+/*
+ * Create a Realm and try to access SME, the Realm must receive undefined abort.
+ */
+test_result_t host_realm_check_sme_undef_abort(void)
+{
+ test_result_t rc;
+ bool realm_rc;
+
+ SKIP_TEST_IF_SME_NOT_SUPPORTED();
+ SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
+
+ rc = host_create_sve_realm_payload(false, 0);
+ if (rc != TEST_RESULT_SUCCESS) {
+ return rc;
+ }
+
+ realm_rc = host_enter_realm_execute(REALM_SME_UNDEF_ABORT, NULL,
+ RMI_EXIT_HOST_CALL, 0U);
+ if (!realm_rc) {
+ ERROR("Realm didn't receive undefined abort\n");
+ rc = TEST_RESULT_FAIL;
+ } else {
+ rc = TEST_RESULT_SUCCESS;
+ }
+
+ host_destroy_realm();
+ return rc;
+}
+
+/*
+ * Check whether RMM preserves NS SME config values and flags
+ * 1. SMCR_EL2.LEN field
+ * 2. SMCR_EL2.FA64 flag
+ * 3. Streaming SVE mode status
+ *
+ * This test case runs for SVE + SME config and SME only config and skipped for
+ * non SME config.
+ */
+test_result_t host_realm_check_sme_configs(void)
+{
+ u_register_t ns_smcr_el2, ns_smcr_el2_cur;
+ u_register_t rmi_feat_reg0;
+ bool ssve_mode;
+ test_result_t rc;
+ uint8_t sve_vq;
+ uint8_t sme_svq;
+ bool sve_en;
+
+ SKIP_TEST_IF_SME_NOT_SUPPORTED();
+ SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
+
+ if (is_armv8_2_sve_present()) {
+ CHECK_SVE_SUPPORT_IN_HW_AND_IN_RMI(rmi_feat_reg0);
+ sve_en = true;
+ sve_vq = EXTRACT(RMI_FEATURE_REGISTER_0_SVE_VL, rmi_feat_reg0);
+ } else {
+ sve_en = false;
+ sve_vq = 0;
+ }
+
+ rc = host_create_sve_realm_payload(sve_en, sve_vq);
+ if (rc != TEST_RESULT_SUCCESS) {
+ return rc;
+ }
+
+ /*
+ * Configure TFTF from 0 to SME_SVQ_ARCH_MAX, and in each iteration
+ * randomly enable or disable FA64 and Streaming SVE mode. Ater calling
+ * Realm, check the NS SME configuration status.
+ */
+ rc = TEST_RESULT_SUCCESS;
+ for (sme_svq = 0U; sme_svq <= SME_SVQ_ARCH_MAX; sme_svq++) {
+ bool realm_rc;
+
+ sme_config_svq(sme_svq);
+
+ /* randomly enable or disable FEAT_SME_FA64 */
+ if (sme_svq % 2) {
+ sme_enable_fa64();
+ sme_smstart(SMSTART_SM);
+ ssve_mode = true;
+ } else {
+ sme_disable_fa64();
+ sme_smstop(SMSTOP_SM);
+ ssve_mode = false;
+ }
+
+ ns_smcr_el2 = read_smcr_el2();
+
+ /*
+ * If SVE is supported then we would have created a Realm with
+ * SVE support, so run SVE command else run FPU command
+ */
+ if (sve_en) {
+ realm_rc = host_enter_realm_execute(REALM_SVE_RDVL, NULL,
+ RMI_EXIT_HOST_CALL,
+ 0U);
+ } else {
+ realm_rc = host_enter_realm_execute(
+ REALM_REQ_FPU_FILL_CMD,
+ NULL,
+ RMI_EXIT_HOST_CALL, 0U);
+ }
+
+ if (!realm_rc) {
+ ERROR("Realm command REALM_SVE_RDVL failed\n");
+ rc = TEST_RESULT_FAIL;
+ break;
+ }
+ ns_smcr_el2_cur = read_smcr_el2();
+
+ if (ns_smcr_el2 != ns_smcr_el2_cur) {
+ ERROR("NS SMCR_EL2 expected: 0x%lx, got: 0x%lx\n",
+ ns_smcr_el2, ns_smcr_el2_cur);
+ rc = TEST_RESULT_FAIL;
+ }
+
+ if (sme_smstat_sm() != ssve_mode) {
+ if (ssve_mode) {
+ ERROR("NS Streaming SVE mode is disabled\n");
+ } else {
+ ERROR("NS Streaming SVE mode is enabled\n");
+ }
+
+ rc = TEST_RESULT_FAIL;
+ }
+ }
+
+ /* Exit Streaming SVE mode if test case enabled it */
+ if (ssve_mode) {
+ sme_smstop(SMSTOP_SM);
+ }
+
+ if (!host_destroy_realm()) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return rc;
+}
diff --git a/tftf/tests/tests-realm-payload.xml b/tftf/tests/tests-realm-payload.xml
index cf707a5..158b91a 100644
--- a/tftf/tests/tests-realm-payload.xml
+++ b/tftf/tests/tests-realm-payload.xml
@@ -63,6 +63,13 @@
function="host_non_sve_realm_check_undef_abort" />
<testcase name="Check various SIMD state preserved across NS/RL switch"
function="host_and_realm_check_simd" />
+ <!-- Test Realm for SME -->
+ <testcase name="Create Realm and test SME ID registers"
+ function="host_realm_check_sme_id_registers" />
+ <testcase name="Check if Realm gets undefined abort when it access SME"
+ function="host_realm_check_sme_undef_abort" />
+ <testcase name="Check whether RMM preserves NS SME configurations"
+ function="host_realm_check_sme_configs" />
<!-- Test case related to PAuth -->
<testcase name="Check if PAuth keys are preserved in RL/SE/NS"
function="host_realm_enable_pauth" />