From f1c6fea282c053f052792bd18f11d409b5e987e9 Mon Sep 17 00:00:00 2001 From: Vincent Guittot Date: Thu, 25 Feb 2021 09:42:35 +0100 Subject: [PATCH 1/3] arch: Remove infinite loop from arch_init Some architectures don't want to loop indefinitly in the same context of the initialization. Let architecture decides if it wants to stay in the initialization context or finish processing the events raised during init and return. No functional changes expected for current arch. fwk_process_event_queue() can then be called to process the pending events. Signed-off-by: Vincent Guittot --- CMakeLists.txt | 6 ++++++ doc/cmake_readme.md | 2 ++ doc/framework.md | 16 ++++++++++++++++ framework/CMakeLists.txt | 4 ++++ framework/include/fwk_core.h | 7 +++++++ framework/include/internal/fwk_core.h | 7 ++++--- framework/src/fwk_arch.c | 14 ++++++++++++++ framework/src/fwk_core.c | 12 +++++++++--- framework/src/fwk_module.c | 2 -- framework/test/test_fwk_core.c | 16 ++++++++-------- framework/test/test_fwk_module.c | 2 +- tools/build_system/cpu.mk | 3 ++- tools/build_system/firmware.mk | 6 ++++++ tools/build_system/rules.mk | 4 ++++ tools/cppcheck_suppress_list.txt | 2 +- 15 files changed, 84 insertions(+), 19 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a01133fa9..4f30068f0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -331,6 +331,12 @@ set(SCP_ENABLE_OVERRIDE_FIRMWARE_NAME ${SCP_ENABLE_OVERRIDE_FIRMWARE_NAME_INIT} CACHE STRING "Override firmware binary name") +cmake_dependent_option( + SCP_ENABLE_SUB_SYSTEM_MODE "Enable the execution as a sub-system?" + "${SCP_ENABLE_SUB_SYSTEM_MODE_INIT}" + "DEFINED SCP_ENABLE_SUB_SYSTEM_MODE_INIT" + "${SCP_ENABLE_SUB_SYSTEM_MODE}") + cmake_dependent_option( SCP_ENABLE_NOTIFICATIONS "Enable the notification subsystem?" "${SCP_ENABLE_NOTIFICATIONS_INIT}" "DEFINED SCP_ENABLE_NOTIFICATIONS_INIT" diff --git a/doc/cmake_readme.md b/doc/cmake_readme.md index 237edbfa4..f2ea184a8 100644 --- a/doc/cmake_readme.md +++ b/doc/cmake_readme.md @@ -120,6 +120,8 @@ few common options can be configured. - SCP_TARGET_EXCLUDE_BASE_PROTOCOL: Exclude Base Protocol functionality from the SCMI Module. +- SCP_ENABLE_SUB_SYSTEM_MODE: Enable the execution as a sub-system. + It can also be used to provide some platform specific settings. e.g. For ARM Juno platform. See below diff --git a/doc/framework.md b/doc/framework.md index eeb00072f..75040faf4 100644 --- a/doc/framework.md +++ b/doc/framework.md @@ -483,6 +483,22 @@ available. This is the final pre-runtime stage. **Note:** Participation in this stage is optional. +#### Runtime phase + +Once the pre-runtime stages have been successfully completed, the firmware will +start to process events raised by modules or interrupts. By default, the +firmware will loop forever waiting for new events to process at the end of the +pre-runtime stages but it is possible to return after processing pending events +when the event list is empty. + +##### Sub system runtime mode + +When SCP_ENABLE_SUB_SYSTEM_MODE is set, fwk_arch_init() will return after +processing the pending events. Then, it's up to the system to call the function +fwk_process_event_queue() when new events have been added into the list. Such +behavior is useful when the SCP-firmware is a sub part of a larger system like +being an application running in an execution environnement (i.e RTOS or TEE). + #### Error Handling Errors that occur during the pre-runtime phase (such as failures that occur diff --git a/framework/CMakeLists.txt b/framework/CMakeLists.txt index 01f93a3bb..1cb76dec3 100644 --- a/framework/CMakeLists.txt +++ b/framework/CMakeLists.txt @@ -41,6 +41,10 @@ target_sources( "${CMAKE_CURRENT_SOURCE_DIR}/src/fwk_core.c") +if(SCP_ENABLE_SUB_SYSTEM_MODE) + target_compile_definitions(framework PUBLIC "BUILD_HAS_SUB_SYSTEM_MODE") +endif() + if(SCP_ENABLE_NOTIFICATIONS) target_sources(framework PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src/fwk_notification.c") diff --git a/framework/include/fwk_core.h b/framework/include/fwk_core.h index 32b7dc2cc..d3f939876 100644 --- a/framework/include/fwk_core.h +++ b/framework/include/fwk_core.h @@ -67,6 +67,13 @@ : __fwk_put_event, struct fwk_event_light * \ : __fwk_put_event_light)(event) + + +/*! + * \brief Processing events already raised by modules and interrupt handlers. + */ +void fwk_process_event_queue(void); + /*! * \brief Get a copy of a delayed response event. * diff --git a/framework/include/internal/fwk_core.h b/framework/include/internal/fwk_core.h index dc109fda4..ca580cd10 100644 --- a/framework/include/internal/fwk_core.h +++ b/framework/include/internal/fwk_core.h @@ -25,12 +25,13 @@ int __fwk_init(size_t event_count); /* - * \brief Begin waiting for and processing events raised by modules and - * interrupt handlers. + * \brief Loop forever, processing events raised by modules and interrupt + * handlers. This function will suspend execution if the queue is empty and + * resume on an interrupt. * * \return The function does not return. */ -noreturn void __fwk_run(void); +noreturn void __fwk_run_main_loop(void); /* * \brief Get the event being currently processed. diff --git a/framework/src/fwk_arch.c b/framework/src/fwk_arch.c index 62376c5eb..f2695f97a 100644 --- a/framework/src/fwk_arch.c +++ b/framework/src/fwk_arch.c @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -31,6 +32,7 @@ extern int fwk_interrupt_init(const struct fwk_arch_interrupt_driver *driver); static int fwk_arch_interrupt_init(int (*interrupt_init_handler)( const struct fwk_arch_interrupt_driver **driver)) { + /* Initialize interrupt management */ int status; const struct fwk_arch_interrupt_driver *driver; @@ -87,6 +89,18 @@ int fwk_arch_init(const struct fwk_arch_init_driver *driver) return FWK_E_PANIC; } + /* + * In case firmware running under other OS context, finish processing of + * any raised events/interrupts and return. Else continue to process events + * in a forever loop. + */ +#if defined(BUILD_HAS_SUB_SYSTEM_MODE) + fwk_process_event_queue(); + (void)fwk_log_unbuffer(); +#else + __fwk_run_main_loop(); +#endif + return FWK_SUCCESS; } diff --git a/framework/src/fwk_core.c b/framework/src/fwk_core.c index f4b74aa41..53882200e 100644 --- a/framework/src/fwk_core.c +++ b/framework/src/fwk_core.c @@ -288,17 +288,23 @@ int __fwk_init(size_t event_count) return FWK_SUCCESS; } -noreturn void __fwk_run(void) +void fwk_process_event_queue(void) { for (;;) { while (!fwk_list_is_empty(&ctx.event_queue)) { process_next_event(); } - if (process_isr()) { - continue; + if (!process_isr()) { + break; } + } +} +noreturn void __fwk_run_main_loop(void) +{ + for (;;) { + fwk_process_event_queue(); (void)fwk_log_unbuffer(); fwk_arch_suspend(); } diff --git a/framework/src/fwk_module.c b/framework/src/fwk_module.c index 269b8a48e..1e39b0fcb 100644 --- a/framework/src/fwk_module.c +++ b/framework/src/fwk_module.c @@ -446,8 +446,6 @@ int fwk_module_start(void) FWK_LOG_CRIT("[FWK] Module initialization complete!"); - __fwk_run(); - return FWK_SUCCESS; } diff --git a/framework/test/test_fwk_core.c b/framework/test/test_fwk_core.c index dc0e64e57..ff5b96c72 100644 --- a/framework/test/test_fwk_core.c +++ b/framework/test/test_fwk_core.c @@ -163,7 +163,7 @@ static void test___fwk_init(void) &((((struct fwk_event *)(fwk_mm_calloc_val)) + 1)->slist_node)); } -static void test___fwk_run(void) +static void test___fwk_run_main_loop(void) { int result; struct fwk_event *free_event, *allocated_event; @@ -218,7 +218,7 @@ static void test___fwk_run(void) /* Event1 processing */ if (setjmp(test_context) == FWK_SUCCESS) - __fwk_run(); + __fwk_run_main_loop(); assert(ctx->isr_event_queue.head == &(event3.slist_node)); assert(ctx->isr_event_queue.tail == &(notification1.slist_node)); assert(ctx->event_queue.head == &(event2.slist_node)); @@ -237,7 +237,7 @@ static void test___fwk_run(void) /* Event2 processing */ if (setjmp(test_context) == FWK_SUCCESS) - __fwk_run(); + __fwk_run_main_loop(); assert(ctx->isr_event_queue.head == &(event3.slist_node)); assert(ctx->isr_event_queue.tail == &(notification1.slist_node)); assert(ctx->event_queue.head == &(allocated_event->slist_node)); @@ -256,7 +256,7 @@ static void test___fwk_run(void) /* Response to Event1 processing */ if (setjmp(test_context) == FWK_SUCCESS) - __fwk_run(); + __fwk_run_main_loop(); assert(ctx->isr_event_queue.head == &(event3.slist_node)); assert(ctx->isr_event_queue.tail == &(notification1.slist_node)); assert(fwk_list_is_empty(&ctx->event_queue)); @@ -276,7 +276,7 @@ static void test___fwk_run(void) /* Extract ISR Event3 and process it */ if (setjmp(test_context) == FWK_SUCCESS) - __fwk_run(); + __fwk_run_main_loop(); assert(ctx->isr_event_queue.head == &(notification1.slist_node)); assert(ctx->isr_event_queue.tail == &(notification1.slist_node)); assert(fwk_list_is_empty(&ctx->event_queue)); @@ -296,7 +296,7 @@ static void test___fwk_run(void) fwk_list_push_tail(&ctx->free_event_queue, &(allocated_event->slist_node)); free_event_queue_break = true; if (setjmp(test_context) == FWK_SUCCESS) - __fwk_run(); + __fwk_run_main_loop(); assert(fwk_list_is_empty(&ctx->isr_event_queue)); assert(ctx->event_queue.head == &(allocated_event->slist_node)); assert(ctx->event_queue.tail == &(allocated_event->slist_node)); @@ -313,7 +313,7 @@ static void test___fwk_run(void) /* Process response to Notification1 */ if (setjmp(test_context) == FWK_SUCCESS) - __fwk_run(); + __fwk_run_main_loop(); assert(fwk_list_is_empty(&ctx->isr_event_queue)); assert(fwk_list_is_empty(&ctx->event_queue)); @@ -522,7 +522,7 @@ static void test___fwk_put_notification(void) static const struct fwk_test_case_desc test_case_table[] = { FWK_TEST_CASE(test___fwk_init), - FWK_TEST_CASE(test___fwk_run), + FWK_TEST_CASE(test___fwk_run_main_loop), FWK_TEST_CASE(test_fwk_put_event), FWK_TEST_CASE(test_fwk_put_event_light), FWK_TEST_CASE(test___fwk_put_notification) diff --git a/framework/test/test_fwk_module.c b/framework/test/test_fwk_module.c index 98923fdd7..bedbdb831 100644 --- a/framework/test/test_fwk_module.c +++ b/framework/test/test_fwk_module.c @@ -200,7 +200,7 @@ int __wrap___fwk_init(size_t event_count) return init_return_val; } -void __wrap___fwk_run(void) +void __wrap___fwk_run_main_loop(void) { } diff --git a/tools/build_system/cpu.mk b/tools/build_system/cpu.mk index 95eb9b48d..f60618ab0 100644 --- a/tools/build_system/cpu.mk +++ b/tools/build_system/cpu.mk @@ -1,6 +1,6 @@ # # Arm SCP/MCP Software -# Copyright (c) 2015-2021, Arm Limited and Contributors. All rights reserved. +# Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # @@ -57,6 +57,7 @@ else ifneq ($(findstring $(BS_FIRMWARE_CPU),$(ARMV8A_CPUS)),) else ifeq ($(BS_FIRMWARE_CPU),host) BS_ARCH_VENDOR := none BS_ARCH_ARCH := host + BS_ARCH_HAS_SUB_SYSTEM_MODE := yes else $(erro "$(BS_FIRMWARE_CPU) is not a supported CPU. Aborting...") endif diff --git a/tools/build_system/firmware.mk b/tools/build_system/firmware.mk index e2168c70f..9cd6d8d33 100644 --- a/tools/build_system/firmware.mk +++ b/tools/build_system/firmware.mk @@ -245,6 +245,12 @@ else BUILD_HAS_SCMI_SENSOR_V2 := no endif +ifeq ($(BS_ARCH_HAS_SUB_SYSTEM_MODE),yes) + BUILD_HAS_SUB_SYSTEM_MODE := yes +else + BUILD_HAS_SUB_SYSTEM_MODE := no +endif + # Add directories to the list of targets to build LIB_TARGETS_y += $(patsubst %,$(MODULES_DIR)/%/src, \ $(BUILD_STANDARD_MODULES)) diff --git a/tools/build_system/rules.mk b/tools/build_system/rules.mk index 05e7eb145..7c3325ca0 100644 --- a/tools/build_system/rules.mk +++ b/tools/build_system/rules.mk @@ -53,6 +53,10 @@ ifeq ($(BUILD_HAS_SENSOR_EXT_ATTRIBS),yes) DEFINES += BUILD_HAS_SENSOR_EXT_ATTRIBS endif +ifeq ($(BUILD_HAS_SUB_SYSTEM_MODE),yes) + DEFINES += BUILD_HAS_SUB_SYSTEM_MODE +endif + export AS := $(CC) export LD := $(CC) diff --git a/tools/cppcheck_suppress_list.txt b/tools/cppcheck_suppress_list.txt index 53af421ba..b5b057738 100755 --- a/tools/cppcheck_suppress_list.txt +++ b/tools/cppcheck_suppress_list.txt @@ -96,7 +96,7 @@ zerodivcond:*product/juno/module/juno_cdcel937/src/mod_juno_cdcel937.c:414 syntaxError:*arch/arm/armv8-a/include/arch_system.h:19 // Cppcheck is not able to parse returned boolean values inside if conditions -internalAstError:*framework/src/fwk_core.c:294 +internalAstError:*framework/src/fwk_core.c:296 // These assignments are used for testing constArgument:*framework/test/test_fwk_macros.c -- GitLab From c4d6309bb8ed1c9b7bb8315f6941dcdbef038f6e Mon Sep 17 00:00:00 2001 From: Vincent Guittot Date: Thu, 25 Feb 2021 09:42:35 +0100 Subject: [PATCH 2/3] fwk: Add support of OS atomic operation Update the interface of fwk_interrupt_global_{enable|disable} functions to save and restore the current interrupt state. Add a new framework interface to get current interrupt context state: - fwk_is_interrupt_context() No functional change expected to current arch. Signed-off-by: Vincent Guittot new atomic --- arch/arm/armv7-m/include/arch_helpers.h | 31 ++++++++++++-- arch/arm/armv7-m/src/arch_main.c | 9 +++- arch/arm/armv7-m/src/arch_nvic.c | 11 +++++ arch/arm/armv8-a/include/arch_helpers.h | 29 +++++++++++-- arch/arm/armv8-a/src/arch_gic.c | 13 +++++- arch/arm/armv8-a/src/arch_main.c | 9 +++- arch/none/host/include/arch_helpers.h | 4 +- arch/none/host/src/arch_interrupt.c | 8 +++- framework/include/fwk_arch.h | 8 ++++ framework/include/fwk_interrupt.h | 42 ++++++++----------- framework/src/fwk_core.c | 41 +++++++++--------- framework/src/fwk_delayed_resp.c | 4 +- framework/src/fwk_interrupt.c | 18 ++++---- framework/src/fwk_log.c | 17 ++++---- framework/src/fwk_notification.c | 19 ++++----- framework/test/CMakeLists.txt | 4 +- framework/test/arch_helpers.h | 16 ++++++- framework/test/fwk_test.c | 8 +++- framework/test/test_fwk_core.c | 12 +++--- framework/test/test_fwk_interrupt.c | 30 +++++++++---- framework/test/test_fwk_notification.c | 18 ++++---- module/bootloader/src/mod_bootloader.c | 2 +- module/dvfs/src/mod_dvfs.c | 3 +- module/dw_apb_i2c/src/mod_dw_apb_i2c.c | 12 +++--- module/smt/src/mod_smt.c | 5 ++- module/statistics/src/mod_stats.c | 10 +++-- .../module/juno_dmc400/src/mod_juno_dmc400.c | 10 +++-- .../module/morello_rom/src/mod_morello_rom.c | 2 +- .../morello/module/morello_smt/src/mod_smt.c | 5 ++- .../module/n1sdp_rom/src/mod_n1sdp_rom.c | 2 +- product/n1sdp/module/n1sdp_smt/src/mod_smt.c | 5 ++- .../module/rcar_system/src/mod_rcar_system.c | 5 ++- .../synquacer_rom/src/mod_synquacer_rom.c | 2 +- tools/cppcheck_suppress_list.txt | 2 +- 34 files changed, 269 insertions(+), 147 deletions(-) diff --git a/arch/arm/armv7-m/include/arch_helpers.h b/arch/arm/armv7-m/include/arch_helpers.h index 050cea7a5..a83e73c12 100644 --- a/arch/arm/armv7-m/include/arch_helpers.h +++ b/arch/arm/armv7-m/include/arch_helpers.h @@ -8,15 +8,31 @@ #ifndef ARCH_HELPERS_H #define ARCH_HELPERS_H +#include + +/* + * This variable is used to ensure spurious nested calls won't + * enable interrupts. This is been defined in arch_main.c + */ +extern unsigned int critical_section_nest_level; + /*! * \brief Enables global CPU interrupts. * * \note inline is necessary as this call can be used in performance sensitive * path */ -inline static void arch_interrupts_enable(void) +inline static void arch_interrupts_enable(unsigned int not_used) { - __asm volatile("cpsie i" : : : "memory"); + /* Decrement critical_section_nest_level only if in critical section */ + if (critical_section_nest_level > 0) { + critical_section_nest_level--; + } + + /* Enable interrupts globally if now outside critical section */ + if (critical_section_nest_level == 0) { + __enable_irq(); + } } /*! @@ -25,9 +41,16 @@ inline static void arch_interrupts_enable(void) * \note inline is necessary as this call can be used in performance sensitive * path */ -inline static void arch_interrupts_disable(void) +inline static unsigned int arch_interrupts_disable(void) { - __asm volatile("cpsid i" : : : "memory"); + critical_section_nest_level++; + + /* If now in outer-most critical section, disable interrupts globally */ + if (critical_section_nest_level == 1) { + __disable_irq(); + } + + return 0; } /*! diff --git a/arch/arm/armv7-m/src/arch_main.c b/arch/arm/armv7-m/src/arch_main.c index d3e120e34..128d7b2d6 100644 --- a/arch/arm/armv7-m/src/arch_main.c +++ b/arch/arm/armv7-m/src/arch_main.c @@ -1,6 +1,6 @@ /* * Arm SCP/MCP Software - * Copyright (c) 2015-2021, Arm Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -18,6 +18,13 @@ #include #include +/* + * This variable is used to ensure spurious nested calls won't + * enable interrupts. This is been accessed from inline function defined in + * arch_helpers.h + */ +unsigned int critical_section_nest_level; + #ifdef __NEWLIB__ /* Platform-dependent backend for the _Exit() function */ void _exit(int status) diff --git a/arch/arm/armv7-m/src/arch_nvic.c b/arch/arm/armv7-m/src/arch_nvic.c index 578af0c0b..2c1219a48 100644 --- a/arch/arm/armv7-m/src/arch_nvic.c +++ b/arch/arm/armv7-m/src/arch_nvic.c @@ -228,6 +228,16 @@ static int get_current(unsigned int *interrupt) return FWK_SUCCESS; } +static bool is_interrupt_context(void) +{ + /* Not an interrupt */ + if (__get_IPSR() == 0) { + return false; + } + + return true; +} + static const struct fwk_arch_interrupt_driver arch_nvic_driver = { .global_enable = global_enable, .global_disable = global_disable, @@ -243,6 +253,7 @@ static const struct fwk_arch_interrupt_driver arch_nvic_driver = { .set_isr_nmi_param = set_isr_nmi_param, .set_isr_fault = set_isr_fault, .get_current = get_current, + .is_interrupt_context = is_interrupt_context, }; static void irq_invalid(void) diff --git a/arch/arm/armv8-a/include/arch_helpers.h b/arch/arm/armv8-a/include/arch_helpers.h index 683ad82f7..295f67ca1 100644 --- a/arch/arm/armv8-a/include/arch_helpers.h +++ b/arch/arm/armv8-a/include/arch_helpers.h @@ -549,15 +549,29 @@ static inline uint64_t el_implemented(unsigned int el) #define read_cpacr() read_cpacr_el1() #define write_cpacr(_v) write_cpacr_el1(_v) +/* + * This variable is used to ensure spurious nested calls won't + * enable interrupts. This is been defined in arch_main.c + */ +extern unsigned int critical_section_nest_level; + /*! * \brief Enables global CPU interrupts. * * \note inline is necessary as this call can be used in performance sensitive * path */ -inline static void arch_interrupts_enable() +inline static void arch_interrupts_enable(unsigned int not_used) { - enable_irq(); + /* Decrement critical_section_nest_level only if in critical section */ + if (critical_section_nest_level > 0) { + critical_section_nest_level--; + } + + /* Enable interrupts globally if now outside critical section */ + if (critical_section_nest_level == 0) { + enable_irq(); + } } /*! @@ -566,9 +580,16 @@ inline static void arch_interrupts_enable() * \note inline is necessary as this call can be used in performance sensitive * path */ -inline static void arch_interrupts_disable() +inline static unsigned int arch_interrupts_disable() { - disable_irq(); + critical_section_nest_level++; + + /* If now in outer-most critical section, disable interrupts globally */ + if (critical_section_nest_level == 1) { + disable_irq(); + } + + return 0; } /*! diff --git a/arch/arm/armv8-a/src/arch_gic.c b/arch/arm/armv8-a/src/arch_gic.c index 75cbb388f..c8df7accc 100644 --- a/arch/arm/armv8-a/src/arch_gic.c +++ b/arch/arm/armv8-a/src/arch_gic.c @@ -1,6 +1,6 @@ /* * Renesas SCP/MCP Software - * Copyright (c) 2020-2021, Renesas Electronics Corporation. All rights + * Copyright (c) 2020-2022, Renesas Electronics Corporation. All rights * reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -552,6 +552,16 @@ static int get_current(unsigned int *interrupt) return FWK_SUCCESS; } +static bool is_interrupt_context(void) +{ + /* Not an interrupt */ + if (c_interrupt == 0) { + return false; + } + + return true; +} + static const struct fwk_arch_interrupt_driver arm_gic_driver = { .global_enable = global_enable, .global_disable = global_disable, @@ -567,6 +577,7 @@ static const struct fwk_arch_interrupt_driver arm_gic_driver = { .set_isr_nmi_param = set_isr_dummy_param, .set_isr_fault = set_isr_dummy, .get_current = get_current, + .is_interrupt_context = is_interrupt_context, }; int arm_gic_init(const struct fwk_arch_interrupt_driver **driver) diff --git a/arch/arm/armv8-a/src/arch_main.c b/arch/arm/armv8-a/src/arch_main.c index 98a2a5a38..743a52d62 100644 --- a/arch/arm/armv8-a/src/arch_main.c +++ b/arch/arm/armv8-a/src/arch_main.c @@ -1,6 +1,6 @@ /* * Renesas SCP/MCP Software - * Copyright (c) 2020-2021, Renesas Electronics Corporation. All rights + * Copyright (c) 2020-2022, Renesas Electronics Corporation. All rights * reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -16,6 +16,13 @@ #include +/* + * This variable is used to ensure spurious nested calls won't + * enable interrupts. This is been accessed from inline function defined in + * arch_helpers.h + */ +unsigned int critical_section_nest_level; + FWK_WEAK int _platform_init(void *params) { return FWK_SUCCESS; diff --git a/arch/none/host/include/arch_helpers.h b/arch/none/host/include/arch_helpers.h index f234f6ce6..5ee3738ce 100644 --- a/arch/none/host/include/arch_helpers.h +++ b/arch/none/host/include/arch_helpers.h @@ -12,7 +12,7 @@ * \brief Enables global CPU interrupts. (stub) * */ -inline static void arch_interrupts_enable(void) +inline static void arch_interrupts_enable(unsigned int not_used) { } @@ -20,7 +20,7 @@ inline static void arch_interrupts_enable(void) * \brief Disables global CPU interrupts. (stub) * */ -inline static void arch_interrupts_disable(void) +inline static unsigned int arch_interrupts_disable(void) { } diff --git a/arch/none/host/src/arch_interrupt.c b/arch/none/host/src/arch_interrupt.c index 640abab2a..64aee4df3 100644 --- a/arch/none/host/src/arch_interrupt.c +++ b/arch/none/host/src/arch_interrupt.c @@ -1,6 +1,6 @@ /* * Arm SCP/MCP Software - * Copyright (c) 2015-2021, Arm Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * @@ -87,6 +87,11 @@ static int get_current(unsigned int *interrupt) return FWK_E_SUPPORT; } +static bool is_interrupt_context(void) +{ + return false; +} + static const struct fwk_arch_interrupt_driver driver = { .global_enable = global_enable, .global_disable = global_disable, @@ -102,6 +107,7 @@ static const struct fwk_arch_interrupt_driver driver = { .set_isr_nmi_param = set_isr_nmi_param, .set_isr_fault = set_isr_fault, .get_current = get_current, + .is_interrupt_context = is_interrupt_context, }; int arch_interrupt_init(const struct fwk_arch_interrupt_driver **_driver) diff --git a/framework/include/fwk_arch.h b/framework/include/fwk_arch.h index 1c7a4b720..e0e4ff31a 100644 --- a/framework/include/fwk_arch.h +++ b/framework/include/fwk_arch.h @@ -178,6 +178,14 @@ struct fwk_arch_interrupt_driver { * \retval ::FWK_E_STATE An interrupt is not currently being serviced. */ int (*get_current)(unsigned int *interrupt); + + /*! + * \brief Check if in interrupt context. + * + * \retval :: \c true if in an interrupt context. + * \retval :: \c false not in an interrupt context. + */ + bool (*is_interrupt_context)(void); }; /*! diff --git a/framework/include/fwk_interrupt.h b/framework/include/fwk_interrupt.h index e75050f7f..2c0a2af27 100644 --- a/framework/include/fwk_interrupt.h +++ b/framework/include/fwk_interrupt.h @@ -1,6 +1,6 @@ /* * Arm SCP/MCP Software - * Copyright (c) 2015-2021, Arm Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * @@ -23,12 +23,6 @@ #include #include -/* - * This variable is used to ensure spurious nested calls won't - * enable interrupts. This is been defined in fwk_interrupt.c - */ -extern unsigned int critical_section_nest_level; - /*! * \addtogroup GroupLibFramework Framework * \{ @@ -82,32 +76,22 @@ int fwk_interrupt_init(const struct fwk_arch_interrupt_driver *driver); /*! * \brief Enable interrupts. - + * + * \param flags Value returned by fwk_interrupt_global_disable. */ -inline static void fwk_interrupt_global_enable(void) +inline static void fwk_interrupt_global_enable(unsigned int flags) { - /* Decrement critical_section_nest_level only if in critical section */ - if (critical_section_nest_level > 0) { - critical_section_nest_level--; - } - - /* Enable interrupts globally if now outside critical section */ - if (critical_section_nest_level == 0) { - arch_interrupts_enable(); - } + arch_interrupts_enable(flags); } /*! * \brief Disable interrupts. + * + * \retval Opaque value to be passed when enabling. */ -inline static void fwk_interrupt_global_disable(void) +inline static unsigned int fwk_interrupt_global_disable(void) { - critical_section_nest_level++; - - /* If now in outer-most critical section, disable interrupts globally */ - if (critical_section_nest_level == 1) { - arch_interrupts_disable(); - } + return arch_interrupts_disable(); } /*! @@ -225,6 +209,14 @@ int fwk_interrupt_set_isr_param(unsigned int interrupt, */ int fwk_interrupt_get_current(unsigned int *interrupt); +/*! + * \brief Check if in interrupt context. + * + * \retval true if in an interrupt context. + * \retval false not in an interrupt context. + */ +bool fwk_is_interrupt_context(void); + /*! * \} */ diff --git a/framework/src/fwk_core.c b/framework/src/fwk_core.c index 53882200e..2ba8b97cf 100644 --- a/framework/src/fwk_core.c +++ b/framework/src/fwk_core.c @@ -61,13 +61,14 @@ static struct fwk_event *duplicate_event( enum fwk_event_type event_type) { struct fwk_event *allocated_event = NULL; + unsigned int flags; fwk_assert(event != NULL); - (void)fwk_interrupt_global_disable(); + flags = fwk_interrupt_global_disable(); allocated_event = FWK_LIST_GET( fwk_list_pop_head(&ctx.free_event_queue), struct fwk_event, slist_node); - (void)fwk_interrupt_global_enable(); + (void)fwk_interrupt_global_enable(flags); if (allocated_event == NULL) { FWK_LOG_CRIT(err_msg_func, FWK_E_NOMEM, __func__); @@ -99,8 +100,6 @@ static int put_event( enum fwk_event_type event_type) { struct fwk_event *allocated_event; - unsigned int interrupt; - int status; struct fwk_event *std_event = NULL; @@ -138,11 +137,10 @@ static int put_event( } if (intr_state == UNKNOWN_STATE) { - status = fwk_interrupt_get_current(&interrupt); - if (status != FWK_SUCCESS) { - intr_state = NOT_INTERRUPT_STATE; - } else { + if (fwk_is_interrupt_context()) { intr_state = INTERRUPT_STATE; + } else { + intr_state = NOT_INTERRUPT_STATE; } } if (intr_state == NOT_INTERRUPT_STATE) { @@ -165,9 +163,11 @@ static int put_event( static void free_event(struct fwk_event *event) { - (void)fwk_interrupt_global_disable(); + unsigned int flags; + + flags = fwk_interrupt_global_disable(); fwk_list_push_tail(&ctx.free_event_queue, &event->slist_node); - (void)fwk_interrupt_global_enable(); + (void)fwk_interrupt_global_enable(flags); } static void process_next_event(void) @@ -241,11 +241,12 @@ static void process_next_event(void) static bool process_isr(void) { struct fwk_event *isr_event; + unsigned int flags; - (void)fwk_interrupt_global_disable(); + flags = fwk_interrupt_global_disable(); isr_event = FWK_LIST_GET( fwk_list_pop_head(&ctx.isr_event_queue), struct fwk_event, slist_node); - (void)fwk_interrupt_global_enable(); + (void)fwk_interrupt_global_enable(flags); if (isr_event == NULL) { return false; @@ -337,7 +338,6 @@ int __fwk_put_notification(struct fwk_event *event) int __fwk_put_event(struct fwk_event *event) { int status = FWK_E_PARAM; - unsigned int interrupt; enum interrupt_states intr_state; #ifdef BUILD_MODE_DEBUG @@ -351,11 +351,10 @@ int __fwk_put_event(struct fwk_event *event) } #endif - status = fwk_interrupt_get_current(&interrupt); - if (status != FWK_SUCCESS) { - intr_state = NOT_INTERRUPT_STATE; - } else { + if (fwk_is_interrupt_context()) { intr_state = INTERRUPT_STATE; + } else { + intr_state = NOT_INTERRUPT_STATE; } if ((intr_state == NOT_INTERRUPT_STATE) && (ctx.current_event != NULL)) { @@ -411,7 +410,6 @@ error: int __fwk_put_event_light(struct fwk_event_light *event) { int status = FWK_E_PARAM; - unsigned int interrupt; enum interrupt_states intr_state; #ifdef BUILD_MODE_DEBUG @@ -425,11 +423,10 @@ int __fwk_put_event_light(struct fwk_event_light *event) } #endif - status = fwk_interrupt_get_current(&interrupt); - if (status != FWK_SUCCESS) { - intr_state = NOT_INTERRUPT_STATE; - } else { + if (fwk_is_interrupt_context()) { intr_state = INTERRUPT_STATE; + } else { + intr_state = NOT_INTERRUPT_STATE; } if ((intr_state == NOT_INTERRUPT_STATE) && (ctx.current_event != NULL)) { diff --git a/framework/src/fwk_delayed_resp.c b/framework/src/fwk_delayed_resp.c index 5d6a74af8..fcb35214c 100644 --- a/framework/src/fwk_delayed_resp.c +++ b/framework/src/fwk_delayed_resp.c @@ -26,9 +26,7 @@ static const char err_msg_func[] = "[FWK] Error %d in %s"; */ static int check_api_call(fwk_id_t id, void *data) { - unsigned int interrupt; - - if (fwk_interrupt_get_current(&interrupt) == FWK_SUCCESS) { + if (fwk_is_interrupt_context()) { return FWK_E_ACCESS; } diff --git a/framework/src/fwk_interrupt.c b/framework/src/fwk_interrupt.c index 7a812e57a..4f8730f30 100644 --- a/framework/src/fwk_interrupt.c +++ b/framework/src/fwk_interrupt.c @@ -1,6 +1,6 @@ /* * Arm SCP/MCP Software - * Copyright (c) 2015-2021, Arm Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * @@ -20,13 +20,6 @@ static bool initialized; static const struct fwk_arch_interrupt_driver *fwk_interrupt_driver; -/* - * This variable is used to ensure spurious nested calls won't - * enable interrupts. This is been accessed from inline function defined in - * fwk_interrupt.h - */ -unsigned int critical_section_nest_level; - int fwk_interrupt_init(const struct fwk_arch_interrupt_driver *driver) { /* Validate driver by checking that all function pointers are non-null */ @@ -193,6 +186,15 @@ int fwk_interrupt_get_current(unsigned int *interrupt) return fwk_interrupt_driver->get_current(interrupt); } +bool fwk_is_interrupt_context(void) +{ + if (!initialized) { + return false; + } + + return fwk_interrupt_driver->is_interrupt_context(); +} + /* This function is only for internal use by the framework */ int fwk_interrupt_set_isr_fault(void (*isr)(void)) { diff --git a/framework/src/fwk_log.c b/framework/src/fwk_log.c index fbf38cb25..0308d1e16 100644 --- a/framework/src/fwk_log.c +++ b/framework/src/fwk_log.c @@ -1,6 +1,6 @@ /* * Arm SCP/MCP Software - * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved. + * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -209,13 +209,14 @@ static bool fwk_log_banner(void) void fwk_log_printf(const char *format, ...) { + unsigned int flags; static bool banner = false; char buffer[FMW_LOG_COLUMNS + sizeof(FWK_LOG_TERMINATOR)]; va_list args; - (void)fwk_interrupt_global_disable(); /* Facilitate reentrancy */ + flags = fwk_interrupt_global_disable(); /* Facilitate reentrancy */ /* * We don't have any way for the log drain entity to communicate that it is @@ -256,7 +257,7 @@ void fwk_log_printf(const char *format, ...) } #endif - (void)fwk_interrupt_global_enable(); + (void)fwk_interrupt_global_enable(flags); } int fwk_log_unbuffer(void) @@ -264,10 +265,11 @@ int fwk_log_unbuffer(void) int status = FWK_SUCCESS; #ifdef FWK_LOG_BUFFERED + unsigned int flags; unsigned char fetched; char ch; - fwk_interrupt_global_disable(); + flags = fwk_interrupt_global_disable(); if (fwk_log_ctx.remaining == 0) { /* @@ -318,7 +320,7 @@ int fwk_log_unbuffer(void) } exit: - fwk_interrupt_global_enable(); + fwk_interrupt_global_enable(flags); #endif return status; @@ -327,14 +329,15 @@ exit: void fwk_log_flush(void) { #ifdef FWK_LOG_BUFFERED + unsigned int flags; int status; - fwk_interrupt_global_disable(); + flags = fwk_interrupt_global_disable(); do { status = fwk_log_unbuffer(); } while (status == FWK_PENDING); - fwk_interrupt_global_enable(); + fwk_interrupt_global_enable(flags); #endif } diff --git a/framework/src/fwk_notification.c b/framework/src/fwk_notification.c index 1fa79873c..a26a93f74 100644 --- a/framework/src/fwk_notification.c +++ b/framework/src/fwk_notification.c @@ -179,11 +179,11 @@ int fwk_notification_subscribe(fwk_id_t notification_id, fwk_id_t source_id, fwk_id_t target_id) { int status; - unsigned int interrupt; + unsigned int flags; struct fwk_dlist *subscription_dlist; struct __fwk_notification_subscription *subscription; - if (fwk_interrupt_get_current(&interrupt) == FWK_SUCCESS) { + if (fwk_is_interrupt_context()) { status = FWK_E_HANDLER; goto error; } @@ -216,9 +216,9 @@ int fwk_notification_subscribe(fwk_id_t notification_id, fwk_id_t source_id, subscription->source_id = source_id; subscription->target_id = target_id; - (void)fwk_interrupt_global_disable(); + flags = fwk_interrupt_global_disable(); fwk_list_push_tail(subscription_dlist, &subscription->dlist_node); - (void)fwk_interrupt_global_enable(); + (void)fwk_interrupt_global_enable(flags); return FWK_SUCCESS; @@ -231,11 +231,11 @@ int fwk_notification_unsubscribe(fwk_id_t notification_id, fwk_id_t source_id, fwk_id_t target_id) { int status; - unsigned int interrupt; + unsigned int flags; struct fwk_dlist *subscription_dlist; struct __fwk_notification_subscription *subscription; - if (fwk_interrupt_get_current(&interrupt) == FWK_SUCCESS) { + if (fwk_is_interrupt_context()) { status = FWK_E_HANDLER; goto error; } @@ -257,9 +257,9 @@ int fwk_notification_unsubscribe(fwk_id_t notification_id, fwk_id_t source_id, goto error; } - (void)fwk_interrupt_global_disable(); + flags = fwk_interrupt_global_disable(); fwk_list_remove(subscription_dlist, &subscription->dlist_node); - (void)fwk_interrupt_global_enable(); + (void)fwk_interrupt_global_enable(flags); fwk_list_push_tail(&ctx.free_subscription_dlist, &subscription->dlist_node); return FWK_SUCCESS; @@ -273,14 +273,13 @@ int fwk_notification_notify(struct fwk_event *notification_event, unsigned int *count) { int status; - unsigned int interrupt; const struct fwk_event *current_event; if ((notification_event == NULL) || (count == NULL)) { return FWK_E_PARAM; } - if (fwk_interrupt_get_current(&interrupt) == FWK_SUCCESS) { + if (fwk_is_interrupt_context()) { if (!fwk_module_is_valid_entity_id(notification_event->source_id)) { status = FWK_E_PARAM; goto error; diff --git a/framework/test/CMakeLists.txt b/framework/test/CMakeLists.txt index b4cf71376..6444d6c56 100644 --- a/framework/test/CMakeLists.txt +++ b/framework/test/CMakeLists.txt @@ -91,7 +91,7 @@ list(APPEND test_fwk_core_WRAP fwk_module_get_ctx) list(APPEND test_fwk_core_WRAP fwk_module_get_element_ctx) list(APPEND test_fwk_core_WRAP __fwk_slist_push_tail) list(APPEND test_fwk_core_WRAP fwk_mm_calloc) -list(APPEND test_fwk_core_WRAP fwk_interrupt_get_current) +list(APPEND test_fwk_core_WRAP fwk_is_interrupt_context) list(APPEND test_fwk_core_WRAP fwk_interrupt_global_disable) list(APPEND test_fwk_core_WRAP fwk_interrupt_global_enable) list(APPEND test_fwk_core_WRAP fwk_module_is_valid_entity_id) @@ -103,7 +103,7 @@ list(APPEND test_fwk_notification_WRAP fwk_module_get_element_ctx) list(APPEND test_fwk_notification_WRAP __fwk_get_current_event) list(APPEND test_fwk_notification_WRAP __fwk_put_notification) list(APPEND test_fwk_notification_WRAP fwk_mm_calloc) -list(APPEND test_fwk_notification_WRAP fwk_interrupt_get_current) +list(APPEND test_fwk_notification_WRAP fwk_is_interrupt_context) list(APPEND test_fwk_notification_WRAP fwk_interrupt_global_disable) list(APPEND test_fwk_notification_WRAP fwk_interrupt_global_enable) list(APPEND test_fwk_notification_WRAP fwk_module_is_valid_entity_id) diff --git a/framework/test/arch_helpers.h b/framework/test/arch_helpers.h index f234f6ce6..13a645f73 100644 --- a/framework/test/arch_helpers.h +++ b/framework/test/arch_helpers.h @@ -7,21 +7,33 @@ #ifndef ARCH_HELPERS_H #define ARCH_HELPERS_H +/* + * This variable is used to ensure spurious nested calls won't + * enable interrupts. This is been defined in fwk_test.c + */ +extern unsigned int critical_section_nest_level; /*! * \brief Enables global CPU interrupts. (stub) * */ -inline static void arch_interrupts_enable(void) +inline static void arch_interrupts_enable(unsigned int not_used) { + /* Decrement critical_section_nest_level only if in critical section */ + if (critical_section_nest_level > 0) { + critical_section_nest_level--; + } } /*! * \brief Disables global CPU interrupts. (stub) * */ -inline static void arch_interrupts_disable(void) +inline static unsigned int arch_interrupts_disable(void) { + critical_section_nest_level++; + + return 0; } /*! diff --git a/framework/test/fwk_test.c b/framework/test/fwk_test.c index 081358be9..cd3eb3bf0 100644 --- a/framework/test/fwk_test.c +++ b/framework/test/fwk_test.c @@ -1,6 +1,6 @@ /* * Arm SCP/MCP Software - * Copyright (c) 2015-2021, Arm Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -15,6 +15,12 @@ #include #include #include +/* + * This variable is used by arm architecture to ensure spurious nested calls + * won't enable interrupts. This is been accessed from inline function defined + * in arch_helpers.h + */ +unsigned int critical_section_nest_level; /* Test information provided by the test suite */ extern struct fwk_test_suite_desc test_suite; diff --git a/framework/test/test_fwk_core.c b/framework/test/test_fwk_core.c index ff5b96c72..81bba301a 100644 --- a/framework/test/test_fwk_core.c +++ b/framework/test/test_fwk_core.c @@ -91,8 +91,8 @@ int __wrap_fwk_interrupt_global_disable(void) return FWK_SUCCESS; } -static int interrupt_get_current_return_val; -int __wrap_fwk_interrupt_get_current(unsigned int *interrupt) +static bool interrupt_get_current_return_val; +bool __wrap_fwk_is_interrupt_context(void) { return interrupt_get_current_return_val; } @@ -131,7 +131,7 @@ static void test_case_setup(void) is_valid_entity_id_return_val = true; is_valid_event_id_return_val = true; is_valid_notification_id_return_val = true; - interrupt_get_current_return_val = FWK_E_STATE; + interrupt_get_current_return_val = false; fwk_mm_calloc_return_val = true; fake_module_desc.process_event = process_event; fake_module_ctx.desc = &fake_module_desc; @@ -389,7 +389,7 @@ static void test_fwk_put_event(void) assert(result_event->is_notification == false); event2.id = FWK_ID_EVENT(0x3, 7); - interrupt_get_current_return_val = FWK_SUCCESS; + interrupt_get_current_return_val = true; result = fwk_put_event(&event2); assert(result == FWK_SUCCESS); assert(fwk_list_is_empty(&ctx->free_event_queue)); @@ -458,7 +458,7 @@ static void test_fwk_put_event_light(void) assert(result_event->is_notification == false); event2.id = FWK_ID_EVENT(0x4, 7); - interrupt_get_current_return_val = FWK_SUCCESS; + interrupt_get_current_return_val = true; result = fwk_put_event(&event2); assert(result == FWK_SUCCESS); assert(fwk_list_is_empty(&ctx->free_event_queue)); @@ -507,7 +507,7 @@ static void test___fwk_put_notification(void) assert(result_event->is_notification == true); event2.id = FWK_ID_EVENT(0x4, 7); - interrupt_get_current_return_val = FWK_SUCCESS; + interrupt_get_current_return_val = true; result = __fwk_put_notification(&event2); assert(result == FWK_SUCCESS); assert(fwk_list_is_empty(&ctx->free_event_queue)); diff --git a/framework/test/test_fwk_interrupt.c b/framework/test/test_fwk_interrupt.c index 7200960e8..be583414e 100644 --- a/framework/test/test_fwk_interrupt.c +++ b/framework/test/test_fwk_interrupt.c @@ -1,6 +1,6 @@ /* * Arm SCP/MCP Software - * Copyright (c) 2015-2021, Arm Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -116,6 +116,11 @@ static int get_current(unsigned int *interrupt) return get_current_return_val; } +static bool is_interrupt_context(void) +{ + return (get_current_return_val == FWK_SUCCESS); +} + static const struct fwk_arch_interrupt_driver driver = { .global_enable = global_enable, .global_disable = global_disable, @@ -131,6 +136,7 @@ static const struct fwk_arch_interrupt_driver driver = { .set_isr_nmi_param = set_isr_nmi_param, .set_isr_fault = set_isr_fault, .get_current = get_current, + .is_interrupt_context = is_interrupt_context, }; static const struct fwk_arch_interrupt_driver driver_invalid = {}; @@ -186,6 +192,9 @@ static void test_fwk_interrupt_before_init(void) result = fwk_interrupt_get_current(&interrupt); assert(result == FWK_E_INIT); + + state = fwk_is_interrupt_context(); + assert(state == false); } static void test_fwk_interrupt_init(void) @@ -205,10 +214,12 @@ static void test_fwk_interrupt_init(void) static void test_fwk_interrupt_critical_section(void) { - fwk_interrupt_global_disable(); + unsigned int flags; + + flags = fwk_interrupt_global_disable(); assert(critical_section_nest_level == 1); - fwk_interrupt_global_enable(); + fwk_interrupt_global_enable(flags); assert(critical_section_nest_level == 0); } @@ -335,22 +346,23 @@ static void test_fwk_interrupt_get_current(void) static void test_fwk_interrupt_nested_critical_section(void) { - fwk_interrupt_global_disable(); + unsigned int flags1, flags2, flags3; + flags1 = fwk_interrupt_global_disable(); assert(critical_section_nest_level == 1); - fwk_interrupt_global_disable(); + flags2 = fwk_interrupt_global_disable(); assert(critical_section_nest_level == 2); - fwk_interrupt_global_disable(); + flags3 =fwk_interrupt_global_disable(); assert(critical_section_nest_level == 3); - fwk_interrupt_global_enable(); + fwk_interrupt_global_enable(flags3); assert(critical_section_nest_level == 2); - fwk_interrupt_global_enable(); + fwk_interrupt_global_enable(flags2); assert(critical_section_nest_level == 1); - fwk_interrupt_global_enable(); + fwk_interrupt_global_enable(flags1); assert(critical_section_nest_level == 0); } diff --git a/framework/test/test_fwk_notification.c b/framework/test/test_fwk_notification.c index 1e347bbe5..7a2fdc8cf 100644 --- a/framework/test/test_fwk_notification.c +++ b/framework/test/test_fwk_notification.c @@ -79,8 +79,8 @@ int __wrap_fwk_interrupt_global_disable(void) return FWK_SUCCESS; } -static int interrupt_get_current_return_val; -int __wrap_fwk_interrupt_get_current(unsigned int *interrupt) +static bool interrupt_get_current_return_val; +bool __wrap_fwk_is_interrupt_context(void) { return interrupt_get_current_return_val; } @@ -108,7 +108,7 @@ static void test_case_setup(void) is_valid_entity_id_return_val = true; is_valid_notification_id_return_val = true; - interrupt_get_current_return_val = FWK_E_STATE; + interrupt_get_current_return_val = false; fwk_mm_calloc_return_val = true; get_current_event_return_val = NULL; notification_event_count = 0; @@ -130,12 +130,12 @@ static void test_fwk_notification_subscribe(void) int result; /* Call from an ISR */ - interrupt_get_current_return_val = FWK_SUCCESS; + interrupt_get_current_return_val = true; result = fwk_notification_subscribe(FWK_ID_NOTIFICATION(0x2, 0x3), FWK_ID_ELEMENT(0x2, 0x9), FWK_ID_MODULE(0x4)); assert(result == FWK_E_HANDLER); - interrupt_get_current_return_val = FWK_E_STATE; + interrupt_get_current_return_val = false; /* Invalid entity ID */ is_valid_entity_id_return_val = false; @@ -189,12 +189,12 @@ static void test_fwk_notification_unsubscribe(void) int result; /* Call from an ISR */ - interrupt_get_current_return_val = FWK_SUCCESS; + interrupt_get_current_return_val = true; result = fwk_notification_unsubscribe(FWK_ID_NOTIFICATION(0x2, 0x3), FWK_ID_ELEMENT(0x2, 0x9), FWK_ID_MODULE(0x4)); assert(result == FWK_E_HANDLER); - interrupt_get_current_return_val = FWK_E_STATE; + interrupt_get_current_return_val = false; /* Invalid entity ID */ is_valid_entity_id_return_val = false; @@ -266,11 +266,11 @@ static void test_fwk_notification_notify(void) unsigned int count; /* Call from an ISR, invalid source identifier */ - interrupt_get_current_return_val = FWK_SUCCESS; + interrupt_get_current_return_val = true; is_valid_entity_id_return_val = false; result = fwk_notification_notify(¬ification_event, &count); assert(result == FWK_E_PARAM); - interrupt_get_current_return_val = FWK_E_STATE; + interrupt_get_current_return_val = false; is_valid_entity_id_return_val = true; /* Current event, incompatible notification and source identifier. */ diff --git a/module/bootloader/src/mod_bootloader.c b/module/bootloader/src/mod_bootloader.c index eacea5cd7..e878a026b 100644 --- a/module/bootloader/src/mod_bootloader.c +++ b/module/bootloader/src/mod_bootloader.c @@ -173,7 +173,7 @@ static int load_image(void) } } - fwk_interrupt_global_disable(); /* We are relocating the vector table */ + (void)fwk_interrupt_global_disable(); /* We are relocating the vector table */ FWK_LOG_INFO("[BOOTLOADER] Booting RAM firmware..."); FWK_LOG_FLUSH(); diff --git a/module/dvfs/src/mod_dvfs.c b/module/dvfs/src/mod_dvfs.c index 09954f3c8..c009de98e 100644 --- a/module/dvfs/src/mod_dvfs.c +++ b/module/dvfs/src/mod_dvfs.c @@ -539,7 +539,6 @@ static int dvfs_set_level(fwk_id_t domain_id, uintptr_t cookie, uint32_t level) { struct mod_dvfs_domain_ctx *ctx; const struct mod_dvfs_opp *new_opp; - unsigned int interrupt; ctx = get_domain_ctx(domain_id); if (ctx == NULL) { @@ -562,7 +561,7 @@ static int dvfs_set_level(fwk_id_t domain_id, uintptr_t cookie, uint32_t level) return FWK_SUCCESS; } - if (fwk_interrupt_get_current(&interrupt) == FWK_SUCCESS) { + if (fwk_is_interrupt_context()) { ctx->request.set_source_id = true; } else { ctx->request.set_source_id = false; diff --git a/module/dw_apb_i2c/src/mod_dw_apb_i2c.c b/module/dw_apb_i2c/src/mod_dw_apb_i2c.c index 9828098fd..e298d5de0 100644 --- a/module/dw_apb_i2c/src/mod_dw_apb_i2c.c +++ b/module/dw_apb_i2c/src/mod_dw_apb_i2c.c @@ -145,7 +145,7 @@ static int transmit_as_controller( struct mod_i2c_request *transmit_request) { int status; - unsigned int sent_bytes; + unsigned int sent_bytes, flags; struct dw_apb_i2c_ctx *ctx; if (transmit_request->transmit_byte_count > I2C_TRANSMIT_BUFFER_LENGTH) { @@ -164,14 +164,14 @@ static int transmit_as_controller( } /* The program of the I2C controller cannot be interrupted. */ - fwk_interrupt_global_disable(); + flags = fwk_interrupt_global_disable(); for (sent_bytes = 0; sent_bytes < transmit_request->transmit_byte_count; sent_bytes++) { ctx->i2c_reg->IC_DATA_CMD = transmit_request->transmit_data[sent_bytes]; } - fwk_interrupt_global_enable(); + fwk_interrupt_global_enable(flags); /* * The data has been pushed to the I2C FIFO for transmission to the @@ -187,7 +187,7 @@ static int receive_as_controller( struct mod_i2c_request *receive_request) { int status; - unsigned int i; + unsigned int i, flags; struct dw_apb_i2c_ctx *ctx; if (receive_request->receive_byte_count > I2C_RECEIVE_BUFFER_LENGTH) { @@ -210,14 +210,14 @@ static int receive_as_controller( } /* The program of the I2C controller cannot be interrupted. */ - fwk_interrupt_global_disable(); + flags = fwk_interrupt_global_disable(); /* Program the I2C controller with the expected reply length in bytes. */ for (i = 0; i < receive_request->receive_byte_count; i++) { ctx->i2c_reg->IC_DATA_CMD = IC_DATA_CMD_READ; } - fwk_interrupt_global_enable(); + fwk_interrupt_global_enable(flags); /* * The command has been sent to the I2C for requesting data from diff --git a/module/smt/src/mod_smt.c b/module/smt/src/mod_smt.c index 32b8fd291..808fee49f 100644 --- a/module/smt/src/mod_smt.c +++ b/module/smt/src/mod_smt.c @@ -194,6 +194,7 @@ static int smt_respond(fwk_id_t channel_id, const void *payload, size_t size) struct smt_channel_ctx *channel_ctx; struct mod_smt_memory *memory; int status = FWK_SUCCESS; + unsigned int flags; channel_ctx = &smt_ctx.channel_ctx_table[fwk_id_get_element_idx(channel_id)]; @@ -215,14 +216,14 @@ static int smt_respond(fwk_id_t channel_id, const void *payload, size_t size) * period anyway, but this guard is included to protect against a * misbehaving agent. */ - fwk_interrupt_global_disable(); + flags = fwk_interrupt_global_disable(); channel_ctx->locked = false; memory->length = (volatile uint32_t)(sizeof(memory->message_header) + size); memory->status |= MOD_SMT_MAILBOX_STATUS_FREE_MASK; - fwk_interrupt_global_enable(); + fwk_interrupt_global_enable(flags); if (memory->flags & MOD_SMT_MAILBOX_FLAGS_IENABLED_MASK) { status = diff --git a/module/statistics/src/mod_stats.c b/module/statistics/src/mod_stats.c index fb235eaa4..874808598 100644 --- a/module/statistics/src/mod_stats.c +++ b/module/statistics/src/mod_stats.c @@ -346,6 +346,7 @@ stats_update_domain(fwk_id_t module_id, fwk_id_t domain_id, uint32_t level_id) uint64_t ts_now_us; uint32_t old_level_id, idx; int stats_id; + unsigned int flags; stats = get_module_stats_info(module_id); if (stats == NULL) { @@ -372,7 +373,7 @@ stats_update_domain(fwk_id_t module_id, fwk_id_t domain_id, uint32_t level_id) ts_now_us = _get_curret_ts_us(); - fwk_interrupt_global_disable(); + flags = fwk_interrupt_global_disable(); /* Update old performance level statistics */ old_level_id = se_map->se_curr_level[stats_id]; @@ -387,7 +388,7 @@ stats_update_domain(fwk_id_t module_id, fwk_id_t domain_id, uint32_t level_id) domain_stats->curr_level_id = (uint16_t)level_id; se_map->se_curr_level[stats_id] = level_id; - fwk_interrupt_global_enable(); + fwk_interrupt_global_enable(flags); return FWK_SUCCESS; } @@ -438,6 +439,7 @@ static void update_all_domains_current_level(fwk_id_t module_id) uint32_t curr_level_id; fwk_id_t domain_id; int stats_id, i; + unsigned int flags; stats = get_module_stats_info(module_id); if (stats == NULL) { @@ -458,7 +460,7 @@ static void update_all_domains_current_level(fwk_id_t module_id) se_map = stats->context->se_stats_map; stats_id = stats->context->se_index_map[i]; - fwk_interrupt_global_disable(); + flags = fwk_interrupt_global_disable(); ts_now_us = _get_curret_ts_us(); @@ -470,7 +472,7 @@ static void update_all_domains_current_level(fwk_id_t module_id) level_stats->total_residency_us += delta_t; domain_stats->ts_last_change_us = ts_now_us; - fwk_interrupt_global_enable(); + fwk_interrupt_global_enable(flags); } } diff --git a/product/juno/module/juno_dmc400/src/mod_juno_dmc400.c b/product/juno/module/juno_dmc400/src/mod_juno_dmc400.c index 0d358465f..bc568fdfe 100644 --- a/product/juno/module/juno_dmc400/src/mod_juno_dmc400.c +++ b/product/juno/module/juno_dmc400/src/mod_juno_dmc400.c @@ -654,6 +654,7 @@ timeout: static int ddr_retraining(fwk_id_t id) { int status; + unsigned int flags; const struct mod_juno_dmc400_element_config *element_config; const struct mod_juno_dmc400_module_config *module_config; struct mod_juno_dmc400_reg *dmc; @@ -662,7 +663,7 @@ static int ddr_retraining(fwk_id_t id) element_config = fwk_module_get_data(id); dmc = (struct mod_juno_dmc400_reg *)element_config->dmc; - fwk_interrupt_global_disable(); + flags = fwk_interrupt_global_disable(); dmc->MEMC_CMD = DMC400_CMD_CONFIG; status = ctx.timer_api->wait(module_config->timer_id, @@ -680,7 +681,7 @@ static int ddr_retraining(fwk_id_t id) dmc->MEMC_CMD = DMC400_CMD_GO; - fwk_interrupt_global_enable(); + fwk_interrupt_global_enable(flags); status = fwk_interrupt_enable((unsigned int)PHY_TRAINING_IRQ); if (status != FWK_SUCCESS) { @@ -953,6 +954,7 @@ static int juno_dmc400_bind(fwk_id_t id, unsigned int round) static int juno_dmc400_start(fwk_id_t id) { int status; + unsigned int flags; const struct mod_juno_dmc400_element_config *element_config; struct mod_juno_dmc400_reg *dmc; @@ -996,14 +998,14 @@ static int juno_dmc400_start(fwk_id_t id) return status; } - fwk_interrupt_global_disable(); + flags = fwk_interrupt_global_disable(); status = ddr_training(id); if (status != FWK_SUCCESS) { return status; } - fwk_interrupt_global_enable(); + fwk_interrupt_global_enable(flags); status = fwk_interrupt_set_isr( (unsigned int)PHY_TRAINING_IRQ, ddr_phy_irq_handler); diff --git a/product/morello/module/morello_rom/src/mod_morello_rom.c b/product/morello/module/morello_rom/src/mod_morello_rom.c index 42df4a70e..0dfd9f970 100644 --- a/product/morello/module/morello_rom/src/mod_morello_rom.c +++ b/product/morello/module/morello_rom/src/mod_morello_rom.c @@ -51,7 +51,7 @@ static void jump_to_ramfw(void) * Disable interrupts for the duration of the ROM firmware to RAM firmware * transition. */ - fwk_interrupt_global_disable(); + (void)fwk_interrupt_global_disable(); ramfw_reset_handler = (void (*)(void)) * reset_base; diff --git a/product/morello/module/morello_smt/src/mod_smt.c b/product/morello/module/morello_smt/src/mod_smt.c index ff9a655a9..bf3ddc875 100644 --- a/product/morello/module/morello_smt/src/mod_smt.c +++ b/product/morello/module/morello_smt/src/mod_smt.c @@ -171,6 +171,7 @@ static int smt_respond(fwk_id_t channel_id, const void *payload, size_t size) { struct smt_channel_ctx *channel_ctx; struct mod_smt_memory *memory; + unsigned int flags; channel_ctx = &smt_ctx.channel_ctx_table[fwk_id_get_element_idx(channel_id)]; @@ -192,14 +193,14 @@ static int smt_respond(fwk_id_t channel_id, const void *payload, size_t size) * period anyway, but this guard is included to protect against a * misbehaving agent. */ - fwk_interrupt_global_disable(); + flags = fwk_interrupt_global_disable(); channel_ctx->locked = false; memory->length = sizeof(memory->message_header) + size; memory->status |= MOD_SMT_MAILBOX_STATUS_FREE_MASK; - fwk_interrupt_global_enable(); + fwk_interrupt_global_enable(flags); if (memory->flags & MOD_SMT_MAILBOX_FLAGS_IENABLED_MASK) channel_ctx->driver_api->raise_interrupt(channel_ctx->driver_id); diff --git a/product/n1sdp/module/n1sdp_rom/src/mod_n1sdp_rom.c b/product/n1sdp/module/n1sdp_rom/src/mod_n1sdp_rom.c index 2438666e0..5daf96428 100644 --- a/product/n1sdp/module/n1sdp_rom/src/mod_n1sdp_rom.c +++ b/product/n1sdp/module/n1sdp_rom/src/mod_n1sdp_rom.c @@ -51,7 +51,7 @@ static void jump_to_ramfw(void) * Disable interrupts for the duration of the ROM firmware to RAM firmware * transition. */ - fwk_interrupt_global_disable(); + (void)fwk_interrupt_global_disable(); ramfw_reset_handler = (void (*)(void))*reset_base; diff --git a/product/n1sdp/module/n1sdp_smt/src/mod_smt.c b/product/n1sdp/module/n1sdp_smt/src/mod_smt.c index 56e514500..7ff961d06 100644 --- a/product/n1sdp/module/n1sdp_smt/src/mod_smt.c +++ b/product/n1sdp/module/n1sdp_smt/src/mod_smt.c @@ -170,6 +170,7 @@ static int smt_respond(fwk_id_t channel_id, const void *payload, size_t size) { struct smt_channel_ctx *channel_ctx; struct mod_smt_memory *memory; + unsigned int flags; channel_ctx = &smt_ctx.channel_ctx_table[fwk_id_get_element_idx(channel_id)]; @@ -190,14 +191,14 @@ static int smt_respond(fwk_id_t channel_id, const void *payload, size_t size) * period anyway, but this guard is included to protect against a * misbehaving agent. */ - fwk_interrupt_global_disable(); + flags = fwk_interrupt_global_disable(); channel_ctx->locked = false; memory->length = sizeof(memory->message_header) + size; memory->status |= MOD_SMT_MAILBOX_STATUS_FREE_MASK; - fwk_interrupt_global_enable(); + fwk_interrupt_global_enable(flags); if (memory->flags & MOD_SMT_MAILBOX_FLAGS_IENABLED_MASK) channel_ctx->driver_api->raise_interrupt(channel_ctx->driver_id); diff --git a/product/rcar/module/rcar_system/src/mod_rcar_system.c b/product/rcar/module/rcar_system/src/mod_rcar_system.c index 1261b2293..026ec8bec 100644 --- a/product/rcar/module/rcar_system/src/mod_rcar_system.c +++ b/product/rcar/module/rcar_system/src/mod_rcar_system.c @@ -130,9 +130,10 @@ void vApplicationIdleHook(void) struct rcar_system_dev_ctx *ctx; fwk_id_t element_id = FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_CLOCK, 0); uint32_t i; + unsigned int flags; if (is_available_shutdown_req(P_STATUS)) { - fwk_interrupt_global_disable(); + flags = fwk_interrupt_global_disable(); req = P_STATUS; P_STATUS = R_CLEAR; switch (req) { @@ -156,7 +157,7 @@ void vApplicationIdleHook(void) messaging_stack_ready(); gic_init(); vConfigureTickInterrupt(); - fwk_interrupt_global_enable(); + fwk_interrupt_global_enable(flags); break; case R_RESET: rcar_system_reset(); diff --git a/product/synquacer/module/synquacer_rom/src/mod_synquacer_rom.c b/product/synquacer/module/synquacer_rom/src/mod_synquacer_rom.c index ad104df2c..4c3d1aa03 100644 --- a/product/synquacer/module/synquacer_rom/src/mod_synquacer_rom.c +++ b/product/synquacer/module/synquacer_rom/src/mod_synquacer_rom.c @@ -41,7 +41,7 @@ static void jump_to_ramfw(void) * Disable interrupts for the duration of the ROM firmware to RAM firmware * transition. */ - fwk_interrupt_global_disable(); + (void)fwk_interrupt_global_disable(); ramfw_reset_handler = (void (*)(void))(*reset_base); diff --git a/tools/cppcheck_suppress_list.txt b/tools/cppcheck_suppress_list.txt index b5b057738..0e2e07182 100755 --- a/tools/cppcheck_suppress_list.txt +++ b/tools/cppcheck_suppress_list.txt @@ -96,7 +96,7 @@ zerodivcond:*product/juno/module/juno_cdcel937/src/mod_juno_cdcel937.c:414 syntaxError:*arch/arm/armv8-a/include/arch_system.h:19 // Cppcheck is not able to parse returned boolean values inside if conditions -internalAstError:*framework/src/fwk_core.c:296 +internalAstError:*framework/src/fwk_core.c:295 // These assignments are used for testing constArgument:*framework/test/test_fwk_macros.c -- GitLab From 4df9b0b2f7e8267b93183603a2873736abfb43b7 Mon Sep 17 00:00:00 2001 From: Vincent Guittot Date: Tue, 20 Apr 2021 14:46:03 +0200 Subject: [PATCH 3/3] fwk: Add stop sequence When the scp is running as an application or sub-system, there is a need to terminate the process gracefully. Let introduce the deinit and stop sequence to allow the modules and their elements to cleanup and release resources before terminating the process Add a new fwk_arch_deinit() to loop on modules and stop them. Signed-off-by: Vincent Guittot --- framework/include/fwk_arch.h | 11 ++++ framework/include/fwk_module.h | 25 +++++++- framework/include/internal/fwk_module.h | 12 ++++ framework/src/fwk_arch.c | 12 ++++ framework/src/fwk_module.c | 85 ++++++++++++++++++++++++- 5 files changed, 143 insertions(+), 2 deletions(-) diff --git a/framework/include/fwk_arch.h b/framework/include/fwk_arch.h index e0e4ff31a..a5d96ee2a 100644 --- a/framework/include/fwk_arch.h +++ b/framework/include/fwk_arch.h @@ -222,6 +222,17 @@ struct fwk_arch_init_driver { */ int fwk_arch_init(const struct fwk_arch_init_driver *driver); +/*! + * \brief Stop the framework library. + * + * \details Before terminating the SCP-firmware, the modules and their elements + * get the opportunity to release or reset some resources. + * + * \retval ::FWK_SUCCESS Operation succeeded. + * \retval ::FWK_E_PANIC Unrecoverable error. + */ +int fwk_arch_deinit(void); + /*! * \brief Architecture defined suspend, will wakup on receiving interrupt * diff --git a/framework/include/fwk_module.h b/framework/include/fwk_module.h index f58d0f1f6..89abe86f6 100644 --- a/framework/include/fwk_module.h +++ b/framework/include/fwk_module.h @@ -1,6 +1,6 @@ /* * Arm SCP/MCP Software - * Copyright (c) 2015-2021, Arm Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * @@ -222,6 +222,29 @@ struct fwk_module { */ int (*start)(fwk_id_t id); + /*! + * \brief Pointer to the stop function. + * + * \details This function is called by the framework for the module and then + * for all of its elements during the stop stage. Elements are + * stopped in the order they are declared in the module configuration + * data. + * + * The framework does not mandate a particular purpose for this + * function. It may be used to perform any final processing of the + * module and its elements before entering the suspend phase. + * + * \note This function is \b optional and aims to release software + * resources or to set hardware resources in a proper state before + * terminating the SCP software. + * + * \param id Identifier of the module or element to start. + * + * \retval ::FWK_SUCCESS The module or element was successfully started. + * \return One of the other module-defined error codes. + */ + int (*stop)(fwk_id_t id); + /*! * \brief Pointer to the bind request processing function. * diff --git a/framework/include/internal/fwk_module.h b/framework/include/internal/fwk_module.h index 582df5790..2c941b9e5 100644 --- a/framework/include/internal/fwk_module.h +++ b/framework/include/internal/fwk_module.h @@ -90,6 +90,18 @@ struct fwk_element_ctx { */ int fwk_module_start(void); +/*! + * \internal + * + * \brief Stop the module component. + * + * \details Stop each module and its elements, running through their + * stop routines. + * + * \return Status code representing the result of the operation. + */ +int fwk_module_stop(void); + /* * \brief Get a pointer to the context of a module or element. * diff --git a/framework/src/fwk_arch.c b/framework/src/fwk_arch.c index f2695f97a..928d9b60f 100644 --- a/framework/src/fwk_arch.c +++ b/framework/src/fwk_arch.c @@ -104,6 +104,18 @@ int fwk_arch_init(const struct fwk_arch_init_driver *driver) return FWK_SUCCESS; } +int fwk_arch_deinit(void) +{ + int status; + + status = fwk_module_stop(); + if (!fwk_expect(status == FWK_SUCCESS)) { + return FWK_E_PANIC; + } + + return FWK_SUCCESS; +} + void fwk_arch_suspend(void) { /* On some arm plaforms, wfe is supported architecturally, however diff --git a/framework/src/fwk_module.c b/framework/src/fwk_module.c index 1e39b0fcb..3740e462b 100644 --- a/framework/src/fwk_module.c +++ b/framework/src/fwk_module.c @@ -36,7 +36,8 @@ enum fwk_module_stage { MODULE_STAGE_INITIALIZE, MODULE_STAGE_BIND, - MODULE_STAGE_START + MODULE_STAGE_START, + MODULE_STAGE_STOP }; static struct { @@ -449,6 +450,88 @@ int fwk_module_start(void) return FWK_SUCCESS; } +static int fwk_module_stop_elements(struct fwk_module_context *module_ctx) +{ + int status; + const struct fwk_module *module; + unsigned int element_idx; + + module = module_ctx->desc; + + for (element_idx = 0; element_idx < module_ctx->element_count; + element_idx++) { + + if (module->stop != NULL) { + status = module->stop( + fwk_id_build_element_id(module_ctx->id, element_idx)); + if (!fwk_expect(status == FWK_SUCCESS)) { + FWK_LOG_CRIT(fwk_module_err_msg_func, status, __func__); + return status; + } + } + + module_ctx->element_ctx_table[element_idx].state = + FWK_MODULE_STATE_SUSPENDED; + } + + return FWK_SUCCESS; +} + +static int fwk_module_stop_module(struct fwk_module_context *module_ctx) +{ + int status; + const struct fwk_module *module; + + module = module_ctx->desc; + + if (module->stop != NULL) { + status = module->stop(module_ctx->id); + if (!fwk_expect(status == FWK_SUCCESS)) { + FWK_LOG_CRIT(fwk_module_err_msg_func, status, __func__); + return status; + } + } + + module_ctx->state = FWK_MODULE_STATE_SUSPENDED; + + return fwk_module_stop_elements(module_ctx); +} + +static int stop_modules(void) +{ + int status; + unsigned int module_idx; + struct fwk_module_context *module_ctx; + + for (module_idx = 0; module_idx < FWK_MODULE_IDX_COUNT; module_idx++) { + module_ctx = &fwk_module_ctx.module_ctx_table[module_idx]; + status = fwk_module_stop_module(module_ctx); + if (status != FWK_SUCCESS) { + return status; + } + } + + return FWK_SUCCESS; +} + +int fwk_module_stop(void) +{ + int status; + + if (!fwk_module_ctx.initialized) { + FWK_LOG_CRIT(fwk_module_err_msg_func, FWK_E_STATE, __func__); + return FWK_E_STATE; + } + + fwk_module_ctx.stage = MODULE_STAGE_STOP; + status = stop_modules(); + if (status != FWK_SUCCESS) { + return status; + } + + return FWK_SUCCESS; +} + struct fwk_module_context *fwk_module_get_ctx(fwk_id_t id) { return &fwk_module_ctx.module_ctx_table[fwk_id_get_module_idx(id)]; -- GitLab