forked from espressif/esp-idf
esp_system: allow defining priorities for startup functions
* Some components have initialization dependencies. To account for them, simple numeric priority values are introduced. * esp_system_init_fn_array moved into Flash from DRAM * System init functions defined using ESP_SYSTEM_INIT_FN now return an error code. This enables simpler and more consistent error handling in the init functions. Returning an error from an init function is now a valid approach — the startup code will print an error and abort.
This commit is contained in:
@@ -7,6 +7,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "esp_attr.h"
|
#include "esp_attr.h"
|
||||||
|
#include "esp_err.h"
|
||||||
|
#include "esp_bit_defs.h"
|
||||||
|
|
||||||
#include "soc/soc_caps.h"
|
#include "soc/soc_caps.h"
|
||||||
#include "hal/cpu_hal.h"
|
#include "hal/cpu_hal.h"
|
||||||
@@ -36,25 +38,44 @@ extern sys_startup_fn_t const g_startup_fn[1];
|
|||||||
void startup_resume_other_cores(void);
|
void startup_resume_other_cores(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal structure describing ESP_SYSTEM_INIT_FN startup functions
|
||||||
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
void (*fn)(void);
|
esp_err_t (*fn)(void); /*!< Pointer to the startup function */
|
||||||
uint32_t cores;
|
uint32_t cores; /*!< Bit map of cores where the function has to be called */
|
||||||
} esp_system_init_fn_t;
|
} esp_system_init_fn_t;
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Declare an component initialization function that will execute on the specified cores (ex. if BIT0 == 1, will execute
|
* @brief Define a system initialization function which will be executed on the specified cores
|
||||||
* on CORE0, CORE1 if BIT1 and so on).
|
|
||||||
*
|
*
|
||||||
* @note Initialization functions should be placed in a compilation unit where at least one other
|
* @param f function name (identifier)
|
||||||
* symbol is referenced 'meaningfully' in another compilation unit, otherwise this gets discarded during linking. (By
|
* @param c bit mask of cores to execute the function on (ex. if BIT0 is set, the function
|
||||||
* 'meaningfully' we mean the reference should not itself get optimized out by the compiler/discarded by the linker).
|
* will be executed on CPU 0, if BIT1 is set - on CPU 1, and so on)
|
||||||
|
* @param priority integer, priority of the initialization function. Higher values mean that
|
||||||
|
* the function will be executed later in the process.
|
||||||
|
* @param (varargs) optional, additional attributes for the function declaration (such as IRAM_ATTR)
|
||||||
|
*
|
||||||
|
* The function defined using this macro must return ESP_OK on success. Any other value will be
|
||||||
|
* logged and the startup process will abort.
|
||||||
|
*
|
||||||
|
* Initialization functions should be placed in a compilation unit where at least one other
|
||||||
|
* symbol is referenced in another compilation unit. This means that the reference should not itself
|
||||||
|
* get optimized out by the compiler or discarded by the linker if the related feature is used.
|
||||||
|
* It is, on the other hand, a good practice to make sure the initialization function does get
|
||||||
|
* discarded if the related feature is not used.
|
||||||
*/
|
*/
|
||||||
#define ESP_SYSTEM_INIT_FN(f, c, ...) \
|
#define ESP_SYSTEM_INIT_FN(f, c, priority, ...) \
|
||||||
static void __attribute__((used)) __VA_ARGS__ __esp_system_init_fn_##f(void); \
|
static esp_err_t __VA_ARGS__ __esp_system_init_fn_##f(void); \
|
||||||
static __attribute__((used)) esp_system_init_fn_t _SECTION_ATTR_IMPL(".esp_system_init_fn", f) \
|
static __attribute__((used)) _SECTION_ATTR_IMPL(".esp_system_init_fn", priority) \
|
||||||
esp_system_init_fn_##f = { .fn = ( __esp_system_init_fn_##f), .cores = (c) }; \
|
esp_system_init_fn_t esp_system_init_fn_##f = { .fn = ( __esp_system_init_fn_##f), .cores = (c) }; \
|
||||||
static __attribute__((used)) __VA_ARGS__ void __esp_system_init_fn_##f(void) // [refactor-todo] this can be made public API if we allow components to declare init functions,
|
static esp_err_t __esp_system_init_fn_##f(void)
|
||||||
// instead of calling them explicitly
|
|
||||||
|
#ifdef CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
|
||||||
|
#define ESP_SYSTEM_INIT_ALL_CORES BIT(0)
|
||||||
|
#else
|
||||||
|
#define ESP_SYSTEM_INIT_ALL_CORES (BIT(SOC_CPU_CORES_NUM) - 1)
|
||||||
|
#endif
|
||||||
|
|
||||||
extern uint64_t g_startup_time; // Startup time that serves as the point of origin for system time. Should be set by the entry
|
extern uint64_t g_startup_time; // Startup time that serves as the point of origin for system time. Should be set by the entry
|
||||||
// function in the port layer. May be 0 as well if this is not backed by a persistent counter, in which case
|
// function in the port layer. May be 0 as well if this is not backed by a persistent counter, in which case
|
||||||
|
@@ -185,10 +185,6 @@ SECTIONS
|
|||||||
*(.gnu.linkonce.s2.*)
|
*(.gnu.linkonce.s2.*)
|
||||||
*(.jcr)
|
*(.jcr)
|
||||||
|
|
||||||
_esp_system_init_fn_array_start = ABSOLUTE(.);
|
|
||||||
KEEP (*(SORT(.esp_system_init_fn) SORT(.esp_system_init_fn.*)))
|
|
||||||
_esp_system_init_fn_array_end = ABSOLUTE(.);
|
|
||||||
|
|
||||||
mapping[dram0_data]
|
mapping[dram0_data]
|
||||||
|
|
||||||
_data_end = ABSOLUTE(.);
|
_data_end = ABSOLUTE(.);
|
||||||
@@ -304,6 +300,10 @@ SECTIONS
|
|||||||
soc_reserved_memory_region_start = ABSOLUTE(.);
|
soc_reserved_memory_region_start = ABSOLUTE(.);
|
||||||
KEEP (*(.reserved_memory_address))
|
KEEP (*(.reserved_memory_address))
|
||||||
soc_reserved_memory_region_end = ABSOLUTE(.);
|
soc_reserved_memory_region_end = ABSOLUTE(.);
|
||||||
|
/* System init functions registered via ESP_SYSTEM_INIT_FN */
|
||||||
|
_esp_system_init_fn_array_start = ABSOLUTE(.);
|
||||||
|
KEEP (*(SORT_BY_INIT_PRIORITY(.esp_system_init_fn.*)))
|
||||||
|
_esp_system_init_fn_array_end = ABSOLUTE(.);
|
||||||
_rodata_end = ABSOLUTE(.);
|
_rodata_end = ABSOLUTE(.);
|
||||||
/* Literals are also RO data. */
|
/* Literals are also RO data. */
|
||||||
_lit4_start = ABSOLUTE(.);
|
_lit4_start = ABSOLUTE(.);
|
||||||
|
@@ -47,10 +47,6 @@ SECTIONS
|
|||||||
*(.gnu.linkonce.s2.*)
|
*(.gnu.linkonce.s2.*)
|
||||||
*(.jcr)
|
*(.jcr)
|
||||||
|
|
||||||
_esp_system_init_fn_array_start = ABSOLUTE(.);
|
|
||||||
KEEP (*(SORT(.esp_system_init_fn) SORT(.esp_system_init_fn.*)))
|
|
||||||
_esp_system_init_fn_array_end = ABSOLUTE(.);
|
|
||||||
|
|
||||||
mapping[dram0_data]
|
mapping[dram0_data]
|
||||||
|
|
||||||
_data_end = ABSOLUTE(.);
|
_data_end = ABSOLUTE(.);
|
||||||
@@ -208,6 +204,10 @@ SECTIONS
|
|||||||
soc_reserved_memory_region_start = ABSOLUTE(.);
|
soc_reserved_memory_region_start = ABSOLUTE(.);
|
||||||
KEEP (*(.reserved_memory_address))
|
KEEP (*(.reserved_memory_address))
|
||||||
soc_reserved_memory_region_end = ABSOLUTE(.);
|
soc_reserved_memory_region_end = ABSOLUTE(.);
|
||||||
|
/* System init functions registered via ESP_SYSTEM_INIT_FN */
|
||||||
|
_esp_system_init_fn_array_start = ABSOLUTE(.);
|
||||||
|
KEEP (*(SORT_BY_INIT_PRIORITY(.esp_system_init_fn.*)))
|
||||||
|
_esp_system_init_fn_array_end = ABSOLUTE(.);
|
||||||
_rodata_end = ABSOLUTE(.);
|
_rodata_end = ABSOLUTE(.);
|
||||||
/* Literals are also RO data. */
|
/* Literals are also RO data. */
|
||||||
_lit4_start = ABSOLUTE(.);
|
_lit4_start = ABSOLUTE(.);
|
||||||
|
@@ -157,10 +157,6 @@ SECTIONS
|
|||||||
*(.gnu.linkonce.s2.*)
|
*(.gnu.linkonce.s2.*)
|
||||||
*(.jcr)
|
*(.jcr)
|
||||||
|
|
||||||
_esp_system_init_fn_array_start = ABSOLUTE(.);
|
|
||||||
KEEP (*(SORT(.esp_system_init_fn) SORT(.esp_system_init_fn.*)))
|
|
||||||
_esp_system_init_fn_array_end = ABSOLUTE(.);
|
|
||||||
|
|
||||||
mapping[dram0_data]
|
mapping[dram0_data]
|
||||||
|
|
||||||
_data_end = ABSOLUTE(.);
|
_data_end = ABSOLUTE(.);
|
||||||
@@ -318,6 +314,10 @@ SECTIONS
|
|||||||
soc_reserved_memory_region_start = ABSOLUTE(.);
|
soc_reserved_memory_region_start = ABSOLUTE(.);
|
||||||
KEEP (*(.reserved_memory_address))
|
KEEP (*(.reserved_memory_address))
|
||||||
soc_reserved_memory_region_end = ABSOLUTE(.);
|
soc_reserved_memory_region_end = ABSOLUTE(.);
|
||||||
|
/* System init functions registered via ESP_SYSTEM_INIT_FN */
|
||||||
|
_esp_system_init_fn_array_start = ABSOLUTE(.);
|
||||||
|
KEEP (*(SORT_BY_INIT_PRIORITY(.esp_system_init_fn.*)))
|
||||||
|
_esp_system_init_fn_array_end = ABSOLUTE(.);
|
||||||
_rodata_end = ABSOLUTE(.);
|
_rodata_end = ABSOLUTE(.);
|
||||||
/* Literals are also RO data. */
|
/* Literals are also RO data. */
|
||||||
_lit4_start = ABSOLUTE(.);
|
_lit4_start = ABSOLUTE(.);
|
||||||
|
@@ -160,10 +160,6 @@ SECTIONS
|
|||||||
*(.gnu.linkonce.s2.*)
|
*(.gnu.linkonce.s2.*)
|
||||||
*(.jcr)
|
*(.jcr)
|
||||||
|
|
||||||
_esp_system_init_fn_array_start = ABSOLUTE(.);
|
|
||||||
KEEP (*(SORT(.esp_system_init_fn) SORT(.esp_system_init_fn.*)))
|
|
||||||
_esp_system_init_fn_array_end = ABSOLUTE(.);
|
|
||||||
|
|
||||||
mapping[dram0_data]
|
mapping[dram0_data]
|
||||||
|
|
||||||
_data_end = ABSOLUTE(.);
|
_data_end = ABSOLUTE(.);
|
||||||
@@ -321,6 +317,10 @@ SECTIONS
|
|||||||
soc_reserved_memory_region_start = ABSOLUTE(.);
|
soc_reserved_memory_region_start = ABSOLUTE(.);
|
||||||
KEEP (*(.reserved_memory_address))
|
KEEP (*(.reserved_memory_address))
|
||||||
soc_reserved_memory_region_end = ABSOLUTE(.);
|
soc_reserved_memory_region_end = ABSOLUTE(.);
|
||||||
|
/* System init functions registered via ESP_SYSTEM_INIT_FN */
|
||||||
|
_esp_system_init_fn_array_start = ABSOLUTE(.);
|
||||||
|
KEEP (*(SORT_BY_INIT_PRIORITY(.esp_system_init_fn.*)))
|
||||||
|
_esp_system_init_fn_array_end = ABSOLUTE(.);
|
||||||
_rodata_end = ABSOLUTE(.);
|
_rodata_end = ABSOLUTE(.);
|
||||||
/* Literals are also RO data. */
|
/* Literals are also RO data. */
|
||||||
_lit4_start = ABSOLUTE(.);
|
_lit4_start = ABSOLUTE(.);
|
||||||
|
@@ -207,10 +207,6 @@ SECTIONS
|
|||||||
*(.gnu.linkonce.s2.*)
|
*(.gnu.linkonce.s2.*)
|
||||||
*(.jcr)
|
*(.jcr)
|
||||||
|
|
||||||
_esp_system_init_fn_array_start = ABSOLUTE(.);
|
|
||||||
KEEP (*(SORT(.esp_system_init_fn) SORT(.esp_system_init_fn.*)))
|
|
||||||
_esp_system_init_fn_array_end = ABSOLUTE(.);
|
|
||||||
|
|
||||||
mapping[dram0_data]
|
mapping[dram0_data]
|
||||||
|
|
||||||
_data_end = ABSOLUTE(.);
|
_data_end = ABSOLUTE(.);
|
||||||
@@ -322,6 +318,10 @@ SECTIONS
|
|||||||
soc_reserved_memory_region_start = ABSOLUTE(.);
|
soc_reserved_memory_region_start = ABSOLUTE(.);
|
||||||
KEEP (*(.reserved_memory_address))
|
KEEP (*(.reserved_memory_address))
|
||||||
soc_reserved_memory_region_end = ABSOLUTE(.);
|
soc_reserved_memory_region_end = ABSOLUTE(.);
|
||||||
|
/* System init functions registered via ESP_SYSTEM_INIT_FN */
|
||||||
|
_esp_system_init_fn_array_start = ABSOLUTE(.);
|
||||||
|
KEEP (*(SORT_BY_INIT_PRIORITY(.esp_system_init_fn.*)))
|
||||||
|
_esp_system_init_fn_array_end = ABSOLUTE(.);
|
||||||
_rodata_end = ABSOLUTE(.);
|
_rodata_end = ABSOLUTE(.);
|
||||||
/* Literals are also RO data. */
|
/* Literals are also RO data. */
|
||||||
_lit4_start = ABSOLUTE(.);
|
_lit4_start = ABSOLUTE(.);
|
||||||
|
@@ -194,10 +194,6 @@ SECTIONS
|
|||||||
*(.gnu.linkonce.s2.*)
|
*(.gnu.linkonce.s2.*)
|
||||||
*(.jcr)
|
*(.jcr)
|
||||||
|
|
||||||
_esp_system_init_fn_array_start = ABSOLUTE(.);
|
|
||||||
KEEP (*(SORT(.esp_system_init_fn) SORT(.esp_system_init_fn.*)))
|
|
||||||
_esp_system_init_fn_array_end = ABSOLUTE(.);
|
|
||||||
|
|
||||||
mapping[dram0_data]
|
mapping[dram0_data]
|
||||||
|
|
||||||
_data_end = ABSOLUTE(.);
|
_data_end = ABSOLUTE(.);
|
||||||
@@ -347,6 +343,10 @@ SECTIONS
|
|||||||
soc_reserved_memory_region_start = ABSOLUTE(.);
|
soc_reserved_memory_region_start = ABSOLUTE(.);
|
||||||
KEEP (*(.reserved_memory_address))
|
KEEP (*(.reserved_memory_address))
|
||||||
soc_reserved_memory_region_end = ABSOLUTE(.);
|
soc_reserved_memory_region_end = ABSOLUTE(.);
|
||||||
|
/* System init functions registered via ESP_SYSTEM_INIT_FN */
|
||||||
|
_esp_system_init_fn_array_start = ABSOLUTE(.);
|
||||||
|
KEEP (*(SORT_BY_INIT_PRIORITY(.esp_system_init_fn.*)))
|
||||||
|
_esp_system_init_fn_array_end = ABSOLUTE(.);
|
||||||
_rodata_end = ABSOLUTE(.);
|
_rodata_end = ABSOLUTE(.);
|
||||||
/* Literals are also RO data. */
|
/* Literals are also RO data. */
|
||||||
_lit4_start = ABSOLUTE(.);
|
_lit4_start = ABSOLUTE(.);
|
||||||
|
@@ -179,17 +179,25 @@ static void do_global_ctors(void)
|
|||||||
|
|
||||||
#if __riscv
|
#if __riscv
|
||||||
for (p = &__init_priority_array_start; p < &__init_priority_array_end; ++p) {
|
for (p = &__init_priority_array_start; p < &__init_priority_array_end; ++p) {
|
||||||
ESP_EARLY_LOGD(TAG, "calling init function: %p", *p);
|
ESP_LOGD(TAG, "calling init function: %p", *p);
|
||||||
(*p)();
|
(*p)();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (p = &__init_array_end - 1; p >= &__init_array_start; --p) {
|
for (p = &__init_array_end - 1; p >= &__init_array_start; --p) {
|
||||||
ESP_EARLY_LOGD(TAG, "calling init function: %p", *p);
|
ESP_LOGD(TAG, "calling init function: %p", *p);
|
||||||
(*p)();
|
(*p)();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Call component init functions defined using ESP_SYSTEM_INIT_Fn macros.
|
||||||
|
* The esp_system_init_fn_t structures describing these functions are collected into
|
||||||
|
* an array [_esp_system_init_fn_array_start, _esp_system_init_fn_array_end) by the
|
||||||
|
* linker. The functions are sorted by their priority value.
|
||||||
|
* The sequence of the init function calls (sorted by priority) is documented in
|
||||||
|
* system_init_fn.txt file.
|
||||||
|
*/
|
||||||
static void do_system_init_fn(void)
|
static void do_system_init_fn(void)
|
||||||
{
|
{
|
||||||
extern esp_system_init_fn_t _esp_system_init_fn_array_start;
|
extern esp_system_init_fn_t _esp_system_init_fn_array_start;
|
||||||
@@ -197,14 +205,20 @@ static void do_system_init_fn(void)
|
|||||||
|
|
||||||
esp_system_init_fn_t *p;
|
esp_system_init_fn_t *p;
|
||||||
|
|
||||||
for (p = &_esp_system_init_fn_array_end - 1; p >= &_esp_system_init_fn_array_start; --p) {
|
int core_id = cpu_hal_get_core_id();
|
||||||
if (p->cores & BIT(cpu_hal_get_core_id())) {
|
for (p = &_esp_system_init_fn_array_start; p < &_esp_system_init_fn_array_end; ++p) {
|
||||||
(*(p->fn))();
|
if (p->cores & BIT(core_id)) {
|
||||||
|
ESP_LOGD(TAG, "calling init function: %p on core: %d", p->fn, core_id);
|
||||||
|
esp_err_t err = (*(p->fn))();
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "init function %p has failed (0x%x), aborting", p->fn, err);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
|
#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
|
||||||
s_system_inited[cpu_hal_get_core_id()] = true;
|
s_system_inited[core_id] = true;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,6 +230,9 @@ static void esp_startup_start_app_other_cores_default(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This function has to be in IRAM, as while it is running on CPU1, CPU0 may do some flash operations
|
||||||
|
* (e.g. initialize the core dump), which means that cache will be disabled.
|
||||||
|
*/
|
||||||
static void IRAM_ATTR start_cpu_other_cores_default(void)
|
static void IRAM_ATTR start_cpu_other_cores_default(void)
|
||||||
{
|
{
|
||||||
do_system_init_fn();
|
do_system_init_fn();
|
||||||
@@ -428,7 +445,7 @@ static void start_cpu0_default(void)
|
|||||||
while (1);
|
while (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
IRAM_ATTR ESP_SYSTEM_INIT_FN(init_components0, BIT(0))
|
ESP_SYSTEM_INIT_FN(init_components0, BIT(0), 200)
|
||||||
{
|
{
|
||||||
esp_timer_init();
|
esp_timer_init();
|
||||||
|
|
||||||
@@ -474,4 +491,6 @@ IRAM_ATTR ESP_SYSTEM_INIT_FN(init_components0, BIT(0))
|
|||||||
_Unwind_SetNoFunctionContextInstall(1);
|
_Unwind_SetNoFunctionContextInstall(1);
|
||||||
_Unwind_SetEnableExceptionFdeSorting(0);
|
_Unwind_SetEnableExceptionFdeSorting(0);
|
||||||
#endif // CONFIG_COMPILER_CXX_EXCEPTIONS
|
#endif // CONFIG_COMPILER_CXX_EXCEPTIONS
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user