test(realm): handle permission fault for planes
Add support for handling permission fault in planes.
Set s2ap in RTTs.
Signed-off-by: Shruti Gupta <shruti.gupta@arm.com>
Change-Id: I590fc5a1c43357b117fa5cb76e8c699c4c7eebad
diff --git a/include/lib/aarch64/arch.h b/include/lib/aarch64/arch.h
index f0d1398..f4c1d87 100644
--- a/include/lib/aarch64/arch.h
+++ b/include/lib/aarch64/arch.h
@@ -1037,13 +1037,22 @@
#define EC_AARCH32_FP U(0x28)
#define EC_AARCH64_FP U(0x2c)
#define EC_SERROR U(0x2f)
+
+/* Common DFSC/IFSC code */
+#define ISS_FSC_MASK U(0x3f)
+#define FSC_L0_ADR_SIZE_FAULT U(0)
+#define FSC_L0_TRANS_FAULT U(4)
+#define FSC_L1_TRANS_FAULT U(5)
+#define FSC_L2_TRANS_FAULT U(6)
+#define FSC_L3_TRANS_FAULT U(7)
+#define FSC_L_MINUS1_TRANS_FAULT U(0x2B)
+#define FSC_L0_PERM_FAULT U(0xC)
+#define FSC_L1_PERM_FAULT U(0xD)
+#define FSC_L2_PERM_FAULT U(0xE)
+#define FSC_L3_PERM_FAULT U(0xF)
+
/* Data Fault Status code, not all error codes listed */
#define ISS_DFSC_MASK U(0x3f)
-#define DFSC_L0_ADR_SIZE_FAULT U(0)
-#define DFSC_L0_TRANS_FAULT U(4)
-#define DFSC_L1_TRANS_FAULT U(5)
-#define DFSC_L2_TRANS_FAULT U(6)
-#define DFSC_L3_TRANS_FAULT U(7)
#define DFSC_NO_WALK_SEA U(0x10)
#define DFSC_L0_SEA U(0x14)
#define DFSC_L1_SEA U(0x15)
@@ -1054,11 +1063,6 @@
/* Instr Fault Status code, not all error codes listed */
#define ISS_IFSC_MASK U(0x3f)
-#define IFSC_L0_ADR_SIZE_FAULT U(0)
-#define IFSC_L0_TRANS_FAULT U(4)
-#define IFSC_L1_TRANS_FAULT U(5)
-#define IFSC_L2_TRANS_FAULT U(6)
-#define IFSC_L3_TRANS_FAULT U(7)
#define IFSC_NO_WALK_SEA U(0x10)
#define IFSC_L0_SEA U(0x24)
#define IFSC_L1_SEA U(0x25)
diff --git a/include/runtime_services/host_realm_managment/host_realm_rmi.h b/include/runtime_services/host_realm_managment/host_realm_rmi.h
index 00435b0..4de9671 100644
--- a/include/runtime_services/host_realm_managment/host_realm_rmi.h
+++ b/include/runtime_services/host_realm_managment/host_realm_rmi.h
@@ -787,7 +787,11 @@
u_register_t far; /* 0x108 */
/* Hypervisor IPA Fault Address register */
u_register_t hpfar; /* 0x110 */
- }, 0x100, 0x200);
+ }, 0x100, 0x118);
+ /* Index of RTT tree active at time of the exit */
+ SET_MEMBER(u_register_t rtt_tree, 0x118, 0x120);/* Offset 0x118 */
+ /* Level of requested RTT */
+ SET_MEMBER(u_register_t rtt_level, 0x120, 0x200);/* Offset 0x120 */
/* General-purpose registers */
SET_MEMBER(u_register_t gprs[REC_EXIT_NR_GPRS], 0x200, 0x300); /* 0x200 */
SET_MEMBER(struct {
@@ -817,7 +821,15 @@
u_register_t ripas_size; /* 0x508 */
/* RIPAS value of pending RIPAS change */
unsigned char ripas_value; /* 0x510 */
- }, 0x500, 0x600);
+ }, 0x500, 0x518);
+ /* Base PA of MMIO region, if RIPAS change
+ * is pending due to exeception of RSI_RDEV_VALIDATE_IO
+ */
+ SET_MEMBER(u_register_t ripas_io_pa, 0x518, 0x520); /* Offset 0x518 */
+ /* Base address of target region for pending S2AP change */
+ SET_MEMBER(u_register_t s2ap_base, 0x520, 0x528); /* Offset 0x520 */
+ /* Top address of target region for pending S2AP change */
+ SET_MEMBER(u_register_t s2ap_top, 0x528, 0x600); /* Offset 0x528 */
/* Host call immediate value */
SET_MEMBER(unsigned int imm, 0x600, 0x700); /* 0x600 */
/* PMU overflow status */
diff --git a/realm/realm_plane.c b/realm/realm_plane.c
index 7affc15..9a604c6 100644
--- a/realm/realm_plane.c
+++ b/realm/realm_plane.c
@@ -67,18 +67,45 @@
}
/* return true to re-enter PlaneN, false to exit to P0 */
-static bool handle_plane_exit(u_register_t plane_index,
+u_register_t handle_plane_exit(u_register_t plane_index,
u_register_t perm_index,
rsi_plane_run *run)
{
u_register_t ec = EC_BITS(run->exit.esr);
u_register_t ret;
+ if (((run->exit.esr & ISS_FSC_MASK) >= FSC_L0_PERM_FAULT) &&
+ ((run->exit.esr & ISS_FSC_MASK) <= FSC_L3_PERM_FAULT)) {
+
+ /* If Plane N exit is due to permission fault, change s2ap */
+ u_register_t base, new_base, response, ret;
+ u_register_t new_cookie = 0UL;
+
+ new_base = base = (run->exit.far & ~PAGE_SIZE_MASK);
+
+ VERBOSE("P0 set s2ap 0x%lx\n", base);
+ while (new_base != (base + PAGE_SIZE)) {
+
+ ret = rsi_mem_set_perm_index(new_base, base + PAGE_SIZE,
+ perm_index, new_cookie, &new_base,
+ &response, &new_cookie);
+
+ if (ret != RSI_SUCCESS || response == RSI_REJECT) {
+ ERROR("rsi_mem_set_perm_index failed 0x%lx\n", new_base);
+ return PSI_RETURN_TO_P0;
+ }
+ }
+
+ restore_plane_context(run);
+ return PSI_RETURN_TO_PN;
+ }
+
/* Disallow SMC from Plane N */
if (ec == EC_AARCH64_SMC) {
+ /* TODO Support PSCI in future */
restore_plane_context(run);
run->enter.gprs[0] = RSI_ERROR_STATE;
- return true;
+ return PSI_RETURN_TO_PN;
}
/* Handle PSI HVC call from Plane N */
@@ -90,22 +117,22 @@
case PSI_CALL_GET_SHARED_BUFF_CMD:
run->enter.gprs[0] = RSI_SUCCESS;
run->enter.gprs[1] = (u_register_t)realm_get_my_shared_structure();
- return true;
+ return PSI_RETURN_TO_PN;
case PSI_CALL_GET_PLANE_ID_CMD:
run->enter.gprs[0] = RSI_SUCCESS;
run->enter.gprs[1] = plane_index;
- return true;
+ return PSI_RETURN_TO_PN;
case PSI_CALL_EXIT_PRINT_CMD:
/* exit to host to flush buffer, then return to PN */
ret = realm_exit_to_host_as_plane_n(HOST_CALL_EXIT_PRINT_CMD, plane_index);
run->enter.gprs[0] = ret;
- return true;
+ return PSI_RETURN_TO_PN;
case PSI_P0_CALL:
default:
- return false;
+ return PSI_RETURN_TO_P0;
}
}
- return false;
+ return PSI_RETURN_TO_P0;
}
static bool plane_common_init(u_register_t plane_index,
@@ -143,7 +170,7 @@
run->enter.flags = flags;
- while (ret1) {
+ while (true) {
ret = rsi_plane_enter(plane_index, (u_register_t)run);
if (ret != RSI_SUCCESS) {
ERROR("Plane %u enter failed ret= 0x%lx\n", plane_index, ret);
@@ -156,8 +183,11 @@
run->exit.hpfar,
run->exit.far);
- ret1 = handle_plane_exit(plane_index, perm_index, run);
+ ret = handle_plane_exit(plane_index, perm_index, run);
+
+ if (ret != PSI_RETURN_TO_PN) {
+ return true;
+ }
}
- return true;
}
diff --git a/tftf/tests/runtime_services/host_realm_managment/host_realm_rmi.c b/tftf/tests/runtime_services/host_realm_managment/host_realm_rmi.c
index 337f2ab..62b360a 100644
--- a/tftf/tests/runtime_services/host_realm_managment/host_realm_rmi.c
+++ b/tftf/tests/runtime_services/host_realm_managment/host_realm_rmi.c
@@ -482,12 +482,12 @@
return REALM_ERROR;
}
}
- ipa_align = ALIGN_DOWN(map_addr, RTT_MAP_SIZE(level - 1));
- ret = host_rmi_rtt_aux_create(realm->rd, rtt, ipa_align, (u_register_t)level,
+ ipa_align = ALIGN_DOWN(map_addr, RTT_MAP_SIZE(level <= 0 ? level : level - 1));
+ ret = host_rmi_rtt_aux_create(realm->rd, rtt, ipa_align, level,
tree_index);
if (ret != RMI_SUCCESS) {
- ERROR("%s() failed, rtt=0x%lx ret=0x%lx\n",
- "host_realm_rtt_aux_create", rtt, ret);
+ ERROR("%s() failed, map_addr =0x%lx ipa_align=0x%lx level=%lx ret=0x%lx\n",
+ "host_realm_rtt_aux_create", map_addr, ipa_align, level, ret);
host_rmi_granule_undelegate(rtt);
page_free(rtt);
return REALM_ERROR;
@@ -551,7 +551,7 @@
level = (long)ulevel;
ret = host_realm_create_rtt_aux_levels(realm, map_addr,
- (u_register_t)level,
+ level,
3U, tree_index);
if (ret != RMI_SUCCESS) {
ERROR("%s() failed, ret=0x%lx line=%u\n",
@@ -1700,6 +1700,126 @@
return MAX_REC_COUNT;
}
+/* Check if adr is in range of any of the Plane Images */
+static bool is_adr_in_par(struct realm *realm, u_register_t addr)
+{
+ if ((addr >= realm->par_base) && (addr <
+ (realm->par_base + (realm->par_size * (realm->num_aux_planes + 1U))))) {
+ return true;
+ }
+ return false;
+}
+
+/* Handle Plane permission falut, return true to return to realm, false to host */
+static bool host_realm_handle_perm_fault(struct realm *realm, struct rmi_rec_run *run)
+{
+ /*
+ * If exception is not in primary rtt
+ * Map Adr in failing Aux RTT and re-enter rec
+ * Validate faulting adr is in Realm payload area
+ * Note - PlaneN uses Primary RTT tree index 0
+ */
+
+ u_register_t fail_index;
+ u_register_t level_pri;
+ u_register_t state;
+ u_register_t ripas;
+ u_register_t ret;
+
+ VERBOSE("host aux_map 0x%lx rtt 0x%lx\n",
+ run->exit.hpfar, run->exit.rtt_tree);
+
+ ret = host_realm_aux_map_protected_data(realm,
+ run->exit.hpfar << 8U,
+ PAGE_SIZE,
+ run->exit.rtt_tree,
+ &fail_index, &level_pri, &state, &ripas);
+
+ if (ret != REALM_SUCCESS) {
+ ERROR("host_realm_aux_map_protected_data failed\n");
+ return false;
+ }
+
+ /* re-enter realm */
+ return true;
+}
+
+/* Handle RSI_MEM_SET_PERM_INDEX by P0, return true to return to realm, false to return to host */
+static bool host_realm_handle_s2ap_change(struct realm *realm, struct rmi_rec_run *run)
+{
+
+
+ u_register_t new_base = run->exit.s2ap_base;
+ u_register_t top = run->exit.s2ap_top;
+ u_register_t rtt_tree, ret;
+ bool ret1 = true;
+
+ while (new_base != top) {
+ ret = host_rmi_rtt_set_s2ap(realm->rd,
+ realm->rec[0U],
+ new_base,
+ top, &new_base,
+ &rtt_tree);
+
+ if (RMI_RETURN_STATUS(ret) == RMI_ERROR_RTT_AUX) {
+
+ int8_t ulevel = RMI_RETURN_INDEX(ret);
+ long level = (long)ulevel;
+
+ assert(rtt_tree != PRIMARY_RTT_INDEX);
+
+ /* create missing aux rtt level */
+ VERBOSE("set s2ap fail missing aux rtt=%lx 0x%lx 0x%lx\n",
+ rtt_tree, new_base, top);
+
+ ret = host_realm_create_rtt_aux_levels(realm, new_base,
+ level,
+ level + 1, rtt_tree);
+ if (ret != RMI_SUCCESS) {
+ INFO("host_rmi_create_rtt_aux_levels \
+ failed 0x%lx\n", new_base);
+ ret1 = false;
+ break;
+ }
+
+ /* Retry RMI_RTT_SET_S2AP */
+ continue;
+ } else if (RMI_RETURN_STATUS(ret) == RMI_ERROR_RTT) {
+
+ int8_t ulevel = RMI_RETURN_INDEX(ret);
+ long level = (long)ulevel;
+
+ assert(rtt_tree == PRIMARY_RTT_INDEX);
+ INFO("set s2ap failed missing rtt=0x%lx 0x%lx 0x%lx\n\n",
+ rtt_tree, new_base, top);
+
+ /* create missing rtt level */
+ ret = host_rmi_create_rtt_levels(realm, new_base,
+ level,
+ level + 1);
+
+ if (ret != RMI_SUCCESS) {
+ INFO("host_rmi_create_rtt_levels \
+ failed 0x%lx\n", new_base);
+ ret1 = false;
+ break;
+ }
+
+ /* Retry RMI_RTT_SET_S2AP */
+ continue;
+ } else if (RMI_RETURN_STATUS(ret) != RMI_SUCCESS) {
+ INFO("host set s2ap failed ret=0x%lx\n",
+ RMI_RETURN_STATUS(ret));
+ ret1 = false;
+ break;
+ }
+ }
+
+ /* re-enter realm */
+ return ret1;
+}
+
+
u_register_t host_realm_rec_enter(struct realm *realm,
u_register_t *exit_reason,
unsigned int *host_call_result,
@@ -1734,6 +1854,28 @@
}
}
+ if ((run->exit.exit_reason == RMI_EXIT_SYNC) &&
+ is_adr_in_par(realm, (run->exit.hpfar << 8U)) &&
+ (((((run->exit.esr & ISS_FSC_MASK) >= FSC_L0_TRANS_FAULT) &&
+ ((run->exit.esr & ISS_FSC_MASK) <= FSC_L3_TRANS_FAULT)) ||
+ ((run->exit.esr & ISS_FSC_MASK) == FSC_L_MINUS1_TRANS_FAULT))) &&
+ !realm->rtt_tree_single &&
+ (realm->num_aux_planes > 0U)) {
+
+ re_enter_rec = host_realm_handle_perm_fault(realm, run);
+ }
+
+ /*
+ * P0 issued RSI_MEM_SET_PERM_INDEX call
+ * Validate base is in range of realm payload area
+ */
+ if ((run->exit.exit_reason == RMI_EXIT_S2AP_CHANGE) &&
+ is_adr_in_par(realm, run->exit.s2ap_base) &&
+ (realm->num_aux_planes > 0U)) {
+
+ re_enter_rec = host_realm_handle_s2ap_change(realm, run);
+ }
+
if (ret != RMI_SUCCESS) {
return ret;
}
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 d1cef4b..632bad8 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
@@ -714,8 +714,8 @@
/* ESR.EC == 0b100000 Instruction Abort from a lower Exception level */
if (!ret1 || ((run->exit.hpfar >> 4U) != (base >> PAGE_SIZE_SHIFT)
|| (EC_BITS(run->exit.esr) != EC_IABORT_LOWER_EL)
- || ((run->exit.esr & ISS_IFSC_MASK) < IFSC_L0_TRANS_FAULT)
- || ((run->exit.esr & ISS_IFSC_MASK) > IFSC_L3_TRANS_FAULT)
+ || ((run->exit.esr & ISS_IFSC_MASK) < FSC_L0_TRANS_FAULT)
+ || ((run->exit.esr & ISS_IFSC_MASK) > FSC_L3_TRANS_FAULT)
|| ((run->exit.esr & (1UL << ESR_ISS_EABORT_EA_BIT)) != 0U))) {
ERROR("Rec did not fault ESR=0x%lx\n", run->exit.esr);
goto undelegate_destroy;
@@ -732,8 +732,8 @@
/* ESR.EC == 0b100100 Data Abort exception from a lower Exception level */
if (!ret1 || ((run->exit.hpfar >> 4U) != (base >> PAGE_SIZE_SHIFT)
|| (EC_BITS(run->exit.esr) != EC_DABORT_LOWER_EL)
- || ((run->exit.esr & ISS_DFSC_MASK) < DFSC_L0_TRANS_FAULT)
- || ((run->exit.esr & ISS_DFSC_MASK) > DFSC_L3_TRANS_FAULT)
+ || ((run->exit.esr & ISS_DFSC_MASK) < FSC_L0_TRANS_FAULT)
+ || ((run->exit.esr & ISS_DFSC_MASK) > FSC_L3_TRANS_FAULT)
|| ((run->exit.esr & (1UL << ESR_ISS_EABORT_EA_BIT)) != 0U))) {
ERROR("Rec did not fault\n");
goto undelegate_destroy;
@@ -824,8 +824,8 @@
/* ESR.EC == 0b100000 Instruction Abort from a lower Exception level */
if (!ret1 || ((run->exit.hpfar >> 4U) != (base >> PAGE_SIZE_SHIFT)
|| (EC_BITS(run->exit.esr) != EC_IABORT_LOWER_EL)
- || ((run->exit.esr & ISS_IFSC_MASK) < IFSC_L0_TRANS_FAULT)
- || ((run->exit.esr & ISS_IFSC_MASK) > IFSC_L3_TRANS_FAULT)
+ || ((run->exit.esr & ISS_IFSC_MASK) < FSC_L0_TRANS_FAULT)
+ || ((run->exit.esr & ISS_IFSC_MASK) > FSC_L3_TRANS_FAULT)
|| ((run->exit.esr & (1UL << ESR_ISS_EABORT_EA_BIT)) != 0U))) {
ERROR("Rec did not fault ESR=0x%lx\n", run->exit.esr);
goto destroy_realm;
@@ -841,8 +841,8 @@
/* ESR.EC == 0b100100 Data Abort exception from a lower Exception level */
if (!ret1 || ((run->exit.hpfar >> 4U) != (base >> PAGE_SIZE_SHIFT)
|| (EC_BITS(run->exit.esr) != EC_DABORT_LOWER_EL)
- || ((run->exit.esr & ISS_DFSC_MASK) < DFSC_L0_TRANS_FAULT)
- || ((run->exit.esr & ISS_DFSC_MASK) > DFSC_L3_TRANS_FAULT)
+ || ((run->exit.esr & ISS_DFSC_MASK) < FSC_L0_TRANS_FAULT)
+ || ((run->exit.esr & ISS_DFSC_MASK) > FSC_L3_TRANS_FAULT)
|| ((run->exit.esr & (1UL << ESR_ISS_EABORT_EA_BIT)) != 0U))) {
ERROR("Rec did not fault ESR=0x%lx\n", run->exit.esr);
goto destroy_realm;
@@ -957,8 +957,8 @@
/* ESR.EC == 0b100000 Instruction Abort from a lower Exception level */
if (!ret1 || ((run->exit.hpfar >> 4U) != (base >> PAGE_SIZE_SHIFT)
|| (EC_BITS(run->exit.esr) != EC_IABORT_LOWER_EL)
- || ((run->exit.esr & ISS_IFSC_MASK) < IFSC_L0_TRANS_FAULT)
- || ((run->exit.esr & ISS_IFSC_MASK) > IFSC_L3_TRANS_FAULT)
+ || ((run->exit.esr & ISS_IFSC_MASK) < FSC_L0_TRANS_FAULT)
+ || ((run->exit.esr & ISS_IFSC_MASK) > FSC_L3_TRANS_FAULT)
|| ((run->exit.esr & (1UL << ESR_ISS_EABORT_EA_BIT)) != 0U))) {
ERROR("Rec did not fault ESR=0x%lx\n", run->exit.esr);
goto destroy_data;
@@ -974,8 +974,8 @@
/* ESR.EC == 0b100100 Data Abort exception from a lower Exception level */
if (!ret1 || ((run->exit.hpfar >> 4U) != (base >> PAGE_SIZE_SHIFT)
|| (EC_BITS(run->exit.esr) != EC_DABORT_LOWER_EL)
- || ((run->exit.esr & ISS_DFSC_MASK) < DFSC_L0_TRANS_FAULT)
- || ((run->exit.esr & ISS_DFSC_MASK) > DFSC_L3_TRANS_FAULT)
+ || ((run->exit.esr & ISS_DFSC_MASK) < FSC_L0_TRANS_FAULT)
+ || ((run->exit.esr & ISS_DFSC_MASK) > FSC_L3_TRANS_FAULT)
|| ((run->exit.esr & (1UL << ESR_ISS_EABORT_EA_BIT)) != 0U))) {
ERROR("Rec did not fault ESR=0x%lx\n", run->exit.esr);
goto destroy_data;
@@ -1215,8 +1215,8 @@
if (!ret1 || (run->exit.hpfar >> 4U) != (base_ipa >> PAGE_SIZE_SHIFT)
|| (EC_BITS(run->exit.esr) != EC_DABORT_LOWER_EL)
- || ((run->exit.esr & ISS_DFSC_MASK) < DFSC_L0_TRANS_FAULT)
- || ((run->exit.esr & ISS_DFSC_MASK) > DFSC_L3_TRANS_FAULT)
+ || ((run->exit.esr & ISS_DFSC_MASK) < FSC_L0_TRANS_FAULT)
+ || ((run->exit.esr & ISS_DFSC_MASK) > FSC_L3_TRANS_FAULT)
|| ((run->exit.esr & (1UL << ESR_ISS_EABORT_EA_BIT)) != 0U)) {
ERROR("Rec1 did not fault exit=0x%lx ret1=%d HPFAR=0x%lx esr=0x%lx\n",
run->exit.exit_reason, ret1, run->exit.hpfar, run->exit.esr);
@@ -1818,7 +1818,7 @@
/* get ESR set by Realm exception handler */
esr = host_shared_data_get_realm_val(&realm, PRIMARY_PLANE_ID, 2U, HOST_ARG2_INDEX);
- if (((esr & ISS_DFSC_MASK) != DFSC_L0_ADR_SIZE_FAULT)
+ if (((esr & ISS_DFSC_MASK) != FSC_L0_ADR_SIZE_FAULT)
|| (EC_BITS(esr) != EC_DABORT_CUR_EL)
|| ((esr & (1UL << ESR_ISS_EABORT_EA_BIT)) != 0U)) {
ERROR("Rec2 incorrect ESR=0x%lx\n", esr);
@@ -1838,7 +1838,7 @@
/* get ESR set by Realm exception handler */
esr = host_shared_data_get_realm_val(&realm, PRIMARY_PLANE_ID, 3U, HOST_ARG2_INDEX);
- if (((esr & ISS_IFSC_MASK) != IFSC_L0_ADR_SIZE_FAULT)
+ if (((esr & ISS_IFSC_MASK) != FSC_L0_ADR_SIZE_FAULT)
|| (EC_BITS(esr) != EC_IABORT_CUR_EL)
|| ((esr & (1UL << ESR_ISS_EABORT_EA_BIT)) != 0U)) {
ERROR("Rec3 did not fault exit=0x%lx ret1=%d HPFAR=0x%lx esr=0x%lx\n",