From cd68f5f245017e23a9422353dde7d193a1fc320e Mon Sep 17 00:00:00 2001 From: Mathieu Choplain Date: Tue, 7 Oct 2025 10:54:36 +0200 Subject: [PATCH 1/4] kernel: hooks: make definitions appear in Doxygen The hooks' signature was not visible to Doxygen due to preprocessor conditionals - instead, the dummy no-op implementation was seen instead. Update #ifdef guard to make the hooks' signature and the associated documentation visible to Doxygen such that it appears in docs. Also fix a tiny typo on soc_reset_hook()'s documentation comment. Signed-off-by: Mathieu Choplain --- include/zephyr/platform/hooks.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/include/zephyr/platform/hooks.h b/include/zephyr/platform/hooks.h index de810747ce05c..9577c5e3098ab 100644 --- a/include/zephyr/platform/hooks.h +++ b/include/zephyr/platform/hooks.h @@ -19,7 +19,7 @@ * directly from application code but may be freely used within the OS. */ -#ifdef CONFIG_SOC_EARLY_RESET_HOOK +#if defined(CONFIG_SOC_EARLY_RESET_HOOK) || defined(__DOXYGEN__) /** * @brief SoC hook executed before data RAM initialization, at the beginning * of the reset vector. @@ -33,9 +33,9 @@ void soc_early_reset_hook(void); #define soc_early_reset_hook() do { } while (0) #endif -#ifdef CONFIG_SOC_RESET_HOOK +#if defined(CONFIG_SOC_RESET_HOOK) || defined(__DOXYGEN__) /** - * @brief SoC hook executed at the beginning of the reset vector. + * @brief SoC hook executed at the beginning of the reset vector. * * This hook is implemented by the SoC and can be used to perform any * SoC-specific initialization. @@ -45,7 +45,7 @@ void soc_reset_hook(void); #define soc_reset_hook() do { } while (0) #endif -#ifdef CONFIG_SOC_PREP_HOOK +#if defined(CONFIG_SOC_PREP_HOOK) || defined(__DOXYGEN__) /** * @brief SoC hook executed after the reset vector. * @@ -57,7 +57,7 @@ void soc_prep_hook(void); #define soc_prep_hook() do { } while (0) #endif -#ifdef CONFIG_SOC_EARLY_INIT_HOOK +#if defined(CONFIG_SOC_EARLY_INIT_HOOK) || defined(__DOXYGEN__) /** * @brief SoC hook executed before the kernel and devices are initialized. * @@ -69,7 +69,7 @@ void soc_early_init_hook(void); #define soc_early_init_hook() do { } while (0) #endif -#ifdef CONFIG_SOC_LATE_INIT_HOOK +#if defined(CONFIG_SOC_LATE_INIT_HOOK) || defined(__DOXYGEN__) /** * @brief SoC hook executed after the kernel and devices are initialized. * @@ -81,7 +81,7 @@ void soc_late_init_hook(void); #define soc_late_init_hook() do { } while (0) #endif -#ifdef CONFIG_SOC_PER_CORE_INIT_HOOK +#if defined(CONFIG_SOC_PER_CORE_INIT_HOOK) || defined(__DOXYGEN__) /** * @brief SoC per-core initialization * @@ -93,7 +93,7 @@ void soc_per_core_init_hook(void); #define soc_per_core_init_hook() do { } while (0) #endif -#ifdef CONFIG_BOARD_EARLY_INIT_HOOK +#if defined(CONFIG_BOARD_EARLY_INIT_HOOK) || defined(__DOXYGEN__) /** * @brief Board hook executed before the kernel starts. * @@ -106,7 +106,7 @@ void board_early_init_hook(void); #define board_early_init_hook() do { } while (0) #endif -#ifdef CONFIG_BOARD_LATE_INIT_HOOK +#if defined(CONFIG_BOARD_LATE_INIT_HOOK) || defined(__DOXYGEN__) /** * @brief Board hook executed after the kernel starts. * From 79be4e94ec0b21d6f639f8173510d53234e1eb0f Mon Sep 17 00:00:00 2001 From: Mathieu Choplain Date: Wed, 15 Oct 2025 16:43:54 +0200 Subject: [PATCH 2/4] kernel: hooks: clean up the top-level documentation comment Clean up the top-level comment in the platform hooks header which is used when generating documentation: - capitalize "soc" as "SoC" - capitalize "zephyr" - simplify "soc and board specific" -> "SoC/board-specific" Signed-off-by: Mathieu Choplain --- include/zephyr/platform/hooks.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/zephyr/platform/hooks.h b/include/zephyr/platform/hooks.h index 9577c5e3098ab..a08f569b8bf6a 100644 --- a/include/zephyr/platform/hooks.h +++ b/include/zephyr/platform/hooks.h @@ -8,14 +8,14 @@ /** * @file - * @brief Soc and Board hooks + * @brief SoC and Board hooks * * This header file contains function prototypes for the interfaces between - * zephyr architecture and initialization code and the SoC and board specific logic + * Zephyr's architecture and initialization code and SoC/board-specific logic * that resides under boards/ and soc/ * - * @note These are all standard soc and board interfaces that are exported from - * soc and board specific logic to OS internal logic. These should never be accessed + * @note These are all standard SoC and board interfaces that are exported from + * SoC/board-specific logic to OS internal logic. These should never be accessed * directly from application code but may be freely used within the OS. */ From 73d527019d28e506f98cca090ed80d5cc6b957fe Mon Sep 17 00:00:00 2001 From: Mathieu Choplain Date: Tue, 7 Oct 2025 10:56:55 +0200 Subject: [PATCH 3/4] doc: add hooks to arch porting documentation Document the expected early boot sequence and when platform hooks should be called by the arch-specific coode, and under what conditions. Signed-off-by: Mathieu Choplain --- doc/hardware/porting/arch.rst | 70 +++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/doc/hardware/porting/arch.rst b/doc/hardware/porting/arch.rst index 7c3e4ff9975dc..8be209f9726c4 100644 --- a/doc/hardware/porting/arch.rst +++ b/doc/hardware/porting/arch.rst @@ -87,6 +87,76 @@ Some examples of architecture-specific steps that have to be taken: race conditions. * Setup FIRQ and regular IRQ handling on ARCv2. +Early Boot Sequence Hooks +========================= + +Zephyr exposes several hooks (described in :zephyr_file:`include/zephyr/platform/hooks.h`) +that allow execution of SoC- or board-specific code at precise moments of the boot process. + +The kernel takes care of calling most of the hooks from architecture-agnostic +code. However, some hooks must be called during the early boot sequence; since +the sequence is implemented in architecture-specific code, the call to the hooks +must also be done there. The following gives a rough overview of the early +boot sequence and when hooks should be called by architecture-specific code: + +#. Execution begins in an architecture-specific entry point whose name + matches :kconfig:option:`CONFIG_KERNEL_ENTRY`. + +#. Architecture-specific state is re-initialized immediately + (if :kconfig:option:`CONFIG_INIT_ARCH_HW_AT_BOOT` is enabled). + +#. :c:func:`soc_early_reset_hook` is called. + + .. note:: + It is not necessary to set up a valid stack before calling this hook. + However, the hook is allowed to overwrite the stack pointer before returning. + The architecture-specific code must not expect the stack pointer register + value to be preserved across the call to :c:func:`soc_early_reset_hook`. + + On architectures with multiple stack pointers, there is usually a *"primary"* + stack pointer accessible directly and *"secondary"* stack pointer register(s). + :c:func:`soc_early_reset_hook` implementations may overwrite the *"primary"* + stack pointer must **not** read or modify the value of any *"secondary"* stack + pointer. (This allows the architecture-specific code to set up any *"secondary"* + stack pointer it desires before calling :c:func:`soc_early_reset_hook`) + + For example, the ARM Cortex-A architecture defines several execution modes, + each of which has its own stack pointer register :samp:`sp_{mode}`. When + the processor is executing in mode :samp:`{X}`, operations involving the + ``sp`` general-purpose register operate on :samp:`sp_{X}`. On this + architecture, assuming that the processor is executing in mode :samp:`{M}` + when :c:func:`soc_early_reset_hook` is called, the hook is allowed to + overwrite :samp:`sp_{M}` (accessible through ``sp``) but **must not** read + or overwrite any other :samp:`sp_{mode}` (where :samp:`{mode} != {M}`). + + :c:func:`soc_early_reset_hook` implementations are allowed to not return + execution to the architecture-specific code, in which case they "take over" + the system. Such hooks are not subject to the aforementioned rules and may + read or overwrite any stack pointer. However, when such an implementation + is provided, the rest of the early boot sequence obviously does not execute. + +#. An initial stack is set up for next steps of the early boot sequence. + +#. Architecture-specific "*resume from suspend-to-RAM*" logic is executed + + .. note:: + Refer to :kconfig:option:`CONFIG_PM_S2RAM` and the architecture-specific + implementation for more details, but note that the rest of the early boot + sequence is not executed if this logic determines that an exit from + suspend-to-RAM is ongoing. + +#. :c:func:`soc_reset_hook` is called. + +#. *Architecture-specific operations (in assembly) are performed here...* + +#. :c:func:`z_prep_c` is called. This architecture-specific function is implemented in C. + +#. :c:func:`z_prep_c` immediately calls :c:func:`soc_prep_hook`. + +#. *Architecture-specific operations (in C) are performed here...* + +#. :c:func:`z_cstart` is called. Architecture-agnostic code begins executing. + Interrupt and Exception Handling ******************************** From cb45bbb54fe4f41b968d12998b594fdd273a7ecd Mon Sep 17 00:00:00 2001 From: Mathieu Choplain Date: Tue, 7 Oct 2025 14:01:14 +0200 Subject: [PATCH 4/4] arch: *: prep_c: remove check for CONFIG_SOC_PREP_HOOK soc_prep_hook() is always called from z_prep_c() which is implemented as a C function. As such, there is no need to check for the associated CONFIG_SOC_PREP_HOOK since the platform/hooks.h header will define hooks as no-op function-like macros if their associated Kconfig isn't enabled. Remove the Kconfig check from all arch implementations of z_prep_c() and call soc_prep_hook() directly instead, to avoid duplicating the Kconfig check already performed in platform/hooks.h Signed-off-by: Mathieu Choplain --- arch/arc/core/prep_c.c | 2 -- arch/arm/core/cortex_a_r/prep_c.c | 3 +-- arch/arm/core/cortex_m/prep_c.c | 2 -- arch/arm64/core/prep_c.c | 2 -- arch/mips/core/prep_c.c | 3 +-- arch/riscv/core/prep_c.c | 2 -- arch/sparc/core/prep_c.c | 3 +-- arch/x86/core/prep_c.c | 3 +-- arch/xtensa/core/prep_c.c | 3 +-- 9 files changed, 5 insertions(+), 18 deletions(-) diff --git a/arch/arc/core/prep_c.c b/arch/arc/core/prep_c.c index 6e8e51e050010..99ded8371de31 100644 --- a/arch/arc/core/prep_c.c +++ b/arch/arc/core/prep_c.c @@ -84,9 +84,7 @@ extern void arc_secureshield_init(void); FUNC_NORETURN void z_prep_c(void) { -#if defined(CONFIG_SOC_PREP_HOOK) soc_prep_hook(); -#endif #ifdef CONFIG_ISA_ARCV3 arc_cluster_scm_enable(); diff --git a/arch/arm/core/cortex_a_r/prep_c.c b/arch/arm/core/cortex_a_r/prep_c.c index d2cd695fb134c..faa662ac71ff2 100644 --- a/arch/arm/core/cortex_a_r/prep_c.c +++ b/arch/arm/core/cortex_a_r/prep_c.c @@ -100,9 +100,8 @@ extern FUNC_NORETURN void z_cstart(void); */ FUNC_NORETURN void z_prep_c(void) { -#if defined(CONFIG_SOC_PREP_HOOK) soc_prep_hook(); -#endif + /* Initialize tpidruro with our struct _cpu instance address */ write_tpidruro((uintptr_t)&_kernel.cpus[0]); diff --git a/arch/arm/core/cortex_m/prep_c.c b/arch/arm/core/cortex_m/prep_c.c index 2ead97a1e6dff..6daa0ae250e0b 100644 --- a/arch/arm/core/cortex_m/prep_c.c +++ b/arch/arm/core/cortex_m/prep_c.c @@ -197,9 +197,7 @@ extern FUNC_NORETURN void z_cstart(void); */ FUNC_NORETURN void z_prep_c(void) { -#if defined(CONFIG_SOC_PREP_HOOK) soc_prep_hook(); -#endif relocate_vector_table(); #if defined(CONFIG_CPU_HAS_FPU) diff --git a/arch/arm64/core/prep_c.c b/arch/arm64/core/prep_c.c index ad71338636722..8bca88680ff8c 100644 --- a/arch/arm64/core/prep_c.c +++ b/arch/arm64/core/prep_c.c @@ -35,9 +35,7 @@ __weak void z_arm64_mm_init(bool is_primary_core) { } */ FUNC_NORETURN void z_prep_c(void) { -#if defined(CONFIG_SOC_PREP_HOOK) soc_prep_hook(); -#endif /* Initialize tpidrro_el0 with our struct _cpu instance address */ write_tpidrro_el0((uintptr_t)&_kernel.cpus[0]); diff --git a/arch/mips/core/prep_c.c b/arch/mips/core/prep_c.c index 823ea58b6dee7..16bbec31c6e24 100644 --- a/arch/mips/core/prep_c.c +++ b/arch/mips/core/prep_c.c @@ -47,9 +47,8 @@ static void interrupt_init(void) FUNC_NORETURN void z_prep_c(void) { -#if defined(CONFIG_SOC_PREP_HOOK) soc_prep_hook(); -#endif + arch_bss_zero(); interrupt_init(); diff --git a/arch/riscv/core/prep_c.c b/arch/riscv/core/prep_c.c index 49cbd1dfb866b..c22df9730f19a 100644 --- a/arch/riscv/core/prep_c.c +++ b/arch/riscv/core/prep_c.c @@ -36,9 +36,7 @@ void soc_interrupt_init(void); FUNC_NORETURN void z_prep_c(void) { -#if defined(CONFIG_SOC_PREP_HOOK) soc_prep_hook(); -#endif arch_bss_zero(); arch_data_copy(); diff --git a/arch/sparc/core/prep_c.c b/arch/sparc/core/prep_c.c index 129ca4a6c2748..ab11a106a784a 100644 --- a/arch/sparc/core/prep_c.c +++ b/arch/sparc/core/prep_c.c @@ -22,9 +22,8 @@ FUNC_NORETURN void z_prep_c(void) { -#if defined(CONFIG_SOC_PREP_HOOK) soc_prep_hook(); -#endif + arch_data_copy(); #if CONFIG_ARCH_CACHE arch_cache_init(); diff --git a/arch/x86/core/prep_c.c b/arch/x86/core/prep_c.c index 0239c602fb0fe..fab26c911d7c1 100644 --- a/arch/x86/core/prep_c.c +++ b/arch/x86/core/prep_c.c @@ -36,9 +36,8 @@ FUNC_NORETURN void z_prep_c(void *arg) { x86_boot_arg_t *cpu_arg = arg; -#if defined(CONFIG_SOC_PREP_HOOK) soc_prep_hook(); -#endif + _kernel.cpus[0].nested = 0; #ifdef CONFIG_MMU diff --git a/arch/xtensa/core/prep_c.c b/arch/xtensa/core/prep_c.c index 8a399196d1bb0..f4063e17fec12 100644 --- a/arch/xtensa/core/prep_c.c +++ b/arch/xtensa/core/prep_c.c @@ -31,9 +31,8 @@ BUILD_ASSERT(CONFIG_DCACHE_LINE_SIZE == XCHAL_DCACHE_LINESIZE); */ FUNC_NORETURN void z_prep_c(void) { -#if defined(CONFIG_SOC_PREP_HOOK) soc_prep_hook(); -#endif + #if CONFIG_SOC_HAS_RUNTIME_NUM_CPUS soc_num_cpus_init(); #endif