feat(rme): add SVE Realm tests
Verifies Realm with SVE support. Below tests are added
- Check whether RMI features reports proper SVE VL
- Create SVE Realm and check rdvl result
- Create SVE Realm with invalid VL and check if it fails
- Create SVE Realm and test ID registers
- Create non SVE Realm and test ID registers
- Create SVE Realm and probe all supported VLs
- Check RMM preserves NS ZCR_EL2 register
Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
Change-Id: I98a20f34ce72c7c1a353ed13678870168fa27c48
diff --git a/tftf/framework/framework.mk b/tftf/framework/framework.mk
index 188e9af..ab9033a 100644
--- a/tftf/framework/framework.mk
+++ b/tftf/framework/framework.mk
@@ -87,7 +87,8 @@
lib/extensions/sme/aarch64/sme.c \
lib/extensions/sme/aarch64/sme2.c \
lib/extensions/sme/aarch64/sme_helpers.S \
- lib/extensions/sme/aarch64/sme2_helpers.S
+ lib/extensions/sme/aarch64/sme2_helpers.S \
+ lib/extensions/sve/aarch64/sve.c
endif
TFTF_LINKERFILE := tftf/framework/tftf.ld.S
diff --git a/tftf/tests/runtime_services/host_realm_managment/host_realm_helper.c b/tftf/tests/runtime_services/host_realm_managment/host_realm_helper.c
index e529c29..f535e11 100644
--- a/tftf/tests/runtime_services/host_realm_managment/host_realm_helper.c
+++ b/tftf/tests/runtime_services/host_realm_managment/host_realm_helper.c
@@ -215,7 +215,7 @@
/* Read Realm Feature Reg 0 */
if (host_rmi_features(0UL, &realm.rmm_feat_reg0) != REALM_SUCCESS) {
ERROR("%s() failed\n", "host_rmi_features");
- goto destroy_realm;
+ return false;
}
/* Disable PMU if not required */
@@ -225,6 +225,16 @@
RMI_FEATURE_REGISTER_0_PMU_NUM_CTRS);
}
+ /* Set SVE bits from feature_flag */
+ realm.rmm_feat_reg0 &= ~(MASK(RMI_FEATURE_REGISTER_0_SVE_EN) |
+ MASK(RMI_FEATURE_REGISTER_0_SVE_VL));
+ realm.rmm_feat_reg0 |= INPLACE(RMI_FEATURE_REGISTER_0_SVE_EN,
+ EXTRACT(RMI_FEATURE_REGISTER_0_SVE_EN,
+ feature_flag));
+ realm.rmm_feat_reg0 |= INPLACE(RMI_FEATURE_REGISTER_0_SVE_VL,
+ EXTRACT(RMI_FEATURE_REGISTER_0_SVE_VL,
+ feature_flag));
+
/* Create Realm */
if (host_realm_create(&realm) != REALM_SUCCESS) {
ERROR("%s() failed\n", "host_realm_create");
diff --git a/tftf/tests/runtime_services/realm_payload/host_realm_payload_sve_tests.c b/tftf/tests/runtime_services/realm_payload/host_realm_payload_sve_tests.c
new file mode 100644
index 0000000..554a497
--- /dev/null
+++ b/tftf/tests/runtime_services/realm_payload/host_realm_payload_sve_tests.c
@@ -0,0 +1,376 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdlib.h>
+
+#include <assert.h>
+#include <arch_features.h>
+#include <debug.h>
+#include <test_helpers.h>
+#include <lib/extensions/sve.h>
+
+#include <host_realm_helper.h>
+#include <host_realm_mem_layout.h>
+#include <host_realm_sve.h>
+#include <host_shared_data.h>
+
+/* Skip test if SVE is not supported in H/W or in RMI features */
+#define CHECK_SVE_SUPPORT_IN_HW_AND_IN_RMI(_reg0) \
+ do { \
+ SKIP_TEST_IF_SVE_NOT_SUPPORTED(); \
+ \
+ /* Get RMM support for SVE and its max SVE VL */ \
+ if (host_rmi_features(0UL, &_reg0) != REALM_SUCCESS) { \
+ ERROR("Failed to get RMI feat_reg0\n"); \
+ return TEST_RESULT_FAIL; \
+ } \
+ \
+ /* SVE not supported in RMI features? */ \
+ if (EXTRACT(RMI_FEATURE_REGISTER_0_SVE_EN, _reg0) == 0UL) { \
+ ERROR("SVE not in RMI features, skipping\n"); \
+ return TEST_RESULT_SKIPPED; \
+ } \
+ } while (false)
+
+static test_result_t host_create_sve_realm_payload(bool sve_en, uint8_t sve_vq)
+{
+ u_register_t rmi_feat_reg0;
+
+ if (sve_en == true) {
+ rmi_feat_reg0 = INPLACE(RMI_FEATURE_REGISTER_0_SVE_EN, true);
+ rmi_feat_reg0 |= INPLACE(RMI_FEATURE_REGISTER_0_SVE_VL, sve_vq);
+ } else {
+ rmi_feat_reg0 = INPLACE(RMI_FEATURE_REGISTER_0_SVE_EN, false);
+ }
+
+ /* Initialise Realm payload */
+ if (!host_create_realm_payload((u_register_t)REALM_IMAGE_BASE,
+ (u_register_t)PAGE_POOL_BASE,
+ (u_register_t)(PAGE_POOL_MAX_SIZE +
+ NS_REALM_SHARED_MEM_SIZE),
+ (u_register_t)PAGE_POOL_MAX_SIZE,
+ rmi_feat_reg0)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Create shared memory between Host and Realm */
+ if (!host_create_shared_mem(NS_REALM_SHARED_MEM_BASE,
+ NS_REALM_SHARED_MEM_SIZE)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/*
+ * RMI should report SVE VL in RMI features and it must be the same value as the
+ * max SVE VL seen by the NS world.
+ */
+test_result_t host_check_rmi_reports_proper_sve_vl(void)
+{
+ u_register_t rmi_feat_reg0;
+ uint8_t rmi_sve_vq;
+ uint8_t ns_sve_vq;
+
+ SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
+
+ CHECK_SVE_SUPPORT_IN_HW_AND_IN_RMI(rmi_feat_reg0);
+
+ rmi_sve_vq = EXTRACT(RMI_FEATURE_REGISTER_0_SVE_VL, rmi_feat_reg0);
+
+ /*
+ * configure NS to arch supported max VL and get the value reported
+ * by rdvl
+ */
+ sve_config_vq(SVE_VQ_ARCH_MAX);
+ ns_sve_vq = SVE_VL_TO_VQ(sve_vector_length_get());
+
+ if (rmi_sve_vq != ns_sve_vq) {
+ ERROR("RMI max SVE VL %u bits doesn't matches NS max "
+ "SVE VL %u bits\n", SVE_VQ_TO_BITS(rmi_sve_vq),
+ SVE_VQ_TO_BITS(ns_sve_vq));
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/* Test Realm creation with SVE enabled and run command rdvl */
+test_result_t host_sve_realm_cmd_rdvl(void)
+{
+ host_shared_data_t *sd;
+ struct sve_cmd_rdvl *rl_output;
+ uint8_t sve_vq, rl_max_sve_vq;
+ u_register_t rmi_feat_reg0;
+ test_result_t rc;
+ bool realm_rc;
+
+ SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
+
+ CHECK_SVE_SUPPORT_IN_HW_AND_IN_RMI(rmi_feat_reg0);
+
+ sve_vq = EXTRACT(RMI_FEATURE_REGISTER_0_SVE_VL, rmi_feat_reg0);
+
+ rc = host_create_sve_realm_payload(true, sve_vq);
+ if (rc != TEST_RESULT_SUCCESS) {
+ ERROR("Failed to create Realm with SVE\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ realm_rc = host_enter_realm_execute(REALM_SVE_RDVL, NULL,
+ RMI_EXIT_HOST_CALL);
+ if (realm_rc != true) {
+ rc = TEST_RESULT_FAIL;
+ goto rm_realm;
+ }
+
+ /* check if rdvl matches the SVE VL created */
+ sd = host_get_shared_structure();
+ rl_output = (struct sve_cmd_rdvl *)sd->realm_cmd_output_buffer;
+ rl_max_sve_vq = SVE_VL_TO_VQ(rl_output->rdvl);
+ if (sve_vq == rl_max_sve_vq) {
+ rc = TEST_RESULT_SUCCESS;
+ } else {
+ ERROR("Realm created with max VL: %u bits, but Realm reported "
+ "max VL as: %u bits\n", SVE_VQ_TO_BITS(sve_vq),
+ SVE_VQ_TO_BITS(rl_max_sve_vq));
+ rc = TEST_RESULT_FAIL;
+ }
+
+rm_realm:
+ if (!host_destroy_realm()) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return rc;
+}
+
+/* Test Realm creation with SVE enabled but with invalid SVE VL */
+test_result_t host_sve_realm_test_invalid_vl(void)
+{
+ u_register_t rmi_feat_reg0;
+ test_result_t rc;
+ uint8_t sve_vq;
+
+ SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
+
+ CHECK_SVE_SUPPORT_IN_HW_AND_IN_RMI(rmi_feat_reg0);
+
+ sve_vq = EXTRACT(RMI_FEATURE_REGISTER_0_SVE_VL, rmi_feat_reg0);
+
+ /*
+ * If RMM supports MAX SVE VQ, we can't pass in an invalid sve_vq to
+ * create a realm, so skip the test. Else pass a sve_vq that is greater
+ * than the value supported by RMM and check whether creating Realm fails
+ */
+ if (sve_vq == SVE_VQ_ARCH_MAX) {
+ INFO("RMI supports arch max SVE VL, skipping\n");
+ return TEST_RESULT_SKIPPED;
+ }
+
+ rc = host_create_sve_realm_payload(true, (sve_vq + 1));
+
+ if (rc == TEST_RESULT_SUCCESS) {
+ ERROR("Error: Realm created with invalid SVE VL\n");
+ host_destroy_realm();
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+static test_result_t _host_sve_realm_check_id_registers(bool sve_en)
+{
+ host_shared_data_t *sd;
+ struct sve_cmd_id_regs *r_regs;
+ u_register_t rmi_feat_reg0;
+ test_result_t rc;
+ bool realm_rc;
+ uint8_t sve_vq = 0U;
+
+ SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
+
+ if (sve_en) {
+ CHECK_SVE_SUPPORT_IN_HW_AND_IN_RMI(rmi_feat_reg0);
+ sve_vq = EXTRACT(RMI_FEATURE_REGISTER_0_SVE_VL, rmi_feat_reg0);
+ }
+
+ rc = host_create_sve_realm_payload(sve_en, sve_vq);
+ if (rc != TEST_RESULT_SUCCESS) {
+ return rc;
+ }
+
+ realm_rc = host_enter_realm_execute(REALM_SVE_ID_REGISTERS, NULL,
+ RMI_EXIT_HOST_CALL);
+ if (!realm_rc) {
+ rc = TEST_RESULT_FAIL;
+ goto rm_realm;
+ }
+
+ sd = host_get_shared_structure();
+ r_regs = (struct sve_cmd_id_regs *)sd->realm_cmd_output_buffer;
+
+ /* Check ID register SVE flags */
+ if (sve_en) {
+ rc = TEST_RESULT_SUCCESS;
+ if (EXTRACT(ID_AA64PFR0_SVE, r_regs->id_aa64pfr0_el1) == 0UL) {
+ ERROR("ID_AA64PFR0_EL1: SVE not enabled\n");
+ rc = TEST_RESULT_FAIL;
+ }
+ if (r_regs->id_aa64zfr0_el1 == 0UL) {
+ ERROR("ID_AA64ZFR0_EL1: No SVE features present\n");
+ rc = TEST_RESULT_FAIL;
+ }
+ } else {
+ rc = TEST_RESULT_SUCCESS;
+ if (EXTRACT(ID_AA64PFR0_SVE, r_regs->id_aa64pfr0_el1) != 0UL) {
+ ERROR("ID_AA64PFR0_EL1: SVE enabled\n");
+ rc = TEST_RESULT_FAIL;
+ }
+ if (r_regs->id_aa64zfr0_el1 != 0UL) {
+ ERROR("ID_AA64ZFR0_EL1: Realm reported non-zero value\n");
+ rc = TEST_RESULT_FAIL;
+ }
+ }
+
+rm_realm:
+ host_destroy_realm();
+ return rc;
+}
+
+/* Test ID_AA64PFR0_EL1, ID_AA64ZFR0_EL1_SVE values in SVE Realm */
+test_result_t host_sve_realm_cmd_id_registers(void)
+{
+ return _host_sve_realm_check_id_registers(true);
+}
+
+/* Test ID_AA64PFR0_EL1, ID_AA64ZFR0_EL1_SVE values in non SVE Realm */
+test_result_t host_non_sve_realm_cmd_id_registers(void)
+{
+ return _host_sve_realm_check_id_registers(false);
+}
+
+static void print_sve_vl_bitmap(uint32_t vl_bitmap)
+{
+ uint8_t vq;
+
+ for (vq = 0U; vq <= SVE_VQ_ARCH_MAX; vq++) {
+ if ((vl_bitmap & BIT_32(vq)) != 0U) {
+ INFO("\t%u\n", SVE_VQ_TO_BITS(vq));
+ }
+ }
+}
+
+/* Create SVE Realm and probe all the supported VLs */
+test_result_t host_sve_realm_cmd_probe_vl(void)
+{
+ host_shared_data_t *sd;
+ struct sve_cmd_probe_vl *rl_output;
+ uint32_t vl_bitmap_expected;
+ u_register_t rmi_feat_reg0;
+ test_result_t rc;
+ bool realm_rc;
+ uint8_t sve_vq;
+
+ SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
+
+ CHECK_SVE_SUPPORT_IN_HW_AND_IN_RMI(rmi_feat_reg0);
+
+ sve_vq = EXTRACT(RMI_FEATURE_REGISTER_0_SVE_VL, rmi_feat_reg0);
+
+ rc = host_create_sve_realm_payload(true, sve_vq);
+ if (rc != TEST_RESULT_SUCCESS) {
+ return rc;
+ }
+
+ /*
+ * Configure TFTF with sve_vq and probe all VLs and compare it with
+ * the bitmap returned from Realm
+ */
+ vl_bitmap_expected = sve_probe_vl(sve_vq);
+
+ realm_rc = host_enter_realm_execute(REALM_SVE_PROBE_VL, NULL,
+ RMI_EXIT_HOST_CALL);
+ if (!realm_rc) {
+ rc = TEST_RESULT_FAIL;
+ goto rm_realm;
+ }
+
+ sd = host_get_shared_structure();
+ rl_output = (struct sve_cmd_probe_vl *)sd->realm_cmd_output_buffer;
+
+ INFO("Supported SVE vector length in bits (expected):\n");
+ print_sve_vl_bitmap(vl_bitmap_expected);
+
+ INFO("Supported SVE vector length in bits (probed):\n");
+ print_sve_vl_bitmap(rl_output->vl_bitmap);
+
+ if (vl_bitmap_expected == rl_output->vl_bitmap) {
+ rc = TEST_RESULT_SUCCESS;
+ } else {
+ rc = TEST_RESULT_FAIL;
+ }
+
+rm_realm:
+ if (!host_destroy_realm()) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return rc;
+}
+
+/* Check whether RMM preserves NS ZCR_EL2 register. */
+test_result_t host_sve_realm_check_config_register(void)
+{
+ u_register_t ns_zcr_el2, ns_zcr_el2_cur;
+ u_register_t rmi_feat_reg0;
+ test_result_t rc;
+ uint8_t vq;
+
+ SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
+
+ CHECK_SVE_SUPPORT_IN_HW_AND_IN_RMI(rmi_feat_reg0);
+
+ vq = EXTRACT(RMI_FEATURE_REGISTER_0_SVE_VL, rmi_feat_reg0);
+
+ rc = host_create_sve_realm_payload(true, vq);
+ if (rc != TEST_RESULT_SUCCESS) {
+ return rc;
+ }
+
+ /*
+ * Configure TFTF from 0 to SVE_VQ_ARCH_MAX, and in each iteration check
+ * if NS ZCR_EL2 is same before and after call to run Realm.
+ */
+ rc = TEST_RESULT_SUCCESS;
+ for (vq = 0U; vq <= SVE_VQ_ARCH_MAX; vq++) {
+ bool realm_rc;
+
+ sve_config_vq(vq);
+ ns_zcr_el2 = read_zcr_el2();
+
+ /* Call Realm to run SVE command */
+ realm_rc = host_enter_realm_execute(REALM_SVE_RDVL, NULL,
+ RMI_EXIT_HOST_CALL);
+ if (!realm_rc) {
+ ERROR("Realm command REALM_SVE_RDVL failed\n");
+ rc = TEST_RESULT_FAIL;
+ break;
+ }
+ ns_zcr_el2_cur = read_zcr_el2();
+
+ if (ns_zcr_el2 != ns_zcr_el2_cur) {
+ ERROR("NS ZCR_EL2 expected: 0x%lx, got: 0x%lx\n",
+ ns_zcr_el2, ns_zcr_el2_cur);
+ rc = TEST_RESULT_FAIL;
+ }
+ }
+
+ if (!host_destroy_realm()) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return rc;
+}
diff --git a/tftf/tests/tests-realm-payload.mk b/tftf/tests/tests-realm-payload.mk
index b3b7d4a..0e0d148 100644
--- a/tftf/tests/tests-realm-payload.mk
+++ b/tftf/tests/tests-realm-payload.mk
@@ -12,6 +12,7 @@
$(addprefix tftf/tests/runtime_services/realm_payload/, \
host_realm_payload_tests.c \
host_realm_spm.c \
+ host_realm_payload_sve_tests.c \
)
TESTS_SOURCES += \
diff --git a/tftf/tests/tests-realm-payload.xml b/tftf/tests/tests-realm-payload.xml
index 7518934..4d4bf81 100644
--- a/tftf/tests/tests-realm-payload.xml
+++ b/tftf/tests/tests-realm-payload.xml
@@ -32,5 +32,20 @@
function="host_realm_sec_interrupt_can_preempt_rl" />
<testcase name="Check that FPU state registers context is preserved in RL/SE/NS"
function="host_realm_fpu_access_in_rl_ns_se" />
+ <!-- Test Realm with SVE support -->
+ <testcase name="Check RMI reports proper SVE VL"
+ function="host_check_rmi_reports_proper_sve_vl" />
+ <testcase name="Create SVE Realm with invalid VL"
+ function="host_sve_realm_test_invalid_vl" />
+ <testcase name="Create SVE Realm and test ID registers"
+ function="host_sve_realm_cmd_id_registers" />
+ <testcase name="Create non SVE Realm and test ID registers"
+ function="host_non_sve_realm_cmd_id_registers" />
+ <testcase name="Create SVE Realm and check rdvl result"
+ function="host_sve_realm_cmd_rdvl" />
+ <testcase name="Create SVE Realm and probe all supported VLs"
+ function="host_sve_realm_cmd_probe_vl" />
+ <testcase name="Check whether RMM preserves NS ZCR_EL2 register"
+ function="host_sve_realm_check_config_register" />
</testsuite>
</testsuites>