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) {