Przeglądaj źródła

Merge branch 'feature/system_init_priorities' into 'master'

esp_system: introduce priorities for startup functions

Closes IDFGH-5683 and IDF-4954

See merge request espressif/esp-idf!18159
Ivan Grokhotkov 3 lat temu
rodzic
commit
230e732018

+ 9 - 0
.gitlab/ci/pre_check.yml

@@ -148,6 +148,15 @@ check_esp_err_to_name:
     - ./gen_esp_err_to_name.py
     - ./gen_esp_err_to_name.py
     - git diff --exit-code -- ../components/esp_common/src/esp_err_to_name.c || { echo 'Differences found. Please run gen_esp_err_to_name.py and commit the changes.'; exit 1; }
     - git diff --exit-code -- ../components/esp_common/src/esp_err_to_name.c || { echo 'Differences found. Please run gen_esp_err_to_name.py and commit the changes.'; exit 1; }
 
 
+check_esp_system:
+  extends:
+    - .pre_check_base_template
+    - .rules:build
+  tags:
+    - build
+  script:
+    - python components/esp_system/check_system_init_priorities.py
+
 scan_tests:
 scan_tests:
   extends:
   extends:
     - .pre_check_base_template
     - .pre_check_base_template

+ 6 - 0
components/app_trace/app_trace.c

@@ -8,6 +8,7 @@
 #include "esp_log.h"
 #include "esp_log.h"
 #include "esp_app_trace.h"
 #include "esp_app_trace.h"
 #include "esp_app_trace_port.h"
 #include "esp_app_trace_port.h"
+#include "esp_private/startup_internal.h"
 
 
 #ifdef CONFIG_APPTRACE_DEST_UART0
 #ifdef CONFIG_APPTRACE_DEST_UART0
 #define ESP_APPTRACE_DEST_UART_NUM 0
 #define ESP_APPTRACE_DEST_UART_NUM 0
@@ -75,6 +76,11 @@ esp_err_t esp_apptrace_init(void)
     return ESP_OK;
     return ESP_OK;
 }
 }
 
 
