feat(system_init): introduce pre-scheduler and pre-app main handler registrations

- Added macros for registering handlers to run before the scheduler and app main.
- Updated various components to utilize the new registration system for initialization.
- Refactored app startup logic to streamline initialization sequence.
This commit is contained in:
Konstantin Kondrashov
2026-09-02 16:58:44 +03:00
parent 40f25003b4
commit 754ac1dd45
21 changed files with 348 additions and 129 deletions
+2 -2
View File
@@ -19,8 +19,8 @@ idf_component_optional_requires(PRIVATE mbedtls)
if(CONFIG_BOOTLOADER_APP_ROLLBACK_CONFIRM_ON_STARTUP)
# ota_auto_confirm.c has no other externally referenced symbol, so force the linker to pull
# it in from the archive to override the weak esp_ota_confirm_rollback_hook() in freertos.
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u esp_ota_confirm_rollback_hook")
# its static PRE_APP_MAIN event registration from the archive.
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u esp_ota_auto_confirm_include")
endif()
idf_define_esp_err_codes(HEADERS include/esp_ota_ops.h)
+10 -4
View File
@@ -10,17 +10,20 @@
#include "esp_ota_ops.h"
#include "esp_log.h"
#include "esp_private/esp_sys_event_app_init.h"
ESP_LOG_ATTR_TAG(TAG, "ota_auto_confirm");
// Strong override of the weak hook declared in components/freertos/app_startup.c
void esp_ota_confirm_rollback_hook(void)
ESP_PRE_APP_MAIN_HANDLER_REGISTER(esp_ota_auto_confirm, 200)
{
(void)user_arg;
(void)ctx;
esp_ota_img_states_t ota_state;
const esp_partition_t *running = esp_ota_get_running_partition();
if (esp_ota_get_state_partition(running, &ota_state) != ESP_OK) {
return;
return ESP_OK;
}
if (ota_state == ESP_OTA_IMG_PENDING_VERIFY) {
@@ -33,13 +36,16 @@ void esp_ota_confirm_rollback_hook(void)
ESP_LOGW(TAG, "Bootloader is not capable of rollback");
} else {
return;
return ESP_OK;
}
esp_err_t err = esp_ota_mark_app_valid_cancel_rollback();
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to mark app valid: %s", esp_err_to_name(err));
}
return ESP_OK;
}
void esp_ota_auto_confirm_include(void) {}
#endif /* CONFIG_BOOTLOADER_APP_ROLLBACK_CONFIRM_ON_STARTUP */
+9
View File
@@ -34,3 +34,12 @@ if(CONFIG_ESP_SYSTEM_PANIC_GDBSTUB)
# Make sure the panic event registration in gdbstub.c is considered by the linker
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u esp_gdbstub_panic_handler")
endif()
if(CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME)
# Pull in the PRE_SCHEDULER registration from gdbstub.c.
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u esp_gdbstub_init")
if(CONFIG_IDF_TARGET_ARCH_XTENSA)
# Pull in the Xtensa debug exception handler from its separate object file.
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u _xt_panic_gdbstub")
endif()
endif()
+9
View File
@@ -25,6 +25,7 @@
#endif
#include "esp_private/esp_sys_event_panic.h"
#include "esp_private/esp_sys_event_app_init.h"
#include "esp_private/panic_internal.h"
#include "esp_private/crosscore_int.h"
@@ -451,6 +452,14 @@ void esp_gdbstub_init(void)
esp_intr_alloc(ETS_UART0_INTR_SOURCE, 0, esp_gdbstub_int, NULL, NULL);
esp_gdbstub_init_dports();
}
ESP_PRE_SCHEDULER_HANDLER_REGISTER(init_gdbstub, 130)
{
(void)user_arg;
(void)ctx;
esp_gdbstub_init();
return ESP_OK;
}
#endif /* CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME */
#ifdef CONFIG_ESP_GDBSTUB_SUPPORT_TASKS
@@ -33,6 +33,7 @@
#include "esp_private/esp_psram_mspi.h"
#include "esp_private/mspi_mem_barrier.h"
#include "esp_private/startup_internal.h"
#include "esp_private/esp_sys_event_app_init.h"
#if SOC_SPIRAM_XIP_SUPPORTED
#include "esp_private/mmu_psram_flash.h"
#endif
@@ -675,6 +676,23 @@ esp_err_t esp_psram_extram_reserve_dma_pool(size_t size)
return ESP_OK;
}
#if CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL
ESP_PRE_APP_MAIN_HANDLER_REGISTER(reserve_dma_pool, 110)
{
(void)user_arg;
(void)ctx;
if (!esp_psram_is_initialized()) {
return ESP_OK;
}
esp_err_t err = esp_psram_extram_reserve_dma_pool(CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Could not reserve internal/DMA pool (error 0x%x)", err);
}
return err;
}
#endif
bool IRAM_ATTR __attribute__((pure)) esp_psram_is_initialized(void)
{
return s_psram_ctx.is_initialised;
+5
View File
@@ -183,6 +183,11 @@ endif()
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u esp_system_include_startup_funcs")
if(CONFIG_ESP_INT_WDT)
# Pull in the PRE_SCHEDULER registrations from int_wdt.c.
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u esp_int_wdt_init")
endif()
# [refactor-todo] requirements due to init code, should be removable
# once link-time registration of component init functions is used.
if(NOT CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT)
@@ -3,7 +3,7 @@
# SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
#
# This file is used to check the order of execution of ESP_SYSTEM_INIT_FN functions.
# This file checks the order of execution of system startup handlers.
# It compares the priorities found in .c source files to the contents of system_init_fn.txt
# In case of an inconsistency, the script prints the differences found and returns with a
# non-zero exit code.
@@ -15,12 +15,47 @@ import re
import sys
COMMENT_REGEX = re.compile(r'//.*?$|/\*.*?\*/', re.DOTALL | re.MULTILINE)
ESP_SYSTEM_INIT_FN_REGEX_SIMPLE = re.compile(r'\bESP_SYSTEM_INIT_FN\s*\(')
ESP_SYSTEM_INIT_FN_REGEX = re.compile(
r'ESP_SYSTEM_INIT_FN\(([a-zA-Z0-9_]+)\s*,\s*([a-zA-Z\ _0-9\(\)|]+)\s*,\s*([a-zA-Z\ _0-9\(\)|]+)\s*,\s*([0-9]+)\)'
ESP_SYSTEM_INIT_FN_REGEX = (
r'{macro}\((?P<func>[a-zA-Z0-9_]+)\s*,\s*'
r'(?P<stage>[a-zA-Z\ _0-9\(\)|]+)\s*,\s*'
r'(?P<affinity>[a-zA-Z\ _0-9\(\)|]+)\s*,\s*'
r'(?P<priority>[0-9]+)\)'
)
APP_INIT_FN_REGEX = r'{macro}\s*\(\s*(?P<func>[a-zA-Z0-9_]+)\s*,\s*(?P<priority>[0-9]+)\s*\)'
STARTUP_REGISTRATIONS = (
(
'ESP_SYSTEM_INIT_FN',
re.compile(ESP_SYSTEM_INIT_FN_REGEX.format(macro='ESP_SYSTEM_INIT_FN')),
'',
'',
),
(
'ESP_PRE_SCHEDULER_HANDLER_REGISTER',
re.compile(APP_INIT_FN_REGEX.format(macro='ESP_PRE_SCHEDULER_HANDLER_REGISTER')),
'PRE_SCHEDULER',
'BIT(0)',
),
(
'ESP_PRE_SCHEDULER_HANDLER_REGISTER_PER_CPU',
re.compile(APP_INIT_FN_REGEX.format(macro='ESP_PRE_SCHEDULER_HANDLER_REGISTER_PER_CPU')),
'PRE_SCHEDULER',
'ESP_SYSTEM_INIT_ALL_CORES',
),
(
'ESP_PRE_APP_MAIN_HANDLER_REGISTER',
re.compile(APP_INIT_FN_REGEX.format(macro='ESP_PRE_APP_MAIN_HANDLER_REGISTER')),
'PRE_APP_MAIN',
'MAIN_TASK',
),
)
STARTUP_ENTRIES_FILE = 'components/esp_system/system_init_fn.txt'
EXCLUDED_SOURCE_DIRS = {'test_apps', 'host_test', 'host_tests'}
STAGE_ORDER = {
'CORE': 0,
'SECONDARY': 1,
'PRE_SCHEDULER': 2,
'PRE_APP_MAIN': 3,
}
class StartupEntry:
@@ -69,36 +104,36 @@ def main() -> None:
file_contents = f_obj.read()
file_contents_no_comments = strip_comments(file_contents)
if not ESP_SYSTEM_INIT_FN_REGEX_SIMPLE.search(file_contents_no_comments):
continue
for macro, pattern, default_stage, default_affinity in STARTUP_REGISTRATIONS:
count_expected = len(re.findall(rf'\b{macro}\s*\(', file_contents_no_comments))
found = list(pattern.finditer(file_contents_no_comments))
if len(found) != count_expected:
print(
f'error: In {filename}, found {macro} {count_expected} time(s), '
f'but regular expression matched {len(found)} time(s)',
file=sys.stderr,
)
has_errors = True
count_expected = len(ESP_SYSTEM_INIT_FN_REGEX_SIMPLE.findall(file_contents_no_comments))
found = ESP_SYSTEM_INIT_FN_REGEX.findall(file_contents_no_comments)
if len(found) != count_expected:
print(
(
f'error: In {filename}, found ESP_SYSTEM_INIT_FN {count_expected} time(s), '
f'but regular expression matched {len(found)} time(s)'
),
file=sys.stderr,
)
has_errors = True
for match in found:
entry = StartupEntry(
filename=relpath, func=match[0], stage=match[1], affinity=match[2], priority=int(match[3])
)
startup_entries.append(entry)
for match in found:
startup_entries.append(
StartupEntry(
relpath,
match.group('func'),
match.groupdict().get('stage') or default_stage,
match.groupdict().get('affinity') or default_affinity,
int(match.group('priority')),
)
)
#
# 2. Sort the ESP_SYSTEM_INIT_FN functions in C source files.
# 2. Sort the startup handlers in C source files.
# In addition to the stage and priority, we also add filename to the sort key,
# to have a stable sorting order in case when the same startup function is defined in multiple files,
# for example for different targets.
#
def sort_key(entry: StartupEntry) -> tuple[str, int, str]:
# luckily 'core' and 'secondary' are in alphabetical order, so we can return the string
return (entry.stage, entry.priority, entry.filename)
def sort_key(entry: StartupEntry) -> tuple[int, int, str]:
return (STAGE_ORDER[entry.stage], entry.priority, entry.filename)
startup_entries = list(sorted(startup_entries, key=sort_key))
startup_entries_lines = [str(entry) for entry in startup_entries]
+9
View File
@@ -11,6 +11,7 @@
#include "esp_intr_alloc.h"
#include "esp_debug_helpers.h"
#include "esp_private/crosscore_int.h"
#include "esp_private/esp_sys_event_app_init.h"
#include "soc/periph_defs.h"
#include "soc/system_intr.h"
#include "hal/crosscore_int_ll.h"
@@ -113,6 +114,14 @@ void esp_crosscore_int_init(void)
ESP_ERROR_CHECK(err);
}
ESP_PRE_SCHEDULER_HANDLER_REGISTER_PER_CPU(init_crosscore_interrupt, 120)
{
(void)user_arg;
(void)ctx;
esp_crosscore_int_init();
return ESP_OK;
}
static void ESP_SYSTEM_IRAM_ATTR esp_crosscore_int_send(int core_id, uint32_t reason_mask)
{
assert(core_id < CONFIG_FREERTOS_NUMBER_OF_CORES);
@@ -0,0 +1,47 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_cpu.h"
#include "esp_private/esp_sys_event.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Register a handler to run on core 0 immediately before the scheduler starts
*/
#define ESP_PRE_SCHEDULER_HANDLER_REGISTER(fn, priority) \
static esp_err_t fn(void *user_arg, void *ctx); \
_ESP_SYS_EVENT_REGISTER(PRE_SCHEDULER, priority, __esp_pre_scheduler_##fn) \
{ \
if (esp_cpu_get_core_id() != 0) { \
return ESP_OK; \
} \
return fn(user_arg, ctx); \
} \
static esp_err_t fn(void *user_arg, void *ctx)
/**
* @brief Register a handler to run on every core immediately before its scheduler starts
*/
#define ESP_PRE_SCHEDULER_HANDLER_REGISTER_PER_CPU(fn, priority) \
_ESP_SYS_EVENT_REGISTER(PRE_SCHEDULER, priority, fn)
/**
* @brief Register a handler to run in the main task immediately before app_main
*
* Handlers run in ascending priority order after all CPUs have completed
* FreeRTOS initialization. The scheduler and heap allocator are available.
*/
#define ESP_PRE_APP_MAIN_HANDLER_REGISTER(fn, priority) \
_ESP_SYS_EVENT_REGISTER(PRE_APP_MAIN, priority, fn)
#ifdef __cplusplus
}
#endif
@@ -34,6 +34,8 @@
#define _ESP_SYS_EVENT_SECTION_SHUTDOWN esysev_shdn
#define _ESP_SYS_EVENT_SECTION_SYSTEM_INIT_CORE esysev_initc
#define _ESP_SYS_EVENT_SECTION_SYSTEM_INIT_SECONDARY esysev_inits
#define _ESP_SYS_EVENT_SECTION_PRE_SCHEDULER esysev_presc
#define _ESP_SYS_EVENT_SECTION_PRE_APP_MAIN esysev_pream
#define _ESP_SYS_EVENT_SECTION_PANIC esysev_panic
#define _ESP_SYS_EVENT_SECTION_PANIC_EARLY_BREAK esysev_paneb
#endif
@@ -42,5 +44,7 @@
ESP_SYS_EVENT_DEF(SHUTDOWN)
ESP_SYS_EVENT_DEF(SYSTEM_INIT_CORE)
ESP_SYS_EVENT_DEF(SYSTEM_INIT_SECONDARY)
ESP_SYS_EVENT_DEF(PRE_SCHEDULER)
ESP_SYS_EVENT_DEF(PRE_APP_MAIN)
ESP_SYS_EVENT_DEF(PANIC)
ESP_SYS_EVENT_DEF(PANIC_EARLY_BREAK)
+17
View File
@@ -23,6 +23,7 @@
#include "esp_freertos_hooks.h"
#include "esp_private/periph_ctrl.h"
#include "esp_private/esp_int_wdt.h"
#include "esp_private/esp_sys_event_app_init.h"
#include "mwdt_priv.h"
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_MWDT_SUPPORT_SLEEP_RETENTION
@@ -194,6 +195,22 @@ void esp_int_wdt_cpu_init(void)
esp_intr_enable_source(ETS_INT_WDT_INUM);
}
ESP_PRE_SCHEDULER_HANDLER_REGISTER(init_int_wdt, 100)
{
(void)user_arg;
(void)ctx;
esp_int_wdt_init();
return ESP_OK;
}
ESP_PRE_SCHEDULER_HANDLER_REGISTER_PER_CPU(init_int_wdt_cpu, 110)
{
(void)user_arg;
(void)ctx;
esp_int_wdt_cpu_init();
return ESP_OK;
}
void ESP_SYSTEM_IRAM_ATTR esp_int_wdt_pause(void)
{
wdt_hal_write_protect_disable(&iwdt_context);
@@ -22,6 +22,16 @@ SECTIONS
KEEP(*(SORT_BY_INIT_PRIORITY(.esysev_inits.*)))
PROVIDE(_esysev_inits_end = .);
. = ALIGN(4);
PROVIDE(_esysev_presc_start = .);
KEEP(*(SORT_BY_INIT_PRIORITY(.esysev_presc.*)))
PROVIDE(_esysev_presc_end = .);
. = ALIGN(4);
PROVIDE(_esysev_pream_start = .);
KEEP(*(SORT_BY_INIT_PRIORITY(.esysev_pream.*)))
PROVIDE(_esysev_pream_end = .);
. = ALIGN(4);
PROVIDE(_esysev_panic_start = .);
KEEP(*(SORT_BY_INIT_PRIORITY(.esysev_panic.*)))
+12
View File
@@ -12,6 +12,14 @@ entries:
entries:
.esysev_inits+
[sections:esysev_presc]
entries:
.esysev_presc+
[sections:esysev_pream]
entries:
.esysev_pream+
[sections:esysev_panic]
entries:
.esysev_panic+
@@ -26,6 +34,8 @@ entries:
esysev_shdn -> flash_rodata
esysev_initc -> flash_rodata
esysev_inits -> flash_rodata
esysev_presc -> flash_rodata
esysev_pream -> flash_rodata
esysev_panic -> flash_rodata
esysev_paneb -> flash_rodata
@@ -36,6 +46,8 @@ entries:
esysev_shdn -> flash_rodata ALIGN(4, pre) KEEP() SORT(init_priority) SURROUND(esysev_shdn),
esysev_initc -> flash_rodata ALIGN(4, pre) KEEP() SORT(init_priority) SURROUND(esysev_initc),
esysev_inits -> flash_rodata ALIGN(4, pre) KEEP() SORT(init_priority) SURROUND(esysev_inits),
esysev_presc -> flash_rodata ALIGN(4, pre) KEEP() SORT(init_priority) SURROUND(esysev_presc),
esysev_pream -> flash_rodata ALIGN(4, pre) KEEP() SORT(init_priority) SURROUND(esysev_pream),
esysev_panic -> flash_rodata ALIGN(4, pre) KEEP() SORT(init_priority) SURROUND(esysev_panic),
esysev_paneb -> flash_rodata ALIGN(4, pre) KEEP() SORT(init_priority) SURROUND(esysev_paneb)
+13
View File
@@ -6,6 +6,7 @@
#include <stdint.h>
#include <string.h>
#include <assert.h>
#include "sdkconfig.h"
#include "esp_attr.h"
@@ -13,8 +14,10 @@
#include "esp_check.h"
#include "esp_system.h"
#include "esp_log.h"
#include "esp_chip_info.h"
#include "esp_xt_wdt.h"
#include "esp_cpu.h"
#include "esp_private/esp_sys_event_app_init.h"
#include "esp_private/startup_internal.h"
#include "freertos/FreeRTOS.h"
#include "soc/soc_caps.h"
@@ -50,6 +53,16 @@ void esp_system_include_startup_funcs(void)
// [refactor-todo] Most of these init functions should be moved to the respective components.
#if !CONFIG_ESP_INT_WDT && CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
ESP_PRE_SCHEDULER_HANDLER_REGISTER(check_cache_lock_bug, 90)
{
(void)user_arg;
(void)ctx;
assert(!soc_has_cache_lock_bug() && "ESP32 Rev 3 + Dual Core + PSRAM requires INT WDT enabled in project config!");
return ESP_OK;
}
#endif
ESP_SYSTEM_INIT_FN(init_show_cpu_freq, CORE, BIT(0), 10)
{
ESP_EARLY_LOGI(TAG, "Pro cpu start user code");
+36 -5
View File
@@ -1,7 +1,7 @@
# This file documents the expected order of execution of ESP_SYSTEM_INIT_FN functions.
# This file documents the expected order of execution of system startup handlers.
#
# When adding new ESP_SYSTEM_INIT_FN functions or changing init priorities of existing functions,
# keep this file up to date. This is checked in CI.
# When adding startup handlers or changing their priorities, keep this file up to date.
# This is checked in CI.
# When adding new functions or changing the priorities, please read the comments and see if
# they need to be updated to be consistent with the changes you are making.
#
@@ -9,7 +9,7 @@
# Each line has the following format:
# stage: prio: function_name in path/to/source_file on affinity_expression
# Where:
# stage: which startup stage the function is executed in (CORE or SECONDARY)
# stage: which startup stage the function is executed in (CORE, SECONDARY, PRE_SCHEDULER, or PRE_APP_MAIN)
# prio: priority value (higher value means function is executed later)
# affinity_expression: bit map of cores the function is executed on
@@ -148,4 +148,35 @@ SECONDARY: 240: psram_adjust_timing_point_via_temperature in components/esp_hw_s
# Now that the application is about to start, disable boot watchdog
SECONDARY: 999: init_disable_rtc_wdt in components/esp_system/startup_funcs.c on BIT(0)
# DO NOT add new init functions here. Add them to the correct stage above.
# DO NOT add new init functions at the end of a stage. Add them at the correct priority.
########### PRE_SCHEDULER startup stage ###########
# If the interrupt watchdog is disabled, validate the ESP32 ECO3 cache lock configuration instead.
PRE_SCHEDULER: 90: check_cache_lock_bug in components/esp_system/startup_funcs.c on BIT(0)
# Initialize the interrupt watchdog globally, then enable it on each core.
PRE_SCHEDULER: 100: init_int_wdt in components/esp_system/int_wdt.c on BIT(0)
PRE_SCHEDULER: 110: init_int_wdt_cpu in components/esp_system/int_wdt.c on ESP_SYSTEM_INIT_ALL_CORES
# Cross-core interrupts must be available before each core starts its scheduler.
PRE_SCHEDULER: 120: init_crosscore_interrupt in components/esp_system/crosscore_int.c on ESP_SYSTEM_INIT_ALL_CORES
# Runtime GDB stub initialization requires cross-core interrupts.
PRE_SCHEDULER: 130: init_gdbstub in components/esp_gdbstub/src/gdbstub.c on BIT(0)
########### PRE_APP_MAIN startup stage ###########
# Reclaim startup stacks only after every core has completed FreeRTOS initialization.
PRE_APP_MAIN: 100: enable_nonos_stack_heaps in components/heap/heap_caps_init.c on MAIN_TASK
# Reserve the internal DMA pool after startup stack memory has been reclaimed.
PRE_APP_MAIN: 110: reserve_dma_pool in components/esp_psram/system_layer/esp_psram.c on MAIN_TASK
# Initialize the task watchdog after the scheduler is available.
PRE_APP_MAIN: 120: init_task_wdt in components/esp_system/task_wdt/task_wdt.c on MAIN_TASK
# Confirm the running OTA image immediately before calling app_main.
PRE_APP_MAIN: 200: esp_ota_auto_confirm in components/app_update/ota_auto_confirm.c on MAIN_TASK
+23
View File
@@ -23,6 +23,7 @@
#include "esp_task_wdt.h"
#include "esp_private/system_internal.h"
#include "esp_private/crosscore_int.h"
#include "esp_private/esp_sys_event_app_init.h"
#include "esp_private/esp_task_wdt.h"
#include "esp_private/esp_task_wdt_impl.h"
@@ -58,6 +59,28 @@ extern bool g_panic_abort;
/* Global flag marking whether the current ISR is a Task Watchdog ISR. */
bool g_twdt_isr = false;
#if CONFIG_ESP_TASK_WDT_INIT
ESP_PRE_APP_MAIN_HANDLER_REGISTER(init_task_wdt, 120)
{
(void)user_arg;
(void)ctx;
esp_task_wdt_config_t config = {
.timeout_ms = CONFIG_ESP_TASK_WDT_TIMEOUT_S * 1000,
.idle_core_mask = 0,
#if CONFIG_ESP_TASK_WDT_PANIC
.trigger_panic = true,
#endif
};
#if CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0
config.idle_core_mask |= BIT(0);
#endif
#if CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1
config.idle_core_mask |= BIT(1);
#endif
return esp_task_wdt_init(&config);
}
#endif
// --------------------------------------------------- Definitions -----------------------------------------------------
// ---------------------- Typedefs -------------------------
-10
View File
@@ -223,22 +223,12 @@ else()
idf_component_optional_requires(PUBLIC esp_trace)
endif()
if(CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME)
# [refactor-todo]: app_startup.c esp_startup_start_app_other_cores() calls esp_gdbstub_init() (called on CPU0).
# This should be resolved when link-time registration of startup functions is added.
idf_component_optional_requires(PRIVATE esp_gdbstub)
endif()
if(CONFIG_FREERTOS_RUN_TIME_STATS_USING_ESP_TIMER)
# [refactor-todo]: esp_timer is required by FreeRTOS when we use esp_timer_get_time() to do profiling
# Introduce a port wrapper function to avoid including esp_timer.h into the public header
idf_component_optional_requires(PUBLIC esp_timer)
endif()
if(CONFIG_SPIRAM)
idf_component_optional_requires(PRIVATE esp_psram)
endif()
if(CONFIG_PM_TRACE)
# esp_pm is required by port_systick.c for tracing
idf_component_optional_requires(PRIVATE esp_pm)
+23 -81
View File
@@ -12,20 +12,7 @@
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/portmacro.h"
#include "esp_private/esp_int_wdt.h"
#include "esp_private/crosscore_int.h"
#include "esp_task_wdt.h"
#include "esp_freertos_hooks.h"
#include "esp_heap_caps_init.h"
#include "esp_chip_info.h"
#if CONFIG_SPIRAM
/* Required by esp_psram_extram_reserve_dma_pool() */
#include "esp_psram.h"
#include "esp_private/esp_psram_extram.h"
#endif
#ifdef CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
#include "esp_gdbstub.h" /* Required by esp_gdbstub_init() */
#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
#include "esp_private/esp_sys_event_internal.h"
/* ------------------------------------------------- App/OS Startup ----------------------------------------------------
* - Functions related to application and FreeRTOS startup
@@ -56,26 +43,18 @@ CONFIG_FREERTOS_UNICORE and CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE should be identic
static void main_task(void* args);
ESP_LOG_ATTR_TAG(APP_START_TAG, "app_start");
static void run_app_startup_event(esp_sys_event_id_t id)
{
ESP_SYS_EVENT_FOREACH(handler, id) {
ESP_ERROR_CHECK(handler->handler(NULL, NULL));
}
}
// ------------------ CPU0 App Startup ---------------------
void esp_startup_start_app(void)
{
#if CONFIG_ESP_INT_WDT
esp_int_wdt_init();
// Initialize the interrupt watch dog for CPU0.
esp_int_wdt_cpu_init();
#elif CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
// If the INT WDT isn't enabled on ESP32 ECO3, issue an error regarding the cache lock bug
assert(!soc_has_cache_lock_bug() && "ESP32 Rev 3 + Dual Core + PSRAM requires INT WDT enabled in project config!");
#endif
// Initialize the cross-core interrupt on CPU0
esp_crosscore_int_init();
#if CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
void esp_gdbstub_init(void);
esp_gdbstub_init();
#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
run_app_startup_event(ESP_SYS_EVENT_PRE_SCHEDULER);
BaseType_t res = xTaskCreatePinnedToCore(main_task, "main",
ESP_TASK_MAIN_STACK, NULL,
@@ -87,11 +66,21 @@ void esp_startup_start_app(void)
If a particular FreeRTOS port has port/arch specific OS startup behavior, they can implement a function of type
"void port_start_app_hook(void)" in their `port.c` files. This function will be called below, thus allowing each
FreeRTOS port to implement port specific app startup behavior.
Deprecated: Register a PRE_SCHEDULER handler with priority 999 to preserve this ordering.
*/
void __attribute__((weak)) port_start_app_hook(void);
// TODO: IDF-16135
void __attribute__((weak, deprecated("port_start_app_hook is deprecated and will be removed in IDF 7.0. Use ESP_PRE_SCHEDULER_HANDLER_REGISTER instead.")))
port_start_app_hook(void);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
if (port_start_app_hook != NULL) {
ESP_EARLY_LOGW(APP_START_TAG,
"port_start_app_hook is deprecated and will be removed in IDF 7.0. "
"Use ESP_PRE_SCHEDULER_HANDLER_REGISTER instead.");
port_start_app_hook();
}
#pragma GCC diagnostic pop
ESP_EARLY_LOGD(APP_START_TAG, "Starting scheduler on CPU0");
vTaskStartScheduler();
@@ -113,13 +102,7 @@ void esp_startup_start_app_other_cores(void)
;
}
#if CONFIG_ESP_INT_WDT
// Initialize the interrupt watch dog for CPU1.
esp_int_wdt_cpu_init();
#endif
// Initialize the cross-core interrupt on CPU1
esp_crosscore_int_init();
run_app_startup_event(ESP_SYS_EVENT_PRE_SCHEDULER);
ESP_EARLY_LOGD(APP_START_TAG, "Starting scheduler on CPU%d", xPortGetCoreID());
xPortStartScheduler();
@@ -154,54 +137,13 @@ static void wait_for_all_cores_ready(void)
#endif // !CONFIG_FREERTOS_UNICORE
}
// Reinitialize the startup stack heaps, so it can be used for heap allocation.
static void reclaim_startup_stack_memory_for_heap(void)
{
wait_for_all_cores_ready();
// [refactor-todo] check if there is a way to move the following block to esp_system startup
heap_caps_enable_nonos_stack_heaps();
// Now we have startup stack RAM available for heap, enable any DMA pool memory
#if CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL
if (esp_psram_is_initialized()) {
esp_err_t r = esp_psram_extram_reserve_dma_pool(CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL);
if (r != ESP_OK) {
ESP_LOGE(MAIN_TAG, "Could not reserve internal/DMA pool (error 0x%x)", r);
abort();
}
}
#endif
}
static void main_task(void* args)
{
ESP_LOGI(MAIN_TAG, "Started on CPU%d", (int)xPortGetCoreID());
reclaim_startup_stack_memory_for_heap();
wait_for_all_cores_ready();
// Initialize TWDT if configured to do so
#if CONFIG_ESP_TASK_WDT_INIT
esp_task_wdt_config_t twdt_config = {
.timeout_ms = CONFIG_ESP_TASK_WDT_TIMEOUT_S * 1000,
.idle_core_mask = 0,
#if CONFIG_ESP_TASK_WDT_PANIC
.trigger_panic = true,
#endif
};
#if CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0
twdt_config.idle_core_mask |= (1 << 0);
#endif
#if CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1
twdt_config.idle_core_mask |= (1 << 1);
#endif
ESP_ERROR_CHECK(esp_task_wdt_init(&twdt_config));
#endif // CONFIG_ESP_TASK_WDT
// app_update overrides it to auto-confirm an OTA rollback right before app_main.
void __attribute__((weak)) esp_ota_confirm_rollback_hook(void);
if (esp_ota_confirm_rollback_hook != NULL) {
esp_ota_confirm_rollback_hook();
}
run_app_startup_event(ESP_SYS_EVENT_PRE_APP_MAIN);
/*
Note: Be careful when changing the "Calling app_main()" log below as multiple pytest scripts expect this log as a
+9
View File
@@ -15,6 +15,7 @@
#include "esp_heap_task_info_internal.h"
#include "heap_memory_layout.h"
#include "esp_private/esp_sys_event_app_init.h"
#include "esp_private/startup_internal.h"
static const char *TAG = "heap_init";
@@ -98,6 +99,14 @@ void heap_caps_enable_nonos_stack_heaps(void)
s_in_startup = false;
}
ESP_PRE_APP_MAIN_HANDLER_REGISTER(enable_nonos_stack_heaps, 100)
{
(void)user_arg;
(void)ctx;
heap_caps_enable_nonos_stack_heaps();
return ESP_OK;
}
/* Initialize the heap allocator to use all of the memory not
used by static data or reserved for other purposes
*/
@@ -3,6 +3,21 @@ System
:link_to_translation:`zh_CN:[中文]`
FreeRTOS
---------
The legacy ``port_start_app_hook`` is deprecated and will be removed in ESP-IDF v7.0. To preserve the previous execution order, replace it with an ``ESP_PRE_SCHEDULER_HANDLER_REGISTER`` handler at priority ``999``.
.. code-block:: c
#include "esp_private/esp_sys_event_app_init.h"
ESP_PRE_SCHEDULER_HANDLER_REGISTER(port_start_app_hook, 999)
{
// Port-specific startup behavior
return ESP_OK;
}
OTA Updates
-----------
@@ -3,6 +3,21 @@
:link_to_translation:`en:[English]`
FreeRTOS
--------
旧版 ``port_start_app_hook`` 已弃用,并将在 ESP-IDF v7.0 中移除。为保持原有执行顺序,请使用优先级为 ``999`` 的 ``ESP_PRE_SCHEDULER_HANDLER_REGISTER`` 处理函数替代。
.. code-block:: c
#include "esp_private/esp_sys_event_app_init.h"
ESP_PRE_SCHEDULER_HANDLER_REGISTER(port_start_app_hook, 999)
{
// 特定于端口的启动行为
return ESP_OK;
}
OTA 更新
--------