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