+ESP_SYSTEM_INIT_FN(esp_apptrace_init, ESP_SYSTEM_INIT_ALL_CORES, 115)
+{
+    return esp_apptrace_init();
+}
+
 void esp_apptrace_down_buffer_config(uint8_t *buf, uint32_t size)
 void esp_apptrace_down_buffer_config(uint8_t *buf, uint32_t size)
 {
 {
     esp_apptrace_channel_t *ch;
     esp_apptrace_channel_t *ch;

+ 14 - 0
components/app_trace/sys_view/esp/SEGGER_RTT_esp.c

@@ -12,6 +12,7 @@
 
 
 #include "esp_app_trace.h"
 #include "esp_app_trace.h"
 #include "esp_log.h"
 #include "esp_log.h"
+#include "esp_private/startup_internal.h"
 
 
 const static char *TAG = "segger_rtt";
 const static char *TAG = "segger_rtt";
 
 
@@ -288,4 +289,17 @@ int SEGGER_RTT_ConfigDownBuffer(unsigned BufferIndex, const char* sName, void* p
   return 0;
   return 0;
 }
 }
 
 
+/*************************** Init hook ****************************
+ *
+ * This init function is placed here because this port file will be
+ * linked whenever SystemView is used.
+ */
+
+ESP_SYSTEM_INIT_FN(sysview_init, BIT(0), 120)
+{
+    SEGGER_SYSVIEW_Conf();
+    return ESP_OK;
+}
+
+
 /*************************** End of file ****************************/
 /*************************** End of file ****************************/

+ 13 - 0
components/esp_hw_support/sleep_modes.c

@@ -45,6 +45,7 @@
 #include "esp_private/brownout.h"
 #include "esp_private/brownout.h"
 #include "esp_private/sleep_retention.h"
 #include "esp_private/sleep_retention.h"
 #include "esp_private/esp_clk.h"
 #include "esp_private/esp_clk.h"
+#include "esp_private/startup_internal.h"
 
 
 #ifdef CONFIG_IDF_TARGET_ESP32
 #ifdef CONFIG_IDF_TARGET_ESP32
 #include "esp32/rom/cache.h"
 #include "esp32/rom/cache.h"
@@ -1395,3 +1396,15 @@ void rtc_sleep_enable_ultra_low(bool enable)
 {
 {
     s_ultra_low_enabled = enable;
     s_ultra_low_enabled = enable;
 }
 }
+
+#if CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND && !CONFIG_PM_SLP_DISABLE_GPIO
+ESP_SYSTEM_INIT_FN(esp_sleep_startup_init, BIT(0), 105)
+{
+    // Configure to isolate (disable the Input/Output/Pullup/Pulldown
+    // function of the pin) all GPIO pins in sleep state
+    esp_sleep_config_gpio_isolate();
+    // Enable automatic switching of GPIO configuration
+    esp_sleep_enable_gpio_switch(true);
+    return ESP_OK;
+}
+#endif

+ 105 - 0
components/esp_system/check_system_init_priorities.py

@@ -0,0 +1,105 @@
+#!/usr/bin/env python
+#
+# SPDX-FileCopyrightText: 2022 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.
+# 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.
+
+import difflib
+import glob
+import itertools
+import os
+import re
+import sys
+import typing
+
+ESP_SYSTEM_INIT_FN_STR = r'ESP_SYSTEM_INIT_FN'
+ESP_SYSTEM_INIT_FN_REGEX_SIMPLE = re.compile(r'ESP_SYSTEM_INIT_FN')
+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*([0-9]+)\)')
+STARTUP_ENTRIES_FILE = 'components/esp_system/system_init_fn.txt'
+
+
+class StartupEntry:
+    def __init__(self, filename: str, func: str, affinity: str, priority: int) -> None:
+        self.filename = filename
+        self.func = func
+        self.affinity = affinity
+        self.priority = priority
+
+    def __str__(self) -> str:
+        return f'{self.priority:3d}: {self.func} in {self.filename} on {self.affinity}'
+
+
+def main() -> None:
+    try:
+        idf_path = os.environ['IDF_PATH']
+    except KeyError:
+        raise SystemExit('IDF_PATH must be set before running this script')
+
+    has_errors = False
+    startup_entries = []  # type: typing.List[StartupEntry]
+
+    #
+    # 1. Iterate over all .c and .cpp source files and find ESP_SYSTEM_INIT_FN definitions
+    #
+    source_files_iters = []
+    for extension in ('c', 'cpp'):
+        glob_iter = glob.glob(os.path.join(idf_path, 'components', '**', f'*.{extension}'), recursive=True)
+        source_files_iters.append(glob_iter)
+    for filename in itertools.chain(*source_files_iters):
+        with open(filename, 'r') as f_obj:
+            file_contents = f_obj.read()
+        if ESP_SYSTEM_INIT_FN_STR not in file_contents:
+            continue
+        count_expected = len(ESP_SYSTEM_INIT_FN_REGEX_SIMPLE.findall(file_contents))
+        found = ESP_SYSTEM_INIT_FN_REGEX.findall(file_contents)
+        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=os.path.relpath(filename, idf_path),
+                func=match[0],
+                affinity=match[1],
+                priority=int(match[2])
+            )
+            startup_entries.append(entry)
+
+    #
+    # 2. Sort the ESP_SYSTEM_INIT_FN functions in C source files by priority
+    #
+    startup_entries = list(sorted(startup_entries, key=lambda e: e.priority))
+    startup_entries_lines = [str(entry) for entry in startup_entries]
+
+    #
+    # 3. Load startup entries list from STARTUP_ENTRIES_FILE, removing comments and empty lines
+    #
+    startup_entries_expected_lines = []
+    with open(os.path.join(idf_path, STARTUP_ENTRIES_FILE), 'r') as startup_entries_expected_file:
+        for line in startup_entries_expected_file:
+            if line.startswith('#') or len(line.strip()) == 0:
+                continue
+            startup_entries_expected_lines.append(line.rstrip())
+
+    #
+    # 4. Print the list of differences, if any
+    #
+    diff_lines = list(difflib.unified_diff(startup_entries_expected_lines, startup_entries_lines, lineterm=''))
+    if len(diff_lines) > 0:
+        print(('error: startup order doesn\'t match the reference file. '
+               f'please update {STARTUP_ENTRIES_FILE} to match the actual startup order:'), file=sys.stderr)
+        for line in diff_lines:
+            print(f'{line}', file=sys.stderr)
+        has_errors = True
+
+    if has_errors:
+        raise SystemExit(1)
+
+
+if __name__ == '__main__':
+    main()

