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" />