feat(realm): add test case for FEAT_DoubleFault2 support on TF-RMM
When FEAT_DoubleFault2 is supported, TF-RMM must take into
account bit SCTLR2_EL1.EASE in order to decide whether to inject
a SEA into the sync exception vector or into the serror one.
The test on this patch verifies that TF-RMM injects the SEA
to the right vector depending on SCTLR2.EASE bit.
Signed-off-by: Javier Almansa Sobrino <javier.almansasobrino@arm.com>
Change-Id: I6c976fecb04d123e3efb96c5973b1466e241097f
diff --git a/realm/aarch64/realm_exceptions.S b/realm/aarch64/realm_exceptions.S
index 210dd3e..c1d1c0c 100644
--- a/realm/aarch64/realm_exceptions.S
+++ b/realm/aarch64/realm_exceptions.S
@@ -43,8 +43,9 @@
b interrupt_vector_entry
end_vector_entry fiq_spx
-unhandled_exception serr_spx
-
+vector_entry serr_spx
+ b serr_exception_vector_entry
+end_vector_entry serr_spx
/*
* Lower EL using AArch64 : 0x400 - 0x600.
*/
@@ -116,6 +117,22 @@
eret
endfunc sync_exception_vector_entry
+func serr_exception_vector_entry
+ sub sp, sp, #0x100
+ save_gp_regs
+ mov x19, sp
+ bl tftf_serror_handler
+ cbnz x0, 0f
+ mov x0, x19
+ /* Save original stack pointer value on the stack */
+ add x1, x0, #0x100
+ str x1, [x0, #0xf8]
+ b realm_print_exception
+0: restore_gp_regs
+ add sp, sp, #0x100
+ eret
+endfunc serr_exception_vector_entry
+
func interrupt_vector_entry
sub sp, sp, #0x100
save_gp_regs
diff --git a/realm/include/realm_tests.h b/realm/include/realm_tests.h
index b58949b..a2cfc9b 100644
--- a/realm/include/realm_tests.h
+++ b/realm/include/realm_tests.h
@@ -27,6 +27,7 @@
bool test_realm_multiple_rec_multiple_cpu_cmd(void);
bool test_realm_sme_read_id_registers(void);
bool test_realm_sme_undef_abort(void);
+bool test_realm_sctlr2_ease(void);
#endif /* REALM_TESTS_H */
diff --git a/realm/realm.mk b/realm/realm.mk
index 305c007..b0536ca 100644
--- a/realm/realm.mk
+++ b/realm/realm.mk
@@ -43,6 +43,7 @@
lib/${ARCH}/misc_helpers.S \
lib/smc/${ARCH}/asm_smc.S \
lib/smc/${ARCH}/smc.c \
+ lib/exceptions/${ARCH}/serror.c \
lib/exceptions/${ARCH}/sync.c \
lib/locks/${ARCH}/spinlock.S \
lib/delay/delay.c \
diff --git a/realm/realm_payload_main.c b/realm/realm_payload_main.c
index 47f9b9f..cf9cce3 100644
--- a/realm/realm_payload_main.c
+++ b/realm/realm_payload_main.c
@@ -16,11 +16,13 @@
#include "realm_def.h"
#include <realm_rsi.h>
#include <realm_tests.h>
+#include <serror.h>
#include <sync.h>
#include <tftf_lib.h>
static fpu_state_t rl_fpu_state_write;
static fpu_state_t rl_fpu_state_read;
+
/*
* This function reads sleep time in ms from shared buffer and spins PE
* in a loop for that time period.
@@ -176,7 +178,7 @@
/* Causes data abort */
realm_printf("Generate Data Abort\n");
*((volatile uint64_t *)base);
- /* Should not return */
+
return false;
}
@@ -200,6 +202,49 @@
return false;
}
+static bool realm_serror_handler_doublefault(void)
+{
+ if ((read_sctlr2_el1() & SCTLR2_EASE_BIT) != 0UL) {
+ /* The serror exception should have been routed here */
+ return true;
+ }
+
+ rsi_exit_to_host(HOST_CALL_EXIT_FAILED_CMD);
+
+ /* Should have never get here */
+ return false;
+}
+
+static bool realm_sync_handler_doublefault(void)
+{
+ if ((read_sctlr2_el1() & SCTLR2_EASE_BIT) == 0UL) {
+ /* The sync exception should have been routed here */
+ return true;
+ }
+
+ rsi_exit_to_host(HOST_CALL_EXIT_FAILED_CMD);
+
+ /* Should have never get here */
+ return false;
+}
+
+static void test_realm_feat_doublefault2(void)
+{
+ u_register_t ease_bit = realm_shared_data_get_my_host_val(HOST_ARG2_INDEX);
+
+ unregister_custom_sync_exception_handler();
+ register_custom_sync_exception_handler(realm_sync_handler_doublefault);
+ register_custom_serror_handler(realm_serror_handler_doublefault);
+
+ if (ease_bit != 0UL) {
+ write_sctlr2_el1(read_sctlr2_el1() | SCTLR2_EASE_BIT);
+ } else {
+ write_sctlr2_el1(read_sctlr2_el1() & ~SCTLR2_EASE_BIT);
+ }
+
+ (void)test_realm_data_access_cmd();
+}
+
/*
* 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,
@@ -213,7 +258,12 @@
bool test_succeed = false;
register_custom_sync_exception_handler(realm_exception_handler);
+
+ /* No serror handler registered by default */
+ unregister_custom_serror_handler();
+
realm_set_shared_structure((host_shared_data_t *)rsi_get_ns_buffer());
+
if (realm_get_my_shared_structure() != NULL) {
uint8_t cmd = realm_shared_data_get_my_realm_cmd();
@@ -232,6 +282,10 @@
case REALM_MULTIPLE_REC_MULTIPLE_CPU_CMD:
test_succeed = test_realm_multiple_rec_multiple_cpu_cmd();
break;
+ case REALM_FEAT_DOUBLEFAULT2_TEST:
+ test_realm_feat_doublefault2();
+ test_succeed = true;
+ break;
case REALM_INSTR_FETCH_CMD:
test_succeed = test_realm_instr_fetch_cmd();
break;