feat: add tests to check SCTLR2, THE and D128 sysregs
This patch adds test cases for verifying that the system registers of
FEAT_SCTLR2, FEAT_THE and FEAT_D128 (FEAT_SYSREG128) are working
correctly by performing a series of reads and writes to the registers.
Change-Id: I5c102daa358a7ec5d1801395bc875e9850e83939
Signed-off-by: Igor Podgainõi <igor.podgainoi@arm.com>
Signed-off-by: Manish Pandey <manish.pandey2@arm.com>
diff --git a/tftf/tests/extensions/d128/test_d128.c b/tftf/tests/extensions/d128/test_d128.c
new file mode 100644
index 0000000..1e8df0c
--- /dev/null
+++ b/tftf/tests/extensions/d128/test_d128.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/extensions/sysreg128.h>
+#include <test_helpers.h>
+
+#include "./test_d128.h"
+
+/*
+ * @brief Test FEAT_D128 feature support when the extension is enabled.
+ *
+ * The test ensures that access to common system registers PAR_EL1, TTBR0_EL1, TTBR1_EL1,
+ * TTBR0_EL2, VTTBR_EL2 and the VHE register TTBR1_EL2 do not trap to EL3.
+ *
+ * Additonally this test verifies that EL1 registers are properly context switched by
+ * making dummy SMC call to TSPD (running at S-EL1).
+ *
+ * TODO: EL2 registers context switching.
+ *
+ * @return test_result_t
+ */
+test_result_t test_d128_support(void)
+{
+#ifdef __aarch64__
+ SKIP_TEST_IF_D128_NOT_SUPPORTED();
+ SKIP_TEST_IF_TSP_NOT_PRESENT();
+
+ smc_args tsp_svc_params;
+
+ /* Access 128 bit variant of system registers */
+ read128_par_el1();
+ read128_ttbr0_el1();
+ read128_ttbr1_el1();
+ read128_ttbr0_el2();
+ read128_ttbr1_el2();
+ if (is_armv8_1_vhe_present()) {
+ read128_vttbr_el2();
+ }
+
+ /*
+ * Check that EL1 registers are properly contexted by EL3. Write to the registers
+ * make dummy SMC call TSP and ensure that values are prorperly contexted.
+ * NOTE: Ideal way would be to modify these registers in TSP in SMC handler
+ */
+ write128_par_el1(PAR_EL1_MASK_FULL);
+ write128_ttbr0_el1(TTBR_REG_MASK_FULL);
+ write128_ttbr1_el1(TTBR_REG_MASK_FULL);
+
+ tsp_svc_params.fid = TSP_STD_FID(TSP_ADD);
+ tsp_svc_params.arg1 = 4;
+ tsp_svc_params.arg2 = 6;
+ tftf_smc(&tsp_svc_params);
+
+ if ((read128_par_el1() != PAR_EL1_MASK_FULL) ||
+ (read128_ttbr0_el1() != TTBR_REG_MASK_FULL) ||
+ (read128_ttbr1_el1() != TTBR_REG_MASK_FULL)) {
+ NOTICE("Unexpected value of registers after context switch\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+#else
+ SKIP_TEST_IF_AARCH32();
+#endif /* __aarch64_ */
+}
diff --git a/tftf/tests/extensions/d128/test_d128.h b/tftf/tests/extensions/d128/test_d128.h
new file mode 100644
index 0000000..2e40753
--- /dev/null
+++ b/tftf/tests/extensions/d128/test_d128.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TEST_D128_H
+#define TEST_D128_H
+
+/* Create Mask setting all used bits except PA */
+#define PAR_EL1_MASK_HIGH 0x0000000000000001
+#define PAR_EL1_MASK_LOW 0xFF00000000000F81
+#define PAR_EL1_MASK_FULL (((uint128_t)PAR_EL1_MASK_HIGH) << 64U | PAR_EL1_MASK_LOW)
+
+/* Masks created by setting all used bits */
+#define TTBR_REG_MASK_HIGH 0x0000000000FF0000
+#define TTBR_REG_MASK_LOW 0xFFFFFFFFFFFFFFE7
+#define TTBR_REG_MASK_FULL (((uint128_t)TTBR_REG_MASK_HIGH) << 64U | TTBR_REG_MASK_LOW)
+
+#endif /* TEST_D128_H */
diff --git a/tftf/tests/extensions/sctlr2/test_sctlr2.c b/tftf/tests/extensions/sctlr2/test_sctlr2.c
new file mode 100644
index 0000000..704d19d
--- /dev/null
+++ b/tftf/tests/extensions/sctlr2/test_sctlr2.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <test_helpers.h>
+
+/*
+ * @brief Test FEAT_SCTLR2 support when the extension is enabled.
+ *
+ * Ensure that reading of SCTLR2_EL1 and SCTLR2_EL2 system registers does not
+ * trap to EL3. Also, verify that SCTLR2_EL1 register value is preserved
+ * correctly during world switch to TSP.
+ *
+ * TODO: Test context switching of SCTLR2_EL2
+ *
+ * @return test_result_t
+ */
+test_result_t test_sctlr2_support(void)
+{
+#ifdef __aarch64__
+ SKIP_TEST_IF_SCTLR2_NOT_SUPPORTED();
+ SKIP_TEST_IF_TSP_NOT_PRESENT();
+
+ smc_args tsp_svc_params;
+
+ /* Access the registers */
+ read_sctlr2_el1();
+ read_sctlr2_el2();
+
+ /* Check that SCTLR2_EL1 is properly contexted by EL3. Write to the registers
+ * make dummy SMC call TSP and ensure that values are prorperly contexted.
+ * Set EnIDCP128_BIT which is guaranteed to be present if SCTLR2 is present.
+ */
+ write_sctlr2_el1(read_sctlr2_el1() | SCTLR2_EnIDCP128_BIT);
+
+ tsp_svc_params.fid = TSP_STD_FID(TSP_ADD);
+ tsp_svc_params.arg1 = 4;
+ tsp_svc_params.arg2 = 6;
+ tftf_smc(&tsp_svc_params);
+
+ if ((read_sctlr2_el1() & SCTLR2_EnIDCP128_BIT) == 0) {
+ ERROR("SCTLR2_EL1 unexpected value after context switch\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+#else
+ SKIP_TEST_IF_AARCH32();
+#endif /* __aarch64_ */
+}
diff --git a/tftf/tests/extensions/the/test_the.c b/tftf/tests/extensions/the/test_the.c
new file mode 100644
index 0000000..b56be93
--- /dev/null
+++ b/tftf/tests/extensions/the/test_the.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/extensions/sysreg128.h>
+#include <test_helpers.h>
+
+#include "./test_the.h"
+
+/*
+ * @brief Test FEAT_THE support when the extension is enabled.
+ *
+ * Write to the RCWMASK_EL1 and RCWSMASK_EL1 system registers with
+ * a mask of allowed bits in 128-bit mode, if FEAT_D128 is supported,
+ * otherwise in 64-bit mode, perform a dummy SMC call, then read the
+ * registers back.
+ *
+ * The test ensures that accesses to these registers do not trap
+ * to EL3 as well as that their values are preserved correctly.
+ *
+ * @return test_result_t
+ */
+test_result_t test_the_support(void)
+{
+#ifdef __aarch64__
+ SKIP_TEST_IF_THE_NOT_SUPPORTED();
+ SKIP_TEST_IF_TSP_NOT_PRESENT();
+
+ smc_args tsp_svc_params;
+ /* Standard SMC to ADD two numbers */
+ tsp_svc_params.fid = TSP_STD_FID(TSP_ADD);
+ tsp_svc_params.arg1 = 4;
+ tsp_svc_params.arg2 = 6;
+
+ if (is_feat_d128_supported()) {
+ uint128_t reg_read;
+
+ write128_rcwmask_el1(RCWMASK_EL1_MASK_FULL);
+ write128_rcwsmask_el1(RCWSMASK_EL1_MASK_FULL);
+ tftf_smc(&tsp_svc_params);
+
+ reg_read = read128_rcwmask_el1();
+ if (reg_read != RCWMASK_EL1_MASK_FULL) {
+ NOTICE("RCWMASK_EL1 unexpected value after context switch: 0x%llx:0x%llx\n",
+ (uint64_t)(reg_read >> 64U), (uint64_t)reg_read);
+ return TEST_RESULT_FAIL;
+ }
+
+ reg_read = read128_rcwsmask_el1();
+ if (reg_read != RCWSMASK_EL1_MASK_FULL) {
+ NOTICE("RCWSMASK_EL1 unexpected value after context switch: 0x%llx:0x%llx\n",
+ (uint64_t)(reg_read >> 64U), (uint64_t)reg_read);
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+ }
+
+ uint64_t reg_read;
+
+ write_rcwmask_el1(RCWMASK_EL1_MASK_LOW);
+ write_rcwsmask_el1(RCWSMASK_EL1_MASK_LOW);
+ tftf_smc(&tsp_svc_params);
+
+ reg_read = read_rcwmask_el1();
+ if (reg_read != RCWMASK_EL1_MASK_LOW) {
+ NOTICE("RCWMASK_EL1 unexpected value after context switch: 0x%llx\n", reg_read);
+ return TEST_RESULT_FAIL;
+ }
+
+ reg_read = read_rcwsmask_el1();
+ if (reg_read != RCWSMASK_EL1_MASK_LOW) {
+ NOTICE("RCWSMASK_EL1 unexpected value after context switch: 0x%llx\n", reg_read);
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+#else
+ SKIP_TEST_IF_AARCH32();
+#endif /* __aarch64_ */
+}
diff --git a/tftf/tests/extensions/the/test_the.h b/tftf/tests/extensions/the/test_the.h
new file mode 100644
index 0000000..92a3768
--- /dev/null
+++ b/tftf/tests/extensions/the/test_the.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TEST_THE_H
+#define TEST_THE_H
+
+#define RCWMASK_EL1_MASK_HIGH 0x807BE01FF8000000
+#define RCWMASK_EL1_MASK_LOW 0xFFEC00000003FFFE
+#define RCWMASK_EL1_MASK_FULL \
+ (((uint128_t)RCWMASK_EL1_MASK_HIGH) << 64U | RCWMASK_EL1_MASK_LOW)
+
+#define RCWSMASK_EL1_MASK_HIGH 0x807BE01FF8000000
+#define RCWSMASK_EL1_MASK_LOW 0xFFFC00000003FFFE
+#define RCWSMASK_EL1_MASK_FULL \
+ (((uint128_t)RCWSMASK_EL1_MASK_HIGH) << 64U | RCWSMASK_EL1_MASK_LOW)
+
+#endif /* TEST_THE_H */
diff --git a/tftf/tests/tests-cpu-extensions.mk b/tftf/tests/tests-cpu-extensions.mk
index a6d6e2a..39783b1 100644
--- a/tftf/tests/tests-cpu-extensions.mk
+++ b/tftf/tests/tests-cpu-extensions.mk
@@ -8,6 +8,7 @@
extensions/afp/test_afp.c \
extensions/amu/test_amu.c \
extensions/brbe/test_brbe.c \
+ extensions/d128/test_d128.c \
extensions/debugv8p9/test_debugv8p9.c \
extensions/ecv/test_ecv.c \
extensions/fgt/test_fgt.c \
@@ -18,11 +19,13 @@
extensions/mte/test_mte.c \
extensions/pauth/test_pauth.c \
extensions/pmuv3/test_pmuv3.c \
+ extensions/sctlr2/test_sctlr2.c \
extensions/sme/test_sme.c \
extensions/sme/test_sme2.c \
extensions/spe/test_spe.c \
extensions/sve/test_sve.c \
extensions/sys_reg_trace/test_sys_reg_trace.c \
+ extensions/the/test_the.c \
extensions/trbe/test_trbe.c \
extensions/trf/test_trf.c \
extensions/wfxt/test_wfxt.c \
diff --git a/tftf/tests/tests-cpu-extensions.xml b/tftf/tests/tests-cpu-extensions.xml
index 0c89840..bc09f37 100644
--- a/tftf/tests/tests-cpu-extensions.xml
+++ b/tftf/tests/tests-cpu-extensions.xml
@@ -40,6 +40,9 @@
<testcase name="PMUv3 SMC counter preservation" function="test_pmuv3_el3_preserves" />
<testcase name="LS64 support" function="test_ls64_instructions" />
<testcase name="LS64-ACCDATA support" function="test_ls64_accdata_sysreg" />
+ <testcase name="SCTLR2 support" function="test_sctlr2_support" />
+ <testcase name="THE support" function="test_the_support" />
+ <testcase name="D128 support" function="test_d128_support" />
</testsuite>
<testsuite name="ARM_ARCH_SVC" description="Arm Architecture Service tests">