1 // Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
21 #include "rom/ets_sys.h"
24 #include "rom/cache.h"
28 #include "soc/dport_reg.h"
29 #include "soc/io_mux_reg.h"
30 #include "soc/rtc_cntl_reg.h"
31 #include "soc/timer_group_reg.h"
33 #include "driver/rtc_io.h"
35 #include "freertos/FreeRTOS.h"
36 #include "freertos/task.h"
37 #include "freertos/semphr.h"
38 #include "freertos/queue.h"
39 #include "freertos/portmacro.h"
41 #include "tcpip_adapter.h"
43 #include "esp_heap_caps_init.h"
44 #include "sdkconfig.h"
45 #include "esp_system.h"
46 #include "esp_spi_flash.h"
47 #include "nvs_flash.h"
48 #include "esp_event.h"
49 #include "esp_spi_flash.h"
51 #include "esp_crosscore_int.h"
52 #include "esp_dport_access.h"
54 #include "esp_vfs_dev.h"
55 #include "esp_newlib.h"
56 #include "esp_brownout.h"
57 #include "esp_int_wdt.h"
58 #include "esp_task_wdt.h"
59 #include "esp_phy_init.h"
60 #include "esp_cache_err_int.h"
61 #include "esp_coexist.h"
62 #include "esp_panic.h"
63 #include "esp_core_dump.h"
64 #include "esp_app_trace.h"
65 #include "esp_efuse.h"
66 #include "esp_spiram.h"
68 #include "esp_timer.h"
71 #define STRINGIFY(s) STRINGIFY2(s)
72 #define STRINGIFY2(s) #s
74 void start_cpu0(void) __attribute__((weak, alias("start_cpu0_default"))) __attribute__((noreturn));
75 void start_cpu0_default(void) IRAM_ATTR __attribute__((noreturn));
76 #if !CONFIG_FREERTOS_UNICORE
77 static void IRAM_ATTR call_start_cpu1() __attribute__((noreturn));
78 void start_cpu1(void) __attribute__((weak, alias("start_cpu1_default"))) __attribute__((noreturn));
79 void start_cpu1_default(void) IRAM_ATTR __attribute__((noreturn));
80 static bool app_cpu_started = false;
81 #endif //!CONFIG_FREERTOS_UNICORE
83 static void do_global_ctors(void);
84 static void main_task(void* args);
85 extern void app_main(void);
87 extern int _bss_start;
89 extern int _rtc_bss_start;
90 extern int _rtc_bss_end;
91 extern int _init_start;
92 extern void (*__init_array_start)(void);
93 extern void (*__init_array_end)(void);
94 extern volatile int port_xSchedulerRunning[2];
96 static const char* TAG = "cpu_start";
98 struct object { long placeholder[ 10 ]; };
99 void __register_frame_info (const void *begin, struct object *ob);
100 extern char __eh_frame[];
103 * We arrive here after the bootloader finished loading the program from flash. The hardware is mostly uninitialized,
104 * and the app CPU is in reset. We do have a stack, so we can do the initialization in C.
107 void IRAM_ATTR call_start_cpu0()
109 #if CONFIG_FREERTOS_UNICORE
110 RESET_REASON rst_reas[1];
112 RESET_REASON rst_reas[2];
114 cpu_configure_region_protection();
116 //Move exception vectors to IRAM
118 "wsr %0, vecbase\n" \
119 ::"r"(&_init_start));
121 rst_reas[0] = rtc_get_reset_reason(0);
123 #if !CONFIG_FREERTOS_UNICORE
124 rst_reas[1] = rtc_get_reset_reason(1);
127 // from panic handler we can be reset by RWDT or TG0WDT
128 if (rst_reas[0] == RTCWDT_SYS_RESET || rst_reas[0] == TG0WDT_SYS_RESET
129 #if !CONFIG_FREERTOS_UNICORE
130 || rst_reas[1] == RTCWDT_SYS_RESET || rst_reas[1] == TG0WDT_SYS_RESET
133 esp_panic_wdt_stop();
136 // Temporary workaround for an ugly crash, until we allow > 192KB of static DRAM
137 if ((intptr_t)&_bss_end > 0x3FFE0000) {
138 // Can't use assert() or logging here because there's no .bss
139 ets_printf("ERROR: Static .bss section extends past 0x3FFE0000. IDF cannot boot.\n");
143 //Clear BSS. Please do not attempt to do any complex stuff (like early logging) before this.
144 memset(&_bss_start, 0, (&_bss_end - &_bss_start) * sizeof(_bss_start));
146 /* Unless waking from deep sleep (implying RTC memory is intact), clear RTC bss */
147 if (rst_reas[0] != DEEPSLEEP_RESET) {
148 memset(&_rtc_bss_start, 0, (&_rtc_bss_end - &_rtc_bss_start) * sizeof(_rtc_bss_start));
151 #if CONFIG_SPIRAM_BOOT_INIT
152 if (esp_spiram_init() != ESP_OK) {
153 ESP_EARLY_LOGE(TAG, "Failed to init external RAM!");
158 ESP_EARLY_LOGI(TAG, "Pro cpu up.");
160 #if !CONFIG_FREERTOS_UNICORE
161 ESP_EARLY_LOGI(TAG, "Starting app cpu, entry point is %p", call_start_cpu1);
162 //Flush and enable icache for APP CPU
164 Cache_Read_Enable(1);
166 // Enable clock and reset APP CPU. Note that OpenOCD may have already
167 // enabled clock and taken APP CPU out of reset. In this case don't reset
168 // APP CPU again, as that will clear the breakpoints which may have already
170 if (!DPORT_GET_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN)) {
171 DPORT_SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN);
172 DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_C_REG, DPORT_APPCPU_RUNSTALL);
173 DPORT_SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING);
174 DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING);
176 ets_set_appcpu_boot_addr((uint32_t)call_start_cpu1);
178 while (!app_cpu_started) {
182 ESP_EARLY_LOGI(TAG, "Single core mode");
183 DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN);
187 #if CONFIG_SPIRAM_MEMTEST
188 bool ext_ram_ok=esp_spiram_test();
190 ESP_EARLY_LOGE(TAG, "External RAM failed memory test!");
195 /* Initialize heap allocator. WARNING: This *needs* to happen *after* the app cpu has booted.
196 If the heap allocator is initialized first, it will put free memory linked list items into
197 memory also used by the ROM. Starting the app cpu will let its ROM initialize that memory,
198 corrupting those linked lists. Initializing the allocator *after* the app cpu has booted
199 works around this problem.
200 With SPI RAM enabled, there's a second reason: half of the SPI RAM will be managed by the
201 app CPU, and when that is not up yet, the memory will be inaccessible and heap_caps_init may
202 fail initializing it properly. */
205 ESP_EARLY_LOGI(TAG, "Pro cpu start user code");
209 #if !CONFIG_FREERTOS_UNICORE
211 static void wdt_reset_cpu1_info_enable(void)
213 DPORT_REG_SET_BIT(DPORT_APP_CPU_RECORD_CTRL_REG, DPORT_APP_CPU_PDEBUG_ENABLE | DPORT_APP_CPU_RECORD_ENABLE);
214 DPORT_REG_CLR_BIT(DPORT_APP_CPU_RECORD_CTRL_REG, DPORT_APP_CPU_RECORD_ENABLE);
217 void IRAM_ATTR call_start_cpu1()
220 "wsr %0, vecbase\n" \
221 ::"r"(&_init_start));
223 ets_set_appcpu_boot_addr(0);
224 cpu_configure_region_protection();
226 #if CONFIG_CONSOLE_UART_NONE
227 ets_install_putc1(NULL);
228 ets_install_putc2(NULL);
229 #else // CONFIG_CONSOLE_UART_NONE
231 ets_install_uart_printf();
232 uart_tx_switch(CONFIG_CONSOLE_UART_NUM);
235 wdt_reset_cpu1_info_enable();
236 ESP_EARLY_LOGI(TAG, "App cpu up.");
240 #endif //!CONFIG_FREERTOS_UNICORE
242 static void intr_matrix_clear(void)
244 //Clear all the interrupt matrix register
245 for (int i = ETS_WIFI_MAC_INTR_SOURCE; i <= ETS_CACHE_IA_INTR_SOURCE; i++) {
246 intr_matrix_set(0, i, ETS_INVALID_INUM);
247 #if !CONFIG_FREERTOS_UNICORE
248 intr_matrix_set(1, i, ETS_INVALID_INUM);
253 void start_cpu0_default(void)
255 esp_setup_syscall_table();
256 //Enable trace memory and immediately start trace.
257 #if CONFIG_ESP32_TRAX
258 #if CONFIG_ESP32_TRAX_TWOBANKS
259 trax_enable(TRAX_ENA_PRO_APP);
261 trax_enable(TRAX_ENA_PRO);
263 trax_start_trace(TRAX_DOWNCOUNT_WORDS);
266 esp_perip_clk_init();
268 #ifndef CONFIG_CONSOLE_UART_NONE
269 uart_div_modify(CONFIG_CONSOLE_UART_NUM, (rtc_clk_apb_freq_get() << 4) / CONFIG_CONSOLE_UART_BAUDRATE);
271 #if CONFIG_BROWNOUT_DET
274 #if CONFIG_DISABLE_BASIC_ROM_CONSOLE
275 esp_efuse_disable_basic_rom_console();
277 rtc_gpio_force_hold_dis_all();
278 esp_vfs_dev_uart_register();
279 esp_reent_init(_GLOBAL_REENT);
280 #ifndef CONFIG_CONSOLE_UART_NONE
281 const char* default_uart_dev = "/dev/uart/" STRINGIFY(CONFIG_CONSOLE_UART_NUM);
282 _GLOBAL_REENT->_stdin = fopen(default_uart_dev, "r");
283 _GLOBAL_REENT->_stdout = fopen(default_uart_dev, "w");
284 _GLOBAL_REENT->_stderr = fopen(default_uart_dev, "w");
286 _GLOBAL_REENT->_stdin = (FILE*) &__sf_fake_stdin;
287 _GLOBAL_REENT->_stdout = (FILE*) &__sf_fake_stdout;
288 _GLOBAL_REENT->_stderr = (FILE*) &__sf_fake_stderr;
291 esp_set_time_from_rtc();
292 #if CONFIG_ESP32_APPTRACE_ENABLE
293 esp_err_t err = esp_apptrace_init();
295 ESP_EARLY_LOGE(TAG, "Failed to init apptrace module on CPU0 (%d)!", err);
298 #if CONFIG_SYSVIEW_ENABLE
299 SEGGER_SYSVIEW_Conf();
308 esp_cache_err_int_init();
309 esp_crosscore_int_init();
311 #ifndef CONFIG_FREERTOS_UNICORE
312 esp_dport_access_int_init();
315 /* init default OS-aware flash access critical section */
316 spi_flash_guard_set(&g_flash_guard_default_ops);
318 #if CONFIG_ESP32_ENABLE_COREDUMP
319 esp_core_dump_init();
322 portBASE_TYPE res = xTaskCreatePinnedToCore(&main_task, "main",
323 ESP_TASK_MAIN_STACK, NULL,
324 ESP_TASK_MAIN_PRIO, NULL, 0);
325 assert(res == pdTRUE);
326 ESP_LOGI(TAG, "Starting scheduler on PRO CPU.");
327 vTaskStartScheduler();
328 abort(); /* Only get to here if not enough free heap to start scheduler */
331 #if !CONFIG_FREERTOS_UNICORE
332 void start_cpu1_default(void)
334 #if CONFIG_ESP32_TRAX_TWOBANKS
335 trax_start_trace(TRAX_DOWNCOUNT_WORDS);
337 #if CONFIG_ESP32_APPTRACE_ENABLE
338 esp_err_t err = esp_apptrace_init();
340 ESP_EARLY_LOGE(TAG, "Failed to init apptrace module on CPU1 (%d)!", err);
343 // Wait for FreeRTOS initialization to finish on PRO CPU
344 while (port_xSchedulerRunning[0] == 0) {
347 //Take care putting stuff here: if asked, FreeRTOS will happily tell you the scheduler
348 //has started, but it isn't active *on this CPU* yet.
349 esp_cache_err_int_init();
350 esp_crosscore_int_init();
351 esp_dport_access_int_init();
353 ESP_EARLY_LOGI(TAG, "Starting scheduler on APP CPU.");
354 xPortStartScheduler();
355 abort(); /* Only get to here if FreeRTOS somehow very broken */
357 #endif //!CONFIG_FREERTOS_UNICORE
359 static void do_global_ctors(void)
361 static struct object ob;
362 __register_frame_info( __eh_frame, &ob );
365 for (p = &__init_array_end - 1; p >= &__init_array_start; --p) {
370 static void main_task(void* args)
372 // Now that the application is about to start, disable boot watchdogs
373 REG_CLR_BIT(TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN_S);
374 REG_CLR_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN);
375 #if !CONFIG_FREERTOS_UNICORE
376 // Wait for FreeRTOS initialization to finish on APP CPU, before replacing its startup stack
377 while (port_xSchedulerRunning[1] == 0) {
381 //Enable allocation in region where the startup stacks were located.
382 heap_caps_enable_nonos_stack_heaps();