test(realm): validate NS EL1/EL2 context is preserved by RMM
- Test validates that NS EL1/EL2 registers are preserved while
entering and exiting realm world.
- Test validates that accessing s2por_el1 in realm causes data abort.
Change-Id: I20cbb9d0d59474507f89ee7cf8e127fff4706610
Signed-off-by: Shruti Gupta <shruti.gupta@arm.com>
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 763306f..3eefd25 100644
--- a/include/runtime_services/host_realm_managment/host_shared_data.h
+++ b/include/runtime_services/host_realm_managment/host_shared_data.h
@@ -45,6 +45,7 @@
enum realm_cmd {
REALM_SLEEP_CMD = 1U,
REALM_LOOP_CMD,
+ REALM_S2POE_ACCESS,
REALM_MPAM_ACCESS,
REALM_MPAM_PRESENT,
REALM_MULTIPLE_REC_PSCI_DENIED_CMD,
diff --git a/realm/realm_payload_main.c b/realm/realm_payload_main.c
index d364aa0..be555fa 100644
--- a/realm/realm_payload_main.c
+++ b/realm/realm_payload_main.c
@@ -144,6 +144,18 @@
}
}
+static bool test_realm_s2poe_undef_abort(void)
+{
+ realm_reset_undef_abort_count();
+
+ /* Install exception handler to catch undefined abort */
+ register_custom_sync_exception_handler(realm_sync_exception_handler);
+ write_s2por_el1(0UL);
+ unregister_custom_sync_exception_handler();
+
+ return (realm_get_undef_abort_count() != 0UL);
+}
+
/*
* This function requests RSI/ABI version from RMM.
*/
@@ -390,6 +402,9 @@
case REALM_PLANE_N_REG_RW_CMD:
test_succeed = test_realm_enter_plane_n_reg_rw();
break;
+ case REALM_S2POE_ACCESS:
+ test_succeed = test_realm_s2poe_undef_abort();
+ break;
case REALM_MPAM_ACCESS:
test_succeed = test_realm_mpam_undef_abort();
break;
diff --git a/tftf/tests/runtime_services/realm_payload/host_realm_payload_tests.c b/tftf/tests/runtime_services/realm_payload/host_realm_payload_tests.c
index 06e6475..8038fb4 100644
--- a/tftf/tests/runtime_services/realm_payload/host_realm_payload_tests.c
+++ b/tftf/tests/runtime_services/realm_payload/host_realm_payload_tests.c
@@ -13,6 +13,8 @@
#include <drivers/arm/arm_gic.h>
#include <drivers/arm/gic_v3.h>
#include <heap/page_alloc.h>
+#include <lib/context_mgmt/context_el1.h>
+#include <lib/context_mgmt/context_el2.h>
#include <pauth.h>
#include <test_helpers.h>
@@ -27,6 +29,10 @@
static struct realm realm[MAX_REALM_COUNT];
static struct pmu_registers pmu_state;
+static el1_ctx_regs_t el1_ctx_before = {0};
+static el1_ctx_regs_t el1_ctx_after = {0};
+static el2_sysregs_t el2_ctx_before = {0};
+static el2_sysregs_t el2_ctx_after = {0};
#if ENABLE_PAUTH
static uint128_t pauth_keys_before[NUM_KEYS];
@@ -148,6 +154,14 @@
return TEST_RESULT_FAIL;
}
+ /* save EL1 registers */
+ save_el1_sysregs_context(&el1_ctx_before);
+ modify_el1_context_sysregs(&el1_ctx_before, NS_CORRUPT_EL1_REGS);
+ save_el1_sysregs_context(&el1_ctx_before);
+
+ /* save EL2 registers */
+ el2_save_registers(&el2_ctx_before);
+
/* CMD for Plane N */
for (unsigned int j = 1U; j <= MAX_AUX_PLANE_COUNT; j++) {
host_shared_data_set_realm_cmd(&realm, REALM_SLEEP_CMD, j, 0U);
@@ -171,6 +185,28 @@
run->exit.esr, run->exit.far);
}
}
+
+ /* save EL1 registers */
+ save_el1_sysregs_context(&el1_ctx_after);
+
+ INFO("Comparing EL1 registers\n");
+ ret2 = compare_el1_contexts(&el1_ctx_before, &el1_ctx_after);
+ if (!ret2) {
+ ERROR("NS EL1 registers corrupted\n");
+ host_destroy_realm(&realm);
+ return TEST_RESULT_FAIL;
+ }
+
+ /* save EL2 registers */
+ el2_save_registers(&el2_ctx_after);
+
+ INFO("Comparing EL2 registers\n");
+ if (memcmp(&el2_ctx_before, &el2_ctx_after, sizeof(el2_sysregs_t))) {
+ ERROR("NS EL2 registers corrupted\n");
+ host_destroy_realm(&realm);
+ return TEST_RESULT_FAIL;
+ }
+
ret2 = host_destroy_realm(&realm);
if (!ret1 || !ret2) {
@@ -185,7 +221,9 @@
/*
* @Test_Aim@ Test realm payload creation with 3 Aux Planes, enter all Planes
* Host cannot enter Aux Planes directly,
- * Host will enter P0, P0 will enter aux plane
+ * Host will enter P0, P0 will enter aux plane.
+ * This test also validates that NS EL1 and NS EL2 registers are preserved by RMM.
+ * This test also validates that s2por_el1 register is not accessible in realm.
*/
test_result_t host_test_realm_create_planes_enter_single_rtt(void)
{
@@ -225,6 +263,12 @@
HOST_ARG1_INDEX, SLEEP_TIME_MS);
}
+ save_el1_sysregs_context(&el1_ctx_before);
+ modify_el1_context_sysregs(&el1_ctx_before, NS_CORRUPT_EL1_REGS);
+ save_el1_sysregs_context(&el1_ctx_before);
+
+ el2_save_registers(&el2_ctx_before);
+
for (unsigned int j = 1U; j <= MAX_AUX_PLANE_COUNT; j++) {
run = (struct rmi_rec_run *)realm.run[0U];
@@ -232,14 +276,43 @@
ret1 = host_enter_realm_execute(&realm, REALM_ENTER_PLANE_N_CMD,
RMI_EXIT_HOST_CALL, 0U);
- if (run->exit.exit_reason != RMI_EXIT_HOST_CALL) {
+ if (!ret1) {
ERROR("Rec0 error exit=0x%lx ret1=%d HPFAR=0x%lx \
esr=0x%lx far=0x%lx\n",
run->exit.exit_reason, ret1,
run->exit.hpfar,
run->exit.esr, run->exit.far);
+ goto destroy_realm;
}
}
+
+ save_el1_sysregs_context(&el1_ctx_before);
+
+ INFO("Comparing EL1 registers\n");
+ ret1 = compare_el1_contexts(&el1_ctx_before, &el1_ctx_after);
+
+ if (!ret1) {
+ ERROR("NS EL1 registers corrupted\n");
+ goto destroy_realm;
+ }
+
+ el2_save_registers(&el2_ctx_after);
+
+ INFO("Comparing EL2 registers\n");
+ if (memcmp(&el2_ctx_before, &el2_ctx_after, sizeof(el2_sysregs_t))) {
+ ERROR("NS EL2 registers corrupted\n");
+ goto destroy_realm;
+ }
+
+ /* Test that realm cannot modify s2por_el1 */
+ ret1 = host_enter_realm_execute(&realm, REALM_S2POE_ACCESS,
+ RMI_EXIT_HOST_CALL, 0U);
+
+ if (!ret1) {
+ ERROR("S2POR_EL1 reg access test failed\n");
+ }
+
+destroy_realm:
ret2 = host_destroy_realm(&realm);
if (!ret1 || !ret2) {