summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOlivier Deprez <olivier.deprez@arm.com>2022-04-04 17:24:36 +0200
committerTrustedFirmware Code Review <review@review.trustedfirmware.org>2022-04-04 17:24:36 +0200
commitc394fcc734fd49221030564df51df58db25540f8 (patch)
tree0b75c952f0bf4406df0d7ea59d40a7734105e465
parent968a869e90b1f1dc8ddb70cd1f0cca657f885e27 (diff)
parentff33cd11268a91bf7fa88b10f08eaf9c74c24fc5 (diff)
Merge changes from topic "mp/sec_intr_management"
* changes: test(interrupts): check if last service interrupt is Trusted Wdog timer feat(interrupts): query last serviced interrupt test(interrupts): use custom handler for interrupt feat(interrupts): support for registering custom handler refactor(interrupts): enhance secure interrupt handling test
-rw-r--r--include/runtime_services/cactus_test_cmds.h36
-rw-r--r--spm/cactus/cactus_interrupt.c17
-rw-r--r--spm/cactus/cactus_main.c3
-rw-r--r--spm/cactus/cactus_tests/cactus_test_interrupts.c79
-rw-r--r--spm/common/sp_helpers.c38
-rw-r--r--spm/common/sp_helpers.h18
-rw-r--r--tftf/tests/runtime_services/secure_service/test_ffa_secure_interrupts.c113
7 files changed, 243 insertions, 61 deletions
diff --git a/include/runtime_services/cactus_test_cmds.h b/include/runtime_services/cactus_test_cmds.h
index 3bffb7b..435d270 100644
--- a/include/runtime_services/cactus_test_cmds.h
+++ b/include/runtime_services/cactus_test_cmds.h
@@ -318,6 +318,29 @@ static inline ffa_id_t cactus_get_fwd_sleep_dest(smc_ret_values ret)
}
/**
+ * Command to request cactus to sleep for half the given time in ms, trigger
+ * trusted watchdog timer and then sleep again for another half the given time.
+ *
+ * The sender of this command expects to receive CACTUS_SUCCESS if the requested
+ * echo interaction happened successfully, or CACTUS_ERROR otherwise.
+ */
+#define CACTUS_SLEEP_TRIGGER_TWDOG_CMD (CACTUS_SLEEP_CMD + 2)
+
+static inline smc_ret_values cactus_sleep_trigger_wdog_cmd(
+ ffa_id_t source, ffa_id_t dest, uint32_t sleep_time,
+ uint64_t wdog_time)
+{
+ return cactus_send_cmd(source, dest, CACTUS_SLEEP_TRIGGER_TWDOG_CMD, sleep_time,
+ wdog_time, 0, 0);
+}
+
+
+static inline uint32_t cactus_get_wdog_trigger_duration(smc_ret_values ret)
+{
+ return (uint32_t)ret.ret5;
+}
+
+/**
* Command to request cactus to enable/disable an interrupt
*
* The command id is the hex representation of string "intr"
@@ -537,4 +560,17 @@ static inline uint32_t cactus_get_req_count(smc_ret_values ret)
return (uint32_t)ret.ret4;
}
+/**
+ * Request SP to return the last serviced secure virtual interrupt.
+ *
+ * The command id is the hex representaton of the string "vINT"
+ */
+#define CACTUS_LAST_INTERRUPT_SERVICED_CMD U(0x76494e54)
+
+static inline smc_ret_values cactus_get_last_interrupt_cmd(
+ ffa_id_t source, ffa_id_t dest)
+{
+ return cactus_send_cmd(source, dest, CACTUS_LAST_INTERRUPT_SERVICED_CMD,
+ 0, 0, 0, 0);
+}
#endif
diff --git a/spm/cactus/cactus_interrupt.c b/spm/cactus/cactus_interrupt.c
index ef3d5cc..2305b01 100644
--- a/spm/cactus/cactus_interrupt.c
+++ b/spm/cactus/cactus_interrupt.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -22,9 +22,15 @@ extern void notification_pending_interrupt_handler(void);
extern ffa_id_t g_ffa_id;
+/* Secure virtual interrupt that was last handled by Cactus SP. */
+uint32_t last_serviced_interrupt[PLATFORM_CORE_COUNT];
+
+extern spinlock_t sp_handler_lock[NUM_VINT_ID];
+
void cactus_interrupt_handler(void)
{
uint32_t intid = spm_interrupt_get();
+ unsigned int core_pos = get_current_core_id();
switch (intid) {
case MANAGED_EXIT_INTERRUPT_ID:
@@ -59,4 +65,13 @@ void cactus_interrupt_handler(void)
intid);
panic();
}
+
+ last_serviced_interrupt[core_pos] = intid;
+
+ /* Invoke the tail end handler registered by the SP. */
+ spin_lock(&sp_handler_lock[intid]);
+ if (sp_interrupt_tail_end_handler[intid]) {
+ sp_interrupt_tail_end_handler[intid]();
+ }
+ spin_unlock(&sp_handler_lock[intid]);
}
diff --git a/spm/cactus/cactus_main.c b/spm/cactus/cactus_main.c
index 58186d1..dd15d97 100644
--- a/spm/cactus/cactus_main.c
+++ b/spm/cactus/cactus_main.c
@@ -206,6 +206,9 @@ void __dead2 cactus_main(bool primary_cold_boot)
/* Configure and enable Stage-1 MMU, enable D-Cache */
cactus_plat_configure_mmu(ffa_id);
+
+ /* Initialize locks for tail end interrupt handler */
+ sp_handler_spin_lock_init();
}
/*
diff --git a/spm/cactus/cactus_tests/cactus_test_interrupts.c b/spm/cactus/cactus_tests/cactus_test_interrupts.c
index ced5dca..dc64512 100644
--- a/spm/cactus/cactus_tests/cactus_test_interrupts.c
+++ b/spm/cactus/cactus_tests/cactus_test_interrupts.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -14,6 +14,16 @@
#include <platform.h>
+/* Secure virtual interrupt that was last handled by Cactus SP. */
+extern uint32_t last_serviced_interrupt[PLATFORM_CORE_COUNT];
+static int flag_set;
+
+static void sec_wdog_interrupt_handled(void)
+{
+ expect(flag_set, 0);
+ flag_set = 1;
+}
+
CACTUS_CMD_HANDLER(sleep_cmd, CACTUS_SLEEP_CMD)
{
uint64_t time_lapsed;
@@ -101,3 +111,70 @@ CACTUS_CMD_HANDLER(twdog_cmd, CACTUS_TWDOG_START_CMD)
return cactus_success_resp(vm_id, source, time_ms);
}
+
+bool handle_twdog_interrupt_sp_sleep(uint32_t sleep_time, uint64_t *time_lapsed)
+{
+ sp_register_interrupt_tail_end_handler(sec_wdog_interrupt_handled,
+ IRQ_TWDOG_INTID);
+ *time_lapsed += sp_sleep_elapsed_time(sleep_time);
+
+ if (flag_set == 0) {
+ return false;
+ }
+
+ /* Reset the flag and unregister the handler. */
+ flag_set = 0;
+ sp_unregister_interrupt_tail_end_handler(IRQ_TWDOG_INTID);
+
+ return true;
+}
+
+CACTUS_CMD_HANDLER(sleep_twdog_cmd, CACTUS_SLEEP_TRIGGER_TWDOG_CMD)
+{
+ uint64_t time_lapsed = 0;
+ uint32_t sleep_time = cactus_get_sleep_time(*args) / 2;
+ uint64_t time_ms = cactus_get_wdog_trigger_duration(*args);
+
+ VERBOSE("Request to sleep %x for %ums.\n", ffa_dir_msg_dest(*args),
+ sleep_time);
+
+ if (!handle_twdog_interrupt_sp_sleep(sleep_time, &time_lapsed)) {
+ goto fail;
+ }
+
+ /* Lapsed time should be at least equal to sleep time. */
+ VERBOSE("Sleep complete: %llu\n", time_lapsed);
+
+ VERBOSE("Starting TWDOG: %llums\n", time_ms);
+ sp805_twdog_refresh();
+ sp805_twdog_start((time_ms * ARM_SP805_TWDG_CLK_HZ) / 1000);
+
+ VERBOSE("2nd Request to sleep %x for %ums.\n", ffa_dir_msg_dest(*args),
+ sleep_time);
+
+ if (!handle_twdog_interrupt_sp_sleep(sleep_time, &time_lapsed)) {
+ goto fail;
+ }
+
+ /* Lapsed time should be at least equal to sleep time. */
+ VERBOSE("2nd Sleep complete: %llu\n", time_lapsed);
+
+ return cactus_response(ffa_dir_msg_dest(*args),
+ ffa_dir_msg_source(*args),
+ time_lapsed);
+fail:
+ /* Test failed. */
+ ERROR("Watchdog interrupt not handled\n");
+ return cactus_error_resp(ffa_dir_msg_dest(*args),
+ ffa_dir_msg_source(*args),
+ CACTUS_ERROR_TEST);
+}
+
+CACTUS_CMD_HANDLER(interrupt_serviced_cmd, CACTUS_LAST_INTERRUPT_SERVICED_CMD)
+{
+ unsigned int core_pos = get_current_core_id();
+
+ return cactus_response(ffa_dir_msg_dest(*args),
+ ffa_dir_msg_source(*args),
+ last_serviced_interrupt[core_pos]);
+}
diff --git a/spm/common/sp_helpers.c b/spm/common/sp_helpers.c
index 77031f8..448084f 100644
--- a/spm/common/sp_helpers.c
+++ b/spm/common/sp_helpers.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -13,6 +13,10 @@
#include "sp_helpers.h"
+spinlock_t sp_handler_lock[NUM_VINT_ID];
+
+void (*sp_interrupt_tail_end_handler[NUM_VINT_ID])(void);
+
uintptr_t bound_rand(uintptr_t min, uintptr_t max)
{
/*
@@ -80,3 +84,35 @@ void sp_sleep(uint32_t ms)
{
(void)sp_sleep_elapsed_time(ms);
}
+
+void sp_handler_spin_lock_init(void)
+{
+ for (uint32_t i = 0; i < NUM_VINT_ID; i++) {
+ init_spinlock(&sp_handler_lock[i]);
+ }
+}
+
+void sp_register_interrupt_tail_end_handler(void (*handler)(void),
+ uint32_t interrupt_id)
+{
+ if (interrupt_id >= NUM_VINT_ID) {
+ ERROR("Cannot register handler for interrupt %u\n", interrupt_id);
+ panic();
+ }
+
+ spin_lock(&sp_handler_lock[interrupt_id]);
+ sp_interrupt_tail_end_handler[interrupt_id] = handler;
+ spin_unlock(&sp_handler_lock[interrupt_id]);
+}
+
+void sp_unregister_interrupt_tail_end_handler(uint32_t interrupt_id)
+{
+ if (interrupt_id >= NUM_VINT_ID) {
+ ERROR("Cannot unregister handler for interrupt %u\n", interrupt_id);
+ panic();
+ }
+
+ spin_lock(&sp_handler_lock[interrupt_id]);
+ sp_interrupt_tail_end_handler[interrupt_id] = NULL;
+ spin_unlock(&sp_handler_lock[interrupt_id]);
+}
diff --git a/spm/common/sp_helpers.h b/spm/common/sp_helpers.h
index 6fe8ec0..ef60221 100644
--- a/spm/common/sp_helpers.h
+++ b/spm/common/sp_helpers.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -10,6 +10,10 @@
#include <stdint.h>
#include <tftf_lib.h>
#include <spm_common.h>
+#include <spinlock.h>
+
+/* Currently, Hafnium/SPM supports only 64 virtual interrupt IDs. */
+#define NUM_VINT_ID 64
typedef struct {
u_register_t fid;
@@ -62,4 +66,16 @@ uint64_t sp_sleep_elapsed_time(uint32_t ms);
/* Sleep for at least 'ms' milliseconds. */
void sp_sleep(uint32_t ms);
+void sp_handler_spin_lock_init(void);
+
+/* Handler invoked at the tail end of interrupt processing by SP. */
+extern void (*sp_interrupt_tail_end_handler[NUM_VINT_ID])(void);
+
+/* Register the handler. */
+void sp_register_interrupt_tail_end_handler(void (*handler)(void),
+ uint32_t interrupt_id);
+
+/* Un-register the handler. */
+void sp_unregister_interrupt_tail_end_handler(uint32_t interrupt_id);
+
#endif /* SP_HELPERS_H */
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_secure_interrupts.c b/tftf/tests/runtime_services/secure_service/test_ffa_secure_interrupts.c
index 6ff30f6..8ed590a 100644
--- a/tftf/tests/runtime_services/secure_service/test_ffa_secure_interrupts.c
+++ b/tftf/tests/runtime_services/secure_service/test_ffa_secure_interrupts.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -59,10 +59,11 @@ static bool disable_trusted_wdog_interrupt(ffa_id_t source, ffa_id_t dest)
* 1. Send a direct message request command to first Cactus SP to start the
* trusted watchdog timer.
*
- * 2. Send a command to SP to sleep by executing a busy loop.
+ * 2. Send a command to SP to first sleep( by executing a busy loop), then
+ * restart trusted watchdog timer and then sleep again.
*
- * 3. While SP is running the busy loop, Secure interrupt should trigger during
- * this time.
+ * 3. While SP is running the first busy loop, Secure interrupt should trigger
+ * during this time.
*
* 4. The interrupt will be trapped to SPM as IRQ. SPM will inject the virtual
* IRQ to the first SP through vIRQ conduit and perform eret to resume
@@ -74,22 +75,25 @@ static bool disable_trusted_wdog_interrupt(ffa_id_t source, ffa_id_t dest)
* 6. Cactus SP will perform End-Of-Interrupt and resume execution in the busy
* loop.
*
- * 7. Cactus SP will send a direct response message with the elapsed time back
+ * 7. Trusted watchdog timer will trigger once again followed by steps 4 to 6.
+ *
+ * 8. Cactus SP will send a direct response message with the elapsed time back
* to the normal world.
*
- * 8. We make sure the time elapsed in the sleep routine by SP is not less than
+ * 9. We make sure the time elapsed in the sleep routine by SP is not less than
* the requested value.
*
- * 9. For robustness of state transition checks, TFTF sends echo command using
- * a direct request message.
+ * 10. TFTF sends a direct request message to SP to query the ID of last serviced
+ * secure virtual interrupt.
*
- * 10. Further, TFTF expects SP to return with a success value through a direct
- * response message.
+ * 11. Further, TFTF expects SP to return the ID of Trusted Watchdog timer
+ * interrupt through a direct response message.
*
- * 11. Test finishes successfully once the TFTF disables the trusted watchdog
+ * 12. Test finishes successfully once the TFTF disables the trusted watchdog
* interrupt through a direct message request command.
*
*/
+
test_result_t test_ffa_sec_interrupt_sp_running(void)
{
smc_ret_values ret_values;
@@ -109,7 +113,7 @@ test_result_t test_ffa_sec_interrupt_sp_running(void)
}
/* Send request to first Cactus SP to sleep */
- ret_values = cactus_sleep_cmd(SENDER, RECEIVER, SP_SLEEP_TIME);
+ ret_values = cactus_sleep_trigger_wdog_cmd(SENDER, RECEIVER, SP_SLEEP_TIME, 50);
/*
* Secure interrupt should trigger during this time, Cactus
@@ -129,16 +133,18 @@ test_result_t test_ffa_sec_interrupt_sp_running(void)
return TEST_RESULT_FAIL;
}
- ret_values = cactus_echo_send_cmd(SENDER, RECEIVER, ECHO_VAL1);
+ /* Check for the last serviced secure virtual interrupt. */
+ ret_values = cactus_get_last_interrupt_cmd(SENDER, RECEIVER);
if (!is_ffa_direct_response(ret_values)) {
- ERROR("Expected direct response for echo command\n");
+ ERROR("Expected a direct response for last serviced interrupt"
+ " command\n");
return TEST_RESULT_FAIL;
}
- if (cactus_get_response(ret_values) != CACTUS_SUCCESS ||
- cactus_echo_get_val(ret_values) != ECHO_VAL1) {
- ERROR("Echo Failed!\n");
+ /* Make sure Trusted Watchdog timer interrupt was serviced*/
+ if (cactus_get_response(ret_values) != IRQ_TWDOG_INTID) {
+ ERROR("Trusted watchdog timer interrupt not serviced by SP\n");
return TEST_RESULT_FAIL;
}
@@ -179,11 +185,11 @@ test_result_t test_ffa_sec_interrupt_sp_running(void)
* 9. We make sure the time elapsed in the sleep routine is not less than
* the requested value.
*
- * 10. For robustness of state transition checks, TFTF sends echo command using
- * a direct request message.
+ * 10. TFTF sends a direct request message to SP to query the ID of last serviced
+ * secure virtual interrupt.
*
- * 11. Further, TFTF expects SP to return with a success value through a direct
- * response message.
+ * 11. Further, TFTF expects SP to return the ID of Trusted Watchdog timer
+ * interrupt through a direct response message.
*
* 12. Test finishes successfully once the TFTF disables the trusted watchdog
* interrupt through a direct message request command.
@@ -231,16 +237,18 @@ test_result_t test_ffa_sec_interrupt_sp_waiting(void)
return TEST_RESULT_FAIL;
}
- ret_values = cactus_echo_send_cmd(SENDER, RECEIVER, ECHO_VAL1);
+ /* Check for the last serviced secure virtual interrupt. */
+ ret_values = cactus_get_last_interrupt_cmd(SENDER, RECEIVER);
if (!is_ffa_direct_response(ret_values)) {
- ERROR("Expected direct response for echo command\n");
+ ERROR("Expected a direct response for last serviced interrupt"
+ " command\n");
return TEST_RESULT_FAIL;
}
- if (cactus_get_response(ret_values) != CACTUS_SUCCESS ||
- cactus_echo_get_val(ret_values) != ECHO_VAL1) {
- ERROR("Echo Failed!\n");
+ /* Make sure Trusted Watchdog timer interrupt was serviced*/
+ if (cactus_get_response(ret_values) != IRQ_TWDOG_INTID) {
+ ERROR("Trusted watchdog timer interrupt not serviced by SP\n");
return TEST_RESULT_FAIL;
}
@@ -280,11 +288,11 @@ test_result_t test_ffa_sec_interrupt_sp_waiting(void)
* 8. First SP checks for the elapsed time and sends a direct response with
* a SUCCESS value back to tftf.
*
- * 9. For robustness of state transition checks, TFTF sends echo command using
- * a direct request message to first SP.
+ * 9. TFTF sends a direct request message to SP to query the ID of last serviced
+ * secure virtual interrupt.
*
- * 10. Further, TFTF expects SP to return with a success value through a direct
- * response message.
+ * 10. Further, TFTF expects SP to return the ID of Trusted Watchdog timer
+ * interrupt through a direct response message.
*
* 11. Test finishes successfully once the TFTF disables the trusted watchdog
* interrupt through a direct message request command.
@@ -327,16 +335,18 @@ test_result_t test_ffa_sec_interrupt_sp_blocked(void)
return TEST_RESULT_FAIL;
}
- ret_values = cactus_echo_send_cmd(SENDER, RECEIVER, ECHO_VAL1);
+ /* Check for the last serviced secure virtual interrupt. */
+ ret_values = cactus_get_last_interrupt_cmd(SENDER, RECEIVER);
if (!is_ffa_direct_response(ret_values)) {
- ERROR("Expected direct response for echo command\n");
+ ERROR("Expected a direct response for last serviced interrupt"
+ " command\n");
return TEST_RESULT_FAIL;
}
- if (cactus_get_response(ret_values) != CACTUS_SUCCESS ||
- cactus_echo_get_val(ret_values) != ECHO_VAL1) {
- ERROR("Echo Failed!\n");
+ /* Make sure Trusted Watchdog timer interrupt was serviced*/
+ if (cactus_get_response(ret_values) != IRQ_TWDOG_INTID) {
+ ERROR("Trusted watchdog timer interrupt not serviced by SP\n");
return TEST_RESULT_FAIL;
}
@@ -378,11 +388,11 @@ test_result_t test_ffa_sec_interrupt_sp_blocked(void)
* 9. We make sure the time elapsed in the sleep routine by SP is not less than
* the requested value.
*
- * 10. For robustness of state transition checks, TFTF sends echo command using
- * a direct request message to both SPs.
+ * 10. TFTF sends a direct request message to SP to query the ID of last serviced
+ * secure virtual interrupt.
*
- * 11. Further, TFTF expects SP to return with a success value through a direct
- * response message.
+ * 11. Further, TFTF expects SP to return the ID of Trusted Watchdog timer
+ * interrupt through a direct response message.
*
* 12. Test finishes successfully once the TFTF disables the trusted watchdog
* interrupt through a direct message request command.
@@ -422,29 +432,18 @@ test_result_t test_ffa_sec_interrupt_sp1_waiting_sp2_running(void)
ERROR("Lapsed time less than requested sleep time\n");
}
- ret_values = cactus_echo_send_cmd(SENDER, RECEIVER, ECHO_VAL1);
-
- if (!is_ffa_direct_response(ret_values)) {
- ERROR("Echo to SP1 Failed no response!\n");
- return TEST_RESULT_FAIL;
- }
-
- if (cactus_get_response(ret_values) != CACTUS_SUCCESS ||
- cactus_echo_get_val(ret_values) != ECHO_VAL1) {
- ERROR("Echo to SP1 Failed!\n");
- return TEST_RESULT_FAIL;
- }
-
- ret_values = cactus_echo_send_cmd(SENDER, RECEIVER_2, ECHO_VAL1);
+ /* Check for the last serviced secure virtual interrupt. */
+ ret_values = cactus_get_last_interrupt_cmd(SENDER, RECEIVER);
if (!is_ffa_direct_response(ret_values)) {
- ERROR("Echo to SP2 Failed no response!\n");
+ ERROR("Expected a direct response for last serviced interrupt"
+ " command\n");
return TEST_RESULT_FAIL;
}
- if (cactus_get_response(ret_values) != CACTUS_SUCCESS ||
- cactus_echo_get_val(ret_values) != ECHO_VAL1) {
- ERROR("Echo to SP2 Failed!\n");
+ /* Make sure Trusted Watchdog timer interrupt was serviced*/
+ if (cactus_get_response(ret_values) != IRQ_TWDOG_INTID) {
+ ERROR("Trusted watchdog timer interrupt not serviced by SP\n");
return TEST_RESULT_FAIL;
}