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 diff --git a/doc/hardware/porting/arch.rst b/doc/hardware/porting/arch.rst index 7c3e4ff9975dc..8663e4e0ae823 100644 --- a/doc/hardware/porting/arch.rst +++ b/doc/hardware/porting/arch.rst @@ -87,6 +87,69 @@ 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 process; since +this is implemented in architecture-specific code, the call to the hooks must +be implemented there too. The following gives a rough overview of the early +boot sequence and when hooks should be called by architecture-specific code: + +* Execution begins in the function named :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 + + * Providing a valid stack to this hook is not necessary. + However, the stack pointer register *may* be overwritten by + the hook before returning. + + * On architectures with multiple stack pointers, there is usually a + "primary" register accessible directly and other "secondary" stack + pointer registers. The hook *may* only overwrite the "primary" stack + pointer register and must leave "secondary" stack pointer registers + untouched. + + * For example, the ARM Cortex-A architecture defines one ``sp_`` + register for each of the processor's execution modes; the ``sp`` + general-purpose register internally corresponds to ``sp_`` + of the processor's current execution mode. On this architecture, + :c:func:`soc_early_reset_hook()` is allowed to overwrite ``sp`` + but not ``sp_`` of a different execution mode. + + * This allows architecture-specific code to set up exception stacks + (when applicable) before calling :c:func:`soc_early_reset_hook` + +* An initial stack for use during the rest of the early boot sequence is setup + +* The architecture-specific "resume from suspend-to-RAM" logic is executed + + * Refer to :kconfig:option:`CONFIG_PM_S2RAM` 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 work (in assembly) occurs here...* + +* :c:func:`z_prep_c` is called + + * This function is implemented in C by the architecture layer + +* :c:func:`z_prep_c()` immediately calls :c:func:`soc_prep_hook()` + +* *Architecture-specific work (in C) occurs here...* + +* :c:func:`z_cstart` is called + + * Architecture-agnostic code takes over when this function is called + Interrupt and Exception Handling ******************************** 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. *