1 /*
2 * SPDX-FileCopyrightText: 2015-2021 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 #include "esp_ota_ops.h"
16
17 #include "sdkconfig.h"
18
19 #include "soc/soc_caps.h"
20 #include "hal/wdt_hal.h"
21 #include "hal/uart_types.h"
22 #include "hal/uart_ll.h"
23
24 #include "esp_system.h"
25 #include "esp_log.h"
26 #include "esp_heap_caps_init.h"
27 #include "esp_spi_flash.h"
28 #include "esp_flash_internal.h"
29 #include "esp_newlib.h"
30 #include "esp_vfs_dev.h"
31 #include "esp_timer.h"
32 #include "esp_efuse.h"
33 #include "esp_flash_encrypt.h"
34 #include "esp_secure_boot.h"
35 #include "esp_sleep.h"
36 #include "esp_xt_wdt.h"
37
38 /***********************************************/
39 // Headers for other components init functions
40 #include "nvs_flash.h"
41 #include "esp_phy_init.h"
42 #include "esp_coexist_internal.h"
43
44 #if CONFIG_ESP_COREDUMP_ENABLE
45 #include "esp_core_dump.h"
46 #endif
47
48 #include "esp_app_trace.h"
49 #include "esp_private/dbg_stubs.h"
50 #include "esp_pm.h"
51 #include "esp_private/pm_impl.h"
52 #include "esp_pthread.h"
53 #include "esp_vfs_console.h"
54
55 #include "brownout.h"
56
57 #include "esp_rom_sys.h"
58
59 // [refactor-todo] make this file completely target-independent
60 #if CONFIG_IDF_TARGET_ESP32
61 #include "esp32/clk.h"
62 #include "esp32/spiram.h"
63 #elif CONFIG_IDF_TARGET_ESP32S2
64 #include "esp32s2/clk.h"
65 #include "esp32s2/spiram.h"
66 #elif CONFIG_IDF_TARGET_ESP32S3
67 #include "esp32s3/clk.h"
68 #include "esp32s3/spiram.h"
69 #elif CONFIG_IDF_TARGET_ESP32C3
70 #include "esp32c3/clk.h"
71 #elif CONFIG_IDF_TARGET_ESP32H2
72 #include "esp32h2/clk.h"
73 #endif
74 /***********************************************/
75
76 #include "esp_private/startup_internal.h"
77
78 // Ensure that system configuration matches the underlying number of cores.
79 // This should enable us to avoid checking for both everytime.
80 #if !(SOC_CPU_CORES_NUM > 1) && !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
81 #error "System has been configured to run on multiple cores, but target SoC only has a single core."
82 #endif
83
84 uint64_t g_startup_time = 0;
85
86 #if SOC_APB_BACKUP_DMA
87 // APB DMA lock initialising API
88 extern void esp_apb_backup_dma_lock_init(void);
89 #endif
90
91 // App entry point for core 0
92 extern void esp_startup_start_app(void);
93
94 // Entry point for core 0 from hardware init (port layer)
95 void start_cpu0(void) __attribute__((weak, alias("start_cpu0_default"))) __attribute__((noreturn));
96
97 #if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
98 // Entry point for core [1..X] from hardware init (port layer)
99 void start_cpu_other_cores(void) __attribute__((weak, alias("start_cpu_other_cores_default"))) __attribute__((noreturn));
100
101 // App entry point for core [1..X]
102 void esp_startup_start_app_other_cores(void) __attribute__((weak, alias("esp_startup_start_app_other_cores_default"))) __attribute__((noreturn));
103
104 static volatile bool s_system_inited[SOC_CPU_CORES_NUM] = { false };
105
106 const sys_startup_fn_t g_startup_fn[SOC_CPU_CORES_NUM] = { [0] = start_cpu0,
107 #if SOC_CPU_CORES_NUM > 1
108 [1 ... SOC_CPU_CORES_NUM - 1] = start_cpu_other_cores
109 #endif
110 };
111
112 static volatile bool s_system_full_inited = false;
113 #else
114 const sys_startup_fn_t g_startup_fn[1] = { start_cpu0 };
115 #endif
116
117 #ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
118 // workaround for C++ exception crashes
119 void _Unwind_SetNoFunctionContextInstall(unsigned char enable) __attribute__((weak, alias("_Unwind_SetNoFunctionContextInstall_Default")));
120 // workaround for C++ exception large memory allocation
121 void _Unwind_SetEnableExceptionFdeSorting(unsigned char enable);
122
_Unwind_SetNoFunctionContextInstall_Default(unsigned char enable)123 static IRAM_ATTR void _Unwind_SetNoFunctionContextInstall_Default(unsigned char enable __attribute__((unused)))
124 {
125 (void)0;
126 }
127 #endif // CONFIG_COMPILER_CXX_EXCEPTIONS
128
129 static const char* TAG = "cpu_start";
130
131 /**
132 * This function overwrites a the same function of libsupc++ (part of libstdc++).
133 * Consequently, libsupc++ will then follow our configured exception emergency pool size.
134 *
135 * It will be called even with -fno-exception for user code since the stdlib still uses exceptions.
136 */
__cxx_eh_arena_size_get(void)137 size_t __cxx_eh_arena_size_get(void)
138 {
139 #ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
140 return CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE;
141 #else
142 return 0;
143 #endif
144 }
145
146 /**
147 * Xtensa gcc is configured to emit a .ctors section, RISC-V gcc is configured with --enable-initfini-array
148 * so it emits an .init_array section instead.
149 * But the init_priority sections will be sorted for iteration in ascending order during startup.
150 * The rest of the init_array sections is sorted for iteration in descending order during startup, however.
151 * Hence a different section is generated for the init_priority functions which is looped
152 * over in ascending direction instead of descending direction.
153 * The RISC-V-specific behavior is dependent on the linker script ld/esp32c3/sections.ld.in.
154 */
do_global_ctors(void)155 static void do_global_ctors(void)
156 {
157 #if __riscv
158 extern void (*__init_priority_array_start)(void);
159 extern void (*__init_priority_array_end)(void);
160 #endif
161
162 extern void (*__init_array_start)(void);
163 extern void (*__init_array_end)(void);
164
165 #ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
166 struct object { long placeholder[ 10 ]; };
167 void __register_frame_info (const void *begin, struct object *ob);
168 extern char __eh_frame[];
169
170 static struct object ob;
171 __register_frame_info( __eh_frame, &ob );
172 #endif // CONFIG_COMPILER_CXX_EXCEPTIONS
173
174 void (**p)(void);
175
176 #if __riscv
177 for (p = &__init_priority_array_start; p < &__init_priority_array_end; ++p) {
178 ESP_EARLY_LOGD(TAG, "calling init function: %p", *p);
179 (*p)();
180 }
181 #endif
182
183 for (p = &__init_array_end - 1; p >= &__init_array_start; --p) {
184 ESP_EARLY_LOGD(TAG, "calling init function: %p", *p);
185 (*p)();
186 }
187 }
188
do_system_init_fn(void)189 static void do_system_init_fn(void)
190 {
191 extern esp_system_init_fn_t _esp_system_init_fn_array_start;
192 extern esp_system_init_fn_t _esp_system_init_fn_array_end;
193
194 esp_system_init_fn_t *p;
195
196 for (p = &_esp_system_init_fn_array_end - 1; p >= &_esp_system_init_fn_array_start; --p) {
197 if (p->cores & BIT(cpu_hal_get_core_id())) {
198 (*(p->fn))();
199 }
200 }
201
202 #if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
203 s_system_inited[cpu_hal_get_core_id()] = true;
204 #endif
205 }
206
207 #if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
esp_startup_start_app_other_cores_default(void)208 static void esp_startup_start_app_other_cores_default(void)
209 {
210 while (1) {
211 esp_rom_delay_us(UINT32_MAX);
212 }
213 }
214
start_cpu_other_cores_default(void)215 static void IRAM_ATTR start_cpu_other_cores_default(void)
216 {
217 do_system_init_fn();
218
219 while (!s_system_full_inited) {
220 esp_rom_delay_us(100);
221 }
222
223 esp_startup_start_app_other_cores();
224 }
225 #endif
226
do_core_init(void)227 static void do_core_init(void)
228 {
229 /* Initialize heap allocator. WARNING: This *needs* to happen *after* the app cpu has booted.
230 If the heap allocator is initialized first, it will put free memory linked list items into
231 memory also used by the ROM. Starting the app cpu will let its ROM initialize that memory,
232 corrupting those linked lists. Initializing the allocator *after* the app cpu has booted
233 works around this problem.
234 With SPI RAM enabled, there's a second reason: half of the SPI RAM will be managed by the
235 app CPU, and when that is not up yet, the memory will be inaccessible and heap_caps_init may
236 fail initializing it properly. */
237 heap_caps_init();
238
239 // When apptrace module is enabled, there will be SEGGER_SYSVIEW calls in the newlib init.
240 // SEGGER_SYSVIEW relies on apptrace module
241 // apptrace module uses esp_timer_get_time to determine timeout conditions.
242 // esp_timer early initialization is required for esp_timer_get_time to work.
243 esp_timer_early_init();
244 esp_newlib_init();
245
246 if (g_spiram_ok) {
247 #if CONFIG_SPIRAM_BOOT_INIT && (CONFIG_SPIRAM_USE_CAPS_ALLOC || CONFIG_SPIRAM_USE_MALLOC)
248 esp_err_t r=esp_spiram_add_to_heapalloc();
249 if (r != ESP_OK) {
250 ESP_EARLY_LOGE(TAG, "External RAM could not be added to heap!");
251 abort();
252 }
253 #if CONFIG_SPIRAM_USE_MALLOC
254 heap_caps_malloc_extmem_enable(CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL);
255 #endif
256 #endif
257 }
258
259 #if CONFIG_ESP32_BROWNOUT_DET || \
260 CONFIG_ESP32S2_BROWNOUT_DET || \
261 CONFIG_ESP32S3_BROWNOUT_DET || \
262 CONFIG_ESP32C3_BROWNOUT_DET || \
263 CONFIG_ESP32H2_BROWNOUT_DET
264 // [refactor-todo] leads to call chain rtc_is_register (driver) -> esp_intr_alloc (esp32/esp32s2) ->
265 // malloc (newlib) -> heap_caps_malloc (heap), so heap must be at least initialized
266 esp_brownout_init();
267 #endif
268
269 esp_newlib_time_init();
270
271 #if CONFIG_VFS_SUPPORT_IO
272 // VFS console register.
273 esp_err_t vfs_err = esp_vfs_console_register();
274 assert(vfs_err == ESP_OK && "Failed to register vfs console");
275 #endif
276
277 #if defined(CONFIG_VFS_SUPPORT_IO) && !defined(CONFIG_ESP_CONSOLE_NONE)
278 const static char *default_stdio_dev = "/dev/console/";
279 esp_reent_init(_GLOBAL_REENT);
280 _GLOBAL_REENT->_stdin = fopen(default_stdio_dev, "r");
281 _GLOBAL_REENT->_stdout = fopen(default_stdio_dev, "w");
282 _GLOBAL_REENT->_stderr = fopen(default_stdio_dev, "w");
283 #else // defined(CONFIG_VFS_SUPPORT_IO) && !defined(CONFIG_ESP_CONSOLE_NONE)
284 _REENT_SMALL_CHECK_INIT(_GLOBAL_REENT);
285 #endif // defined(CONFIG_VFS_SUPPORT_IO) && !defined(CONFIG_ESP_CONSOLE_NONE)
286
287 esp_err_t err __attribute__((unused));
288
289 err = esp_pthread_init();
290 assert(err == ESP_OK && "Failed to init pthread module!");
291
292 spi_flash_init();
293 /* init default OS-aware flash access critical section */
294 spi_flash_guard_set(&g_flash_guard_default_ops);
295
296 esp_flash_app_init();
297 esp_err_t flash_ret = esp_flash_init_default_chip();
298 assert(flash_ret == ESP_OK);
299 (void)flash_ret;
300
301 #ifdef CONFIG_EFUSE_VIRTUAL
302 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!");
303 #ifdef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
304 const esp_partition_t *efuse_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_EFUSE_EM, NULL);
305 if (efuse_partition) {
306 esp_efuse_init_virtual_mode_in_flash(efuse_partition->address, efuse_partition->size);
307 }
308 #endif
309 #endif
310
311 #if CONFIG_SECURE_DISABLE_ROM_DL_MODE
312 err = esp_efuse_disable_rom_download_mode();
313 assert(err == ESP_OK && "Failed to disable ROM download mode");
314 #endif
315
316 #if CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE
317 err = esp_efuse_enable_rom_secure_download_mode();
318 assert(err == ESP_OK && "Failed to enable Secure Download mode");
319 #endif
320
321 #if CONFIG_ESP32_DISABLE_BASIC_ROM_CONSOLE
322 esp_efuse_disable_basic_rom_console();
323 #endif
324
325 #ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
326 esp_flash_encryption_init_checks();
327 #endif
328
329 #if defined(CONFIG_SECURE_BOOT) || defined(CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT)
330 // Note: in some configs this may read flash, so placed after flash init
331 esp_secure_boot_init_checks();
332 #endif
333
334 #if CONFIG_ESP_XT_WDT
335 esp_xt_wdt_config_t cfg = {
336 .timeout = CONFIG_ESP_XT_WDT_TIMEOUT,
337 .auto_backup_clk_enable = CONFIG_ESP_XT_WDT_BACKUP_CLK_ENABLE,
338 };
339 err = esp_xt_wdt_init(&cfg);
340 assert(err == ESP_OK && "Failed to init xtwdt");
341 #endif
342 }
343
do_secondary_init(void)344 static void do_secondary_init(void)
345 {
346 #if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
347 // The port layer transferred control to this function with other cores 'paused',
348 // resume execution so that cores might execute component initialization functions.
349 startup_resume_other_cores();
350 #endif
351
352 // Execute initialization functions esp_system_init_fn_t assigned to the main core. While
353 // this is happening, all other cores are executing the initialization functions
354 // assigned to them since they have been resumed already.
355 do_system_init_fn();
356
357 #if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
358 // Wait for all cores to finish secondary init.
359 volatile bool system_inited = false;
360
361 while (!system_inited) {
362 system_inited = true;
363 for (int i = 0; i < SOC_CPU_CORES_NUM; i++) {
364 system_inited &= s_system_inited[i];
365 }
366 esp_rom_delay_us(100);
367 }
368 #endif
369 }
370
start_cpu0_default(void)371 static void start_cpu0_default(void)
372 {
373
374 ESP_EARLY_LOGI(TAG, "Pro cpu start user code");
375 int cpu_freq = esp_clk_cpu_freq();
376 ESP_EARLY_LOGI(TAG, "cpu freq: %d", cpu_freq);
377
378 // Display information about the current running image.
379 if (LOG_LOCAL_LEVEL >= ESP_LOG_INFO) {
380 const esp_app_desc_t *app_desc = esp_ota_get_app_description();
381 ESP_EARLY_LOGI(TAG, "Application information:");
382 #ifndef CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR
383 ESP_EARLY_LOGI(TAG, "Project name: %s", app_desc->project_name);
384 #endif
385 #ifndef CONFIG_APP_EXCLUDE_PROJECT_VER_VAR
386 ESP_EARLY_LOGI(TAG, "App version: %s", app_desc->version);
387 #endif
388 #ifdef CONFIG_BOOTLOADER_APP_SECURE_VERSION
389 ESP_EARLY_LOGI(TAG, "Secure version: %d", app_desc->secure_version);
390 #endif
391 #ifdef CONFIG_APP_COMPILE_TIME_DATE
392 ESP_EARLY_LOGI(TAG, "Compile time: %s %s", app_desc->date, app_desc->time);
393 #endif
394 char buf[17];
395 esp_ota_get_app_elf_sha256(buf, sizeof(buf));
396 ESP_EARLY_LOGI(TAG, "ELF file SHA256: %s...", buf);
397 ESP_EARLY_LOGI(TAG, "ESP-IDF: %s", app_desc->idf_ver);
398 }
399
400 // Initialize core components and services.
401 do_core_init();
402
403 // Execute constructors.
404 do_global_ctors();
405
406 // Execute init functions of other components; blocks
407 // until all cores finish (when !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE).
408 do_secondary_init();
409
410 // Now that the application is about to start, disable boot watchdog
411 #ifndef CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE
412 wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL};
413 wdt_hal_write_protect_disable(&rtc_wdt_ctx);
414 wdt_hal_disable(&rtc_wdt_ctx);
415 wdt_hal_write_protect_enable(&rtc_wdt_ctx);
416 #endif
417
418 #if SOC_CPU_CORES_NUM > 1 && !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
419 s_system_full_inited = true;
420 #endif
421
422 esp_startup_start_app();
423 while (1);
424 }
425
426 IRAM_ATTR ESP_SYSTEM_INIT_FN(init_components0, BIT(0))
427 {
428 esp_timer_init();
429
430 #if CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND && !CONFIG_PM_SLP_DISABLE_GPIO
431 // Configure to isolate (disable the Input/Output/Pullup/Pulldown
432 // function of the pin) all GPIO pins in sleep state
433 esp_sleep_config_gpio_isolate();
434 // Enable automatic switching of GPIO configuration
435 esp_sleep_enable_gpio_switch(true);
436 #endif
437
438 #if CONFIG_APPTRACE_ENABLE
439 esp_err_t err = esp_apptrace_init();
440 assert(err == ESP_OK && "Failed to init apptrace module on PRO CPU!");
441 #endif
442 #if CONFIG_APPTRACE_SV_ENABLE
443 SEGGER_SYSVIEW_Conf();
444 #endif
445
446 #if CONFIG_ESP_DEBUG_STUBS_ENABLE
447 esp_dbg_stubs_init();
448 #endif
449
450 #if defined(CONFIG_PM_ENABLE)
451 esp_pm_impl_init();
452 #endif
453
454 #if CONFIG_ESP_COREDUMP_ENABLE
455 esp_core_dump_init();
456 #endif
457
458 #if SOC_APB_BACKUP_DMA
459 esp_apb_backup_dma_lock_init();
460 #endif
461
462 #if CONFIG_SW_COEXIST_ENABLE || CONFIG_EXTERNAL_COEX_ENABLE
463 esp_coex_adapter_register(&g_coex_adapter_funcs);
464 coex_pre_init();
465 #endif
466
467 #ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
468 ESP_EARLY_LOGD(TAG, "Setting C++ exception workarounds.");
469 _Unwind_SetNoFunctionContextInstall(1);
470 _Unwind_SetEnableExceptionFdeSorting(0);
471 #endif // CONFIG_COMPILER_CXX_EXCEPTIONS
472 }
473