diff --git a/components/bootloader/src/main/bootloader_start.c b/components/bootloader/src/main/bootloader_start.c index f56bc5e6b..116c7a98d 100644 --- a/components/bootloader/src/main/bootloader_start.c +++ b/components/bootloader/src/main/bootloader_start.c @@ -24,6 +24,7 @@ #include "rom/crc.h" #include "soc/soc.h" +#include "soc/cpu.h" #include "soc/dport_reg.h" #include "soc/io_mux_reg.h" #include "soc/efuse_reg.h" @@ -60,36 +61,7 @@ void IRAM_ATTR set_cache_and_start_app(uint32_t drom_addr, void IRAM_ATTR call_start_cpu0() { - //Make page 0 access raise an exception - //Also some other unused pages so we can catch weirdness - //ToDo: this but nicer. - asm volatile (\ - "movi a4,0x00000000\n" \ - "movi a5,0xf\n" \ - "wdtlb a5,a4\n" \ - "witlb a5,a4\n" \ - "movi a4,0x80000000\n" \ - "wdtlb a5,a4\n" \ - "witlb a5,a4\n" \ - "movi a4,0xa0000000\n" \ - "wdtlb a5,a4\n" \ - "witlb a5,a4\n" \ - "movi a4,0xc0000000\n" \ - "wdtlb a5,a4\n" \ - "witlb a5,a4\n" \ - "movi a4,0xe0000000\n" \ - "wdtlb a5,a4\n" \ - "witlb a5,a4\n" \ - "movi a4,0x20000000\n" \ - "movi a5,0x0\n" \ - "wdtlb a5,a4\n" \ - "witlb a5,a4\n" \ - "movi a4,0x40000000\n" \ - "movi a5,0x2\n" \ - "wdtlb a5,a4\n" \ - "witlb a5,a4\n" \ - "isync\n" \ - :::"a4","a5"); + cpu_configure_region_protection(); //Clear bss memset(&_bss_start, 0, (&_bss_end - &_bss_start) * sizeof(_bss_start)); diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c index cfc628b12..20c6d379c 100644 --- a/components/esp32/cpu_start.c +++ b/components/esp32/cpu_start.c @@ -20,8 +20,10 @@ #include "rom/ets_sys.h" #include "rom/uart.h" +#include "soc/cpu.h" #include "soc/dport_reg.h" #include "soc/io_mux_reg.h" +#include "soc/rtc_cntl_reg.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -45,169 +47,104 @@ static void IRAM_ATTR user_start_cpu0(void); static void IRAM_ATTR call_user_start_cpu1(); static void IRAM_ATTR user_start_cpu1(void); extern void ets_setup_syscalls(void); +extern esp_err_t app_main(void *ctx); - -extern int __cpu1_entry_point; extern int _bss_start; extern int _bss_end; extern int _init_start; -extern int _init_end; -extern int _iram_romjumptable_start; -extern int _iram_romjumptable_end; -extern int _iram_text_start; -extern int _iram_text_end; - -static const char* TAG = "cpu_start"; - -/* -We arrive here after the bootloader finished loading the program from flash. The hardware is mostly uninitialized, -flash cache is down and the app CPU is in reset. We do have a stack, so we can do the initialization in C. -*/ - -static bool app_cpu_started = false; - -void IRAM_ATTR call_user_start_cpu0() { - //Kill wdt - REG_CLR_BIT(0x3ff4808c, BIT(10)); //RTCCNTL+8C RTC_WDTCONFIG0 RTC_ - REG_CLR_BIT(0x6001f048, BIT(14)); //DR_REG_BB_BASE+48 - - //Move exception vectors to IRAM - asm volatile (\ - "wsr %0, vecbase\n" \ - ::"r"(&_init_start)); - - uartAttach(); - ets_install_uart_printf(); - - //Make page 0 access raise an exception - //Also some other unused pages so we can catch weirdness - //ToDo: this but nicer. - asm volatile (\ - "movi a4,0x00000000\n" \ - "movi a5,0xf\n" \ - "wdtlb a5,a4\n" \ - "witlb a5,a4\n" \ - "movi a4,0x80000000\n" \ - "wdtlb a5,a4\n" \ - "witlb a5,a4\n" \ - "movi a4,0xa0000000\n" \ - "wdtlb a5,a4\n" \ - "witlb a5,a4\n" \ - "movi a4,0xc0000000\n" \ - "wdtlb a5,a4\n" \ - "witlb a5,a4\n" \ - "movi a4,0xe0000000\n" \ - "wdtlb a5,a4\n" \ - "witlb a5,a4\n" \ - "movi a4,0x20000000\n" \ - "movi a5,0x0\n" \ - "wdtlb a5,a4\n" \ - "witlb a5,a4\n" \ - "movi a4,0x40000000\n" \ - "movi a5,0x2\n" \ - "wdtlb a5,a4\n" \ - "witlb a5,a4\n" \ - "isync\n" \ - :::"a4","a5"); - - memset(&_bss_start, 0, (&_bss_end - &_bss_start) * sizeof(_bss_start)); - - // Initialize heap allocator - heap_alloc_caps_init(); - - ESP_EARLY_LOGI(TAG, "Pro cpu up."); - -#ifndef CONFIG_FREERTOS_UNICORE - ESP_EARLY_LOGI(TAG, "Starting app cpu, entry point is %p", call_user_start_cpu1); - - SET_PERI_REG_MASK(APPCPU_CTRL_REG_B, DPORT_APPCPU_CLKGATE_EN); - CLEAR_PERI_REG_MASK(APPCPU_CTRL_REG_C, DPORT_APPCPU_RUNSTALL); - SET_PERI_REG_MASK(APPCPU_CTRL_REG_A, DPORT_APPCPU_RESETTING); - CLEAR_PERI_REG_MASK(APPCPU_CTRL_REG_A, DPORT_APPCPU_RESETTING); - ets_set_appcpu_boot_addr((uint32_t)call_user_start_cpu1); - - while (!app_cpu_started) { - ets_delay_us(100); - } -#else - ESP_EARLY_LOGI(TAG, "Single core mode"); - CLEAR_PERI_REG_MASK(APPCPU_CTRL_REG_B, DPORT_APPCPU_CLKGATE_EN); -#endif - ESP_EARLY_LOGI(TAG, "Pro cpu start user code"); - user_start_cpu0(); -} - - -extern int _init_start; - -void IRAM_ATTR call_user_start_cpu1() { - asm volatile (\ - "wsr %0, vecbase\n" \ - ::"r"(&_init_start)); - - //Make page 0 access raise an exception - //Also some other unused pages so we can catch weirdness - //ToDo: this but nicer. - asm volatile (\ - "movi a4,0x00000000\n" \ - "movi a5,0xf\n" \ - "wdtlb a5,a4\n" \ - "witlb a5,a4\n" \ - "movi a4,0x80000000\n" \ - "wdtlb a5,a4\n" \ - "witlb a5,a4\n" \ - "movi a4,0xa0000000\n" \ - "wdtlb a5,a4\n" \ - "witlb a5,a4\n" \ - "movi a4,0xc0000000\n" \ - "wdtlb a5,a4\n" \ - "witlb a5,a4\n" \ - "movi a4,0xe0000000\n" \ - "wdtlb a5,a4\n" \ - "witlb a5,a4\n" \ - "movi a4,0x20000000\n" \ - "movi a5,0x0\n" \ - "wdtlb a5,a4\n" \ - "witlb a5,a4\n" \ - "movi a4,0x40000000\n" \ - "movi a5,0x2\n" \ - "wdtlb a5,a4\n" \ - "witlb a5,a4\n" \ - "isync\n" \ - :::"a4","a5"); - - ESP_EARLY_LOGI(TAG, "App cpu up."); - app_cpu_started = 1; - user_start_cpu1(); -} - -extern volatile int port_xSchedulerRunning[2]; - -void IRAM_ATTR user_start_cpu1(void) { - // Wait for FreeRTOS initialization to finish on PRO CPU - while (port_xSchedulerRunning[0] == 0) { - ; - } - ESP_LOGI(TAG, "Starting scheduler on APP CPU."); - xPortStartScheduler(); -} - extern void (*__init_array_start)(void); extern void (*__init_array_end)(void); +extern volatile int port_xSchedulerRunning[2]; -static void do_global_ctors(void) { - void (**p)(void); - for(p = &__init_array_start; p != &__init_array_end; ++p) - (*p)(); +static const char* TAG = "cpu_start"; +static bool app_cpu_started = false; + +/* + * We arrive here after the bootloader finished loading the program from flash. The hardware is mostly uninitialized, + * and the app CPU is in reset. We do have a stack, so we can do the initialization in C. + */ + +void IRAM_ATTR call_user_start_cpu0() +{ + //Kill wdt + REG_CLR_BIT(RTC_WDTCONFIG0, RTC_CNTL_WDT_FLASHBOOT_MOD_EN); + REG_CLR_BIT(0x6001f048, BIT(14)); //DR_REG_BB_BASE+48 + + cpu_configure_region_protection(); + + //Move exception vectors to IRAM + asm volatile (\ + "wsr %0, vecbase\n" \ + ::"r"(&_init_start)); + + uartAttach(); + ets_install_uart_printf(); + + memset(&_bss_start, 0, (&_bss_end - &_bss_start) * sizeof(_bss_start)); + + // Initialize heap allocator + heap_alloc_caps_init(); + + ESP_EARLY_LOGI(TAG, "Pro cpu up."); + +#ifndef CONFIG_FREERTOS_UNICORE + ESP_EARLY_LOGI(TAG, "Starting app cpu, entry point is %p", call_user_start_cpu1); + + SET_PERI_REG_MASK(APPCPU_CTRL_REG_B, DPORT_APPCPU_CLKGATE_EN); + CLEAR_PERI_REG_MASK(APPCPU_CTRL_REG_C, DPORT_APPCPU_RUNSTALL); + SET_PERI_REG_MASK(APPCPU_CTRL_REG_A, DPORT_APPCPU_RESETTING); + CLEAR_PERI_REG_MASK(APPCPU_CTRL_REG_A, DPORT_APPCPU_RESETTING); + ets_set_appcpu_boot_addr((uint32_t)call_user_start_cpu1); + + while (!app_cpu_started) { + ets_delay_us(100); + } +#else + ESP_EARLY_LOGI(TAG, "Single core mode"); + CLEAR_PERI_REG_MASK(APPCPU_CTRL_REG_B, DPORT_APPCPU_CLKGATE_EN); +#endif + ESP_EARLY_LOGI(TAG, "Pro cpu start user code"); + user_start_cpu0(); } -extern esp_err_t app_main(void *ctx); -void user_start_cpu0(void) { +void IRAM_ATTR call_user_start_cpu1() +{ + asm volatile (\ + "wsr %0, vecbase\n" \ + ::"r"(&_init_start)); + + cpu_configure_region_protection(); + + ESP_EARLY_LOGI(TAG, "App cpu up."); + app_cpu_started = 1; + user_start_cpu1(); +} + +void IRAM_ATTR user_start_cpu1(void) +{ + // Wait for FreeRTOS initialization to finish on PRO CPU + while (port_xSchedulerRunning[0] == 0) { + ; + } + ESP_LOGI(TAG, "Starting scheduler on APP CPU."); + xPortStartScheduler(); +} + +static void do_global_ctors(void) +{ + void (**p)(void); + for (p = &__init_array_start; p != &__init_array_end; ++p) { + (*p)(); + } +} + +void user_start_cpu0(void) +{ ets_setup_syscalls(); - do_global_ctors(); - esp_ipc_init(); - spi_flash_init(); + do_global_ctors(); + esp_ipc_init(); + spi_flash_init(); #if CONFIG_WIFI_ENABLED esp_err_t ret = nvs_flash_init(5, 3); @@ -216,20 +153,18 @@ void user_start_cpu0(void) { } system_init(); - esp_event_init(NULL, NULL); - tcpip_adapter_init(); #endif #if CONFIG_WIFI_ENABLED && CONFIG_WIFI_AUTO_STARTUP #include "esp_wifi.h" - esp_wifi_startup(app_main, NULL); + esp_wifi_startup(app_main, NULL); #else - app_main(NULL); + app_main(NULL); #endif - ESP_LOGI(TAG, "Starting scheduler on PRO CPU."); - vTaskStartScheduler(); + ESP_LOGI(TAG, "Starting scheduler on PRO CPU."); + vTaskStartScheduler(); } diff --git a/components/esp32/include/soc/cpu.h b/components/esp32/include/soc/cpu.h index fdcf62190..b45f742ce 100644 --- a/components/esp32/include/soc/cpu.h +++ b/components/esp32/include/soc/cpu.h @@ -33,4 +33,39 @@ static inline bool cpu_in_interrupt_context(void) return (ps & PS_UM) == 0; } +/* Functions to set page attributes for Region Protection option in the CPU. + * See Xtensa ISA Reference manual for explanation of arguments (section 4.6.3.2). + */ + +static inline void cpu_write_dtlb(uint32_t vpn, unsigned attr) +{ + asm volatile ("wdtlb %1, %0; dsync\n" :: "r" (vpn), "r" (attr)); +} + + +static inline void cpu_write_itlb(unsigned vpn, unsigned attr) +{ + asm volatile ("witlb %1, %0; isync\n" :: "r" (vpn), "r" (attr)); +} + +/* Make page 0 access raise an exception. + * Also protect some other unused pages so we can catch weirdness. + * Useful attribute values: + * 0 — cached, RW + * 2 — bypass cache, RWX (default value after CPU reset) + * 15 — no access, raise exception + */ + +static inline void cpu_configure_region_protection() +{ + const uint32_t pages_to_protect[] = {0x00000000, 0x80000000, 0xa0000000, 0xc0000000, 0xe0000000}; + for (int i = 0; i < sizeof(pages_to_protect)/sizeof(pages_to_protect[0]); ++i) { + cpu_write_dtlb(pages_to_protect[i], 0xf); + cpu_write_itlb(pages_to_protect[i], 0xf); + } + cpu_write_dtlb(0x20000000, 0); + cpu_write_itlb(0x20000000, 0); +} + + #endif