+ 35 - 14
components/esp_system/include/esp_private/startup_internal.h

@@ -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);
-  uint32_t cores;
+    esp_err_t (*fn)(void);   /*!< Pointer to the startup function */
+    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
- * on CORE0, CORE1 if BIT1 and so on).
+/**
+ * @brief Define a system initialization function which will be executed on the specified cores
+ *
+ * @param f  function name (identifier)
+ * @param c  bit mask of cores to execute the function on (ex. if BIT0 is set, the function
+ *           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.
  *
  *
- * @note Initialization functions should be placed in a compilation unit where at least one other
- * symbol is referenced 'meaningfully' in another compilation unit, otherwise this gets discarded during linking. (By
- * 'meaningfully' we mean the reference should not itself get optimized out by the compiler/discarded by the linker).
+ * 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, ...) \
-static void  __attribute__((used)) __VA_ARGS__ __esp_system_init_fn_##f(void); \
-static __attribute__((used)) esp_system_init_fn_t _SECTION_ATTR_IMPL(".esp_system_init_fn", f) \
-                    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,
-                                                                             // instead of calling them explicitly
+#define ESP_SYSTEM_INIT_FN(f, c, priority, ...) \
+    static esp_err_t __VA_ARGS__ __esp_system_init_fn_##f(void); \
+    static __attribute__((used)) _SECTION_ATTR_IMPL(".esp_system_init_fn", priority) \
+        esp_system_init_fn_t esp_system_init_fn_##f = { .fn = ( __esp_system_init_fn_##f), .cores = (c) }; \
+    static esp_err_t __esp_system_init_fn_##f(void)
+
+#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

+ 4 - 4
components/esp_system/ld/esp32/sections.ld.in

@@ -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(.);

+ 4 - 4
components/esp_system/ld/esp32c2/sections.ld.in

@@ -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(.);

+ 4 - 4
components/esp_system/ld/esp32c3/sections.ld.in

@@ -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(.);

+ 4 - 4
components/esp_system/ld/esp32h2/sections.ld.in

@@ -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(.);

+ 4 - 4
components/esp_system/ld/esp32s2/sections.ld.in

@@ -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(.);

+ 4 - 4
components/esp_system/ld/esp32s3/sections.ld.in

@@ -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(.);

+ 26 - 30
components/esp_system/startup.c

@@ -30,7 +30,6 @@
 #include "esp_efuse.h"
 #include "esp_efuse.h"
 #include "esp_flash_encrypt.h"
 #include "esp_flash_encrypt.h"
 #include "esp_secure_boot.h"
 #include "esp_secure_boot.h"
-#include "esp_sleep.h"
 #include "esp_xt_wdt.h"
 #include "esp_xt_wdt.h"
 
 
 #if __has_include("esp_ota_ops.h")
 #if __has_include("esp_ota_ops.h")
@@ -48,10 +47,6 @@
 #include "esp_core_dump.h"
 #include "esp_core_dump.h"
 #endif
 #endif
 
 
-#if CONFIG_APPTRACE_ENABLE
-#include "esp_app_trace.h"
-#endif
-
 #include "esp_private/dbg_stubs.h"
 #include "esp_private/dbg_stubs.h"
 
 
 #if CONFIG_PM_ENABLE
 #if CONFIG_PM_ENABLE
@@ -179,17 +174,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 +200,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) {
-        if (p->cores & BIT(cpu_hal_get_core_id())) {
-            (*(p->fn))();
+    int core_id = cpu_hal_get_core_id();
+    for (p = &_esp_system_init_fn_array_start; p < &_esp_system_init_fn_array_end; ++p) {
+        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 +225,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,26 +440,8 @@ 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();
-
-#if CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND && !CONFIG_PM_SLP_DISABLE_GPIO
-    // Configure to isolate (disable the Input/Output/Pullup/Pulldown
-    // function of the pin) all GPIO pins in sleep state
-    esp_sleep_config_gpio_isolate();
-    // Enable automatic switching of GPIO configuration
-    esp_sleep_enable_gpio_switch(true);
-#endif
-
-#if CONFIG_APPTRACE_ENABLE
-    esp_err_t err = esp_apptrace_init();
-    assert(err == ESP_OK && "Failed to init apptrace module on PRO CPU!");
-#endif
-#if CONFIG_APPTRACE_SV_ENABLE
-    SEGGER_SYSVIEW_Conf();
-#endif
-
 #if CONFIG_ESP_DEBUG_STUBS_ENABLE
 #if CONFIG_ESP_DEBUG_STUBS_ENABLE
     esp_dbg_stubs_init();
     esp_dbg_stubs_init();
 #endif
 #endif
@@ -474,4 +468,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;
 }
 }

+ 28 - 0
components/esp_system/system_init_fn.txt

@@ -0,0 +1,28 @@
+# This file documents the expected order of execution of ESP_SYSTEM_INIT_FN functions.
+#
+# 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 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.
+#
+# Entries are ordered by the order of execution (i.e. from low priority values to high ones).
+# Each line has the following format:
+#   prio: function_name in path/to/source_file on affinity_expression
+# Where:
+#   prio: priority value (higher value means function is executed later)
+#   affinity_expression: bit map of cores the function is executed on
+
+
+# esp_timer has to be initialized early, since it is used by several other components
+100: esp_timer_startup_init in components/esp_timer/src/esp_timer.c on BIT(0)
+
+# esp_sleep doesn't have init dependencies
+105: esp_sleep_startup_init in components/esp_hw_support/sleep_modes.c on BIT(0)
+
+# app_trace has to be initialized before systemview
+115: esp_apptrace_init in components/app_trace/app_trace.c on ESP_SYSTEM_INIT_ALL_CORES
+120: sysview_init in components/app_trace/sys_view/esp/SEGGER_RTT_esp.c on BIT(0)
+
+# the rest of the components which are initialized from startup.c
+# [refactor-todo]: move init calls into respective components
+200: init_components0 in components/esp_system/startup.c on BIT(0)

+ 5 - 0
components/esp_timer/src/esp_timer.c

@@ -460,6 +460,11 @@ out:
     return ESP_ERR_NO_MEM;
     return ESP_ERR_NO_MEM;
 }
 }
 
 
+ESP_SYSTEM_INIT_FN(esp_timer_startup_init, BIT(0), 100)
+{
+    return esp_timer_init();
+}
+
 esp_err_t esp_timer_deinit(void)
 esp_err_t esp_timer_deinit(void)
 {
 {
     if (!is_initialized()) {
     if (!is_initialized()) {

+ 1 - 1
docs/en/api-guides/startup.rst

@@ -142,7 +142,7 @@ The primary system initialization stage includes:
    - Initialize SPI flash API support.
    - Initialize SPI flash API support.
    - Call global C++ constructors and any C functions marked with ``__attribute__((constructor))``.
    - Call global C++ constructors and any C functions marked with ``__attribute__((constructor))``.
 
 
-Secondary system initialization allows individual components to be initialized. If a component has an initialization function annotated with the ``ESP_SYSTEM_INIT_FN`` macro, it will be called as part of secondary initialization.
+Secondary system initialization allows individual components to be initialized. If a component has an initialization function annotated with the ``ESP_SYSTEM_INIT_FN`` macro, it will be called as part of secondary initialization. Component initialization functions have priorities assigned to them to ensure the desired initialization order. The priorities are documented in :component_file:`esp_system/system_init_fn.txt` and ``ESP_SYSTEM_INIT_FN`` definition in source code are checked against this file.
 
 
 .. _app-main-task:
 .. _app-main-task: