aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Boulby <daniel.boulby@arm.com>2021-02-02 19:27:41 +0000
committerDaniel Boulby <daniel.boulby@arm.com>2021-09-17 13:20:36 +0100
commit39e4df2e33d0acd31c131c218db44be3f39b08d8 (patch)
tree030680f5148c5ba62f081a780d8382aa172cccdf
parentcf664616030fbf634812c2a16595c434d642dd86 (diff)
downloadtf-a-tests-39e4df2e33d0acd31c131c218db44be3f39b08d8.tar.gz
Add test to check PSTATE in the SDEI handler
When handling an SDEI event the processor must be in a known state. The SDEI specification requires PSTATE bits DAIF= 0b1111, EL = Client_El, nRw = 0 and SP = 1. All other bits are populated according to the AArch64.TakeException() pseudocode function defined in the Arm Architecture Reference Manual. This patch adds tests to check the PSTATE in the event handler to follow these requirements Change-Id: If7178c5f1c25e92c49612631b9a6a57c9e3062cd Signed-off-by: Daniel Boulby <daniel.boulby@arm.com>
-rw-r--r--include/lib/aarch64/arch.h16
-rw-r--r--include/lib/aarch64/arch_features.h14
-rw-r--r--include/lib/aarch64/arch_helpers.h9
-rw-r--r--tftf/tests/runtime_services/standard_service/sdei/system_tests/sdei_entrypoint.S30
-rw-r--r--tftf/tests/runtime_services/standard_service/sdei/system_tests/test_sdei_pstate.c318
-rw-r--r--tftf/tests/tests-sdei.mk3
-rw-r--r--tftf/tests/tests-sdei.xml3
7 files changed, 389 insertions, 4 deletions
diff --git a/include/lib/aarch64/arch.h b/include/lib/aarch64/arch.h
index f2681676a..f7d2420b6 100644
--- a/include/lib/aarch64/arch.h
+++ b/include/lib/aarch64/arch.h
@@ -223,6 +223,14 @@
#define ID_AA64MMFR0_EL1_TGRAN16_SUPPORTED ULL(0x1)
#define ID_AA64MMFR0_EL1_TGRAN16_NOT_SUPPORTED ULL(0x0)
+/* ID_AA64MMFR1_EL1 definitions */
+#define ID_AA64MMFR1_EL1_PAN_SHIFT U(20)
+#define ID_AA64MMFR1_EL1_PAN_MASK ULL(0xf)
+#define ID_AA64MMFR1_EL1_PAN_NOT_SUPPORTED ULL(0x0)
+#define ID_AA64MMFR1_EL1_PAN_SUPPORTED ULL(0x1)
+#define ID_AA64MMFR1_EL1_PAN2_SUPPORTED ULL(0x2)
+#define ID_AA64MMFR1_EL1_PAN3_SUPPORTED ULL(0x3)
+
/* ID_AA64MMFR2_EL1 definitions */
#define ID_AA64MMFR2_EL1 S3_0_C0_C7_2
@@ -289,6 +297,7 @@
#define SCTLR_WXN_BIT (ULL(1) << 19)
#define SCTLR_UWXN_BIT (ULL(1) << 20)
#define SCTLR_IESB_BIT (ULL(1) << 21)
+#define SCTLR_SPAN_BIT (ULL(1) << 23)
#define SCTLR_E0E_BIT (ULL(1) << 24)
#define SCTLR_EE_BIT (ULL(1) << 25)
#define SCTLR_UCI_BIT (ULL(1) << 26)
@@ -371,6 +380,7 @@
#define HCR_AMVOFFEN_BIT (ULL(1) << 51)
#define HCR_API_BIT (ULL(1) << 41)
#define HCR_APK_BIT (ULL(1) << 40)
+#define HCR_E2H_BIT (ULL(1) << 34)
#define HCR_TGE_BIT (ULL(1) << 27)
#define HCR_RW_SHIFT U(31)
#define HCR_RW_BIT (ULL(1) << HCR_RW_SHIFT)
@@ -952,6 +962,12 @@
#define ERXPFGCTL_CDEN_BIT (U(1) << 31)
/*******************************************************************************
+ * Armv8.1 Registers - Privileged Access Never Registers
+ ******************************************************************************/
+#define PAN S3_0_C4_C2_3
+#define PAN_BIT BIT(22)
+
+/*******************************************************************************
* Armv8.3 Pointer Authentication Registers
******************************************************************************/
#define APIAKeyLo_EL1 S3_0_C2_C1_0
diff --git a/include/lib/aarch64/arch_features.h b/include/lib/aarch64/arch_features.h
index 15eb784a7..0ecd03955 100644
--- a/include/lib/aarch64/arch_features.h
+++ b/include/lib/aarch64/arch_features.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -17,6 +17,12 @@ static inline bool is_armv7_gentimer_present(void)
return true;
}
+static inline bool is_armv8_1_pan_present(void)
+{
+ return ((read_id_aa64mmfr1_el1() >> ID_AA64MMFR1_EL1_PAN_SHIFT) &
+ ID_AA64MMFR1_EL1_PAN_MASK) != 0U;
+}
+
static inline bool is_armv8_2_sve_present(void)
{
return ((read_id_aa64pfr0_el1() >> ID_AA64PFR0_SVE_SHIFT) &
@@ -56,6 +62,12 @@ static inline bool is_armv8_3_pauth_gpa_gpi_present(void)
return (read_id_aa64isar1_el1() & mask) != 0U;
}
+static inline bool is_armv8_4_dit_present(void)
+{
+ return ((read_id_aa64pfr0_el1() >> ID_AA64PFR0_DIT_SHIFT) &
+ ID_AA64PFR0_DIT_MASK) == 1U;
+}
+
static inline bool is_armv8_4_ttst_present(void)
{
return ((read_id_aa64mmfr2_el1() >> ID_AA64MMFR2_EL1_ST_SHIFT) &
diff --git a/include/lib/aarch64/arch_helpers.h b/include/lib/aarch64/arch_helpers.h
index 39f1e3b87..801ad082b 100644
--- a/include/lib/aarch64/arch_helpers.h
+++ b/include/lib/aarch64/arch_helpers.h
@@ -187,6 +187,8 @@ DEFINE_SYSREG_READ_FUNC(id_afr0_el1)
DEFINE_SYSREG_READ_FUNC(CurrentEl)
DEFINE_SYSREG_READ_FUNC(ctr_el0)
DEFINE_SYSREG_RW_FUNCS(daif)
+DEFINE_SYSREG_RW_FUNCS(nzcv)
+DEFINE_SYSREG_READ_FUNC(spsel)
DEFINE_SYSREG_RW_FUNCS(spsr_el1)
DEFINE_SYSREG_RW_FUNCS(spsr_el2)
DEFINE_SYSREG_RW_FUNCS(spsr_el3)
@@ -292,6 +294,7 @@ void __dead2 smc(uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3,
DEFINE_SYSREG_READ_FUNC(midr_el1)
DEFINE_SYSREG_READ_FUNC(mpidr_el1)
DEFINE_SYSREG_READ_FUNC(id_aa64mmfr0_el1)
+DEFINE_SYSREG_READ_FUNC(id_aa64mmfr1_el1)
DEFINE_SYSREG_RW_FUNCS(scr_el3)
DEFINE_SYSREG_RW_FUNCS(hcr_el2)
@@ -451,6 +454,9 @@ DEFINE_RENAME_SYSREG_READ_FUNC(erxaddr_el1, ERXADDR_EL1)
DEFINE_RENAME_SYSREG_READ_FUNC(erxmisc0_el1, ERXMISC0_EL1)
DEFINE_RENAME_SYSREG_READ_FUNC(erxmisc1_el1, ERXMISC1_EL1)
+/* Armv8.1 Registers */
+DEFINE_RENAME_SYSREG_RW_FUNCS(pan, PAN)
+
/* Armv8.2 Registers */
DEFINE_RENAME_SYSREG_READ_FUNC(id_aa64mmfr2_el1, ID_AA64MMFR2_EL1)
@@ -479,6 +485,9 @@ DEFINE_RENAME_SYSREG_RW_FUNCS(tfsr_el1, TFSR_EL1)
DEFINE_RENAME_SYSREG_RW_FUNCS(rgsr_el1, RGSR_EL1)
DEFINE_RENAME_SYSREG_RW_FUNCS(gcr_el1, GCR_EL1)
+/* Armv8.4 Data Independent Timing */
+DEFINE_RENAME_SYSREG_RW_FUNCS(dit, DIT)
+
/* Armv8.6 Fine Grained Virtualization Traps Registers */
DEFINE_RENAME_SYSREG_RW_FUNCS(hfgrtr_el2, HFGRTR_EL2)
DEFINE_RENAME_SYSREG_RW_FUNCS(hfgwtr_el2, HFGWTR_EL2)
diff --git a/tftf/tests/runtime_services/standard_service/sdei/system_tests/sdei_entrypoint.S b/tftf/tests/runtime_services/standard_service/sdei/system_tests/sdei_entrypoint.S
index 74fe4a60c..a88723465 100644
--- a/tftf/tests/runtime_services/standard_service/sdei/system_tests/sdei_entrypoint.S
+++ b/tftf/tests/runtime_services/standard_service/sdei/system_tests/sdei_entrypoint.S
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -13,6 +13,7 @@
.globl sdei_entrypoint_resume
.globl sdei_handler_done
.globl sdei_rm_any_entrypoint
+ .globl sdei_check_pstate_entrypoint
.local event_handled
.comm event_handled, PLATFORM_CORE_COUNT * 4, 8
@@ -126,6 +127,33 @@ func sdei_rm_any_entrypoint
b .
endfunc sdei_rm_any_entrypoint
+func sdei_check_pstate_entrypoint
+ stp x2, x30, [sp, #-16]!
+
+ /* Dispatch to C handler */
+ bl sdei_check_pstate_handler
+
+ /* Calculate address of event completion variable */
+ mrs x0, mpidr_el1
+ mov_imm x1, MPID_MASK
+ and x0, x0, x1
+ bl platform_get_core_pos
+ lsl x0, x0, #2
+ adrp x1, event_handled
+ add x1, x1, :lo12:event_handled
+ add x1, x0, x1
+
+ /* Mark event handling as complete so `sdei_handler_done` can return */
+ mov w2, #1
+ str w2, [x1]
+ sev
+
+ /* Populate `x0` and `x1` to prepare for SMC call */
+ ldp x1, x30, [sp], #16
+ mov_imm x0, SDEI_EVENT_COMPLETE_AND_RESUME
+ smc #0
+endfunc sdei_check_pstate_entrypoint
+
#else /* AARCH32 */
func sdei_entrypoint
/* SDEI is not supported on AArch32. */
diff --git a/tftf/tests/runtime_services/standard_service/sdei/system_tests/test_sdei_pstate.c b/tftf/tests/runtime_services/standard_service/sdei/system_tests/test_sdei_pstate.c
new file mode 100644
index 000000000..024352e9c
--- /dev/null
+++ b/tftf/tests/runtime_services/standard_service/sdei/system_tests/test_sdei_pstate.c
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_features.h>
+#include <arch_helpers.h>
+#include <debug.h>
+#include <events.h>
+#include <plat_topology.h>
+#include <platform.h>
+#include <power_management.h>
+#include <sdei.h>
+#include <test_helpers.h>
+#include <tftf_lib.h>
+#include <timer.h>
+
+#ifdef __aarch64__
+
+#define EV_COOKIE 0xDEADBEEF
+
+extern sdei_handler_t sdei_check_pstate_entrypoint;
+
+u_register_t daif;
+u_register_t sp;
+u_register_t pan;
+u_register_t dit;
+
+int sdei_check_pstate_handler(int ev, unsigned long long arg)
+{
+ printf("%s: handler fired\n", __func__);
+ daif = read_daif();
+ sp = read_spsel();
+ if (is_armv8_1_pan_present())
+ pan = read_pan();
+
+ if (is_armv8_4_dit_present())
+ dit = read_dit();
+
+ assert(arg == EV_COOKIE);
+ return 0;
+}
+
+static test_result_t sdei_event_check_pstate(void)
+{
+ long long ret;
+
+ ret = sdei_event_register(0, sdei_check_pstate_entrypoint, EV_COOKIE,
+ SDEI_REGF_RM_PE, read_mpidr_el1());
+ if (ret < 0) {
+ tftf_testcase_printf("SDEI event register failed: 0x%llx\n",
+ ret);
+ return TEST_RESULT_FAIL;
+ }
+
+ ret = sdei_event_enable(0);
+ if (ret < 0) {
+ tftf_testcase_printf("SDEI event enable failed: 0x%llx\n", ret);
+ goto err0;
+ }
+
+ ret = sdei_pe_unmask();
+ if (ret < 0) {
+ tftf_testcase_printf("SDEI pe unmask failed: 0x%llx\n", ret);
+ goto err1;
+ }
+
+ /* Check the common bits are set correctly */
+ ret = sdei_event_signal(read_mpidr_el1());
+ if (ret < 0) {
+ tftf_testcase_printf("SDEI event signal failed: 0x%llx\n", ret);
+ goto err2;
+ }
+ sdei_handler_done();
+
+ u_register_t all_interrupts_masked = 0x3c0;
+
+ if (daif != all_interrupts_masked) {
+ tftf_testcase_printf("Interrupts were not correctly masked " \
+ "during SDEI event signal\n" \
+ "Expected DAIF: 0x%lx, " \
+ "Actual DAIF: 0x%lx\n",
+ all_interrupts_masked, daif);
+ ret = -1;
+ goto err1;
+ }
+
+ u_register_t use_sp_elx = 0x1;
+
+ if (sp != use_sp_elx) {
+ tftf_testcase_printf("The SPSel PSTATE Bit was not set " \
+ "correctly during SDEI event signal\n" \
+ "Expected SPSel: 0x%lx, " \
+ "Actual SPSel: 0x%lx\n",
+ use_sp_elx, sp);
+ ret = -1;
+ goto err1;
+ }
+
+ if (is_armv8_1_pan_present()) {
+ printf("PAN Enabled so testing PAN PSTATE bit\n");
+ /*
+ * Check that when the SPAN bit is 0
+ * the PAN PSTATE bit is maintained
+ */
+
+ /* When PAN bit is 0 */
+ u_register_t expected_pan = 0;
+
+ write_pan(expected_pan);
+ ret = sdei_event_signal(read_mpidr_el1());
+ if (ret < 0) {
+ tftf_testcase_printf("SDEI event signal failed: " \
+ "0x%llx\n", ret);
+ goto err2;
+ }
+ sdei_handler_done();
+ if (pan != expected_pan) {
+ tftf_testcase_printf("PAN PSTATE bit not maintained " \
+ "during SDEI event signal\n" \
+ "Expected PAN: 0x%lx, " \
+ "Actual PAN: 0x%lx\n",
+ expected_pan, pan);
+ ret = -1;
+ goto err1;
+ }
+
+ /* When PAN bit is 1 */
+ expected_pan = PAN_BIT;
+ write_pan(expected_pan);
+ ret = sdei_event_signal(read_mpidr_el1());
+ if (ret < 0) {
+ tftf_testcase_printf("SDEI event signal failed: " \
+ "0x%llx\n", ret);
+ goto err2;
+ }
+ sdei_handler_done();
+ if (pan != expected_pan) {
+ tftf_testcase_printf("PAN PSTATE bit not maintained " \
+ "during SDEI event signal\n" \
+ "Expected PAN: 0x%lx, " \
+ "Actual PAN: 0x%lx\n",
+ expected_pan, pan);
+ ret = -1;
+ goto err1;
+ }
+
+ /* Test that the SPAN condition is met */
+ /* Set the SPAN bit */
+ u_register_t old_sctlr = read_sctlr_el2();
+
+ write_sctlr_el2(old_sctlr & ~SCTLR_SPAN_BIT);
+
+ expected_pan = 0;
+ /*
+ * Check that when the HCR_EL2.{E2H, TGE} != {1, 1}
+ * the PAN bit is maintained
+ */
+ ret = sdei_event_signal(read_mpidr_el1());
+ if (ret < 0) {
+ tftf_testcase_printf("SDEI event signal failed: " \
+ "0x%llx\n", ret);
+ goto err2;
+ }
+ sdei_handler_done();
+ if (pan != expected_pan) {
+ tftf_testcase_printf("PAN PSTATE bit not maintained " \
+ "during SDEI event signal " \
+ "when the SPAN bit is set and " \
+ "HCR_EL2.{E2H, TGE} != {1, 1}\n" \
+ "Expected PAN: 0x%lx, " \
+ "Actual PAN: 0x%lx\n",
+ expected_pan, pan);
+ ret = -1;
+ goto err1;
+ }
+
+ expected_pan = PAN_BIT;
+ write_pan(expected_pan);
+ ret = sdei_event_signal(read_mpidr_el1());
+ if (ret < 0) {
+ tftf_testcase_printf("SDEI event signal failed: " \
+ "0x%llx\n", ret);
+ goto err2;
+ }
+ sdei_handler_done();
+ if (pan != expected_pan) {
+ tftf_testcase_printf("PAN PSTATE bit not maintained " \
+ "during SDEI event signal " \
+ "when the SPAN bit is set and " \
+ "HCR_EL2.{E2H, TGE} != {1, 1}\n" \
+ "Expected PAN: 0x%lx, " \
+ "Actual PAN: 0x%lx\n",
+ expected_pan, pan);
+ ret = -1;
+ goto err1;
+ }
+
+ /*
+ * Check that when the HCR_EL2.{E2H, TGE} = {1, 1}
+ * PAN bit is forced to 1
+ */
+ /* Set E2H Bit */
+ u_register_t old_hcr_el2 = read_hcr_el2();
+
+ write_hcr_el2(old_hcr_el2 | HCR_E2H_BIT);
+
+ ret = sdei_event_signal(read_mpidr_el1());
+ if (ret < 0) {
+ tftf_testcase_printf("SDEI event signal failed: " \
+ "0x%llx\n", ret);
+ goto err2;
+ }
+ sdei_handler_done();
+ if (pan != PAN_BIT) {
+ tftf_testcase_printf("PAN PSTATE bit was not forced " \
+ "to 1 during SDEI event signal " \
+ "when the SPAN bit is set and " \
+ "HCR_EL2.{E2H, TGE} = {1, 1}\n");
+ ret = -1;
+ goto err1;
+ }
+
+ /*
+ * Set the SCTLR and HCR_EL2 registers back to their old values
+ */
+ write_sctlr_el2(old_sctlr);
+ write_hcr_el2(old_hcr_el2);
+ }
+
+ /* Check that the DIT PSTATE bit is maintained during event signal */
+ if (is_armv8_4_dit_present()) {
+ printf("DIT Enabled so testing DIT PSTATE bit\n");
+ /* When DIT bit is 0 */
+ u_register_t expected_dit = 0;
+
+ write_dit(expected_dit);
+ ret = sdei_event_signal(read_mpidr_el1());
+
+ if (ret < 0) {
+ tftf_testcase_printf("SDEI event signal failed: " \
+ "0x%llx\n", ret);
+ goto err2;
+ }
+ sdei_handler_done();
+ if (dit != expected_dit) {
+ tftf_testcase_printf("DIT PSTATE bit not maintained " \
+ "during SDEI event signal\n" \
+ "Expected DIT: 0x%lx, " \
+ "Actual DIT: 0x%lx\n",
+ expected_dit, dit);
+ ret = -1;
+ goto err1;
+ }
+
+ /* When dit bit is 1 */
+ expected_dit = DIT_BIT;
+ write_dit(expected_dit);
+ ret = sdei_event_signal(read_mpidr_el1());
+ if (ret < 0) {
+ tftf_testcase_printf("SDEI event signal failed: " \
+ "0x%llx\n", ret);
+ goto err2;
+ }
+ sdei_handler_done();
+ if (dit != expected_dit) {
+ tftf_testcase_printf("DIT PSTATE bit not maintained " \
+ "during SDEI event signal\n" \
+ "Expected DIT: 0x%lx, " \
+ "Actual DIT: 0x%lx\n",
+ expected_dit, dit);
+ ret = -1;
+ goto err1;
+ }
+ }
+
+err2:
+ sdei_pe_mask();
+err1:
+ sdei_event_disable(0);
+err0:
+ sdei_event_unregister(0);
+
+ if (ret < 0)
+ return TEST_RESULT_FAIL;
+
+ return TEST_RESULT_SUCCESS;
+}
+#endif /* __aarch64__ */
+
+/* Each core signals itself using SDEI event signalling. */
+test_result_t test_sdei_event_check_pstate(void)
+{
+ SKIP_TEST_IF_AARCH32();
+#ifdef __aarch64__
+ long long ret;
+
+ ret = sdei_version();
+ if (ret != MAKE_SDEI_VERSION(1, 0, 0)) {
+ tftf_testcase_printf("Unexpected SDEI version: 0x%llx\n", ret);
+ return TEST_RESULT_SKIPPED;
+ }
+
+ disable_irq();
+ /* We only need to run these tests on the main CPU */
+ if (sdei_event_check_pstate() != TEST_RESULT_SUCCESS) {
+ ret = -1;
+ goto err0;
+ }
+
+err0:
+ enable_irq();
+ if (ret < 0)
+ return TEST_RESULT_FAIL;
+ return TEST_RESULT_SUCCESS;
+#endif /* __aarch64__ */
+}
diff --git a/tftf/tests/tests-sdei.mk b/tftf/tests/tests-sdei.mk
index 0c495d99f..e73bfb72b 100644
--- a/tftf/tests/tests-sdei.mk
+++ b/tftf/tests/tests-sdei.mk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2020, Arm Limited. All rights reserved.
+# Copyright (c) 2020-2021, Arm Limited. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -10,4 +10,5 @@ TESTS_SOURCES += \
test_sdei.c \
test_sdei_state.c \
test_sdei_rm_any.c \
+ test_sdei_pstate.c \
)
diff --git a/tftf/tests/tests-sdei.xml b/tftf/tests/tests-sdei.xml
index 147835bc5..38c7c0d0e 100644
--- a/tftf/tests/tests-sdei.xml
+++ b/tftf/tests/tests-sdei.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (c) 2020, Arm Limited. All rights reserved.
+ Copyright (c) 2020-2021, Arm Limited. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause
-->
@@ -15,6 +15,7 @@
<testcase name="SDEI event signaling: each core signals itself" function="test_sdei_event_signal_serial" />
<testcase name="SDEI event signaling: one core signals all others" function="test_sdei_event_signal_all" />
<testcase name="SDEI event routing all: SPI events routed to all CPUs" function="test_sdei_routing_any" />
+ <testcase name="SDEI event handler pstate testing" function="test_sdei_event_check_pstate" />
</testsuite>
</testsuites>