]> granicus.if.org Git - esp-idf/blob - components/esp32/cpu_start.c
Merge branch 'feature/esp-wrover-kit-v4_1' into 'master'
[esp-idf] / components / esp32 / cpu_start.c
1 // Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
2 //
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
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
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.
14
15 #include <stdint.h>
16 #include <string.h>
17
18 #include "esp_attr.h"
19 #include "esp_err.h"
20
21 #include "rom/ets_sys.h"
22 #include "rom/uart.h"
23 #include "rom/rtc.h"
24 #include "rom/cache.h"
25
26 #include "soc/cpu.h"
27 #include "soc/rtc.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"
32 #include "soc/rtc_wdt.h"
33
34 #include "driver/rtc_io.h"
35
36 #include "freertos/FreeRTOS.h"
37 #include "freertos/task.h"
38 #include "freertos/semphr.h"
39 #include "freertos/queue.h"
40 #include "freertos/portmacro.h"
41
42 #include "esp_heap_caps_init.h"
43 #include "sdkconfig.h"
44 #include "esp_system.h"
45 #include "esp_spi_flash.h"
46 #include "nvs_flash.h"
47 #include "esp_event.h"
48 #include "esp_spi_flash.h"
49 #include "esp_ipc.h"
50 #include "esp_crosscore_int.h"
51 #include "esp_dport_access.h"
52 #include "esp_log.h"
53 #include "esp_vfs_dev.h"
54 #include "esp_newlib.h"
55 #include "esp_brownout.h"
56 #include "esp_int_wdt.h"
57 #include "esp_task.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_dbg_stubs.h"
66 #include "esp_efuse.h"
67 #include "esp_spiram.h"
68 #include "esp_clk_internal.h"
69 #include "esp_timer.h"
70 #include "esp_pm.h"
71 #include "pm_impl.h"
72 #include "trax.h"
73
74 #define STRINGIFY(s) STRINGIFY2(s)
75 #define STRINGIFY2(s) #s
76
77 void start_cpu0(void) __attribute__((weak, alias("start_cpu0_default"))) __attribute__((noreturn));
78 void start_cpu0_default(void) IRAM_ATTR __attribute__((noreturn));
79 #if !CONFIG_FREERTOS_UNICORE
80 static void IRAM_ATTR call_start_cpu1() __attribute__((noreturn));
81 void start_cpu1(void) __attribute__((weak, alias("start_cpu1_default"))) __attribute__((noreturn));
82 void start_cpu1_default(void) IRAM_ATTR __attribute__((noreturn));
83 static bool app_cpu_started = false;
84 #endif //!CONFIG_FREERTOS_UNICORE
85
86 static void do_global_ctors(void);
87 static void main_task(void* args);
88 extern void app_main(void);
89 extern esp_err_t esp_pthread_init(void);
90
91 extern int _bss_start;
92 extern int _bss_end;
93 extern int _rtc_bss_start;
94 extern int _rtc_bss_end;
95 extern int _init_start;
96 extern void (*__init_array_start)(void);
97 extern void (*__init_array_end)(void);
98 extern volatile int port_xSchedulerRunning[2];
99
100 static const char* TAG = "cpu_start";
101
102 struct object { long placeholder[ 10 ]; };
103 void __register_frame_info (const void *begin, struct object *ob);
104 extern char __eh_frame[];
105
106 //If CONFIG_SPIRAM_IGNORE_NOTFOUND is set and external RAM is not found or errors out on testing, this is set to false.
107 static bool s_spiram_okay=true;
108
109 /*
110  * We arrive here after the bootloader finished loading the program from flash. The hardware is mostly uninitialized,
111  * and the app CPU is in reset. We do have a stack, so we can do the initialization in C.
112  */
113
114 void IRAM_ATTR call_start_cpu0()
115 {
116 #if CONFIG_FREERTOS_UNICORE
117     RESET_REASON rst_reas[1];
118 #else
119     RESET_REASON rst_reas[2];
120 #endif
121     cpu_configure_region_protection();
122
123     //Move exception vectors to IRAM
124     asm volatile (\
125                   "wsr    %0, vecbase\n" \
126                   ::"r"(&_init_start));
127
128     rst_reas[0] = rtc_get_reset_reason(0);
129
130 #if !CONFIG_FREERTOS_UNICORE
131     rst_reas[1] = rtc_get_reset_reason(1);
132 #endif
133
134     // from panic handler we can be reset by RWDT or TG0WDT
135     if (rst_reas[0] == RTCWDT_SYS_RESET || rst_reas[0] == TG0WDT_SYS_RESET
136 #if !CONFIG_FREERTOS_UNICORE
137         || rst_reas[1] == RTCWDT_SYS_RESET || rst_reas[1] == TG0WDT_SYS_RESET
138 #endif
139     ) {
140 #ifndef CONFIG_BOOTLOADER_WDT_ENABLE
141         rtc_wdt_disable();
142 #endif
143     }
144
145     //Clear BSS. Please do not attempt to do any complex stuff (like early logging) before this.
146     memset(&_bss_start, 0, (&_bss_end - &_bss_start) * sizeof(_bss_start));
147
148     /* Unless waking from deep sleep (implying RTC memory is intact), clear RTC bss */
149     if (rst_reas[0] != DEEPSLEEP_RESET) {
150         memset(&_rtc_bss_start, 0, (&_rtc_bss_end - &_rtc_bss_start) * sizeof(_rtc_bss_start));
151     }
152
153 #if CONFIG_SPIRAM_BOOT_INIT
154     esp_spiram_init_cache();
155     if (esp_spiram_init() != ESP_OK) {
156 #if CONFIG_SPIRAM_IGNORE_NOTFOUND
157         ESP_EARLY_LOGI(TAG, "Failed to init external RAM; continuing without it.");
158         s_spiram_okay = false;
159 #else
160         ESP_EARLY_LOGE(TAG, "Failed to init external RAM!");
161         abort();
162 #endif
163     }
164 #endif
165
166     ESP_EARLY_LOGI(TAG, "Pro cpu up.");
167
168 #if !CONFIG_FREERTOS_UNICORE
169     ESP_EARLY_LOGI(TAG, "Starting app cpu, entry point is %p", call_start_cpu1);
170     //Flush and enable icache for APP CPU
171     Cache_Flush(1);
172     Cache_Read_Enable(1);
173     esp_cpu_unstall(1);
174     // Enable clock and reset APP CPU. Note that OpenOCD may have already
175     // enabled clock and taken APP CPU out of reset. In this case don't reset
176     // APP CPU again, as that will clear the breakpoints which may have already
177     // been set.
178     if (!DPORT_GET_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN)) {
179         DPORT_SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN);
180         DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_C_REG, DPORT_APPCPU_RUNSTALL);
181         DPORT_SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING);
182         DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING);
183     }
184     ets_set_appcpu_boot_addr((uint32_t)call_start_cpu1);
185
186     while (!app_cpu_started) {
187         ets_delay_us(100);
188     }
189 #else
190     ESP_EARLY_LOGI(TAG, "Single core mode");
191     DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN);
192 #endif
193
194
195 #if CONFIG_SPIRAM_MEMTEST
196     if (s_spiram_okay) {
197         bool ext_ram_ok=esp_spiram_test();
198         if (!ext_ram_ok) {
199             ESP_EARLY_LOGE(TAG, "External RAM failed memory test!");
200             abort();
201         }
202     }
203 #endif
204
205     /* Initialize heap allocator. WARNING: This *needs* to happen *after* the app cpu has booted.
206        If the heap allocator is initialized first, it will put free memory linked list items into
207        memory also used by the ROM. Starting the app cpu will let its ROM initialize that memory,
208        corrupting those linked lists. Initializing the allocator *after* the app cpu has booted
209        works around this problem.
210        With SPI RAM enabled, there's a second reason: half of the SPI RAM will be managed by the
211        app CPU, and when that is not up yet, the memory will be inaccessible and heap_caps_init may
212        fail initializing it properly. */
213     heap_caps_init();
214
215     ESP_EARLY_LOGI(TAG, "Pro cpu start user code");
216     start_cpu0();
217 }
218
219 #if !CONFIG_FREERTOS_UNICORE
220
221 static void wdt_reset_cpu1_info_enable(void)
222 {
223     DPORT_REG_SET_BIT(DPORT_APP_CPU_RECORD_CTRL_REG, DPORT_APP_CPU_PDEBUG_ENABLE | DPORT_APP_CPU_RECORD_ENABLE);
224     DPORT_REG_CLR_BIT(DPORT_APP_CPU_RECORD_CTRL_REG, DPORT_APP_CPU_RECORD_ENABLE);
225 }
226
227 void IRAM_ATTR call_start_cpu1()
228 {
229     asm volatile (\
230                   "wsr    %0, vecbase\n" \
231                   ::"r"(&_init_start));
232
233     ets_set_appcpu_boot_addr(0);
234     cpu_configure_region_protection();
235
236 #if CONFIG_CONSOLE_UART_NONE
237     ets_install_putc1(NULL);
238     ets_install_putc2(NULL);
239 #else // CONFIG_CONSOLE_UART_NONE
240     uartAttach();
241     ets_install_uart_printf();
242     uart_tx_switch(CONFIG_CONSOLE_UART_NUM);
243 #endif
244
245     wdt_reset_cpu1_info_enable();
246     ESP_EARLY_LOGI(TAG, "App cpu up.");
247     app_cpu_started = 1;
248     start_cpu1();
249 }
250 #endif //!CONFIG_FREERTOS_UNICORE
251
252 static void intr_matrix_clear(void)
253 {
254     //Clear all the interrupt matrix register
255     for (int i = ETS_WIFI_MAC_INTR_SOURCE; i <= ETS_CACHE_IA_INTR_SOURCE; i++) {
256         intr_matrix_set(0, i, ETS_INVALID_INUM);
257 #if !CONFIG_FREERTOS_UNICORE
258         intr_matrix_set(1, i, ETS_INVALID_INUM);
259 #endif
260     }
261 }
262
263 void start_cpu0_default(void)
264 {
265     esp_err_t err;
266     esp_setup_syscall_table();
267
268     if (s_spiram_okay) {
269 #if CONFIG_SPIRAM_BOOT_INIT && (CONFIG_SPIRAM_USE_CAPS_ALLOC || CONFIG_SPIRAM_USE_MALLOC)
270         esp_err_t r=esp_spiram_add_to_heapalloc();
271         if (r != ESP_OK) {
272             ESP_EARLY_LOGE(TAG, "External RAM could not be added to heap!");
273             abort();
274         }
275 #if CONFIG_SPIRAM_USE_MALLOC
276         heap_caps_malloc_extmem_enable(CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL);
277 #endif
278 #endif
279     }
280
281 //Enable trace memory and immediately start trace.
282 #if CONFIG_ESP32_TRAX
283 #if CONFIG_ESP32_TRAX_TWOBANKS
284     trax_enable(TRAX_ENA_PRO_APP);
285 #else
286     trax_enable(TRAX_ENA_PRO);
287 #endif
288     trax_start_trace(TRAX_DOWNCOUNT_WORDS);
289 #endif
290     esp_clk_init();
291     esp_perip_clk_init();
292     intr_matrix_clear();
293
294 #ifndef CONFIG_CONSOLE_UART_NONE
295 #ifdef CONFIG_PM_ENABLE
296     const int uart_clk_freq = REF_CLK_FREQ;
297     /* When DFS is enabled, use REFTICK as UART clock source */
298     CLEAR_PERI_REG_MASK(UART_CONF0_REG(CONFIG_CONSOLE_UART_NUM), UART_TICK_REF_ALWAYS_ON);
299 #else
300     const int uart_clk_freq = APB_CLK_FREQ;
301 #endif // CONFIG_PM_DFS_ENABLE
302     uart_div_modify(CONFIG_CONSOLE_UART_NUM, (uart_clk_freq << 4) / CONFIG_CONSOLE_UART_BAUDRATE);
303 #endif // CONFIG_CONSOLE_UART_NONE
304
305 #if CONFIG_BROWNOUT_DET
306     esp_brownout_init();
307 #endif
308 #if CONFIG_DISABLE_BASIC_ROM_CONSOLE
309     esp_efuse_disable_basic_rom_console();
310 #endif
311     rtc_gpio_force_hold_dis_all();
312     esp_vfs_dev_uart_register();
313     esp_reent_init(_GLOBAL_REENT);
314 #ifndef CONFIG_CONSOLE_UART_NONE
315     const char* default_uart_dev = "/dev/uart/" STRINGIFY(CONFIG_CONSOLE_UART_NUM);
316     _GLOBAL_REENT->_stdin  = fopen(default_uart_dev, "r");
317     _GLOBAL_REENT->_stdout = fopen(default_uart_dev, "w");
318     _GLOBAL_REENT->_stderr = fopen(default_uart_dev, "w");
319 #else
320     _GLOBAL_REENT->_stdin  = (FILE*) &__sf_fake_stdin;
321     _GLOBAL_REENT->_stdout = (FILE*) &__sf_fake_stdout;
322     _GLOBAL_REENT->_stderr = (FILE*) &__sf_fake_stderr;
323 #endif
324     esp_timer_init();
325     esp_set_time_from_rtc();
326 #if CONFIG_ESP32_APPTRACE_ENABLE
327     err = esp_apptrace_init();
328     assert(err == ESP_OK && "Failed to init apptrace module on PRO CPU!");
329 #endif
330 #if CONFIG_SYSVIEW_ENABLE
331     SEGGER_SYSVIEW_Conf();
332 #endif
333 #if CONFIG_ESP32_DEBUG_STUBS_ENABLE
334     esp_dbg_stubs_init();
335 #endif
336     err = esp_pthread_init();
337     assert(err == ESP_OK && "Failed to init pthread module!");
338
339     do_global_ctors();
340 #if CONFIG_INT_WDT
341     esp_int_wdt_init();
342     //Initialize the interrupt watch dog for CPU0.
343     esp_int_wdt_cpu_init();
344 #endif
345     esp_cache_err_int_init();
346     esp_crosscore_int_init();
347     esp_ipc_init();
348 #ifndef CONFIG_FREERTOS_UNICORE
349     esp_dport_access_int_init();
350 #endif
351     spi_flash_init();
352     /* init default OS-aware flash access critical section */
353     spi_flash_guard_set(&g_flash_guard_default_ops);
354 #ifdef CONFIG_PM_ENABLE
355     esp_pm_impl_init();
356 #ifdef CONFIG_PM_DFS_INIT_AUTO
357     rtc_cpu_freq_t max_freq;
358     rtc_clk_cpu_freq_from_mhz(CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ, &max_freq);
359     esp_pm_config_esp32_t cfg = {
360             .max_cpu_freq = max_freq,
361             .min_cpu_freq = RTC_CPU_FREQ_XTAL
362     };
363     esp_pm_configure(&cfg);
364 #endif //CONFIG_PM_DFS_INIT_AUTO
365 #endif //CONFIG_PM_ENABLE
366
367 #if CONFIG_ESP32_ENABLE_COREDUMP
368     esp_core_dump_init();
369 #endif
370
371     portBASE_TYPE res = xTaskCreatePinnedToCore(&main_task, "main",
372                                                 ESP_TASK_MAIN_STACK, NULL,
373                                                 ESP_TASK_MAIN_PRIO, NULL, 0);
374     assert(res == pdTRUE);
375     ESP_LOGI(TAG, "Starting scheduler on PRO CPU.");
376     vTaskStartScheduler();
377     abort(); /* Only get to here if not enough free heap to start scheduler */
378 }
379
380 #if !CONFIG_FREERTOS_UNICORE
381 void start_cpu1_default(void)
382 {
383     // Wait for FreeRTOS initialization to finish on PRO CPU
384     while (port_xSchedulerRunning[0] == 0) {
385         ;
386     }
387 #if CONFIG_ESP32_TRAX_TWOBANKS
388     trax_start_trace(TRAX_DOWNCOUNT_WORDS);
389 #endif
390 #if CONFIG_ESP32_APPTRACE_ENABLE
391     esp_err_t err = esp_apptrace_init();
392     assert(err == ESP_OK && "Failed to init apptrace module on APP CPU!");
393 #endif
394 #if CONFIG_INT_WDT
395     //Initialize the interrupt watch dog for CPU1.
396     esp_int_wdt_cpu_init();
397 #endif
398     //Take care putting stuff here: if asked, FreeRTOS will happily tell you the scheduler
399     //has started, but it isn't active *on this CPU* yet.
400     esp_cache_err_int_init();
401     esp_crosscore_int_init();
402     esp_dport_access_int_init();
403
404     ESP_EARLY_LOGI(TAG, "Starting scheduler on APP CPU.");
405     xPortStartScheduler();
406     abort(); /* Only get to here if FreeRTOS somehow very broken */
407 }
408 #endif //!CONFIG_FREERTOS_UNICORE
409
410 #ifdef CONFIG_CXX_EXCEPTIONS
411 size_t __cxx_eh_arena_size_get()
412 {
413     return CONFIG_CXX_EXCEPTIONS_EMG_POOL_SIZE;
414 }
415 #endif
416
417 static void do_global_ctors(void)
418 {
419 #ifdef CONFIG_CXX_EXCEPTIONS
420     static struct object ob;
421     __register_frame_info( __eh_frame, &ob );
422 #endif
423
424     void (**p)(void);
425     for (p = &__init_array_end - 1; p >= &__init_array_start; --p) {
426         (*p)();
427     }
428 }
429
430 static void main_task(void* args)
431 {
432 #if !CONFIG_FREERTOS_UNICORE
433     // Wait for FreeRTOS initialization to finish on APP CPU, before replacing its startup stack
434     while (port_xSchedulerRunning[1] == 0) {
435         ;
436     }
437 #endif
438     //Enable allocation in region where the startup stacks were located.
439     heap_caps_enable_nonos_stack_heaps();
440
441     // Now we have startup stack RAM available for heap, enable any DMA pool memory
442 #if CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL
443     esp_err_t r = esp_spiram_reserve_dma_pool(CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL);
444     if (r != ESP_OK) {
445         ESP_EARLY_LOGE(TAG, "Could not reserve internal/DMA pool (error 0x%x)", r);
446         abort();
447     }
448 #endif
449
450     //Initialize task wdt if configured to do so
451 #ifdef CONFIG_TASK_WDT_PANIC
452     ESP_ERROR_CHECK(esp_task_wdt_init(CONFIG_TASK_WDT_TIMEOUT_S, true))
453 #elif CONFIG_TASK_WDT
454     ESP_ERROR_CHECK(esp_task_wdt_init(CONFIG_TASK_WDT_TIMEOUT_S, false))
455 #endif
456
457     //Add IDLE 0 to task wdt
458 #ifdef CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0
459     TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCPU(0);
460     if(idle_0 != NULL){
461         ESP_ERROR_CHECK(esp_task_wdt_add(idle_0))
462     }
463 #endif
464     //Add IDLE 1 to task wdt
465 #ifdef CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1
466     TaskHandle_t idle_1 = xTaskGetIdleTaskHandleForCPU(1);
467     if(idle_1 != NULL){
468         ESP_ERROR_CHECK(esp_task_wdt_add(idle_1))
469     }
470 #endif
471
472     // Now that the application is about to start, disable boot watchdog
473 #ifndef CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE
474     rtc_wdt_disable();
475 #endif
476     app_main();
477     vTaskDelete(NULL);
478 }
479