test(realm): add testcase for REC exit due to Data/Instr abort
Add testcase to cause instruction or data abort in Realm by
accessing addr with
* HIPAS=UNASSIGNED and RIPAS=DESTROYED
* HIPAS=ASSIGNED and RIPAS=DESTROYED
* HIPAS=UNASSIGNED and RIPAS=RAM
Verify rec exit due to abort
Change-Id: Ic04c0ddaf1b18ec0cfd71c28753c4ed7298302da
Signed-off-by: Shruti Gupta <shruti.gupta@arm.com>
diff --git a/include/lib/aarch64/arch.h b/include/lib/aarch64/arch.h
index 88c873c..653dfd9 100644
--- a/include/lib/aarch64/arch.h
+++ b/include/lib/aarch64/arch.h
@@ -828,8 +828,28 @@
#define EC_SERROR U(0x2f)
/* Data Fault Status code, not all error codes listed */
#define ISS_DFSC_MASK U(0x3f)
+#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_L0_SEA U(0x14)
+#define DFSC_L1_SEA U(0x15)
+#define DFSC_L2_SEA U(0x16)
+#define DFSC_L3_SEA U(0x17)
#define DFSC_EXT_DABORT U(0x10)
#define DFSC_GPF_DABORT U(0x28)
+
+/* Instr Fault Status code, not all error codes listed */
+#define ISS_IFSC_MASK U(0x3f)
+#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_L0_SEA U(0x24)
+#define IFSC_L1_SEA U(0x25)
+#define IFSC_L2_SEA U(0x26)
+#define IFSC_L3_SEA U(0x27)
+
/* ISS encoding an exception from HVC or SVC instruction execution */
#define ISS_HVC_SMC_IMM16_MASK U(0xffff)
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 4f81042..3159ad4 100644
--- a/include/runtime_services/host_realm_managment/host_realm_rmi.h
+++ b/include/runtime_services/host_realm_managment/host_realm_rmi.h
@@ -549,37 +549,64 @@
u_register_t host_rmi_realm_create(u_register_t rd, u_register_t params_ptr);
u_register_t host_rmi_realm_destroy(u_register_t rd);
u_register_t host_rmi_features(u_register_t index, u_register_t *features);
+u_register_t host_rmi_data_destroy(u_register_t rd,
+ u_register_t map_addr,
+ u_register_t *data,
+ u_register_t *top);
+u_register_t host_rmi_rtt_readentry(u_register_t rd,
+ u_register_t map_addr,
+ u_register_t level,
+ struct rtt_entry *rtt);
+u_register_t host_rmi_rtt_destroy(u_register_t rd,
+ u_register_t map_addr,
+ u_register_t level,
+ u_register_t *rtt,
+ u_register_t *top);
+u_register_t host_rmi_rtt_init_ripas(u_register_t rd,
+ u_register_t start,
+ u_register_t end,
+ u_register_t *top);
+u_register_t host_rmi_create_rtt_levels(struct realm *realm,
+ u_register_t map_addr,
+ u_register_t level,
+ u_register_t max_level);
+u_register_t host_rmi_rtt_unmap_unprotected(u_register_t rd,
+ u_register_t map_addr,
+ u_register_t level,
+ u_register_t *top);
+u_register_t host_rmi_rtt_set_ripas(u_register_t rd,
+ u_register_t rec,
+ u_register_t start,
+ u_register_t end,
+ u_register_t *top);
+u_register_t host_rmi_psci_complete(u_register_t calling_rec, u_register_t target_rec,
+ unsigned long status);
+void host_rmi_init_cmp_result(void);
+bool host_rmi_get_cmp_result(void);
/* Realm management */
u_register_t host_realm_create(struct realm *realm);
u_register_t host_realm_map_payload_image(struct realm *realm,
u_register_t realm_payload_adr);
u_register_t host_realm_map_ns_shared(struct realm *realm,
- u_register_t ns_shared_mem_adr,
- u_register_t ns_shared_mem_size);
+ u_register_t ns_shared_mem_adr,
+ u_register_t ns_shared_mem_size);
u_register_t host_realm_rec_create(struct realm *realm);
unsigned int host_realm_find_rec_by_mpidr(unsigned int mpidr, struct realm *realm);
u_register_t host_realm_activate(struct realm *realm);
u_register_t host_realm_destroy(struct realm *realm);
u_register_t host_realm_rec_enter(struct realm *realm,
- u_register_t *exit_reason,
- unsigned int *host_call_result,
- unsigned int rec_num);
+ u_register_t *exit_reason,
+ unsigned int *host_call_result,
+ unsigned int rec_num);
u_register_t host_realm_init_ipa_state(struct realm *realm, u_register_t level,
- u_register_t start, uint64_t end);
-u_register_t host_rmi_psci_complete(u_register_t calling_rec, u_register_t target_rec,
- unsigned long status);
-void host_rmi_init_cmp_result(void);
-bool host_rmi_get_cmp_result(void);
-u_register_t host_realm_map_protected_data(bool unknown,
- struct realm *realm,
- u_register_t target_pa,
- u_register_t map_size,
- u_register_t src_pa);
-u_register_t host_rmi_rtt_set_ripas(u_register_t rd,
- u_register_t rec,
- u_register_t start,
- u_register_t end,
- u_register_t *top);
+ u_register_t start, uint64_t end);
+u_register_t host_realm_delegate_map_protected_data(bool unknown,
+ struct realm *realm,
+ u_register_t target_pa,
+ u_register_t map_size,
+ u_register_t src_pa);
+u_register_t host_realm_map_unprotected(struct realm *realm, u_register_t ns_pa,
+ u_register_t map_size);
#endif /* HOST_REALM_RMI_H */
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 8549512..1ae1533 100644
--- a/include/runtime_services/host_realm_managment/host_shared_data.h
+++ b/include/runtime_services/host_realm_managment/host_shared_data.h
@@ -47,6 +47,8 @@
REALM_MULTIPLE_REC_PSCI_DENIED_CMD,
REALM_MULTIPLE_REC_MULTIPLE_CPU_CMD,
REALM_GET_RSI_VERSION,
+ REALM_INSTR_FETCH_CMD,
+ REALM_DATA_ACCESS_CMD,
REALM_PMU_CYCLE,
REALM_PMU_EVENT,
REALM_PMU_PRESERVE,
diff --git a/realm/realm_payload_main.c b/realm/realm_payload_main.c
index ddaa3cb..55b5f9a 100644
--- a/realm/realm_payload_main.c
+++ b/realm/realm_payload_main.c
@@ -129,6 +129,38 @@
return false;
}
+static bool test_realm_instr_fetch_cmd(void)
+{
+ u_register_t base;
+ void (*func_ptr)(void);
+ rsi_ripas_type ripas;
+
+ base = realm_shared_data_get_my_host_val(HOST_ARG1_INDEX);
+ rsi_ipa_state_get(base, &ripas);
+ realm_printf("Initial ripas=0x%lx\n", ripas);
+ /* causes instruction abort */
+ realm_printf("Generate Instruction Abort\n");
+ func_ptr = (void (*)(void))base;
+ func_ptr();
+ /* should not return */
+ return false;
+}
+
+static bool test_realm_data_access_cmd(void)
+{
+ u_register_t base;
+ rsi_ripas_type ripas;
+
+ base = realm_shared_data_get_my_host_val(HOST_ARG1_INDEX);
+ rsi_ipa_state_get(base, &ripas);
+ realm_printf("Initial ripas=0x%lx\n", ripas);
+ /* causes data abort */
+ realm_printf("Generate Data Abort\n");
+ *((volatile uint64_t *)base);
+ /* should not return */
+ return false;
+}
+
/*
* This is the entry function for Realm payload, it first requests the shared buffer
* IPA address from Host using HOST_CALL/RSI, it reads the command to be executed,
@@ -156,9 +188,16 @@
break;
case REALM_MULTIPLE_REC_PSCI_DENIED_CMD:
test_succeed = test_realm_multiple_rec_psci_denied_cmd();
+ break;
case REALM_MULTIPLE_REC_MULTIPLE_CPU_CMD:
test_succeed = test_realm_multiple_rec_multiple_cpu_cmd();
break;
+ case REALM_INSTR_FETCH_CMD:
+ test_succeed = test_realm_instr_fetch_cmd();
+ break;
+ case REALM_DATA_ACCESS_CMD:
+ test_succeed = test_realm_data_access_cmd();
+ break;
case REALM_PAUTH_SET_CMD:
test_succeed = test_realm_pauth_set_cmd();
break;
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 b706e3a..057dd00 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
@@ -142,10 +142,10 @@
return host_rmi_handler(&(smc_args) {RMI_REALM_DESTROY, rd}, 2U).ret0;
}
-static inline u_register_t host_rmi_data_destroy(u_register_t rd,
- u_register_t map_addr,
- u_register_t *data,
- u_register_t *top)
+u_register_t host_rmi_data_destroy(u_register_t rd,
+ u_register_t map_addr,
+ u_register_t *data,
+ u_register_t *top)
{
smc_ret_values rets;
@@ -179,11 +179,11 @@
rd, rtt, map_addr, level}, 5U).ret0;
}
-static inline u_register_t host_rmi_rtt_destroy(u_register_t rd,
- u_register_t map_addr,
- u_register_t level,
- u_register_t *rtt,
- u_register_t *top)
+u_register_t host_rmi_rtt_destroy(u_register_t rd,
+ u_register_t map_addr,
+ u_register_t level,
+ u_register_t *rtt,
+ u_register_t *top)
{
smc_ret_values rets;
@@ -203,10 +203,10 @@
return rets.ret0;
}
-static inline u_register_t host_rmi_rtt_init_ripas(u_register_t rd,
- u_register_t start,
- u_register_t end,
- u_register_t *top)
+u_register_t host_rmi_rtt_init_ripas(u_register_t rd,
+ u_register_t start,
+ u_register_t end,
+ u_register_t *top)
{
smc_ret_values rets;
@@ -263,10 +263,10 @@
rd, map_addr, level, ns_pa}, 5U).ret0;
}
-static u_register_t host_rmi_rtt_readentry(u_register_t rd,
- u_register_t map_addr,
- u_register_t level,
- struct rtt_entry *rtt)
+u_register_t host_rmi_rtt_readentry(u_register_t rd,
+ u_register_t map_addr,
+ u_register_t level,
+ struct rtt_entry *rtt)
{
smc_ret_values rets;
@@ -279,10 +279,10 @@
return rets.ret0;
}
-static inline u_register_t host_rmi_rtt_unmap_unprotected(u_register_t rd,
- u_register_t map_addr,
- u_register_t level,
- u_register_t *top)
+u_register_t host_rmi_rtt_unmap_unprotected(u_register_t rd,
+ u_register_t map_addr,
+ u_register_t level,
+ u_register_t *top)
{
smc_ret_values rets;
@@ -292,7 +292,7 @@
return rets.ret0;
}
-static inline u_register_t host_rtt_level_mapsize(u_register_t level)
+u_register_t host_rtt_level_mapsize(u_register_t level)
{
if (level > RTT_MAX_LEVEL) {
return PAGE_SIZE;
@@ -315,10 +315,10 @@
return host_rmi_rtt_create(realm->rd, phys, addr, level);
}
-static u_register_t host_rmi_create_rtt_levels(struct realm *realm,
- u_register_t map_addr,
- u_register_t level,
- u_register_t max_level)
+u_register_t host_rmi_create_rtt_levels(struct realm *realm,
+ u_register_t map_addr,
+ u_register_t level,
+ u_register_t max_level)
{
u_register_t rtt, ret;
@@ -381,11 +381,11 @@
}
-u_register_t host_realm_map_protected_data(bool unknown,
- struct realm *realm,
- u_register_t target_pa,
- u_register_t map_size,
- u_register_t src_pa)
+u_register_t host_realm_delegate_map_protected_data(bool unknown,
+ struct realm *realm,
+ u_register_t target_pa,
+ u_register_t map_size,
+ u_register_t src_pa)
{
u_register_t rd = realm->rd;
u_register_t map_level, level;
@@ -514,7 +514,6 @@
ERROR("Unknown map_size=0x%lx\n", map_size);
return REALM_ERROR;
}
-
u_register_t desc = phys | S2TTE_ATTR_FWB_WB_RW;
ret = host_rmi_rtt_mapunprotected(rd, map_addr, map_level, desc);
@@ -858,7 +857,7 @@
/* MAP image regions */
while (i < (realm->par_size / PAGE_SIZE)) {
- ret = host_realm_map_protected_data(false, realm,
+ ret = host_realm_delegate_map_protected_data(false, realm,
realm->par_base + i * PAGE_SIZE,
PAGE_SIZE,
src_pa + i * PAGE_SIZE);
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 1948c1f..796d27e 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
@@ -456,11 +456,11 @@
base + (PAGE_SIZE * test_page_num));
for (unsigned int i = 0U; i < test_page_num; i++) {
- ret = host_realm_map_protected_data(true, &realm,
+ ret = host_realm_delegate_map_protected_data(true, &realm,
base + (PAGE_SIZE * i), PAGE_SIZE,
base + (PAGE_SIZE * i));
if (ret != REALM_SUCCESS) {
- ERROR("host_realm_map_protected_data failed\n");
+ ERROR("host_realm_delegate_map_protected_data failed\n");
goto destroy_realm;
}
}
@@ -548,9 +548,9 @@
base = (u_register_t)page_alloc(PAGE_SIZE);
- ret = host_realm_map_protected_data(true, &realm, base, PAGE_SIZE, base);
+ ret = host_realm_delegate_map_protected_data(true, &realm, base, PAGE_SIZE, base);
if (ret != RMI_SUCCESS) {
- ERROR("host_realm_map_protected_data failede\n");
+ ERROR("host_realm_delegate_map_protected_data failede\n");
goto destroy_realm;
}
host_shared_data_set_host_val(&realm, 0U, HOST_ARG1_INDEX, base);
@@ -584,3 +584,369 @@
return host_call_result;
}
+/*
+ * Test aims to generate REALM Exit due to abort
+ * when access page with RIPAS=DESTOYED HIPAS=ASSIGNED
+ * Host maps a protected page (calls data_create) when realm is in new state
+ * Initial state of PAGE is RIPAS=RAM HIPAS=ASSIGNED
+ * Host calls data_destroy, new state HIPAS=UNASSIGNED RIPAS=DESTROYED
+ * Enter Realm, Rec0 executes from page, and Rec1 reads the page
+ * Realm should trigger an Instr/Data abort, and will exit to Host.
+ * The Host verifies exit reason is Instr/Data abort
+ */
+test_result_t host_realm_abort_unassigned_destroyed(void)
+{
+ bool ret1, ret2;
+ test_result_t res = TEST_RESULT_FAIL;
+ u_register_t ret, data, top;
+ struct realm realm;
+ struct rmi_rec_run *run;
+ struct rtt_entry rtt;
+ u_register_t rec_flag[2U] = {RMI_RUNNABLE, RMI_RUNNABLE}, base;
+
+ SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
+
+ if (!host_create_realm_payload(&realm, (u_register_t)REALM_IMAGE_BASE,
+ (u_register_t)PAGE_POOL_BASE,
+ (u_register_t)PAGE_POOL_MAX_SIZE,
+ 0UL, rec_flag, 2U)) {
+ return TEST_RESULT_FAIL;
+ }
+ if (!host_create_shared_mem(&realm, NS_REALM_SHARED_MEM_BASE,
+ NS_REALM_SHARED_MEM_SIZE)) {
+ goto destroy_realm;
+ }
+
+ base = (u_register_t)page_alloc(PAGE_SIZE);
+
+ run = (struct rmi_rec_run *)realm.run[0];
+
+ /* DATA_CREATE
+ * Copies content of TFTF_BASE in newly created page, any PA can be used for dummy copy
+ * maps 1:1 IPA:PA
+ */
+ ret = host_realm_delegate_map_protected_data(false, &realm, base, PAGE_SIZE, TFTF_BASE);
+ if (ret != RMI_SUCCESS) {
+ ERROR("host_realm_delegate_map_protected_data failed\n");
+ goto destroy_realm;
+ }
+ ret = host_rmi_rtt_readentry(realm.rd, base, 3U, &rtt);
+ if (ret != RMI_SUCCESS || rtt.state != RMI_ASSIGNED ||
+ (rtt.ripas != RMI_RAM)) {
+ ERROR("wrong state after DATA_CRATE_UNKNOWN\n");
+ goto undelegate_destroy;
+ }
+ INFO("Initial state base = 0x%lx rtt.state=0x%lx rtt.ripas=0x%lx\n",
+ base, rtt.state, rtt.ripas);
+ host_shared_data_set_host_val(&realm, 0U, HOST_ARG1_INDEX, base);
+ host_shared_data_set_host_val(&realm, 1U, HOST_ARG1_INDEX, base);
+
+ ret = host_rmi_data_destroy(realm.rd, base, &data, &top);
+ if (ret != RMI_SUCCESS || data != base) {
+ ERROR("host_rmi_data_destroy failed\n");
+ goto undelegate_destroy;
+ }
+ ret = host_rmi_rtt_readentry(realm.rd, base, 3U, &rtt);
+ if (ret != RMI_SUCCESS || rtt.state != RMI_UNASSIGNED ||
+ rtt.ripas != RMI_DESTROYED) {
+ ERROR("Wrong state after host_rmi_data_destroy\n");
+ goto undelegate_destroy;
+ }
+
+ INFO("New state4 base = 0x%lx rtt.state=0x%lx rtt.ripas=0x%lx\n",
+ base, rtt.state, rtt.ripas);
+
+ if (host_realm_activate(&realm) != REALM_SUCCESS) {
+ ERROR("%s() failed\n", "host_realm_activate");
+ goto undelegate_destroy;
+ }
+
+ /* Realm0 expect rec exit due to Instr Abort unassigned destroyed page */
+ ret1 = host_enter_realm_execute(&realm, REALM_INSTR_FETCH_CMD,
+ RMI_EXIT_SYNC, 0U);
+
+ /* 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 & (1UL << ESR_ISS_EABORT_EA_BIT)) != 0U))) {
+ ERROR("Rec did not fault ESR=0x%lx\n", run->exit.esr);
+ goto undelegate_destroy;
+ }
+ INFO("IA FAR=0x%lx, HPFAR=0x%lx ESR=0x%lx\n", run->exit.far, run->exit.hpfar,
+ run->exit.esr);
+
+ run = (struct rmi_rec_run *)realm.run[1];
+
+ /* Realm1 expect rec exit due to Data Abort unassigned destroyed page */
+ ret1 = host_enter_realm_execute(&realm, REALM_DATA_ACCESS_CMD,
+ RMI_EXIT_SYNC, 1U);
+
+ /* 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 & (1UL << ESR_ISS_EABORT_EA_BIT)) != 0U))) {
+ ERROR("Rec did not fault\n");
+ goto undelegate_destroy;
+ }
+ INFO("DA FAR=0x%lx, HPFAR=0x%lx ESR= 0x%lx\n", run->exit.far, run->exit.hpfar,
+ run->exit.esr);
+ res = TEST_RESULT_SUCCESS;
+
+undelegate_destroy:
+ ret = host_rmi_granule_undelegate(base);
+destroy_realm:
+ ret2 = host_destroy_realm(&realm);
+
+ if (!ret2) {
+ ERROR("%s(): destroy=%d\n",
+ __func__, ret2);
+ return TEST_RESULT_FAIL;
+ }
+
+ return res;
+}
+
+/*
+ * Test aims to generate REALM Exit due to Abort
+ * when access page with RIPAS=RAM HIPAS=UNASSIGNED
+ * Host allocates a PAGE, calls init_ripas when realm is in new state
+ * Initial state of PAGE is RIPAS=RAM HIPAS=UNASSIGNED
+ * Enter Realm, REC0 executes from page, and REC1 reads the page
+ * Realm should trigger an Instr/Data abort, and will exit to Host.
+ * Host verifies exit reason is Instr/Data abort.
+ */
+test_result_t host_realm_abort_unassigned_ram(void)
+{
+ bool ret1, ret2;
+ u_register_t ret, top;
+ struct realm realm;
+ struct rmi_rec_run *run;
+ struct rtt_entry rtt;
+ test_result_t res = TEST_RESULT_FAIL;
+ u_register_t rec_flag[2U] = {RMI_RUNNABLE, RMI_RUNNABLE}, base;
+
+ SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
+
+ if (!host_create_realm_payload(&realm, (u_register_t)REALM_IMAGE_BASE,
+ (u_register_t)PAGE_POOL_BASE,
+ (u_register_t)PAGE_POOL_MAX_SIZE,
+ 0UL, rec_flag, 2U)) {
+ return TEST_RESULT_FAIL;
+ }
+ if (!host_create_shared_mem(&realm, NS_REALM_SHARED_MEM_BASE,
+ NS_REALM_SHARED_MEM_SIZE)) {
+ goto destroy_realm;
+ }
+
+ /* This is dummy allocation to get a base address */
+ base = (u_register_t)page_alloc(PAGE_SIZE);
+
+ run = (struct rmi_rec_run *)realm.run[0];
+
+ /* Set RIPAS of PAGE to RAM */
+ ret = host_rmi_rtt_init_ripas(realm.rd, base, base + PAGE_SIZE, &top);
+ if (ret != RMI_SUCCESS) {
+ ERROR("%s() failed, ret=0x%lx line=%u\n",
+ "host_rmi_rtt_init_ripas", ret, __LINE__);
+ goto destroy_realm;
+ }
+ if (host_realm_activate(&realm) != REALM_SUCCESS) {
+ ERROR("%s() failed\n", "host_realm_activate");
+ goto destroy_realm;
+ }
+
+ ret = host_rmi_rtt_readentry(realm.rd, base, 3U, &rtt);
+ if (ret != RMI_SUCCESS || rtt.state != RMI_UNASSIGNED ||
+ (rtt.ripas != RMI_RAM)) {
+ ERROR("wrong initial state\n");
+ goto destroy_realm;
+ }
+ INFO("Initial state base = 0x%lx rtt.state=0x%lx rtt.ripas=0x%lx\n",
+ base, rtt.state, rtt.ripas);
+ host_shared_data_set_host_val(&realm, 0U, HOST_ARG1_INDEX, base);
+ host_shared_data_set_host_val(&realm, 1U, HOST_ARG1_INDEX, base);
+
+ /* Rec0 expect rec exit due to Instr Abort unassigned ram page */
+ ret1 = host_enter_realm_execute(&realm, REALM_INSTR_FETCH_CMD,
+ RMI_EXIT_SYNC, 0U);
+
+ /* 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 & (1UL << ESR_ISS_EABORT_EA_BIT)) != 0U))) {
+ ERROR("Rec did not fault ESR=0x%lx\n", run->exit.esr);
+ goto destroy_realm;
+ }
+ INFO("IA FAR=0x%lx, HPFAR=0x%lx ESR=0x%lx\n", run->exit.far, run->exit.hpfar,
+ run->exit.esr);
+ run = (struct rmi_rec_run *)realm.run[1];
+
+ /* Rec1 expect rec exit due to Data Abort unassigned ram page */
+ ret1 = host_enter_realm_execute(&realm, REALM_DATA_ACCESS_CMD,
+ RMI_EXIT_SYNC, 1U);
+
+ /* 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 & (1UL << ESR_ISS_EABORT_EA_BIT)) != 0U))) {
+ ERROR("Rec did not fault ESR=0x%lx\n", run->exit.esr);
+ goto destroy_realm;
+ }
+ INFO("DA FAR=0x%lx, HPFAR=0x%lx ESR=0x%lx\n", run->exit.far, run->exit.hpfar,
+ run->exit.esr);
+ res = TEST_RESULT_SUCCESS;
+
+destroy_realm:
+ ret2 = host_destroy_realm(&realm);
+
+ if (!ret2) {
+ ERROR("%s(): destroy=%d\n",
+ __func__, ret2);
+ return TEST_RESULT_FAIL;
+ }
+
+ return res;
+}
+
+/*
+ * Test aims to generate REALM Exit due to Abort
+ * when access page with RIPAS=DESTOYED HIPAS=Assigned
+ * Host maps a protected page (calls data_create) when realm is in new state
+ * initial state of PAGE is RIPAS=RAM HIPAS=ASSIGNED
+ * Host calls data_destroy, new state HIPAS=UNASSIGNED RIPAS=DESTROYED
+ * Host calls data_create_unknown, new state HIPAS=ASSIGNED RIPAS=DESTROYED
+ * Enter Realm, REC0 executes from page, and REC1 reads the page
+ * Realm should trigger an Instr/Data abort, and will exit to Host.
+ * The Host verifies exit reason is Instr/Data abort
+ */
+test_result_t host_realm_abort_assigned_destroyed(void)
+{
+ bool ret1, ret2;
+ test_result_t res = TEST_RESULT_FAIL;
+ u_register_t ret, top, data;
+ struct realm realm;
+ struct rmi_rec_run *run;
+ struct rtt_entry rtt;
+ u_register_t rec_flag[2U] = {RMI_RUNNABLE, RMI_RUNNABLE}, base;
+
+ SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
+
+ if (!host_create_realm_payload(&realm, (u_register_t)REALM_IMAGE_BASE,
+ (u_register_t)PAGE_POOL_BASE,
+ (u_register_t)PAGE_POOL_MAX_SIZE,
+ 0UL, rec_flag, 2U)) {
+ return TEST_RESULT_FAIL;
+ }
+ if (!host_create_shared_mem(&realm, NS_REALM_SHARED_MEM_BASE,
+ NS_REALM_SHARED_MEM_SIZE)) {
+ goto destroy_realm;
+ }
+
+ base = (u_register_t)page_alloc(PAGE_SIZE);
+ run = (struct rmi_rec_run *)realm.run[0];
+
+ /* DATA_CREATE */
+ /* Copied content of TFTF_BASE to new page, can use any adr, maps 1:1 IPA:PA */
+ ret = host_realm_delegate_map_protected_data(false, &realm, base, PAGE_SIZE, TFTF_BASE);
+ if (ret != RMI_SUCCESS) {
+ ERROR("host_realm_delegate_map_protected_data failed\n");
+ goto destroy_realm;
+ }
+ ret = host_rmi_rtt_readentry(realm.rd, base, 3U, &rtt);
+ if (ret != RMI_SUCCESS || rtt.state != RMI_ASSIGNED ||
+ (rtt.ripas != RMI_RAM)) {
+ ERROR("wrong state after data create\n");
+ goto destroy_realm;
+ }
+ INFO("Initial state base = 0x%lx rtt.state=0x%lx rtt.ripas=0x%lx\n",
+ base, rtt.state, rtt.ripas);
+ host_shared_data_set_host_val(&realm, 0U, HOST_ARG1_INDEX, base);
+ host_shared_data_set_host_val(&realm, 1U, HOST_ARG1_INDEX, base);
+
+ if (host_realm_activate(&realm) != REALM_SUCCESS) {
+ ERROR("%s() failed\n", "host_realm_activate");
+ goto destroy_realm;
+ }
+
+ ret = host_rmi_data_destroy(realm.rd, base, &data, &top);
+ if (ret != RMI_SUCCESS || data != base) {
+ ERROR("host_rmi_data_destroy failed\n");
+ goto destroy_realm;
+ }
+ ret = host_rmi_rtt_readentry(realm.rd, base, 3U, &rtt);
+ if (ret != RMI_SUCCESS || rtt.state != RMI_UNASSIGNED ||
+ rtt.ripas != RMI_DESTROYED) {
+ ERROR("Wrong state after host_rmi_data_destroy\n");
+ goto destroy_realm;
+ }
+ ret = host_rmi_granule_undelegate(base);
+
+ /* DATA_CREATE_UNKNOWN */
+ ret = host_realm_delegate_map_protected_data(true, &realm, base, PAGE_SIZE, 0U);
+ if (ret != RMI_SUCCESS) {
+ ERROR("host_realm_delegate_map_protected_data failede\n");
+ goto destroy_realm;
+ }
+ ret = host_rmi_rtt_readentry(realm.rd, base, 3U, &rtt);
+ if (ret != RMI_SUCCESS || rtt.state != RMI_ASSIGNED ||
+ (rtt.ripas != RMI_DESTROYED)) {
+ ERROR("wrong state after data create unknown\n");
+ goto destroy_data;
+ }
+
+ /* Rec0, expect rec exit due to Instr Abort assigned destroyed page */
+ ret1 = host_enter_realm_execute(&realm, REALM_INSTR_FETCH_CMD,
+ RMI_EXIT_SYNC, 0U);
+
+ /* 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 & (1UL << ESR_ISS_EABORT_EA_BIT)) != 0U))) {
+ ERROR("Rec did not fault ESR=0x%lx\n", run->exit.esr);
+ goto destroy_data;
+ }
+ INFO("IA FAR=0x%lx, HPFAR=0x%lx ESR=0x%lx\n", run->exit.far, run->exit.hpfar,
+ run->exit.esr);
+ run = (struct rmi_rec_run *)realm.run[1];
+
+ /* Rec1 expect rec exit due to Data Abort assigned destroyed page */
+ ret1 = host_enter_realm_execute(&realm, REALM_DATA_ACCESS_CMD,
+ RMI_EXIT_SYNC, 1U);
+
+ /* 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 & (1UL << ESR_ISS_EABORT_EA_BIT)) != 0U))) {
+ ERROR("Rec did not fault ESR=0x%lx\n", run->exit.esr);
+ goto destroy_data;
+ }
+ INFO("DA FAR=0x%lx, HPFAR=0x%lx ESR=0x%lx\n", run->exit.far, run->exit.hpfar,
+ run->exit.esr);
+ res = TEST_RESULT_SUCCESS;
+
+destroy_data:
+ ret = host_rmi_data_destroy(realm.rd, base, &data, &top);
+ ret = host_rmi_granule_undelegate(base);
+destroy_realm:
+ ret2 = host_destroy_realm(&realm);
+
+ if (!ret2) {
+ ERROR("%s(): destroy=%d\n",
+ __func__, ret2);
+ return TEST_RESULT_FAIL;
+ }
+
+ return res;
+}
diff --git a/tftf/tests/tests-realm-payload.xml b/tftf/tests/tests-realm-payload.xml
index 68d68dd..934a34e 100644
--- a/tftf/tests/tests-realm-payload.xml
+++ b/tftf/tests/tests-realm-payload.xml
@@ -16,6 +16,12 @@
function="host_realm_multi_rec_multiple_cpu" />
<testcase name="Realm payload multi rec validations"
function="host_realm_multi_rec_multiple_cpu2" />
+ <testcase name="Realm Abort Unassigned RAM"
+ function="host_realm_abort_unassigned_ram" />
+ <testcase name="Realm Abort Unassigned Destroyed"
+ function="host_realm_abort_unassigned_destroyed" />
+ <testcase name="Realm Abort Assigned destroyed"
+ function="host_realm_abort_assigned_destroyed" />
<testcase name="Realm payload multi rec single cpu"
function="host_realm_multi_rec_single_cpu" />
<testcase name="Realm payload multi rec psci denied"