diff options
-rw-r--r-- | include/runtime_services/cactus_test_cmds.h | 50 | ||||
-rw-r--r-- | include/runtime_services/ffa_helpers.h | 1 | ||||
-rw-r--r-- | include/runtime_services/spm_common.h | 12 | ||||
-rw-r--r-- | spm/cactus/aarch64/cactus_entrypoint.S | 4 | ||||
-rw-r--r-- | spm/cactus/aarch64/cactus_exceptions.S | 131 | ||||
-rw-r--r-- | spm/cactus/cactus.mk | 5 | ||||
-rw-r--r-- | spm/cactus/cactus_debug.c | 2 | ||||
-rw-r--r-- | spm/cactus/cactus_interrupt.c | 51 | ||||
-rw-r--r-- | spm/cactus/cactus_main.c | 17 | ||||
-rw-r--r-- | spm/cactus/cactus_tests/cactus_test_ffa.c | 1 | ||||
-rw-r--r-- | spm/cactus/cactus_tests/cactus_test_interrupts.c | 51 | ||||
-rw-r--r-- | spm/cactus/plat/arm/fvp/fdts/cactus.dts | 4 | ||||
-rw-r--r-- | spm/common/sp_helpers.c | 25 | ||||
-rw-r--r-- | spm/common/sp_helpers.h | 16 | ||||
-rw-r--r-- | spm/common/spm_helpers.c | 51 | ||||
-rw-r--r-- | spm/common/spm_helpers.h | 26 | ||||
-rw-r--r-- | tftf/tests/runtime_services/secure_service/test_ffa_interrupts.c | 150 | ||||
-rw-r--r-- | tftf/tests/runtime_services/secure_service/test_spci_blocking_interrupt.c | 121 | ||||
-rw-r--r-- | tftf/tests/tests-spm.mk | 1 | ||||
-rw-r--r-- | tftf/tests/tests-spm.xml | 6 |
20 files changed, 555 insertions, 170 deletions
diff --git a/include/runtime_services/cactus_test_cmds.h b/include/runtime_services/cactus_test_cmds.h index 246f4f979..d03a97fcb 100644 --- a/include/runtime_services/cactus_test_cmds.h +++ b/include/runtime_services/cactus_test_cmds.h @@ -8,6 +8,7 @@ #define CACTUS_TEST_CMDS #include <ffa_helpers.h> +#include <spm_common.h> /** * Success and error return to be sent over a msg response. @@ -249,4 +250,53 @@ static inline smc_ret_values cactus_req_simd_fill_send_cmd( 0); } +/** + * Command to request cactus to sleep for the given time in ms + * + * The command id is the hex representation of string "sleep" + */ +#define CACTUS_SLEEP_CMD U(0x736c656570) + +static inline smc_ret_values cactus_sleep_cmd( + ffa_vm_id_t source, ffa_vm_id_t dest, uint32_t sleep_time) +{ + return cactus_send_cmd(source, dest, CACTUS_SLEEP_CMD, sleep_time, 0, 0, + 0); +} + +static inline uint32_t cactus_get_sleep_time(smc_ret_values ret) +{ + return (uint32_t)ret.ret4; +} + +/** + * Command to request cactus to enable/disable an interrupt + * + * The command id is the hex representation of string "intr" + */ +#define CACTUS_INTERRUPT_CMD U(0x696e7472) + +static inline smc_ret_values cactus_interrupt_cmd( + ffa_vm_id_t source, ffa_vm_id_t dest, uint32_t interrupt_id, + bool enable, uint32_t pin) +{ + return cactus_send_cmd(source, dest, CACTUS_INTERRUPT_CMD, interrupt_id, + enable, pin, 0); +} + +static inline uint32_t cactus_get_interrupt_id(smc_ret_values ret) +{ + return (uint32_t)ret.ret4; +} + +static inline bool cactus_get_interrupt_enable(smc_ret_values ret) +{ + return (bool)ret.ret5; +} + +static inline enum interrupt_pin cactus_get_interrupt_pin(smc_ret_values ret) +{ + return (enum interrupt_pin)ret.ret6; +} + #endif diff --git a/include/runtime_services/ffa_helpers.h b/include/runtime_services/ffa_helpers.h index 4af051b87..592327af7 100644 --- a/include/runtime_services/ffa_helpers.h +++ b/include/runtime_services/ffa_helpers.h @@ -17,7 +17,6 @@ typedef unsigned short ffa_vm_id_t; typedef unsigned short ffa_vm_count_t; typedef unsigned short ffa_vcpu_count_t; -typedef uint32_t ffa_int_id_t; typedef uint64_t ffa_memory_handle_t; /** Flags to indicate properties of receivers during memory region retrieval. */ typedef uint8_t ffa_memory_receiver_flags_t; diff --git a/include/runtime_services/spm_common.h b/include/runtime_services/spm_common.h index dbb113bac..50159ecb8 100644 --- a/include/runtime_services/spm_common.h +++ b/include/runtime_services/spm_common.h @@ -14,6 +14,18 @@ /* Hypervisor ID at physical FFA instance */ #define HYP_ID (0) +/* ID for the first Secure Partition. */ +#define SPM_VM_ID_FIRST SP_ID(1) + +/* INTID for the managed exit virtual interrupt. */ +#define MANAGED_EXIT_INTERRUPT_ID U(4) + +/** IRQ/FIQ pin used for signaling a virtual interrupt. */ +enum interrupt_pin { + INTERRUPT_TYPE_IRQ, + INTERRUPT_TYPE_FIQ, +}; + /* * The bit 15 of the FF-A ID indicates whether the partition is executing * in the normal world, in case it is a Virtual Machine (VM); or in the diff --git a/spm/cactus/aarch64/cactus_entrypoint.S b/spm/cactus/aarch64/cactus_entrypoint.S index 7775b4697..154106337 100644 --- a/spm/cactus/aarch64/cactus_entrypoint.S +++ b/spm/cactus/aarch64/cactus_entrypoint.S @@ -59,8 +59,8 @@ secondary_cold_entry: isb /* Set up exceptions vector table */ - adrp x1, tftf_vector - add x1, x1, :lo12:tftf_vector + adrp x1, cactus_vector + add x1, x1, :lo12:cactus_vector msr vbar_el1, x1 isb diff --git a/spm/cactus/aarch64/cactus_exceptions.S b/spm/cactus/aarch64/cactus_exceptions.S new file mode 100644 index 000000000..31cdbf9a5 --- /dev/null +++ b/spm/cactus/aarch64/cactus_exceptions.S @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2021, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <asm_macros.S> + + .globl cactus_vector + +/* + * Exception vector code for unhandled exceptions. + * Print a crash dump on the UART and loops forever. + */ +.macro unhandled_exception name + vector_entry \name + b crash_dump + end_vector_entry \name +.endm + +vector_base cactus_vector + + /* + * Current EL with SP0 : 0x0 - 0x200. + */ +unhandled_exception sync_sp0 +unhandled_exception irq_sp0 +unhandled_exception fiq_sp0 +unhandled_exception serr_sp0 + + /* + * Current EL with SPx : 0x200 - 0x400. + */ +unhandled_exception sync_spx + +vector_entry irq_spx + b irq_vector_entry +end_vector_entry irq_spx + +vector_entry fiq_spx + b fiq_vector_entry +end_vector_entry fiq_spx + +unhandled_exception serr_spx + + /* + * Lower EL using AArch64 : 0x400 - 0x600. + */ +unhandled_exception sync_a64 +unhandled_exception irq_a64 +unhandled_exception fiq_a64 +unhandled_exception serr_a64 + + /* + * Lower EL using AArch32 : 0x600 - 0x800. + */ +unhandled_exception sync_a32 +unhandled_exception irq_a32 +unhandled_exception fiq_a32 +unhandled_exception serr_a32 + +.macro save_gp_regs + stp x0, x1, [sp, #0x0] + stp x2, x3, [sp, #0x10] + stp x4, x5, [sp, #0x20] + stp x6, x7, [sp, #0x30] + stp x8, x9, [sp, #0x40] + stp x10, x11, [sp, #0x50] + stp x12, x13, [sp, #0x60] + stp x14, x15, [sp, #0x70] + stp x16, x17, [sp, #0x80] + stp x18, x19, [sp, #0x90] + stp x20, x21, [sp, #0xa0] + stp x22, x23, [sp, #0xb0] + stp x24, x25, [sp, #0xc0] + stp x26, x27, [sp, #0xd0] + stp x28, x29, [sp, #0xe0] + /* We push xzr simply to keep the stack 16-byte aligned. */ + stp x30, xzr, [sp, #0xf0] +.endm + +.macro restore_gp_regs + ldp x30, xzr, [sp, #0xf0] + ldp x28, x29, [sp, #0xe0] + ldp x26, x27, [sp, #0xd0] + ldp x24, x25, [sp, #0xc0] + ldp x22, x23, [sp, #0xb0] + ldp x20, x21, [sp, #0xa0] + ldp x18, x19, [sp, #0x90] + ldp x16, x17, [sp, #0x80] + ldp x14, x15, [sp, #0x70] + ldp x12, x13, [sp, #0x60] + ldp x10, x11, [sp, #0x50] + ldp x8, x9, [sp, #0x40] + ldp x6, x7, [sp, #0x30] + ldp x4, x5, [sp, #0x20] + ldp x2, x3, [sp, #0x10] + ldp x0, x1, [sp, #0x0] +.endm + +func irq_vector_entry + sub sp, sp, #0x100 + save_gp_regs + bl cactus_irq_handler + restore_gp_regs + add sp, sp, #0x100 + eret +endfunc irq_vector_entry + +func fiq_vector_entry + sub sp, sp, #0x100 + save_gp_regs + bl cactus_fiq_handler + restore_gp_regs + add sp, sp, #0x100 + eret +endfunc fiq_vector_entry + +func crash_dump + /* Save general-purpose registers on the stack. */ + sub sp, sp, #0x100 + save_gp_regs + + /* Save original stack pointer value on the stack. */ + add x1, sp, #0x100 + str x1, [sp, #0xf8] + + /* Print the saved CPU context on the UART. */ + mov x0, sp + b print_exception +endfunc crash_dump diff --git a/spm/cactus/cactus.mk b/spm/cactus/cactus.mk index 08b824c13..a52120f1f 100644 --- a/spm/cactus/cactus.mk +++ b/spm/cactus/cactus.mk @@ -32,18 +32,22 @@ CACTUS_INCLUDES := \ CACTUS_SOURCES := \ $(addprefix spm/cactus/, \ aarch64/cactus_entrypoint.S \ + aarch64/cactus_exceptions.S \ cactus_debug.c \ + cactus_interrupt.c \ cactus_main.c \ ) \ $(addprefix spm/common/, \ aarch64/sp_arch_helpers.S \ sp_helpers.c \ + spm_helpers.c \ ) \ $(addprefix spm/cactus/cactus_tests/, \ cactus_message_loop.c \ cactus_test_cpu_features.c \ cactus_test_direct_messaging.c \ cactus_test_ffa.c \ + cactus_test_interrupts.c \ cactus_test_memory_sharing.c \ ) @@ -53,7 +57,6 @@ CACTUS_SOURCES += \ tftf/framework/${ARCH}/asm_debug.S \ tftf/tests/runtime_services/secure_service/ffa_helpers.c \ tftf/tests/runtime_services/secure_service/spm_common.c \ - tftf/framework/${ARCH}/exceptions.S \ tftf/framework/${ARCH}/exception_report.c CACTUS_SOURCES += drivers/arm/pl011/${ARCH}/pl011_console.S \ diff --git a/spm/cactus/cactus_debug.c b/spm/cactus/cactus_debug.c index 43093a6bb..30a25278d 100644 --- a/spm/cactus/cactus_debug.c +++ b/spm/cactus/cactus_debug.c @@ -6,7 +6,7 @@ #include <drivers/arm/pl011.h> #include <drivers/console.h> -#include <sp_helpers.h> +#include <spm_helpers.h> #include "cactus.h" diff --git a/spm/cactus/cactus_interrupt.c b/spm/cactus/cactus_interrupt.c new file mode 100644 index 000000000..7de36cf0c --- /dev/null +++ b/spm/cactus/cactus_interrupt.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2021, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <debug.h> + +#include <ffa_helpers.h> +#include <sp_helpers.h> +#include <spm_helpers.h> + +#include "cactus_test_cmds.h" +#include "spm_common.h" + +extern ffa_vm_id_t g_ffa_id; + +static void managed_exit_handler(void) +{ + /* + * Real SP will save its context here. + * Send interrupt ID for acknowledgement + */ + cactus_response(g_ffa_id, HYP_ID, MANAGED_EXIT_INTERRUPT_ID); +} + +int cactus_irq_handler(void) +{ + uint32_t irq_num; + + irq_num = spm_interrupt_get(); + + ERROR("%s: Interrupt ID %u not handled!\n", __func__, irq_num); + + return 0; +} + +int cactus_fiq_handler(void) +{ + uint32_t fiq_num; + + fiq_num = spm_interrupt_get(); + + if (fiq_num == MANAGED_EXIT_INTERRUPT_ID) { + managed_exit_handler(); + } else { + ERROR("%s: Interrupt ID %u not handled!\n", __func__, fiq_num); + } + + return 0; +} diff --git a/spm/cactus/cactus_main.c b/spm/cactus/cactus_main.c index e54f3b0da..45d2db039 100644 --- a/spm/cactus/cactus_main.c +++ b/spm/cactus/cactus_main.c @@ -20,6 +20,7 @@ #include <plat/common/platform.h> #include <platform_def.h> #include <sp_helpers.h> +#include <spm_helpers.h> #include <std_svc.h> #include "cactus_def.h" @@ -32,6 +33,9 @@ extern const char version_string[]; extern void secondary_cold_entry(void); +/* Global ffa_id */ +ffa_vm_id_t g_ffa_id; + /* * * Message loop function @@ -175,18 +179,17 @@ void __dead2 cactus_main(bool primary_cold_boot) /* Get current FFA id */ smc_ret_values ffa_id_ret = ffa_id_get(); + ffa_vm_id_t ffa_id = (ffa_vm_id_t)(ffa_id_ret.ret2 & 0xffff); if (ffa_func_id(ffa_id_ret) != FFA_SUCCESS_SMC32) { ERROR("FFA_ID_GET failed.\n"); panic(); } - ffa_vm_id_t ffa_id = ffa_id_ret.ret2 & 0xffff; if (primary_cold_boot == true) { /* Clear BSS */ memset((void *)CACTUS_BSS_START, 0, CACTUS_BSS_END - CACTUS_BSS_START); - mb.send = (void *) get_sp_tx_start(ffa_id); mb.recv = (void *) get_sp_rx_start(ffa_id); @@ -194,8 +197,18 @@ void __dead2 cactus_main(bool primary_cold_boot) cactus_plat_configure_mmu(ffa_id); } + /* + * The local ffa_id value is held on the stack. The global g_ffa_id + * value is set after BSS is cleared. + */ + g_ffa_id = ffa_id; + enable_mmu_el1(0); + /* Enable IRQ/FIQ */ + enable_irq(); + enable_fiq(); + if (primary_cold_boot == false) { goto msg_loop; } diff --git a/spm/cactus/cactus_tests/cactus_test_ffa.c b/spm/cactus/cactus_tests/cactus_test_ffa.c index c1ba78350..2ade7bd98 100644 --- a/spm/cactus/cactus_tests/cactus_test_ffa.c +++ b/spm/cactus/cactus_tests/cactus_test_ffa.c @@ -11,6 +11,7 @@ #include <cactus_platform_def.h> #include <ffa_endpoints.h> #include <sp_helpers.h> +#include <spm_helpers.h> #include <spm_common.h> #include <lib/libc/string.h> diff --git a/spm/cactus/cactus_tests/cactus_test_interrupts.c b/spm/cactus/cactus_tests/cactus_test_interrupts.c new file mode 100644 index 000000000..b675dfc1e --- /dev/null +++ b/spm/cactus/cactus_tests/cactus_test_interrupts.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2021, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <common/debug.h> +#include <sp_helpers.h> +#include <spm_helpers.h> + +#include "cactus_message_loop.h" +#include "cactus_test_cmds.h" + +CACTUS_CMD_HANDLER(sleep_cmd, CACTUS_SLEEP_CMD) +{ + uint64_t timer_freq = read_cntfrq_el0(); + uint64_t time1, time2, time_lapsed; + uint32_t sleep_time = cactus_get_sleep_time(*args); + + VERBOSE("Request to sleep %x for %ums.\n", ffa_dir_msg_dest(*args), sleep_time); + + time1 = read_cntvct_el0(); + sp_sleep(sleep_time); + time2 = read_cntvct_el0(); + + /* Lapsed time should be at least equal to sleep time */ + time_lapsed = ((time2 - time1) * 1000) / timer_freq; + + return cactus_response(ffa_dir_msg_dest(*args), + ffa_dir_msg_source(*args), + time_lapsed); +} + +CACTUS_CMD_HANDLER(interrupt_cmd, CACTUS_INTERRUPT_CMD) +{ + uint32_t int_id = cactus_get_interrupt_id(*args); + bool enable = cactus_get_interrupt_enable(*args); + enum interrupt_pin pin = cactus_get_interrupt_pin(*args); + int64_t ret; + + ret = spm_interrupt_enable(int_id, enable, pin); + if (ret != 0) { + return cactus_error_resp(ffa_dir_msg_dest(*args), + ffa_dir_msg_source(*args), + CACTUS_ERROR_TEST); + } + + return cactus_response(ffa_dir_msg_dest(*args), + ffa_dir_msg_source(*args), + CACTUS_SUCCESS); +} diff --git a/spm/cactus/plat/arm/fvp/fdts/cactus.dts b/spm/cactus/plat/arm/fvp/fdts/cactus.dts index 45292730a..eb569f7a1 100644 --- a/spm/cactus/plat/arm/fvp/fdts/cactus.dts +++ b/spm/cactus/plat/arm/fvp/fdts/cactus.dts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020, Arm Limited. All rights reserved. + * Copyright (c) 2019-2021, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * @@ -27,7 +27,7 @@ entrypoint-offset = <0x00001000>; xlat-granule = <0>; /* 4KiB */ boot-order = <0>; - messaging-method = <0>; /* Direct messaging only */ + messaging-method = <3>; /* Direct messaging with managed exit */ run-time-model = <0>; /* Run to completion */ /* Boot protocol */ diff --git a/spm/common/sp_helpers.c b/spm/common/sp_helpers.c index 5d76dc8e0..a6b6bc5d9 100644 --- a/spm/common/sp_helpers.c +++ b/spm/common/sp_helpers.c @@ -71,28 +71,3 @@ void sp_sleep(uint32_t ms) time2 = read_cntvct_el0(); } } - -/******************************************************************************* - * Hypervisor Calls Wrappers - ******************************************************************************/ - -ffa_int_id_t spm_interrupt_get(void) -{ - hvc_args args = { - .fid = SPM_INTERRUPT_GET - }; - - hvc_ret_values ret = tftf_hvc(&args); - - return ret.ret0; -} - -void spm_debug_log(char c) -{ - hvc_args args = { - .fid = SPM_DEBUG_LOG, - .arg1 = c - }; - - (void)tftf_hvc(&args); -} diff --git a/spm/common/sp_helpers.h b/spm/common/sp_helpers.h index ec9222789..399200a01 100644 --- a/spm/common/sp_helpers.h +++ b/spm/common/sp_helpers.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2020, Arm Limited. All rights reserved. + * Copyright (c) 2018-2021, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -11,12 +11,6 @@ #include <tftf_lib.h> #include <ffa_helpers.h> -#define SPM_VM_ID_FIRST SP_ID(1) - -/* Should match with IDs defined in SPM/Hafnium */ -#define SPM_INTERRUPT_GET (0xFF04) -#define SPM_DEBUG_LOG (0xBD000000) - typedef struct { u_register_t fid; u_register_t arg1; @@ -65,12 +59,4 @@ void announce_test_end(const char *test_desc); /* Sleep for at least 'ms' milliseconds. */ void sp_sleep(uint32_t ms); -/* - * Hypervisor Calls Wrappers - */ - -ffa_int_id_t spm_interrupt_get(void); - -void spm_debug_log(char c); - #endif /* SP_HELPERS_H */ diff --git a/spm/common/spm_helpers.c b/spm/common/spm_helpers.c new file mode 100644 index 000000000..2ccf3f7d5 --- /dev/null +++ b/spm/common/spm_helpers.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2021, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <spm_helpers.h> + +/******************************************************************************* + * Hypervisor Calls Wrappers + ******************************************************************************/ + +uint32_t spm_interrupt_get(void) +{ + hvc_args args = { + .fid = SPM_INTERRUPT_GET + }; + + hvc_ret_values ret = tftf_hvc(&args); + + return ret.ret0; +} + +void spm_debug_log(char c) +{ + hvc_args args = { + .fid = SPM_DEBUG_LOG, + .arg1 = c + }; + + (void)tftf_hvc(&args); +} + +/** + * Hypervisor call to enable/disable SP delivery of a virtual interrupt of + * int_id value through the IRQ or FIQ vector (pin). + * Returns 0 on success, or -1 if passing an invalid interrupt id. + */ +int64_t spm_interrupt_enable(uint32_t int_id, bool enable, enum interrupt_pin pin) +{ + hvc_args args = { + .fid = SPM_INTERRUPT_ENABLE, + .arg1 = int_id, + .arg2 = enable, + .arg3 = pin + }; + + hvc_ret_values ret = tftf_hvc(&args); + + return (int64_t)ret.ret0; +} diff --git a/spm/common/spm_helpers.h b/spm/common/spm_helpers.h new file mode 100644 index 000000000..10f73161c --- /dev/null +++ b/spm/common/spm_helpers.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2021, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef SPMC_H +#define SPMC_H + +#include <ffa_helpers.h> +#include <spm_common.h> + +/* Should match with IDs defined in SPM/Hafnium */ +#define SPM_INTERRUPT_ENABLE (0xFF03) +#define SPM_INTERRUPT_GET (0xFF04) +#define SPM_DEBUG_LOG (0xBD000000) + +/* + * Hypervisor Calls Wrappers + */ + +uint32_t spm_interrupt_get(void); +int64_t spm_interrupt_enable(uint32_t int_id, bool enable, enum interrupt_pin pin); +void spm_debug_log(char c); + +#endif /* SPMC_H */ diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_interrupts.c b/tftf/tests/runtime_services/secure_service/test_ffa_interrupts.c new file mode 100644 index 000000000..7c70de2c3 --- /dev/null +++ b/tftf/tests/runtime_services/secure_service/test_ffa_interrupts.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2021, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <cactus_test_cmds.h> +#include <ffa_endpoints.h> +#include <ffa_helpers.h> +#include <test_helpers.h> +#include <timer.h> + +static volatile int timer_irq_received; + +#define SENDER HYP_ID +#define RECEIVER SP_ID(1) +#define SLEEP_TIME 200U + +static const struct ffa_uuid expected_sp_uuids[] = { + {PRIMARY_UUID} + }; + +/* + * ISR for the timer interrupt. Update a global variable to check it has been + * called. + */ +static int timer_handler(void *data) +{ + assert(timer_irq_received == 0); + timer_irq_received = 1; + return 0; +} + +/* + * @Test_Aim@ Test non-secure interrupts while executing Secure Partition. + * + * 1. Enable managed exit interrupt by sending interrupt_enable command to + * Cactus. + * + * 2. Register a handler for the non-secure timer interrupt. Program it to fire + * in a certain time. + * + * 3. Send a blocking request to Cactus to execute in busy loop. + * + * 4. While executing in busy loop, the non-secure timer should + * fire and trap into SPM running at S-EL2 as FIQ. + * + * 5. SPM injects a managed exit virtual FIQ into Cactus (as configured in the + * interrupt enable call), causing it to run its interrupt handler. + * + * 6. Cactus's managed exit handler acknowledges interrupt arrival by + * requesting the interrupt id to the SPMC, and check if it is the + * MANAGED_EXIT_INTERRUPT_ID. + * + * 7. Check whether the pending non-secure timer interrupt successfully got + * handled in TFTF. + * + * 8. Send a direct message request command to resume Cactus's execution. + * It resumes in the sleep loop and completes it. It then returns with + * a direct message response. Check if time lapsed is greater than + * sleeping time. + * + */ +test_result_t test_ffa_ns_interrupt(void) +{ + int ret; + smc_ret_values ret_values; + + CHECK_SPMC_TESTING_SETUP(1, 0, expected_sp_uuids); + + /* Enable managed exit interrupt as FIQ in the secure side. */ + ret_values = cactus_interrupt_cmd(SENDER, RECEIVER, MANAGED_EXIT_INTERRUPT_ID, + true, INTERRUPT_TYPE_FIQ); + + if (!is_ffa_direct_response(ret_values)) { + return TEST_RESULT_FAIL; + } + + if (cactus_get_response(ret_values) != CACTUS_SUCCESS) { + ERROR("Failed to enable Managed exit interrupt\n"); + return TEST_RESULT_FAIL; + } + + /* Program timer */ + timer_irq_received = 0; + tftf_timer_register_handler(timer_handler); + + ret = tftf_program_timer(100); + if (ret < 0) { + ERROR("Failed to program timer (%d)\n", ret); + return TEST_RESULT_FAIL; + } + + /* Send request to primary Cactus to sleep for 200ms */ + ret_values = cactus_sleep_cmd(SENDER, RECEIVER, SLEEP_TIME); + + if (!is_ffa_direct_response(ret_values)) { + return TEST_RESULT_FAIL; + } + + /* + * Managed exit interrupt occurs during this time, Cactus + * will respond with interrupt ID. + */ + if (cactus_get_response(ret_values) != MANAGED_EXIT_INTERRUPT_ID) { + ERROR("Managed exit interrupt did not occur!\n"); + return TEST_RESULT_FAIL; + } + + /* Check that the timer interrupt has been handled in NS-world (TFTF) */ + tftf_cancel_timer(); + tftf_timer_unregister_handler(); + + if (timer_irq_received == 0) { + ERROR("Timer interrupt hasn't actually been handled.\n"); + return TEST_RESULT_FAIL; + } + + /* + * Send a dummy direct message request to relinquish CPU cycles. + * This resumes Cactus in the sleep routine. + */ + ret_values = ffa_msg_send_direct_req64(SENDER, RECEIVER, + 0, 0, 0, 0, 0); + + if (!is_ffa_direct_response(ret_values)) { + return TEST_RESULT_FAIL; + } + + /* Make sure elapsed time not less than sleep time */ + if (cactus_get_response(ret_values) < SLEEP_TIME) { + ERROR("Lapsed time less than requested sleep time\n"); + return TEST_RESULT_FAIL; + } + + /* Disable Managed exit interrupt */ + ret_values = cactus_interrupt_cmd(SENDER, RECEIVER, MANAGED_EXIT_INTERRUPT_ID, + false, 0); + + if (!is_ffa_direct_response(ret_values)) { + return TEST_RESULT_FAIL; + } + + if (cactus_get_response(ret_values) != CACTUS_SUCCESS) { + ERROR("Failed to disable Managed exit interrupt\n"); + return TEST_RESULT_FAIL; + } + + return TEST_RESULT_SUCCESS; +} diff --git a/tftf/tests/runtime_services/secure_service/test_spci_blocking_interrupt.c b/tftf/tests/runtime_services/secure_service/test_spci_blocking_interrupt.c deleted file mode 100644 index 44ee0f9a9..000000000 --- a/tftf/tests/runtime_services/secure_service/test_spci_blocking_interrupt.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2018, Arm Limited. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include <arch_helpers.h> -#include <assert.h> -#include <cactus_def.h> -#include <debug.h> -#include <smccc.h> -#include <spci_helpers.h> -#include <spci_svc.h> -#include <string.h> -#include <test_helpers.h> -#include <tftf_lib.h> -#include <timer.h> - -static volatile int timer_irq_received; - -/* - * ISR for the timer interrupt. Update a global variable to check it has been - * called. - */ -static int timer_handler(void *data) -{ - assert(timer_irq_received == 0); - timer_irq_received = 1; - return 0; -} - -/* - * @Test_Aim@ Test that non-secure interrupts do not interrupt blocking - * requests. - * - * 1. Register a handler for the non-secure timer interrupt. Program it to fire - * in a certain time. - * - * 2. Send a blocking request to Cactus to sleep for more time than the timer. - * - * 3. While servicing the timer sleep request, the non-secure timer should - * fire but not interrupt Cactus. - * - * 4. Once back in TFTF, check the response from Cactus, which shows whether the - * secure service indeed ran to completion. - * - * 5. Also check whether the pending non-secure timer interrupt successfully got - * handled in TFTF. - */ -test_result_t test_spci_blocking_interrupt_by_ns(void) -{ - int ret; - uint16_t handle_cactus; - test_result_t result = TEST_RESULT_SUCCESS; - - SKIP_TEST_IF_SPCI_VERSION_LESS_THAN(0, 1); - - /* Open handle */ - - ret = spci_service_handle_open(TFTF_SPCI_CLIENT_ID, &handle_cactus, - CACTUS_SERVICE1_UUID); - if (ret != SPCI_SUCCESS) { - tftf_testcase_printf("%d: SPM failed to return a valid handle. Returned: %d\n", - __LINE__, ret); - return TEST_RESULT_FAIL; - } - - /* Program timer */ - - timer_irq_received = 0; - tftf_timer_register_handler(timer_handler); - - ret = tftf_program_timer(100); - if (ret < 0) { - tftf_testcase_printf("Failed to program timer (%d)\n", ret); - result = TEST_RESULT_FAIL; - } - - /* Send request to Cactus */ - - ret = spci_service_request_blocking(CACTUS_SLEEP_MS, 200U, - 0, 0, 0, 0, - TFTF_SPCI_CLIENT_ID, - handle_cactus, - NULL, NULL, NULL); - if (ret != SPCI_SUCCESS) { - /* - * If the interrupt is handled during the blocking call, there - * will be a crash in EL3 because the function that invokes a - * blocking call doesn't know how to handle it. The CPU won't - * come back here (because it should never happen!). - */ - tftf_testcase_printf("%d: SPM should have returned SPCI_SUCCESS. Returned: %d\n", - __LINE__, ret); - result = TEST_RESULT_FAIL; - } - - /* Check that the interrupt has been handled */ - - tftf_cancel_timer(); - tftf_timer_unregister_handler(); - - if (timer_irq_received == 0) { - tftf_testcase_printf("%d: Timer interrupt hasn't actually been handled.\n", - __LINE__); - result = TEST_RESULT_FAIL; - } - - /* Close handle */ - - ret = spci_service_handle_close(TFTF_SPCI_CLIENT_ID, handle_cactus); - if (ret != SPCI_SUCCESS) { - tftf_testcase_printf("%d: SPM failed to close the handle. Returned: %d\n", - __LINE__, ret); - result = TEST_RESULT_FAIL; - } - - /* All tests finished */ - - return result; -} diff --git a/tftf/tests/tests-spm.mk b/tftf/tests/tests-spm.mk index 73d2baf3d..9364052b6 100644 --- a/tftf/tests/tests-spm.mk +++ b/tftf/tests/tests-spm.mk @@ -10,6 +10,7 @@ TESTS_SOURCES += \ spm_common.c \ test_ffa_direct_messaging.c \ test_ffa_features.c \ + test_ffa_interrupts.c \ test_ffa_memory_sharing.c \ test_ffa_rxtx_map.c \ test_ffa_version.c \ diff --git a/tftf/tests/tests-spm.xml b/tftf/tests/tests-spm.xml index ee3429278..01ebceab2 100644 --- a/tftf/tests/tests-spm.xml +++ b/tftf/tests/tests-spm.xml @@ -78,4 +78,10 @@ function="test_simd_vectors_preserved" /> </testsuite> + <testsuite name="FF-A Interrupt" + description="Test non-secure Interrupts" > + <testcase name="Test NS interrupts" + function="test_ffa_ns_interrupt" /> + </testsuite> + </testsuites> |