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