feat(rme): test access outside PAR from Plane N
Signed-off-by: Javier Almansa Sobrino <javier.almansasobrino@arm.com>
Change-Id: I3c5069e14fdf27e6c36bd1e0651ceff4ee7396ef
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 744e14a..a698395 100644
--- a/include/runtime_services/host_realm_managment/host_shared_data.h
+++ b/include/runtime_services/host_realm_managment/host_shared_data.h
@@ -83,7 +83,8 @@
REALM_ATTESTATION_FAULT,
REALM_ENTER_PLANE_N_CMD,
REALM_PLANE_N_REG_RW_CMD,
- REALM_WRITE_BRBCR_EL1
+ REALM_WRITE_BRBCR_EL1,
+ REALM_PLANE_N_INST_FETCH_ABORT
};
/*
diff --git a/realm/realm_payload_main.c b/realm/realm_payload_main.c
index 70687f1..248d191 100644
--- a/realm/realm_payload_main.c
+++ b/realm/realm_payload_main.c
@@ -336,6 +336,29 @@
return false;
}
+static bool test_realm_plane_n_inst_fetch(void)
+{
+ u_register_t esr, far, test_ipa;
+
+ bool ret = test_realm_enter_plane_n();
+
+ if (!ret) {
+ ERROR("Failed to enter Plane N\n");
+ return false;
+ }
+
+ esr = run.exit.esr;
+ far = run.exit.far;
+ test_ipa = realm_shared_data_get_my_host_val(HOST_ARG2_INDEX);
+
+ if ((EC_BITS(esr) != EC_IABORT_LOWER_EL) || (far != test_ipa)) {
+ ERROR("Plane N: incorrect ESR=0x%lx FAR=0x%lx\n", esr, far);
+ return false;
+ }
+
+ return true;
+}
+
static bool realm_exception_handler(void)
{
u_register_t base, far, esr, elr;
@@ -348,11 +371,24 @@
if (far == base) {
/* Return ESR to Host */
realm_shared_data_set_my_realm_val(HOST_ARG2_INDEX, esr);
- rsi_exit_to_host(HOST_CALL_EXIT_SUCCESS_CMD);
+ if (realm_is_plane0()) {
+ rsi_exit_to_host(HOST_CALL_EXIT_SUCCESS_CMD);
+ } else {
+ realm_shared_data_set_my_realm_val(HOST_ARG3_INDEX, far);
+ psi_exit_to_plane0(PSI_CALL_EXIT_SUCCESS_CMD,
+ 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
+ }
}
+
realm_printf("Realm Abort fail incorrect FAR=0x%lx ESR=0x%lx ELR=0x%lx\n",
far, esr, elr);
- rsi_exit_to_host(HOST_CALL_EXIT_FAILED_CMD);
+
+ if (realm_is_plane0()) {
+ rsi_exit_to_host(HOST_CALL_EXIT_FAILED_CMD);
+ } else {
+ psi_exit_to_plane0(PSI_CALL_EXIT_FAILED_CMD,
+ 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
+ }
/* Should not return */
return false;
@@ -558,6 +594,9 @@
case REALM_WRITE_BRBCR_EL1:
test_succeed = test_realm_write_brbcr_el1_reg();
break;
+ case REALM_PLANE_N_INST_FETCH_ABORT:
+ test_succeed = test_realm_plane_n_inst_fetch();
+ break;
default:
realm_printf("%s() invalid cmd %u\n", __func__, cmd);
break;
diff --git a/realm/realm_plane.c b/realm/realm_plane.c
index 656c688..a29a1ca 100644
--- a/realm/realm_plane.c
+++ b/realm/realm_plane.c
@@ -150,6 +150,10 @@
ret = realm_exit_to_host_as_plane_n(HOST_CALL_EXIT_PRINT_CMD, plane_index);
run->enter.gprs[0] = ret;
return PSI_RETURN_TO_PN;
+ case PSI_CALL_EXIT_SUCCESS_CMD:
+ case PSI_CALL_EXIT_FAILED_CMD:
+ run->exit.gprs[0] = hvc_id;
+ return PSI_RETURN_TO_P0;
case PSI_P0_CALL:
default:
return PSI_RETURN_TO_P0;
@@ -207,8 +211,8 @@
ret = handle_plane_exit(plane_index, perm_index, run);
- if (ret != PSI_RETURN_TO_PN) {
- return true;
+ if (ret == PSI_RETURN_TO_P0) {
+ return !(run->exit.gprs[0] == PSI_CALL_EXIT_FAILED_CMD);
}
}
}
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 2478d4f..a598e16 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
@@ -96,6 +96,7 @@
}
return host_cmp_result();
}
+
/*
* @Test_Aim@ Test realm payload creation with 3 Aux Planes, enter all Planes
* Host cannot enter Aux Planes directly,
@@ -307,6 +308,146 @@
}
/*
+ * @Test_Aim@ Test that an access from Pn to an unprotected IPA ouside the PAR
+ * causes an undefined abort taken to P0.
+ */
+test_result_t host_test_realm_pn_access_outside_par(void)
+{
+ struct realm realm;
+ u_register_t feature_flag0;
+ u_register_t feature_reg0;
+ u_register_t esr, far;
+ u_register_t test_ipa;
+ unsigned long s2sz;
+ struct rmi_rec_run *run;
+ bool iaccess_pass = false, daccess_pass = false;
+ u_register_t rec_flag[] = {RMI_RUNNABLE, RMI_RUNNABLE};
+
+ SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
+
+ /* Test is skipped if S2POE is not supported so to keep it simpler */
+ if (!(are_planes_supported() && is_single_rtt_supported())) {
+ return TEST_RESULT_SKIPPED;
+ }
+
+ /* Read Realm Feature Reg 0 */
+ if (host_rmi_features(0UL, &feature_reg0) != REALM_SUCCESS) {
+ ERROR("%s() failed\n", "host_rmi_features");
+ return TEST_RESULT_FAIL;
+ }
+
+ /*
+ * Calculate the IPA range for the realm. This would be below the
+ * maximum supported by the architecture.
+ */
+ s2sz = EXTRACT(RMI_FEATURE_REGISTER_0_S2SZ, feature_reg0);
+ feature_flag0 = INPLACE(RMI_FEATURE_REGISTER_0_S2SZ, s2sz - 5U);
+
+ if (!host_create_activate_realm_payload(&realm, (u_register_t)REALM_IMAGE_BASE,
+ feature_flag0, 0U, RTT_MIN_LEVEL, rec_flag, 2U, 1U)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Generate IPA ouside the PAR to test */
+ test_ipa = TFTF_BASE | (1UL << (EXTRACT(RMI_FEATURE_REGISTER_0_S2SZ,
+ realm.rmm_feat_reg0) + 1U));
+
+ /* Instruct Plane0 to enter Plane1 on REC 0 */
+ host_realm_set_aux_plane_args(&realm, 1U, 0U);
+
+ /* Instruct Plane1 on Rec0 to execute REALM_DATA_ACCESS_CMD */
+ host_shared_data_set_realm_cmd(&realm, REALM_DATA_ACCESS_CMD, 1U, 0U);
+
+ /*
+ * Argument for REALM_DATA_ACCESS_CMD on Plane 1: Try to do a data
+ * access to the address @test_ipa.
+ */
+ host_shared_data_set_host_val(&realm, 1U, 0U, HOST_ARG3_INDEX, test_ipa);
+
+ run = (struct rmi_rec_run *)realm.run[0U];
+
+ daccess_pass = host_enter_realm_execute(&realm,
+ REALM_PLANE_N_EXCEPTION_CMD,
+ RMI_EXIT_HOST_CALL, 0U);
+
+ if (!daccess_pass) {
+ ERROR("Couldn't enter to REC0\n");
+ goto destroy_realm;
+ }
+
+ /*
+ * Data access from Plane N outside of the PAR causes an exception
+ * taken to Plane N.
+ *
+ * Upon exception, Plane N will return back to Plane 0 passing esr
+ * and far values, which in turn will be forwarded to the host for
+ * further validation.
+ */
+ esr = host_shared_data_get_realm_val(&realm, 1U, 0U, HOST_ARG2_INDEX);
+ far = host_shared_data_get_realm_val(&realm, 1U, 0U, HOST_ARG3_INDEX);
+
+ if (run->exit.exit_reason != RMI_EXIT_HOST_CALL) {
+ ERROR("Rec0 error exit=0x%lx HPFAR=0x%lx \
+ esr=0x%lx far=0x%lx\n",
+ run->exit.exit_reason,
+ run->exit.hpfar,
+ esr, far);
+ daccess_pass = false;
+ goto destroy_realm;
+ }
+
+ if ((EC_BITS(esr) != EC_DABORT_CUR_EL) || (far != test_ipa)) {
+ ERROR("Rec0, Plane 1: incorrect ESR=0x%lx FAR=0x%lx\n", esr, far);
+ daccess_pass = false;
+ goto destroy_realm;
+ }
+ INFO("Rec0 ESR=0x%lx\n", esr);
+
+ /*
+ * Instruct Plane0 to enter Plane1 on REC 1.
+ * We use REC 1 for convenience, as this avoids the need to
+ * reboot REC 0, simplifying the test.
+ */
+ host_realm_set_aux_plane_args(&realm, 1U, 1U);
+
+ /* Instruct Plane1 on Rec1 to execute REALM_INSTR_FETCH_CMD */
+ host_shared_data_set_realm_cmd(&realm, REALM_INSTR_FETCH_CMD, 1U, 1U);
+
+ /*
+ * Argument for REALM_INSTR_FETCH_CMD on Plane 1: Address where to
+ * attempt the instruction fetch.
+ */
+ host_shared_data_set_host_val(&realm, 1U, 1U, HOST_ARG3_INDEX, test_ipa);
+
+ /*
+ * Argument for REALM_PLANE_N_INST_FETCH_ABORT on Plane 0.
+ *
+ * An instruction fetch outside PAR from Plane N causes a Plane exit
+ * due to instruction abort. We pass here the expected address at
+ * which the attempted fetch took place so that Plane 0 can match it
+ * against the address reported at run.exit.far.
+ */
+ host_shared_data_set_host_val(&realm, 0U, 1U, HOST_ARG2_INDEX, test_ipa);
+
+ run = (struct rmi_rec_run *)realm.run[0U];
+
+ iaccess_pass = host_enter_realm_execute(&realm,
+ REALM_PLANE_N_INST_FETCH_ABORT,
+ RMI_EXIT_HOST_CALL, 1U);
+
+ if (!iaccess_pass) {
+ ERROR("Failed to cause instruction abort on Plane N\n");
+ }
+
+destroy_realm:
+
+ if (!host_destroy_realm(&realm) || !daccess_pass || !iaccess_pass) {
+ return TEST_RESULT_FAIL;
+ }
+ return host_cmp_result();
+}
+
+/*
* @Test_Aim@ Test realm payload creation, execution and destruction iteratively
*/
test_result_t host_test_realm_create_enter(void)
diff --git a/tftf/tests/tests-realm-payload.xml b/tftf/tests/tests-realm-payload.xml
index b9e83fe..3d88382 100644
--- a/tftf/tests/tests-realm-payload.xml
+++ b/tftf/tests/tests-realm-payload.xml
@@ -88,6 +88,8 @@
function="host_realm_reject_set_ripas" />
<testcase name="Realm FEAT_DoubleFault2"
function="host_test_feat_doublefault2" />
+ <testcase name="Realm Plane N accessing outside PAR"
+ function="host_test_realm_pn_access_outside_par" />
<!-- Test case related to SVE support and SIMD state -->
<testcase name="Check RMI reports proper SVE VL"
function="host_check_rmi_reports_proper_sve_vl" />