startup.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  1. /*
  2. * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <stdint.h>
  7. #include <string.h>
  8. #include "esp_attr.h"
  9. #include "esp_err.h"
  10. #include "esp_system.h"
  11. #include "esp_log.h"
  12. #include "sdkconfig.h"
  13. #include "soc/soc_caps.h"
  14. #include "hal/wdt_hal.h"
  15. #include "hal/uart_types.h"
  16. #include "hal/uart_ll.h"
  17. #include "hal/efuse_hal.h"
  18. #include "esp_heap_caps_init.h"
  19. #include "spi_flash_mmap.h"
  20. #include "esp_flash_internal.h"
  21. #include "esp_newlib.h"
  22. #include "esp_timer.h"
  23. #include "esp_efuse.h"
  24. #include "esp_flash_encrypt.h"
  25. #include "esp_secure_boot.h"
  26. #include "esp_xt_wdt.h"
  27. #include "esp_cpu.h"
  28. #include "esp_partition.h"
  29. /***********************************************/
  30. // Headers for other components init functions
  31. #if CONFIG_SW_COEXIST_ENABLE || CONFIG_EXTERNAL_COEX_ENABLE
  32. #include "esp_coexist_internal.h"
  33. #endif
  34. #if __has_include("esp_app_desc.h")
  35. #define WITH_APP_IMAGE_INFO
  36. #include "esp_app_desc.h"
  37. #endif
  38. #if CONFIG_ESP_COREDUMP_ENABLE
  39. #include "esp_core_dump.h"
  40. #endif
  41. #include "esp_private/dbg_stubs.h"
  42. #if CONFIG_PM_ENABLE
  43. #include "esp_pm.h"
  44. #include "esp_private/pm_impl.h"
  45. #endif
  46. #if CONFIG_VFS_SUPPORT_IO
  47. #include "esp_vfs_dev.h"
  48. #include "esp_vfs_console.h"
  49. #endif
  50. #include "esp_pthread.h"
  51. #include "esp_private/esp_clk.h"
  52. #include "esp_private/spi_flash_os.h"
  53. #include "esp_private/brownout.h"
  54. #include "esp_rom_caps.h"
  55. #include "esp_rom_sys.h"
  56. #if CONFIG_SPIRAM
  57. #include "esp_psram.h"
  58. #include "esp_private/esp_psram_extram.h"
  59. #endif
  60. /***********************************************/
  61. #include "esp_private/startup_internal.h"
  62. // Ensure that system configuration matches the underlying number of cores.
  63. // This should enable us to avoid checking for both everytime.
  64. #if !(SOC_CPU_CORES_NUM > 1) && !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
  65. #error "System has been configured to run on multiple cores, but target SoC only has a single core."
  66. #endif
  67. // Set efuse ROM_LOG_MODE on first boot
  68. //
  69. // For CONFIG_BOOT_ROM_LOG_ALWAYS_ON (default) or undefined (ESP32), leave
  70. // ROM_LOG_MODE undefined (no need to call this function during startup)
  71. #if CONFIG_BOOT_ROM_LOG_ALWAYS_OFF
  72. #define ROM_LOG_MODE ESP_EFUSE_ROM_LOG_ALWAYS_OFF
  73. #elif CONFIG_BOOT_ROM_LOG_ON_GPIO_LOW
  74. #define ROM_LOG_MODE ESP_EFUSE_ROM_LOG_ON_GPIO_LOW
  75. #elif CONFIG_BOOT_ROM_LOG_ON_GPIO_HIGH
  76. #define ROM_LOG_MODE ESP_EFUSE_ROM_LOG_ON_GPIO_HIGH
  77. #endif
  78. uint64_t g_startup_time = 0;
  79. #if SOC_APB_BACKUP_DMA
  80. // APB DMA lock initialising API
  81. extern void esp_apb_backup_dma_lock_init(void);
  82. #endif
  83. // App entry point for core 0
  84. extern void esp_startup_start_app(void);
  85. // Entry point for core 0 from hardware init (port layer)
  86. void start_cpu0(void) __attribute__((weak, alias("start_cpu0_default"))) __attribute__((noreturn));
  87. #if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
  88. // Entry point for core [1..X] from hardware init (port layer)
  89. void start_cpu_other_cores(void) __attribute__((weak, alias("start_cpu_other_cores_default"))) __attribute__((noreturn));
  90. // App entry point for core [1..X]
  91. void esp_startup_start_app_other_cores(void) __attribute__((weak, alias("esp_startup_start_app_other_cores_default"))) __attribute__((noreturn));
  92. static volatile bool s_system_inited[SOC_CPU_CORES_NUM] = { false };
  93. const sys_startup_fn_t g_startup_fn[SOC_CPU_CORES_NUM] = { [0] = start_cpu0,
  94. #if SOC_CPU_CORES_NUM > 1
  95. [1 ... SOC_CPU_CORES_NUM - 1] = start_cpu_other_cores
  96. #endif
  97. };
  98. static volatile bool s_system_full_inited = false;
  99. #else
  100. const sys_startup_fn_t g_startup_fn[1] = { start_cpu0 };
  101. #endif
  102. #ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
  103. // workaround for C++ exception crashes
  104. void _Unwind_SetNoFunctionContextInstall(unsigned char enable) __attribute__((weak, alias("_Unwind_SetNoFunctionContextInstall_Default")));
  105. // workaround for C++ exception large memory allocation
  106. void _Unwind_SetEnableExceptionFdeSorting(unsigned char enable);
  107. static IRAM_ATTR void _Unwind_SetNoFunctionContextInstall_Default(unsigned char enable __attribute__((unused)))
  108. {
  109. (void)0;
  110. }
  111. #endif // CONFIG_COMPILER_CXX_EXCEPTIONS
  112. static const char* TAG = "cpu_start";
  113. /**
  114. * This function overwrites a the same function of libsupc++ (part of libstdc++).
  115. * Consequently, libsupc++ will then follow our configured exception emergency pool size.
  116. *
  117. * It will be called even with -fno-exception for user code since the stdlib still uses exceptions.
  118. */
  119. size_t __cxx_eh_arena_size_get(void)
  120. {
  121. #ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
  122. return CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE;
  123. #else
  124. return 0;
  125. #endif
  126. }
  127. /**
  128. * Xtensa gcc is configured to emit a .ctors section, RISC-V gcc is configured with --enable-initfini-array
  129. * so it emits an .init_array section instead.
  130. * But the init_priority sections will be sorted for iteration in ascending order during startup.
  131. * The rest of the init_array sections is sorted for iteration in descending order during startup, however.
  132. * Hence a different section is generated for the init_priority functions which is looped
  133. * over in ascending direction instead of descending direction.
  134. * The RISC-V-specific behavior is dependent on the linker script ld/esp32c3/sections.ld.in.
  135. */
  136. static void do_global_ctors(void)
  137. {
  138. #if __riscv
  139. extern void (*__init_priority_array_start)(void);
  140. extern void (*__init_priority_array_end)(void);
  141. #endif
  142. extern void (*__init_array_start)(void);
  143. extern void (*__init_array_end)(void);
  144. #ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
  145. struct object { long placeholder[ 10 ]; };
  146. void __register_frame_info (const void *begin, struct object *ob);
  147. extern char __eh_frame[];
  148. static struct object ob;
  149. __register_frame_info( __eh_frame, &ob );
  150. #endif // CONFIG_COMPILER_CXX_EXCEPTIONS
  151. void (**p)(void);
  152. #if __riscv
  153. for (p = &__init_priority_array_start; p < &__init_priority_array_end; ++p) {
  154. ESP_LOGD(TAG, "calling init function: %p", *p);
  155. (*p)();
  156. }
  157. #endif
  158. for (p = &__init_array_end - 1; p >= &__init_array_start; --p) {
  159. ESP_LOGD(TAG, "calling init function: %p", *p);
  160. (*p)();
  161. }
  162. }
  163. /**
  164. * @brief Call component init functions defined using ESP_SYSTEM_INIT_Fn macros.
  165. * The esp_system_init_fn_t structures describing these functions are collected into
  166. * an array [_esp_system_init_fn_array_start, _esp_system_init_fn_array_end) by the
  167. * linker. The functions are sorted by their priority value.
  168. * The sequence of the init function calls (sorted by priority) is documented in
  169. * system_init_fn.txt file.
  170. */
  171. static void do_system_init_fn(void)
  172. {
  173. extern esp_system_init_fn_t _esp_system_init_fn_array_start;
  174. extern esp_system_init_fn_t _esp_system_init_fn_array_end;
  175. esp_system_init_fn_t *p;
  176. int core_id = esp_cpu_get_core_id();
  177. for (p = &_esp_system_init_fn_array_start; p < &_esp_system_init_fn_array_end; ++p) {
  178. if (p->cores & BIT(core_id)) {
  179. ESP_LOGD(TAG, "calling init function: %p on core: %d", p->fn, core_id);
  180. esp_err_t err = (*(p->fn))();
  181. if (err != ESP_OK) {
  182. ESP_LOGE(TAG, "init function %p has failed (0x%x), aborting", p->fn, err);
  183. abort();
  184. }
  185. }
  186. }
  187. #if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
  188. s_system_inited[core_id] = true;
  189. #endif
  190. }
  191. #if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
  192. static void esp_startup_start_app_other_cores_default(void)
  193. {
  194. while (1) {
  195. esp_rom_delay_us(UINT32_MAX);
  196. }
  197. }
  198. /* This function has to be in IRAM, as while it is running on CPU1, CPU0 may do some flash operations
  199. * (e.g. initialize the core dump), which means that cache will be disabled.
  200. */
  201. static void IRAM_ATTR start_cpu_other_cores_default(void)
  202. {
  203. do_system_init_fn();
  204. while (!s_system_full_inited) {
  205. esp_rom_delay_us(100);
  206. }
  207. esp_startup_start_app_other_cores();
  208. }
  209. #endif
  210. static void do_core_init(void)
  211. {
  212. /* Initialize heap allocator. WARNING: This *needs* to happen *after* the app cpu has booted.
  213. If the heap allocator is initialized first, it will put free memory linked list items into
  214. memory also used by the ROM. Starting the app cpu will let its ROM initialize that memory,
  215. corrupting those linked lists. Initializing the allocator *after* the app cpu has booted
  216. works around this problem.
  217. With SPI RAM enabled, there's a second reason: half of the SPI RAM will be managed by the
  218. app CPU, and when that is not up yet, the memory will be inaccessible and heap_caps_init may
  219. fail initializing it properly. */
  220. heap_caps_init();
  221. // When apptrace module is enabled, there will be SEGGER_SYSVIEW calls in the newlib init.
  222. // SEGGER_SYSVIEW relies on apptrace module
  223. // apptrace module uses esp_timer_get_time to determine timeout conditions.
  224. // esp_timer early initialization is required for esp_timer_get_time to work.
  225. esp_timer_early_init();
  226. esp_newlib_init();
  227. #if CONFIG_SPIRAM_BOOT_INIT && (CONFIG_SPIRAM_USE_CAPS_ALLOC || CONFIG_SPIRAM_USE_MALLOC)
  228. if (esp_psram_is_initialized()) {
  229. esp_err_t r=esp_psram_extram_add_to_heap_allocator();
  230. if (r != ESP_OK) {
  231. ESP_EARLY_LOGE(TAG, "External RAM could not be added to heap!");
  232. abort();
  233. }
  234. #if CONFIG_SPIRAM_USE_MALLOC
  235. heap_caps_malloc_extmem_enable(CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL);
  236. #endif
  237. }
  238. #endif
  239. #if CONFIG_ESP_BROWNOUT_DET
  240. // [refactor-todo] leads to call chain rtc_is_register (driver) -> esp_intr_alloc (esp32/esp32s2) ->
  241. // malloc (newlib) -> heap_caps_malloc (heap), so heap must be at least initialized
  242. esp_brownout_init();
  243. #endif
  244. esp_newlib_time_init();
  245. #if CONFIG_VFS_SUPPORT_IO
  246. // VFS console register.
  247. esp_err_t vfs_err = esp_vfs_console_register();
  248. assert(vfs_err == ESP_OK && "Failed to register vfs console");
  249. #endif
  250. #if defined(CONFIG_VFS_SUPPORT_IO) && !defined(CONFIG_ESP_CONSOLE_NONE)
  251. const static char *default_stdio_dev = "/dev/console/";
  252. esp_reent_init(_GLOBAL_REENT);
  253. _GLOBAL_REENT->_stdin = fopen(default_stdio_dev, "r");
  254. _GLOBAL_REENT->_stdout = fopen(default_stdio_dev, "w");
  255. _GLOBAL_REENT->_stderr = fopen(default_stdio_dev, "w");
  256. #if ESP_ROM_NEEDS_SWSETUP_WORKAROUND
  257. /*
  258. - This workaround for printf functions using 32-bit time_t after the 64-bit time_t upgrade
  259. - The 32-bit time_t usage is triggered through ROM Newlib functions printf related functions calling __swsetup_r() on
  260. the first call to a particular file pointer (i.e., stdin, stdout, stderr)
  261. - Thus, we call the toolchain version of __swsetup_r() now (before any printf calls are made) to setup all of the
  262. file pointers. Thus, the ROM newlib code will never call the ROM version of __swsetup_r().
  263. - See IDFGH-7728 for more details
  264. */
  265. extern int __swsetup_r(struct _reent *, FILE *);
  266. __swsetup_r(_GLOBAL_REENT, _GLOBAL_REENT->_stdout);
  267. __swsetup_r(_GLOBAL_REENT, _GLOBAL_REENT->_stderr);
  268. __swsetup_r(_GLOBAL_REENT, _GLOBAL_REENT->_stdin);
  269. #endif // ESP_ROM_NEEDS_SWSETUP_WORKAROUND
  270. #else // defined(CONFIG_VFS_SUPPORT_IO) && !defined(CONFIG_ESP_CONSOLE_NONE)
  271. _REENT_SMALL_CHECK_INIT(_GLOBAL_REENT);
  272. #endif // defined(CONFIG_VFS_SUPPORT_IO) && !defined(CONFIG_ESP_CONSOLE_NONE)
  273. esp_err_t err __attribute__((unused));
  274. err = esp_pthread_init();
  275. assert(err == ESP_OK && "Failed to init pthread module!");
  276. #if CONFIG_SPI_FLASH_ROM_IMPL
  277. spi_flash_rom_impl_init();
  278. #endif
  279. esp_flash_app_init();
  280. esp_err_t flash_ret = esp_flash_init_default_chip();
  281. assert(flash_ret == ESP_OK);
  282. (void)flash_ret;
  283. #if CONFIG_SPI_FLASH_BROWNOUT_RESET
  284. spi_flash_needs_reset_check();
  285. #endif // CONFIG_SPI_FLASH_BROWNOUT_RESET
  286. #ifdef CONFIG_EFUSE_VIRTUAL
  287. ESP_LOGW(TAG, "eFuse virtual mode is enabled. If Secure boot or Flash encryption is enabled then it does not provide any security. FOR TESTING ONLY!");
  288. #ifdef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
  289. const esp_partition_t *efuse_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_EFUSE_EM, NULL);
  290. if (efuse_partition) {
  291. esp_efuse_init_virtual_mode_in_flash(efuse_partition->address, efuse_partition->size);
  292. }
  293. #endif
  294. #endif
  295. #if CONFIG_SECURE_DISABLE_ROM_DL_MODE
  296. err = esp_efuse_disable_rom_download_mode();
  297. assert(err == ESP_OK && "Failed to disable ROM download mode");
  298. #endif
  299. #if CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE
  300. err = esp_efuse_enable_rom_secure_download_mode();
  301. assert(err == ESP_OK && "Failed to enable Secure Download mode");
  302. #endif
  303. #if CONFIG_ESP32_DISABLE_BASIC_ROM_CONSOLE
  304. esp_efuse_disable_basic_rom_console();
  305. #endif
  306. #ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
  307. esp_flash_encryption_init_checks();
  308. #endif
  309. #if defined(CONFIG_SECURE_BOOT) || defined(CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT)
  310. // Note: in some configs this may read flash, so placed after flash init
  311. esp_secure_boot_init_checks();
  312. #endif
  313. #ifdef ROM_LOG_MODE
  314. esp_efuse_set_rom_log_scheme(ROM_LOG_MODE);
  315. #endif
  316. #if CONFIG_ESP_XT_WDT
  317. esp_xt_wdt_config_t cfg = {
  318. .timeout = CONFIG_ESP_XT_WDT_TIMEOUT,
  319. .auto_backup_clk_enable = CONFIG_ESP_XT_WDT_BACKUP_CLK_ENABLE,
  320. };
  321. err = esp_xt_wdt_init(&cfg);
  322. assert(err == ESP_OK && "Failed to init xtwdt");
  323. #endif
  324. }
  325. static void do_secondary_init(void)
  326. {
  327. #if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
  328. // The port layer transferred control to this function with other cores 'paused',
  329. // resume execution so that cores might execute component initialization functions.
  330. startup_resume_other_cores();
  331. #endif
  332. // Execute initialization functions esp_system_init_fn_t assigned to the main core. While
  333. // this is happening, all other cores are executing the initialization functions
  334. // assigned to them since they have been resumed already.
  335. do_system_init_fn();
  336. #if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
  337. // Wait for all cores to finish secondary init.
  338. volatile bool system_inited = false;
  339. while (!system_inited) {
  340. system_inited = true;
  341. for (int i = 0; i < SOC_CPU_CORES_NUM; i++) {
  342. system_inited &= s_system_inited[i];
  343. }
  344. esp_rom_delay_us(100);
  345. }
  346. #endif
  347. }
  348. static void start_cpu0_default(void)
  349. {
  350. ESP_EARLY_LOGI(TAG, "Pro cpu start user code");
  351. int cpu_freq = esp_clk_cpu_freq();
  352. ESP_EARLY_LOGI(TAG, "cpu freq: %d Hz", cpu_freq);
  353. #ifdef WITH_APP_IMAGE_INFO
  354. // Display information about the current running image.
  355. if (LOG_LOCAL_LEVEL >= ESP_LOG_INFO) {
  356. const esp_app_desc_t *app_desc = esp_app_get_description();
  357. ESP_EARLY_LOGI(TAG, "Application information:");
  358. #ifndef CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR
  359. ESP_EARLY_LOGI(TAG, "Project name: %s", app_desc->project_name);
  360. #endif
  361. #ifndef CONFIG_APP_EXCLUDE_PROJECT_VER_VAR
  362. ESP_EARLY_LOGI(TAG, "App version: %s", app_desc->version);
  363. #endif
  364. #ifdef CONFIG_BOOTLOADER_APP_SECURE_VERSION
  365. ESP_EARLY_LOGI(TAG, "Secure version: %d", app_desc->secure_version);
  366. #endif
  367. #ifdef CONFIG_APP_COMPILE_TIME_DATE
  368. ESP_EARLY_LOGI(TAG, "Compile time: %s %s", app_desc->date, app_desc->time);
  369. #endif
  370. char buf[17];
  371. esp_app_get_elf_sha256(buf, sizeof(buf));
  372. ESP_EARLY_LOGI(TAG, "ELF file SHA256: %s...", buf);
  373. ESP_EARLY_LOGI(TAG, "ESP-IDF: %s", app_desc->idf_ver);
  374. ESP_EARLY_LOGI(TAG, "Min chip rev: v%d.%d", CONFIG_ESP_REV_MIN_FULL / 100, CONFIG_ESP_REV_MIN_FULL % 100);
  375. ESP_EARLY_LOGI(TAG, "Max chip rev: v%d.%d %s",CONFIG_ESP_REV_MAX_FULL / 100, CONFIG_ESP_REV_MAX_FULL % 100,
  376. efuse_ll_get_disable_wafer_version_major() ? "(constraint ignored)" : "");
  377. unsigned revision = efuse_hal_chip_revision();
  378. ESP_EARLY_LOGI(TAG, "Chip rev: v%d.%d", revision / 100, revision % 100);
  379. }
  380. #endif
  381. // Initialize core components and services.
  382. do_core_init();
  383. // Execute constructors.
  384. do_global_ctors();
  385. // Execute init functions of other components; blocks
  386. // until all cores finish (when !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE).
  387. do_secondary_init();
  388. // Now that the application is about to start, disable boot watchdog
  389. #ifndef CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE
  390. #if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2// ESP32H2, ESP32C6-TODO: IDF-5653
  391. wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &LP_WDT};
  392. #else
  393. wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL};
  394. #endif
  395. wdt_hal_write_protect_disable(&rtc_wdt_ctx);
  396. wdt_hal_disable(&rtc_wdt_ctx);
  397. wdt_hal_write_protect_enable(&rtc_wdt_ctx);
  398. #endif
  399. #if SOC_CPU_CORES_NUM > 1 && !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
  400. s_system_full_inited = true;
  401. #endif
  402. esp_startup_start_app();
  403. while (1);
  404. }
  405. ESP_SYSTEM_INIT_FN(init_components0, BIT(0), 200)
  406. {
  407. #if CONFIG_ESP_DEBUG_STUBS_ENABLE
  408. esp_dbg_stubs_init();
  409. #endif
  410. #if defined(CONFIG_PM_ENABLE)
  411. esp_pm_impl_init();
  412. #endif
  413. #if CONFIG_ESP_COREDUMP_ENABLE
  414. esp_core_dump_init();
  415. #endif
  416. #if SOC_APB_BACKUP_DMA
  417. esp_apb_backup_dma_lock_init();
  418. #endif
  419. #if CONFIG_SW_COEXIST_ENABLE || CONFIG_EXTERNAL_COEX_ENABLE
  420. esp_coex_adapter_register(&g_coex_adapter_funcs);
  421. coex_pre_init();
  422. #endif
  423. #ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
  424. ESP_EARLY_LOGD(TAG, "Setting C++ exception workarounds.");
  425. _Unwind_SetNoFunctionContextInstall(1);
  426. _Unwind_SetEnableExceptionFdeSorting(0);
  427. #endif // CONFIG_COMPILER_CXX_EXCEPTIONS
  428. return ESP_OK;
  429. }