diff options
-rw-r--r-- | include/runtime_services/cactus_test_cmds.h | 36 | ||||
-rw-r--r-- | spm/cactus/cactus_interrupt.c | 17 | ||||
-rw-r--r-- | spm/cactus/cactus_main.c | 3 | ||||
-rw-r--r-- | spm/cactus/cactus_tests/cactus_test_interrupts.c | 79 | ||||
-rw-r--r-- | spm/common/sp_helpers.c | 38 | ||||
-rw-r--r-- | spm/common/sp_helpers.h | 18 | ||||
-rw-r--r-- | tftf/tests/runtime_services/secure_service/test_ffa_secure_interrupts.c | 113 |
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; } |