diff --git a/components/bootloader/subproject/main/Makefile.projbuild b/components/bootloader/subproject/main/Makefile.projbuild deleted file mode 100644 index 92ecc49340..0000000000 --- a/components/bootloader/subproject/main/Makefile.projbuild +++ /dev/null @@ -1,4 +0,0 @@ -# Submodules normally added in component.mk, but fully qualified -# paths can be added at this level (we need binary librtc to be -# available to link bootloader). -COMPONENT_SUBMODULES += $(IDF_PATH)/components/esp_wifi/lib diff --git a/components/bootloader/subproject/main/bootloader_start.c b/components/bootloader/subproject/main/bootloader_start.c index ac679002db..29c61e43f7 100644 --- a/components/bootloader/subproject/main/bootloader_start.c +++ b/components/bootloader/subproject/main/bootloader_start.c @@ -1,4 +1,4 @@ -// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -11,30 +11,17 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -#include -#include #include #include "esp_log.h" -#include "bootloader_config.h" #include "bootloader_init.h" #include "bootloader_utility.h" #include "bootloader_common.h" -#include "sdkconfig.h" -#include "esp_image_format.h" -#if CONFIG_IDF_TARGET_ESP32 -#include "esp32/rom/gpio.h" -#include "esp32/rom/rtc.h" -#include "esp32/rom/spi_flash.h" -#elif CONFIG_IDF_TARGET_ESP32S2BETA -#include "esp32s2beta/rom/gpio.h" -#include "esp32s2beta/rom/rtc.h" -#include "esp32s2beta/rom/spi_flash.h" -#endif static const char *TAG = "boot"; -static int select_partition_number (bootloader_state_t *bs); +static int select_partition_number(bootloader_state_t *bs); static int selected_boot_partition(const bootloader_state_t *bs); + /* * We arrive here after the ROM bootloader finished loading this second stage bootloader from flash. * The hardware is mostly uninitialized, flash cache is down and the app CPU is in reset. @@ -56,7 +43,7 @@ void __attribute__((noreturn)) call_start_cpu0(void) #endif // 2. Select the number of boot partition - bootloader_state_t bs = { 0 }; + bootloader_state_t bs = {0}; int boot_index = select_partition_number(&bs); if (boot_index == INVALID_INDEX) { bootloader_reset(); @@ -67,7 +54,7 @@ void __attribute__((noreturn)) call_start_cpu0(void) } // Select the number of boot partition -static int select_partition_number (bootloader_state_t *bs) +static int select_partition_number(bootloader_state_t *bs) { // 1. Load partition table if (!bootloader_utility_load_partition_table(bs)) { @@ -89,7 +76,7 @@ static int selected_boot_partition(const bootloader_state_t *bs) if (boot_index == INVALID_INDEX) { return boot_index; // Unrecoverable failure (not due to corrupt ota data or bad partition contents) } - if (rtc_get_reset_reason(0) != DEEPSLEEP_RESET) { + if (bootloader_common_get_reset_reason(0) != DEEPSLEEP_RESET) { // Factory firmware. #ifdef CONFIG_BOOTLOADER_FACTORY_RESET if (bootloader_common_check_long_hold_gpio(CONFIG_BOOTLOADER_NUM_PIN_FACTORY_RESET, CONFIG_BOOTLOADER_HOLD_TIME_GPIO) == 1) { @@ -128,7 +115,7 @@ static int selected_boot_partition(const bootloader_state_t *bs) } // Return global reent struct if any newlib functions are linked to bootloader -struct _reent* __getreent(void) { +struct _reent *__getreent(void) +{ return _GLOBAL_REENT; } - diff --git a/components/bootloader_support/include/bootloader_common.h b/components/bootloader_support/include/bootloader_common.h index 7ed874ad31..3b2caf469f 100644 --- a/components/bootloader_support/include/bootloader_common.h +++ b/components/bootloader_support/include/bootloader_common.h @@ -16,6 +16,12 @@ #include "esp_flash_partitions.h" #include "esp_image_format.h" #include "esp_app_format.h" +// RESET_REASON is declared in rom/rtc.h +#if CONFIG_IDF_TARGET_ESP32 +#include "esp32/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32S2BETA +#include "esp32s2beta/rom/rtc.h" +#endif #ifdef __cplusplus extern "C" { @@ -161,6 +167,14 @@ esp_err_t bootloader_common_get_partition_description(const esp_partition_pos_t */ uint8_t bootloader_common_get_chip_revision(void); +/** + * @brief Query reset reason + * + * @param cpu_no CPU number + * @return reset reason enumeration + */ +RESET_REASON bootloader_common_get_reset_reason(int cpu_no); + /** * @brief Check if the image (bootloader and application) has valid chip ID and revision * diff --git a/components/bootloader_support/include_bootloader/bootloader_flash.h b/components/bootloader_support/include_bootloader/bootloader_flash.h index 18baad594b..12bef10b36 100644 --- a/components/bootloader_support/include_bootloader/bootloader_flash.h +++ b/components/bootloader_support/include_bootloader/bootloader_flash.h @@ -18,7 +18,6 @@ #include #include #include -#include "esp_spi_flash.h" #define FLASH_SECTOR_SIZE 0x1000 #define FLASH_BLOCK_SIZE 0x10000 diff --git a/components/bootloader_support/include_bootloader/bootloader_init.h b/components/bootloader_support/include_bootloader/bootloader_init.h index 9c1f8719af..0d5c95f3a2 100644 --- a/components/bootloader_support/include_bootloader/bootloader_init.h +++ b/components/bootloader_support/include_bootloader/bootloader_init.h @@ -14,6 +14,37 @@ #pragma once #include "esp_err.h" +#include "esp_image_format.h" + +/**@{*/ +/** + * @brief labels from bootloader linker script: bootloader.ld + * + */ +extern int _bss_start; +extern int _bss_end; +extern int _data_start; +extern int _data_end; +/**@}*/ + +/** + * @brief bootloader image header + * + */ +extern esp_image_header_t bootloader_image_hdr; + +/**@{*/ +/** + * @brief Common initialization steps that are applied to all targets. + * + */ +esp_err_t bootloader_read_bootloader_header(void); +esp_err_t bootloader_check_bootloader_validity(void); +void bootloader_clear_bss_section(void); +void bootloader_config_wdt(void); +void bootloader_enable_random(void); +void bootloader_print_banner(void); +/**@}*/ /* @brief Prepares hardware for work. * diff --git a/components/bootloader_support/src/bootloader_common.c b/components/bootloader_support/src/bootloader_common.c index a6eec3cfc0..d3db882434 100644 --- a/components/bootloader_support/src/bootloader_common.c +++ b/components/bootloader_support/src/bootloader_common.c @@ -293,11 +293,16 @@ esp_err_t bootloader_common_check_chip_validity(const esp_image_header_t* img_hd ESP_LOGE(TAG, "can't run on lower chip revision, expected %d, found %d", revision, img_hdr->min_chip_rev); err = ESP_FAIL; } else if (revision != img_hdr->min_chip_rev) { - ESP_LOGI(TAG, "chip revision: %d, min. %s chip revision: %d", revision, type == ESP_IMAGE_BOOTLOADER ? "bootloader" : "application", img_hdr->min_chip_rev); + ESP_LOGI(TAG, "min. %s chip revision: %d", type == ESP_IMAGE_BOOTLOADER ? "bootloader" : "application", img_hdr->min_chip_rev); } return err; } +RESET_REASON bootloader_common_get_reset_reason(int cpu_no) +{ + return rtc_get_reset_reason(cpu_no); +} + #if defined( CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP ) || defined( CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC ) rtc_retain_mem_t *const rtc_retain_mem = (rtc_retain_mem_t *)(SOC_RTC_DRAM_HIGH - sizeof(rtc_retain_mem_t)); diff --git a/components/bootloader_support/src/bootloader_init.c b/components/bootloader_support/src/bootloader_init.c index 5da6712e01..9cf02b02b1 100644 --- a/components/bootloader_support/src/bootloader_init.c +++ b/components/bootloader_support/src/bootloader_init.c @@ -1,4 +1,4 @@ -// Copyright 2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,179 +13,54 @@ // limitations under the License. #include #include -#include -#include - -#include "esp_attr.h" -#include "esp_log.h" - -#if CONFIG_IDF_TARGET_ESP32 -#include "esp32/rom/cache.h" -#include "esp32/rom/efuse.h" -#include "esp32/rom/ets_sys.h" -#include "esp32/rom/spi_flash.h" -#include "esp32/rom/crc.h" -#include "esp32/rom/rtc.h" -#include "esp32/rom/uart.h" -#include "esp32/rom/gpio.h" -#include "esp32/rom/secure_boot.h" -#elif CONFIG_IDF_TARGET_ESP32S2BETA -#include "esp32s2beta/rom/cache.h" -#include "esp32s2beta/rom/efuse.h" -#include "esp32s2beta/rom/ets_sys.h" -#include "esp32s2beta/rom/spi_flash.h" -#include "esp32s2beta/rom/crc.h" -#include "esp32s2beta/rom/rtc.h" -#include "esp32s2beta/rom/uart.h" -#include "esp32s2beta/rom/gpio.h" -#include "esp32s2beta/rom/secure_boot.h" -#else -#error "Unsupported IDF_TARGET" -#endif - -#include "soc/soc.h" -#include "soc/cpu.h" -#include "soc/rtc.h" -#include "soc/dport_reg.h" -#include "soc/gpio_periph.h" -#include "soc/efuse_periph.h" -#include "soc/rtc_periph.h" -#include "soc/timer_periph.h" -#include "soc/rtc_wdt.h" -#include "soc/spi_periph.h" -#if CONFIG_IDF_TARGET_ESP32S2BETA -#include "soc/spi_mem_reg.h" -#include "soc/extmem_reg.h" -#include "soc/assist_debug_reg.h" -#endif - #include "sdkconfig.h" -#include "esp_image_format.h" -#include "esp_secure_boot.h" -#include "esp_flash_encrypt.h" -#include "esp_flash_partitions.h" +#include "esp_log.h" +#include "bootloader_init.h" #include "bootloader_flash.h" +#include "bootloader_flash_config.h" #include "bootloader_random.h" -#include "bootloader_config.h" -#include "bootloader_common.h" #include "bootloader_clock.h" #include "bootloader_common.h" -#include "bootloader_flash_config.h" - -#include "flash_qio_mode.h" +#include "esp_flash_encrypt.h" #include "hal/timer_ll.h" +#include "soc/cpu.h" +#include "soc/rtc.h" +#include "soc/rtc_wdt.h" -extern int _bss_start; -extern int _bss_end; -extern int _data_start; -extern int _data_end; static const char *TAG = "boot"; -static esp_err_t bootloader_main(void); -static void print_flash_info(const esp_image_header_t* pfhdr); -static void update_flash_config(const esp_image_header_t* pfhdr); -static void bootloader_init_flash_configure(const esp_image_header_t* pfhdr); -static void uart_console_configure(void); -static void wdt_reset_check(void); +esp_image_header_t bootloader_image_hdr; - -esp_err_t bootloader_init(void) +void bootloader_clear_bss_section(void) { - cpu_configure_region_protection(); - cpu_init_memctl(); - - /* Sanity check that static RAM is after the stack */ -#ifndef NDEBUG - { - assert(&_bss_start <= &_bss_end); - assert(&_data_start <= &_data_end); -#if CONFIG_IDF_TARGET_ESP32 - int *sp = get_sp(); - assert(sp < &_bss_start); - assert(sp < &_data_start); -#endif - } -#endif - - //Clear bss memset(&_bss_start, 0, (&_bss_end - &_bss_start) * sizeof(_bss_start)); +} - /* completely reset MMU for both CPUs - (in case serial bootloader was running) */ -#if CONFIG_IDF_TARGET_ESP32 - Cache_Read_Disable(0); - Cache_Read_Disable(1); - Cache_Flush(0); - Cache_Flush(1); - mmu_init(0); - DPORT_REG_SET_BIT(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MMU_IA_CLR); - mmu_init(1); - DPORT_REG_CLR_BIT(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MMU_IA_CLR); -#elif CONFIG_IDF_TARGET_ESP32S2BETA - //TODO, save the autoload value - Cache_Suspend_ICache(); - Cache_Invalidate_ICache_All(); - Cache_MMU_Init(); -#endif - /* (above steps probably unnecessary for most serial bootloader - usage, all that's absolutely needed is that we unmask DROM0 - cache on the following two lines - normal ROM boot exits with - DROM0 cache unmasked, but serial bootloader exits with it - masked. However can't hurt to be thorough and reset - everything.) - - The lines which manipulate DPORT_APP_CACHE_MMU_IA_CLR bit are - necessary to work around a hardware bug. - */ -#if CONFIG_IDF_TARGET_ESP32 - DPORT_REG_CLR_BIT(DPORT_PRO_CACHE_CTRL1_REG, DPORT_PRO_CACHE_MASK_DROM0); - DPORT_REG_CLR_BIT(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MASK_DROM0); -#elif CONFIG_IDF_TARGET_ESP32S2BETA - DPORT_REG_CLR_BIT(DPORT_PRO_ICACHE_CTRL1_REG, DPORT_PRO_ICACHE_MASK_DROM0); -#endif - if (bootloader_main() != ESP_OK) { +esp_err_t bootloader_read_bootloader_header(void) +{ + /* load bootloader image header */ + if (bootloader_flash_read(ESP_BOOTLOADER_OFFSET, &bootloader_image_hdr, sizeof(esp_image_header_t), true) != ESP_OK) { + ESP_LOGE(TAG, "failed to load bootloader image header!"); return ESP_FAIL; } return ESP_OK; } -static esp_err_t bootloader_main(void) +esp_err_t bootloader_check_bootloader_validity(void) { - bootloader_common_vddsdio_configure(); - /* Read and keep flash ID, for further use. */ - g_rom_flashchip.device_id = bootloader_read_flash_id(); - esp_image_header_t fhdr; - if (bootloader_flash_read(ESP_BOOTLOADER_OFFSET, &fhdr, sizeof(esp_image_header_t), true) != ESP_OK) { - ESP_LOGE(TAG, "failed to load bootloader header!"); - return ESP_FAIL; - } - - /* Check chip ID and minimum chip revision that supported by this image */ + /* read chip revision from efuse */ uint8_t revision = bootloader_common_get_chip_revision(); - ESP_LOGI(TAG, "Chip Revision: %d", revision); - if (bootloader_common_check_chip_validity(&fhdr, ESP_IMAGE_BOOTLOADER) != ESP_OK) { + ESP_LOGI(TAG, "chip revision: %d", revision); + /* compare with the one set in bootloader image header */ + if (bootloader_common_check_chip_validity(&bootloader_image_hdr, ESP_IMAGE_BOOTLOADER) != ESP_OK) { return ESP_FAIL; } + return ESP_OK; +} - bootloader_init_flash_configure(&fhdr); - -#ifdef CONFIG_IDF_TARGET_ESP32 - int rated_freq = bootloader_clock_get_rated_freq_mhz(); - if (rated_freq < CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ) { - ESP_LOGE(TAG, "Chip CPU frequency rated for %dMHz, configured for %dMHz. Modify CPU frequency in menuconfig", - rated_freq, CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ); - return ESP_FAIL; - } -#endif - - bootloader_clock_configure(); - uart_console_configure(); - wdt_reset_check(); - ESP_LOGI(TAG, "ESP-IDF %s 2nd stage bootloader", IDF_VER); - - ESP_LOGI(TAG, "compile time " __TIME__ ); - +void bootloader_config_wdt(void) +{ #ifdef CONFIG_BOOTLOADER_WDT_ENABLE ESP_LOGD(TAG, "Enabling RTCWDT(%d ms)", CONFIG_BOOTLOADER_WDT_TIME_MS); rtc_wdt_protect_off(); @@ -196,343 +71,28 @@ static esp_err_t bootloader_main(void) rtc_wdt_set_time(RTC_WDT_STAGE0, CONFIG_BOOTLOADER_WDT_TIME_MS); rtc_wdt_enable(); rtc_wdt_protect_on(); -#else - /* disable watch dog here */ +#else /* disable watch dog */ rtc_wdt_disable(); #endif timer_ll_wdt_set_protect(&TIMERG0, false); timer_ll_wdt_flashboot_en(&TIMERG0, false); +} -#ifndef CONFIG_SPI_FLASH_ROM_DRIVER_PATCH - const uint32_t spiconfig = ets_efuse_get_spiconfig(); - if (spiconfig != EFUSE_SPICONFIG_SPI_DEFAULTS && spiconfig != EFUSE_SPICONFIG_HSPI_DEFAULTS) { - ESP_LOGE(TAG, "SPI flash pins are overridden. \"Enable SPI flash ROM driver patched functions\" must be enabled in menuconfig"); - return ESP_FAIL; - } -#endif - - esp_rom_spiflash_unlock(); - +void bootloader_enable_random(void) +{ ESP_LOGI(TAG, "Enabling RNG early entropy source..."); bootloader_random_enable(); - -#if CONFIG_ESPTOOLPY_FLASHMODE_QIO || CONFIG_ESPTOOLPY_FLASHMODE_QOUT - bootloader_enable_qio_mode(); -#endif - - print_flash_info(&fhdr); - - update_flash_config(&fhdr); - return ESP_OK; } -static void update_flash_config(const esp_image_header_t *pfhdr) +void bootloader_print_banner(void) { - uint32_t size; - switch (pfhdr->spi_size) { - case ESP_IMAGE_FLASH_SIZE_1MB: - size = 1; - break; - case ESP_IMAGE_FLASH_SIZE_2MB: - size = 2; - break; - case ESP_IMAGE_FLASH_SIZE_4MB: - size = 4; - break; - case ESP_IMAGE_FLASH_SIZE_8MB: - size = 8; - break; - case ESP_IMAGE_FLASH_SIZE_16MB: - size = 16; - break; - default: - size = 2; - } -#if CONFIG_IDF_TARGET_ESP32 - Cache_Read_Disable(0); -#elif CONFIG_IDF_TARGET_ESP32S2BETA - uint32_t autoload = Cache_Suspend_ICache(); -#endif - // Set flash chip size - esp_rom_spiflash_config_param(g_rom_flashchip.device_id, size * 0x100000, 0x10000, 0x1000, 0x100, 0xffff); - // TODO: set mode - // TODO: set frequency -#if CONFIG_IDF_TARGET_ESP32 - Cache_Flush(0); - Cache_Read_Enable(0); -#elif CONFIG_IDF_TARGET_ESP32S2BETA - Cache_Resume_ICache(autoload); -#endif -} - -static void print_flash_info(const esp_image_header_t *phdr) -{ -#if (BOOT_LOG_LEVEL >= BOOT_LOG_LEVEL_NOTICE) - - ESP_LOGD(TAG, "magic %02x", phdr->magic ); - ESP_LOGD(TAG, "segments %02x", phdr->segment_count ); - ESP_LOGD(TAG, "spi_mode %02x", phdr->spi_mode ); - ESP_LOGD(TAG, "spi_speed %02x", phdr->spi_speed ); - ESP_LOGD(TAG, "spi_size %02x", phdr->spi_size ); - - const char *str; - switch ( phdr->spi_speed ) { - case ESP_IMAGE_SPI_SPEED_40M: - str = "40MHz"; - break; - case ESP_IMAGE_SPI_SPEED_26M: - str = "26.7MHz"; - break; - case ESP_IMAGE_SPI_SPEED_20M: - str = "20MHz"; - break; - case ESP_IMAGE_SPI_SPEED_80M: - str = "80MHz"; - break; - default: - str = "20MHz"; - break; - } - ESP_LOGI(TAG, "SPI Speed : %s", str ); - - /* SPI mode could have been set to QIO during boot already, - so test the SPI registers not the flash header */ -#if CONFIG_IDF_TARGET_ESP32 - uint32_t spi_ctrl = REG_READ(SPI_CTRL_REG(0)); - if (spi_ctrl & SPI_FREAD_QIO) { - str = "QIO"; - } else if (spi_ctrl & SPI_FREAD_QUAD) { - str = "QOUT"; - } else if (spi_ctrl & SPI_FREAD_DIO) { - str = "DIO"; - } else if (spi_ctrl & SPI_FREAD_DUAL) { - str = "DOUT"; - } else if (spi_ctrl & SPI_FASTRD_MODE) { - str = "FAST READ"; - } else { - str = "SLOW READ"; - } -#elif CONFIG_IDF_TARGET_ESP32S2BETA - uint32_t spi_ctrl = REG_READ(SPI_MEM_CTRL_REG(0)); - if (spi_ctrl & SPI_MEM_FREAD_QIO) { - str = "QIO"; - } else if (spi_ctrl & SPI_MEM_FREAD_QUAD) { - str = "QOUT"; - } else if (spi_ctrl & SPI_MEM_FREAD_DIO) { - str = "DIO"; - } else if (spi_ctrl & SPI_MEM_FREAD_DUAL) { - str = "DOUT"; - } else if (spi_ctrl & SPI_MEM_FASTRD_MODE) { - str = "FAST READ"; - } else { - str = "SLOW READ"; - } -#endif - ESP_LOGI(TAG, "SPI Mode : %s", str ); - - switch ( phdr->spi_size ) { - case ESP_IMAGE_FLASH_SIZE_1MB: - str = "1MB"; - break; - case ESP_IMAGE_FLASH_SIZE_2MB: - str = "2MB"; - break; - case ESP_IMAGE_FLASH_SIZE_4MB: - str = "4MB"; - break; - case ESP_IMAGE_FLASH_SIZE_8MB: - str = "8MB"; - break; - case ESP_IMAGE_FLASH_SIZE_16MB: - str = "16MB"; - break; - default: - str = "2MB"; - break; - } - ESP_LOGI(TAG, "SPI Flash Size : %s", str ); -#endif -} - -static void IRAM_ATTR bootloader_init_flash_configure(const esp_image_header_t* pfhdr) -{ - bootloader_flash_gpio_config(pfhdr); - bootloader_flash_dummy_config(pfhdr); - bootloader_flash_cs_timing_config(); -} - -static void uart_console_configure(void) -{ -#if CONFIG_ESP_CONSOLE_UART_NONE - ets_install_putc1(NULL); - ets_install_putc2(NULL); -#else // CONFIG_ESP_CONSOLE_UART_NONE - const int uart_num = CONFIG_ESP_CONSOLE_UART_NUM; - - uartAttach(); - ets_install_uart_printf(); - - // Wait for UART FIFO to be empty. - uart_tx_wait_idle(0); - -#if CONFIG_ESP_CONSOLE_UART_CUSTOM - // Some constants to make the following code less upper-case - const int uart_tx_gpio = CONFIG_ESP_CONSOLE_UART_TX_GPIO; - const int uart_rx_gpio = CONFIG_ESP_CONSOLE_UART_RX_GPIO; - // Switch to the new UART (this just changes UART number used for - // ets_printf in ROM code). - uart_tx_switch(uart_num); - // If console is attached to UART1 or if non-default pins are used, - // need to reconfigure pins using GPIO matrix - if (uart_num != 0 || uart_tx_gpio != 1 || uart_rx_gpio != 3) { - // Change pin mode for GPIO1/3 from UART to GPIO - PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD_GPIO3); - PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD_GPIO1); - // Route GPIO signals to/from pins - // (arrays should be optimized away by the compiler) - const uint32_t tx_idx_list[3] = { U0TXD_OUT_IDX, U1TXD_OUT_IDX, U2TXD_OUT_IDX }; - const uint32_t rx_idx_list[3] = { U0RXD_IN_IDX, U1RXD_IN_IDX, U2RXD_IN_IDX }; - const uint32_t uart_reset[3] = { DPORT_UART_RST, DPORT_UART1_RST, DPORT_UART2_RST }; - const uint32_t tx_idx = tx_idx_list[uart_num]; - const uint32_t rx_idx = rx_idx_list[uart_num]; - - PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[uart_rx_gpio]); - gpio_pad_pullup(uart_rx_gpio); - - gpio_matrix_out(uart_tx_gpio, tx_idx, 0, 0); - gpio_matrix_in(uart_rx_gpio, rx_idx, 0); - - DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, uart_reset[uart_num]); - DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, uart_reset[uart_num]); - } -#endif // CONFIG_ESP_CONSOLE_UART_CUSTOM - - // Set configured UART console baud rate - const int uart_baud = CONFIG_ESP_CONSOLE_UART_BAUDRATE; - uart_div_modify(uart_num, (rtc_clk_apb_freq_get() << 4) / uart_baud); - -#endif // CONFIG_ESP_CONSOLE_UART_NONE -} - -static void wdt_reset_cpu0_info_enable(void) -{ -#if CONFIG_IDF_TARGET_ESP32 - //We do not reset core1 info here because it didn't work before cpu1 was up. So we put it into call_start_cpu1. - DPORT_REG_SET_BIT(DPORT_PRO_CPU_RECORD_CTRL_REG, DPORT_PRO_CPU_PDEBUG_ENABLE | DPORT_PRO_CPU_RECORD_ENABLE); - DPORT_REG_CLR_BIT(DPORT_PRO_CPU_RECORD_CTRL_REG, DPORT_PRO_CPU_RECORD_ENABLE); -#elif CONFIG_IDF_TARGET_ESP32S2BETA - DPORT_REG_SET_BIT(DPORT_PERI_CLK_EN_REG, DPORT_PERI_EN_ASSIST_DEBUG); - DPORT_REG_CLR_BIT(DPORT_PERI_RST_EN_REG, DPORT_PERI_EN_ASSIST_DEBUG); - REG_WRITE(ASSIST_DEBUG_PRO_PDEBUGENABLE, 1); - REG_WRITE(ASSIST_DEBUG_PRO_RCD_RECORDING, 1); -#endif -} - -static void wdt_reset_info_dump(int cpu) -{ - uint32_t inst = 0, pid = 0, stat = 0, data = 0, pc = 0, - lsstat = 0, lsaddr = 0, lsdata = 0, dstat = 0; - const char *cpu_name = cpu ? "APP" : "PRO"; - -#if CONFIG_IDF_TARGET_ESP32 - if (cpu == 0) { - stat = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_STATUS_REG); - pid = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PID_REG); - inst = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGINST_REG); - dstat = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGSTATUS_REG); - data = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGDATA_REG); - pc = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGPC_REG); - lsstat = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGLS0STAT_REG); - lsaddr = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGLS0ADDR_REG); - lsdata = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGLS0DATA_REG); - } else { - stat = DPORT_REG_READ(DPORT_APP_CPU_RECORD_STATUS_REG); - pid = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PID_REG); - inst = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGINST_REG); - dstat = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGSTATUS_REG); - data = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGDATA_REG); - pc = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGPC_REG); - lsstat = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGLS0STAT_REG); - lsaddr = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGLS0ADDR_REG); - lsdata = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGLS0DATA_REG); - } -#elif CONFIG_IDF_TARGET_ESP32S2BETA - stat = 0xdeadbeef; - pid = 0; - inst = REG_READ(ASSIST_DEBUG_PRO_RCD_PDEBUGINST); - dstat = REG_READ(ASSIST_DEBUG_PRO_RCD_PDEBUGSTATUS); - data = REG_READ(ASSIST_DEBUG_PRO_RCD_PDEBUGDATA); - pc = REG_READ(ASSIST_DEBUG_PRO_RCD_PDEBUGPC); - lsstat = REG_READ(ASSIST_DEBUG_PRO_RCD_PDEBUGLS0STAT); - lsaddr = REG_READ(ASSIST_DEBUG_PRO_RCD_PDEBUGLS0ADDR); - lsdata = REG_READ(ASSIST_DEBUG_PRO_RCD_PDEBUGLS0DATA); -#endif - - if (DPORT_RECORD_PDEBUGINST_SZ(inst) == 0 && - DPORT_RECORD_PDEBUGSTATUS_BBCAUSE(dstat) == DPORT_RECORD_PDEBUGSTATUS_BBCAUSE_WAITI) { - ESP_LOGW(TAG, "WDT reset info: %s CPU PC=0x%x (waiti mode)", cpu_name, pc); - } else { - ESP_LOGW(TAG, "WDT reset info: %s CPU PC=0x%x", cpu_name, pc); - } - ESP_LOGD(TAG, "WDT reset info: %s CPU STATUS 0x%08x", cpu_name, stat); - ESP_LOGD(TAG, "WDT reset info: %s CPU PID 0x%08x", cpu_name, pid); - ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGINST 0x%08x", cpu_name, inst); - ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGSTATUS 0x%08x", cpu_name, dstat); - ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGDATA 0x%08x", cpu_name, data); - ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGPC 0x%08x", cpu_name, pc); - ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGLS0STAT 0x%08x", cpu_name, lsstat); - ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGLS0ADDR 0x%08x", cpu_name, lsaddr); - ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGLS0DATA 0x%08x", cpu_name, lsdata); -} - -static void wdt_reset_check(void) -{ - int wdt_rst = 0; - RESET_REASON rst_reas[2]; - - rst_reas[0] = rtc_get_reset_reason(0); -#if CONFIG_IDF_TARGET_ESP32 - rst_reas[1] = rtc_get_reset_reason(1); - if (rst_reas[0] == RTCWDT_SYS_RESET || rst_reas[0] == TG0WDT_SYS_RESET || rst_reas[0] == TG1WDT_SYS_RESET || - rst_reas[0] == TGWDT_CPU_RESET || rst_reas[0] == RTCWDT_CPU_RESET) { - ESP_LOGW(TAG, "PRO CPU has been reset by WDT."); - wdt_rst = 1; - } - if (rst_reas[1] == RTCWDT_SYS_RESET || rst_reas[1] == TG0WDT_SYS_RESET || rst_reas[1] == TG1WDT_SYS_RESET || - rst_reas[1] == TGWDT_CPU_RESET || rst_reas[1] == RTCWDT_CPU_RESET) { - ESP_LOGW(TAG, "APP CPU has been reset by WDT."); - wdt_rst = 1; - } -#elif CONFIG_IDF_TARGET_ESP32S2BETA - if (rst_reas[0] == RTCWDT_SYS_RESET || rst_reas[0] == TG0WDT_SYS_RESET || rst_reas[0] == TG1WDT_SYS_RESET || - rst_reas[0] == TG0WDT_CPU_RESET || rst_reas[0] == TG1WDT_CPU_RESET || rst_reas[0] == RTCWDT_CPU_RESET) { - ESP_LOGW(TAG, "PRO CPU has been reset by WDT."); - wdt_rst = 1; - } -#endif - if (wdt_rst) { - // if reset by WDT dump info from trace port - wdt_reset_info_dump(0); -#if CONFIG_IDF_TARGET_ESP32 - wdt_reset_info_dump(1); -#endif - } - wdt_reset_cpu0_info_enable(); + ESP_LOGI(TAG, "ESP-IDF %s 2nd stage bootloader", IDF_VER); + ESP_LOGI(TAG, "compile time " __TIME__); } void __assert_func(const char *file, int line, const char *func, const char *expr) { ESP_LOGE(TAG, "Assert failed in %s, %s:%d (%s)", func, file, line, expr); - while (1) {} -} - -void abort(void) -{ -#if !(CONFIG_ESP32_PANIC_SILENT_REBOOT || CONFIG_ESP32S2_PANIC_SILENT_REBOOT) - ets_printf("abort() was called at PC 0x%08x\r\n", (intptr_t)__builtin_return_address(0) - 3); -#endif - if (esp_cpu_in_ocd_debug_mode()) { - __asm__ ("break 0,0"); + while (1) { } - while (1) {} } diff --git a/components/bootloader_support/src/esp32/bootloader_esp32.c b/components/bootloader_support/src/esp32/bootloader_esp32.c index 7e9cba9130..4be56fe065 100644 --- a/components/bootloader_support/src/esp32/bootloader_esp32.c +++ b/components/bootloader_support/src/esp32/bootloader_esp32.c @@ -11,15 +11,35 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. - -#include "bootloader_common.h" +#include #include "sdkconfig.h" +#include "esp_attr.h" +#include "esp_log.h" +#include "esp_image_format.h" +#include "flash_qio_mode.h" + +#include "bootloader_init.h" +#include "bootloader_clock.h" +#include "bootloader_common.h" +#include "bootloader_flash_config.h" + +#include "soc/cpu.h" +#include "soc/dport_reg.h" #include "soc/efuse_reg.h" #include "soc/gpio_sig_map.h" #include "soc/io_mux_reg.h" +#include "soc/rtc.h" +#include "soc/spi_periph.h" + +#include "esp32/rom/cache.h" #include "esp32/rom/efuse.h" +#include "esp32/rom/ets_sys.h" #include "esp32/rom/gpio.h" #include "esp32/rom/spi_flash.h" +#include "esp32/rom/rtc.h" +#include "esp32/rom/uart.h" + +static const char *TAG = "boot.esp32"; #define FLASH_CLK_IO SPI_CLK_GPIO_NUM #define FLASH_CS_IO SPI_CS0_GPIO_NUM @@ -71,7 +91,7 @@ void bootloader_configure_spi_pins(int drv) PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK); SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S); - #if CONFIG_SPIRAM_TYPE_ESPPSRAM32 || CONFIG_SPIRAM_TYPE_ESPPSRAM64 +#if CONFIG_SPIRAM_TYPE_ESPPSRAM32 || CONFIG_SPIRAM_TYPE_ESPPSRAM64 uint32_t flash_id = g_rom_flashchip.device_id; if (flash_id == FLASH_ID_GD25LQ32C) { // Set drive ability for 1.8v flash in 80Mhz. @@ -82,7 +102,379 @@ void bootloader_configure_spi_pins(int drv) SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CMD_U, FUN_DRV, 3, FUN_DRV_S); SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, 3, FUN_DRV_S); } - #endif +#endif } } } + +static void bootloader_reset_mmu(void) +{ + /* completely reset MMU in case serial bootloader was running */ + Cache_Read_Disable(0); +#if !CONFIG_FREERTOS_UNICORE + Cache_Read_Disable(1); +#endif + Cache_Flush(0); +#if !CONFIG_FREERTOS_UNICORE + Cache_Flush(1); +#endif + mmu_init(0); +#if !CONFIG_FREERTOS_UNICORE + /* The lines which manipulate DPORT_APP_CACHE_MMU_IA_CLR bit are + necessary to work around a hardware bug. */ + DPORT_REG_SET_BIT(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MMU_IA_CLR); + mmu_init(1); + DPORT_REG_CLR_BIT(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MMU_IA_CLR); +#endif + + /* normal ROM boot exits with DROM0 cache unmasked, + but serial bootloader exits with it masked. */ + DPORT_REG_CLR_BIT(DPORT_PRO_CACHE_CTRL1_REG, DPORT_PRO_CACHE_MASK_DROM0); +#if !CONFIG_FREERTOS_UNICORE + DPORT_REG_CLR_BIT(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MASK_DROM0); +#endif +} + +static esp_err_t bootloader_check_rated_cpu_clock(void) +{ + int rated_freq = bootloader_clock_get_rated_freq_mhz(); + if (rated_freq < CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ) { + ESP_LOGE(TAG, "Chip CPU frequency rated for %dMHz, configured for %dMHz. Modify CPU frequency in menuconfig", + rated_freq, CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ); + return ESP_FAIL; + } + return ESP_OK; +} + +static void update_flash_config(const esp_image_header_t *bootloader_hdr) +{ + uint32_t size; + switch (bootloader_hdr->spi_size) { + case ESP_IMAGE_FLASH_SIZE_1MB: + size = 1; + break; + case ESP_IMAGE_FLASH_SIZE_2MB: + size = 2; + break; + case ESP_IMAGE_FLASH_SIZE_4MB: + size = 4; + break; + case ESP_IMAGE_FLASH_SIZE_8MB: + size = 8; + break; + case ESP_IMAGE_FLASH_SIZE_16MB: + size = 16; + break; + default: + size = 2; + } + Cache_Read_Disable(0); + // Set flash chip size + esp_rom_spiflash_config_param(g_rom_flashchip.device_id, size * 0x100000, 0x10000, 0x1000, 0x100, 0xffff); + // TODO: set mode + // TODO: set frequency + Cache_Flush(0); + Cache_Read_Enable(0); +} + +static void print_flash_info(const esp_image_header_t *bootloader_hdr) +{ + ESP_LOGD(TAG, "magic %02x", bootloader_hdr->magic); + ESP_LOGD(TAG, "segments %02x", bootloader_hdr->segment_count); + ESP_LOGD(TAG, "spi_mode %02x", bootloader_hdr->spi_mode); + ESP_LOGD(TAG, "spi_speed %02x", bootloader_hdr->spi_speed); + ESP_LOGD(TAG, "spi_size %02x", bootloader_hdr->spi_size); + + const char *str; + switch (bootloader_hdr->spi_speed) { + case ESP_IMAGE_SPI_SPEED_40M: + str = "40MHz"; + break; + case ESP_IMAGE_SPI_SPEED_26M: + str = "26.7MHz"; + break; + case ESP_IMAGE_SPI_SPEED_20M: + str = "20MHz"; + break; + case ESP_IMAGE_SPI_SPEED_80M: + str = "80MHz"; + break; + default: + str = "20MHz"; + break; + } + ESP_LOGI(TAG, "SPI Speed : %s", str); + + /* SPI mode could have been set to QIO during boot already, + so test the SPI registers not the flash header */ + uint32_t spi_ctrl = REG_READ(SPI_CTRL_REG(0)); + if (spi_ctrl & SPI_FREAD_QIO) { + str = "QIO"; + } else if (spi_ctrl & SPI_FREAD_QUAD) { + str = "QOUT"; + } else if (spi_ctrl & SPI_FREAD_DIO) { + str = "DIO"; + } else if (spi_ctrl & SPI_FREAD_DUAL) { + str = "DOUT"; + } else if (spi_ctrl & SPI_FASTRD_MODE) { + str = "FAST READ"; + } else { + str = "SLOW READ"; + } + ESP_LOGI(TAG, "SPI Mode : %s", str); + + switch (bootloader_hdr->spi_size) { + case ESP_IMAGE_FLASH_SIZE_1MB: + str = "1MB"; + break; + case ESP_IMAGE_FLASH_SIZE_2MB: + str = "2MB"; + break; + case ESP_IMAGE_FLASH_SIZE_4MB: + str = "4MB"; + break; + case ESP_IMAGE_FLASH_SIZE_8MB: + str = "8MB"; + break; + case ESP_IMAGE_FLASH_SIZE_16MB: + str = "16MB"; + break; + default: + str = "2MB"; + break; + } + ESP_LOGI(TAG, "SPI Flash Size : %s", str); +} + +static void IRAM_ATTR bootloader_init_flash_configure(void) +{ + bootloader_flash_gpio_config(&bootloader_image_hdr); + bootloader_flash_dummy_config(&bootloader_image_hdr); + bootloader_flash_cs_timing_config(); +} + +static esp_err_t bootloader_init_spi_flash(void) +{ + bootloader_init_flash_configure(); +#ifndef CONFIG_SPI_FLASH_ROM_DRIVER_PATCH + const uint32_t spiconfig = ets_efuse_get_spiconfig(); + if (spiconfig != EFUSE_SPICONFIG_SPI_DEFAULTS && spiconfig != EFUSE_SPICONFIG_HSPI_DEFAULTS) { + ESP_LOGE(TAG, "SPI flash pins are overridden. Enable CONFIG_SPI_FLASH_ROM_DRIVER_PATCH in menuconfig"); + return ESP_FAIL; + } +#endif + + esp_rom_spiflash_unlock(); + +#if CONFIG_ESPTOOLPY_FLASHMODE_QIO || CONFIG_ESPTOOLPY_FLASHMODE_QOUT + bootloader_enable_qio_mode(); +#endif + + print_flash_info(&bootloader_image_hdr); + update_flash_config(&bootloader_image_hdr); + return ESP_OK; +} + +static void bootloader_init_uart_console(void) +{ +#if CONFIG_ESP_CONSOLE_UART_NONE + ets_install_putc1(NULL); + ets_install_putc2(NULL); +#else // CONFIG_ESP_CONSOLE_UART_NONE + const int uart_num = CONFIG_ESP_CONSOLE_UART_NUM; + + uartAttach(); + ets_install_uart_printf(); + + // Wait for UART FIFO to be empty. + uart_tx_wait_idle(0); + +#if CONFIG_ESP_CONSOLE_UART_CUSTOM + // Some constants to make the following code less upper-case + const int uart_tx_gpio = CONFIG_ESP_CONSOLE_UART_TX_GPIO; + const int uart_rx_gpio = CONFIG_ESP_CONSOLE_UART_RX_GPIO; + // Switch to the new UART (this just changes UART number used for + // ets_printf in ROM code). + uart_tx_switch(uart_num); + // If console is attached to UART1 or if non-default pins are used, + // need to reconfigure pins using GPIO matrix + if (uart_num != 0 || uart_tx_gpio != 1 || uart_rx_gpio != 3) { + // Change pin mode for GPIO1/3 from UART to GPIO + PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD_GPIO3); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD_GPIO1); + // Route GPIO signals to/from pins + // (arrays should be optimized away by the compiler) + const uint32_t tx_idx_list[3] = {U0TXD_OUT_IDX, U1TXD_OUT_IDX, U2TXD_OUT_IDX}; + const uint32_t rx_idx_list[3] = {U0RXD_IN_IDX, U1RXD_IN_IDX, U2RXD_IN_IDX}; + const uint32_t uart_reset[3] = {DPORT_UART_RST, DPORT_UART1_RST, DPORT_UART2_RST}; + const uint32_t tx_idx = tx_idx_list[uart_num]; + const uint32_t rx_idx = rx_idx_list[uart_num]; + + PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[uart_rx_gpio]); + gpio_pad_pullup(uart_rx_gpio); + + gpio_matrix_out(uart_tx_gpio, tx_idx, 0, 0); + gpio_matrix_in(uart_rx_gpio, rx_idx, 0); + + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, uart_reset[uart_num]); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, uart_reset[uart_num]); + } +#endif // CONFIG_ESP_CONSOLE_UART_CUSTOM + + // Set configured UART console baud rate + const int uart_baud = CONFIG_ESP_CONSOLE_UART_BAUDRATE; + uart_div_modify(uart_num, (rtc_clk_apb_freq_get() << 4) / uart_baud); + +#endif // CONFIG_ESP_CONSOLE_UART_NONE +} + +static void wdt_reset_cpu0_info_enable(void) +{ + //We do not reset core1 info here because it didn't work before cpu1 was up. So we put it into call_start_cpu1. + DPORT_REG_SET_BIT(DPORT_PRO_CPU_RECORD_CTRL_REG, DPORT_PRO_CPU_PDEBUG_ENABLE | DPORT_PRO_CPU_RECORD_ENABLE); + DPORT_REG_CLR_BIT(DPORT_PRO_CPU_RECORD_CTRL_REG, DPORT_PRO_CPU_RECORD_ENABLE); +} + +static void wdt_reset_info_dump(int cpu) +{ + uint32_t inst = 0, pid = 0, stat = 0, data = 0, pc = 0, + lsstat = 0, lsaddr = 0, lsdata = 0, dstat = 0; + const char *cpu_name = cpu ? "APP" : "PRO"; + + if (cpu == 0) { + stat = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_STATUS_REG); + pid = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PID_REG); + inst = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGINST_REG); + dstat = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGSTATUS_REG); + data = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGDATA_REG); + pc = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGPC_REG); + lsstat = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGLS0STAT_REG); + lsaddr = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGLS0ADDR_REG); + lsdata = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGLS0DATA_REG); + } else { +#if !CONFIG_FREERTOS_UNICORE + stat = DPORT_REG_READ(DPORT_APP_CPU_RECORD_STATUS_REG); + pid = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PID_REG); + inst = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGINST_REG); + dstat = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGSTATUS_REG); + data = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGDATA_REG); + pc = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGPC_REG); + lsstat = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGLS0STAT_REG); + lsaddr = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGLS0ADDR_REG); + lsdata = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGLS0DATA_REG); +#else + ESP_LOGE(TAG, "WDT reset info: &s CPU not support!\n", cpu_name); + return; +#endif + } + + if (DPORT_RECORD_PDEBUGINST_SZ(inst) == 0 && + DPORT_RECORD_PDEBUGSTATUS_BBCAUSE(dstat) == DPORT_RECORD_PDEBUGSTATUS_BBCAUSE_WAITI) { + ESP_LOGW(TAG, "WDT reset info: %s CPU PC=0x%x (waiti mode)", cpu_name, pc); + } else { + ESP_LOGW(TAG, "WDT reset info: %s CPU PC=0x%x", cpu_name, pc); + } + ESP_LOGD(TAG, "WDT reset info: %s CPU STATUS 0x%08x", cpu_name, stat); + ESP_LOGD(TAG, "WDT reset info: %s CPU PID 0x%08x", cpu_name, pid); + ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGINST 0x%08x", cpu_name, inst); + ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGSTATUS 0x%08x", cpu_name, dstat); + ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGDATA 0x%08x", cpu_name, data); + ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGPC 0x%08x", cpu_name, pc); + ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGLS0STAT 0x%08x", cpu_name, lsstat); + ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGLS0ADDR 0x%08x", cpu_name, lsaddr); + ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGLS0DATA 0x%08x", cpu_name, lsdata); +} + +static void bootloader_check_wdt_reset(void) +{ + int wdt_rst = 0; + RESET_REASON rst_reas[2]; + + rst_reas[0] = rtc_get_reset_reason(0); + rst_reas[1] = rtc_get_reset_reason(1); + if (rst_reas[0] == RTCWDT_SYS_RESET || rst_reas[0] == TG0WDT_SYS_RESET || rst_reas[0] == TG1WDT_SYS_RESET || + rst_reas[0] == TGWDT_CPU_RESET || rst_reas[0] == RTCWDT_CPU_RESET) { + ESP_LOGW(TAG, "PRO CPU has been reset by WDT."); + wdt_rst = 1; + } + if (rst_reas[1] == RTCWDT_SYS_RESET || rst_reas[1] == TG0WDT_SYS_RESET || rst_reas[1] == TG1WDT_SYS_RESET || + rst_reas[1] == TGWDT_CPU_RESET || rst_reas[1] == RTCWDT_CPU_RESET) { + ESP_LOGW(TAG, "APP CPU has been reset by WDT."); + wdt_rst = 1; + } + if (wdt_rst) { + // if reset by WDT dump info from trace port + wdt_reset_info_dump(0); + wdt_reset_info_dump(1); + } + wdt_reset_cpu0_info_enable(); +} + +void abort(void) +{ +#if !CONFIG_ESP32_PANIC_SILENT_REBOOT + ets_printf("abort() was called at PC 0x%08x\r\n", (intptr_t)__builtin_return_address(0) - 3); +#endif + if (esp_cpu_in_ocd_debug_mode()) { + __asm__("break 0,0"); + } + while (1) { + } +} + +esp_err_t bootloader_init(void) +{ + esp_err_t ret = ESP_OK; + // workaround for tensilica erratum572 + cpu_init_memctl(); + // protect memory region + cpu_configure_region_protection(); + // check that static RAM is after the stack +#ifndef NDEBUG + { + assert(&_bss_start <= &_bss_end); + assert(&_data_start <= &_data_end); + int *sp = get_sp(); + assert(sp < &_bss_start); + assert(sp < &_data_start); + } +#endif + // clear bss section + bootloader_clear_bss_section(); + // bootst up vddsdio + bootloader_common_vddsdio_configure(); + // reset MMU + bootloader_reset_mmu(); + // check rated CPU clock + if ((ret = bootloader_check_rated_cpu_clock()) != ESP_OK) { + goto err; + } + // config clock + bootloader_clock_configure(); + // initialize uart console, from now on, we can use esp_log + bootloader_init_uart_console(); + /* print 2nd bootloader banner */ + bootloader_print_banner(); + // update flash ID + bootloader_flash_update_id(); + // read bootloader header + if ((ret = bootloader_read_bootloader_header()) != ESP_OK) { + goto err; + } + // read chip revision and check if it's compatible to bootloader + if ((ret = bootloader_check_bootloader_validity()) != ESP_OK) { + goto err; + } + // initialize spi flash + if ((ret = bootloader_init_spi_flash()) != ESP_OK) { + goto err; + } + // check whether a WDT reset happend + bootloader_check_wdt_reset(); + // config WDT + bootloader_config_wdt(); + // enable RNG early entropy source + bootloader_enable_random(); +err: + return ret; +} diff --git a/components/bootloader_support/src/esp32/secure_boot_signatures.c b/components/bootloader_support/src/esp32/secure_boot_signatures.c index dbc32eab5f..6b54aa40c8 100644 --- a/components/bootloader_support/src/esp32/secure_boot_signatures.c +++ b/components/bootloader_support/src/esp32/secure_boot_signatures.c @@ -18,6 +18,7 @@ #include "esp_log.h" #include "esp_image_format.h" #include "esp_secure_boot.h" +#include "esp_spi_flash.h" #include "esp32/rom/sha.h" #include "uECC.h" diff --git a/components/bootloader_support/src/esp32s2beta/bootloader_esp32s2beta.c b/components/bootloader_support/src/esp32s2beta/bootloader_esp32s2beta.c index 452974f7d0..066271e4f7 100644 --- a/components/bootloader_support/src/esp32s2beta/bootloader_esp32s2beta.c +++ b/components/bootloader_support/src/esp32s2beta/bootloader_esp32s2beta.c @@ -11,9 +11,9 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. - -#include "bootloader_common.h" +#include #include "sdkconfig.h" +#include "bootloader_common.h" #include "soc/efuse_reg.h" #include "soc/gpio_sig_map.h" #include "soc/io_mux_reg.h" @@ -21,6 +21,27 @@ #include "esp32s2beta/rom/gpio.h" #include "esp32s2beta/rom/spi_flash.h" +#include "bootloader_init.h" +#include "bootloader_clock.h" +#include "bootloader_flash_config.h" + +#include "esp32s2beta/rom/cache.h" +#include "esp32s2beta/rom/ets_sys.h" +#include "esp32s2beta/rom/spi_flash.h" +#include "esp32s2beta/rom/rtc.h" +#include "esp32s2beta/rom/uart.h" +#include "esp_attr.h" +#include "esp_log.h" +#include "esp_image_format.h" +#include "flash_qio_mode.h" +#include "soc/assist_debug_reg.h" +#include "soc/cpu.h" +#include "soc/dport_reg.h" +#include "soc/rtc.h" +#include "soc/spi_periph.h" + +static const char *TAG = "boot.esp32s2"; + #define FLASH_CLK_IO SPI_CLK_GPIO_NUM #define FLASH_CS_IO SPI_CS0_GPIO_NUM #define FLASH_SPIQ_IO SPI_Q_GPIO_NUM @@ -66,3 +87,313 @@ void bootloader_configure_spi_pins(int drv) #endif } } + +static void bootloader_reset_mmu(void) +{ + //ToDo: save the autoload value + Cache_Suspend_ICache(); + Cache_Invalidate_ICache_All(); + Cache_MMU_Init(); + + /* normal ROM boot exits with DROM0 cache unmasked, + but serial bootloader exits with it masked. */ + DPORT_REG_CLR_BIT(DPORT_PRO_ICACHE_CTRL1_REG, DPORT_PRO_ICACHE_MASK_DROM0); +} + +static void update_flash_config(const esp_image_header_t *bootloader_hdr) +{ + uint32_t size; + switch (bootloader_hdr->spi_size) { + case ESP_IMAGE_FLASH_SIZE_1MB: + size = 1; + break; + case ESP_IMAGE_FLASH_SIZE_2MB: + size = 2; + break; + case ESP_IMAGE_FLASH_SIZE_4MB: + size = 4; + break; + case ESP_IMAGE_FLASH_SIZE_8MB: + size = 8; + break; + case ESP_IMAGE_FLASH_SIZE_16MB: + size = 16; + break; + default: + size = 2; + } + uint32_t autoload = Cache_Suspend_ICache(); + // Set flash chip size + esp_rom_spiflash_config_param(g_rom_flashchip.device_id, size * 0x100000, 0x10000, 0x1000, 0x100, 0xffff); + // TODO: set mode + // TODO: set frequency + Cache_Resume_ICache(autoload); +} + +static void print_flash_info(const esp_image_header_t *bootloader_hdr) +{ + ESP_LOGD(TAG, "magic %02x", bootloader_hdr->magic); + ESP_LOGD(TAG, "segments %02x", bootloader_hdr->segment_count); + ESP_LOGD(TAG, "spi_mode %02x", bootloader_hdr->spi_mode); + ESP_LOGD(TAG, "spi_speed %02x", bootloader_hdr->spi_speed); + ESP_LOGD(TAG, "spi_size %02x", bootloader_hdr->spi_size); + + const char *str; + switch (bootloader_hdr->spi_speed) { + case ESP_IMAGE_SPI_SPEED_40M: + str = "40MHz"; + break; + case ESP_IMAGE_SPI_SPEED_26M: + str = "26.7MHz"; + break; + case ESP_IMAGE_SPI_SPEED_20M: + str = "20MHz"; + break; + case ESP_IMAGE_SPI_SPEED_80M: + str = "80MHz"; + break; + default: + str = "20MHz"; + break; + } + ESP_LOGI(TAG, "SPI Speed : %s", str); + + /* SPI mode could have been set to QIO during boot already, + so test the SPI registers not the flash header */ + uint32_t spi_ctrl = REG_READ(SPI_MEM_CTRL_REG(0)); + if (spi_ctrl & SPI_MEM_FREAD_QIO) { + str = "QIO"; + } else if (spi_ctrl & SPI_MEM_FREAD_QUAD) { + str = "QOUT"; + } else if (spi_ctrl & SPI_MEM_FREAD_DIO) { + str = "DIO"; + } else if (spi_ctrl & SPI_MEM_FREAD_DUAL) { + str = "DOUT"; + } else if (spi_ctrl & SPI_MEM_FASTRD_MODE) { + str = "FAST READ"; + } else { + str = "SLOW READ"; + } + ESP_LOGI(TAG, "SPI Mode : %s", str); + + switch (bootloader_hdr->spi_size) { + case ESP_IMAGE_FLASH_SIZE_1MB: + str = "1MB"; + break; + case ESP_IMAGE_FLASH_SIZE_2MB: + str = "2MB"; + break; + case ESP_IMAGE_FLASH_SIZE_4MB: + str = "4MB"; + break; + case ESP_IMAGE_FLASH_SIZE_8MB: + str = "8MB"; + break; + case ESP_IMAGE_FLASH_SIZE_16MB: + str = "16MB"; + break; + default: + str = "2MB"; + break; + } + ESP_LOGI(TAG, "SPI Flash Size : %s", str); +} + +static void IRAM_ATTR bootloader_init_flash_configure(void) +{ + bootloader_flash_gpio_config(&bootloader_image_hdr); + bootloader_flash_dummy_config(&bootloader_image_hdr); + bootloader_flash_cs_timing_config(); +} + +static esp_err_t bootloader_init_spi_flash(void) +{ + bootloader_init_flash_configure(); +#ifndef CONFIG_SPI_FLASH_ROM_DRIVER_PATCH + const uint32_t spiconfig = ets_efuse_get_spiconfig(); + if (spiconfig != EFUSE_SPICONFIG_SPI_DEFAULTS && spiconfig != EFUSE_SPICONFIG_HSPI_DEFAULTS) { + ESP_LOGE(TAG, "SPI flash pins are overridden. Enable CONFIG_SPI_FLASH_ROM_DRIVER_PATCH in menuconfig"); + return ESP_FAIL; + } +#endif + + esp_rom_spiflash_unlock(); + +#if CONFIG_ESPTOOLPY_FLASHMODE_QIO || CONFIG_ESPTOOLPY_FLASHMODE_QOUT + bootloader_enable_qio_mode(); +#endif + + print_flash_info(&bootloader_image_hdr); + update_flash_config(&bootloader_image_hdr); + return ESP_OK; +} + +static void bootloader_init_uart_console(void) +{ +#if CONFIG_ESP_CONSOLE_UART_NONE + ets_install_putc1(NULL); + ets_install_putc2(NULL); +#else // CONFIG_ESP_CONSOLE_UART_NONE + const int uart_num = CONFIG_ESP_CONSOLE_UART_NUM; + + uartAttach(); + ets_install_uart_printf(); + + // Wait for UART FIFO to be empty. + uart_tx_wait_idle(0); + +#if CONFIG_ESP_CONSOLE_UART_CUSTOM + // Some constants to make the following code less upper-case + const int uart_tx_gpio = CONFIG_ESP_CONSOLE_UART_TX_GPIO; + const int uart_rx_gpio = CONFIG_ESP_CONSOLE_UART_RX_GPIO; + // Switch to the new UART (this just changes UART number used for + // ets_printf in ROM code). + uart_tx_switch(uart_num); + // If console is attached to UART1 or if non-default pins are used, + // need to reconfigure pins using GPIO matrix + if (uart_num != 0 || uart_tx_gpio != 1 || uart_rx_gpio != 3) { + // Change pin mode for GPIO1/3 from UART to GPIO + PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD_GPIO3); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD_GPIO1); + // Route GPIO signals to/from pins + // (arrays should be optimized away by the compiler) + const uint32_t tx_idx_list[3] = {U0TXD_OUT_IDX, U1TXD_OUT_IDX, U2TXD_OUT_IDX}; + const uint32_t rx_idx_list[3] = {U0RXD_IN_IDX, U1RXD_IN_IDX, U2RXD_IN_IDX}; + const uint32_t uart_reset[3] = {DPORT_UART_RST, DPORT_UART1_RST, DPORT_UART2_RST}; + const uint32_t tx_idx = tx_idx_list[uart_num]; + const uint32_t rx_idx = rx_idx_list[uart_num]; + + PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[uart_rx_gpio]); + gpio_pad_pullup(uart_rx_gpio); + + gpio_matrix_out(uart_tx_gpio, tx_idx, 0, 0); + gpio_matrix_in(uart_rx_gpio, rx_idx, 0); + + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, uart_reset[uart_num]); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, uart_reset[uart_num]); + } +#endif // CONFIG_ESP_CONSOLE_UART_CUSTOM + + // Set configured UART console baud rate + const int uart_baud = CONFIG_ESP_CONSOLE_UART_BAUDRATE; + uart_div_modify(uart_num, (rtc_clk_apb_freq_get() << 4) / uart_baud); + +#endif // CONFIG_ESP_CONSOLE_UART_NONE +} + +static void wdt_reset_cpu0_info_enable(void) +{ + DPORT_REG_SET_BIT(DPORT_PERI_CLK_EN_REG, DPORT_PERI_EN_ASSIST_DEBUG); + DPORT_REG_CLR_BIT(DPORT_PERI_RST_EN_REG, DPORT_PERI_EN_ASSIST_DEBUG); + REG_WRITE(ASSIST_DEBUG_PRO_PDEBUGENABLE, 1); + REG_WRITE(ASSIST_DEBUG_PRO_RCD_RECORDING, 1); +} + +static void wdt_reset_info_dump(int cpu) +{ + uint32_t inst = 0, pid = 0, stat = 0, data = 0, pc = 0, + lsstat = 0, lsaddr = 0, lsdata = 0, dstat = 0; + const char *cpu_name = cpu ? "APP" : "PRO"; + + stat = 0xdeadbeef; + pid = 0; + inst = REG_READ(ASSIST_DEBUG_PRO_RCD_PDEBUGINST); + dstat = REG_READ(ASSIST_DEBUG_PRO_RCD_PDEBUGSTATUS); + data = REG_READ(ASSIST_DEBUG_PRO_RCD_PDEBUGDATA); + pc = REG_READ(ASSIST_DEBUG_PRO_RCD_PDEBUGPC); + lsstat = REG_READ(ASSIST_DEBUG_PRO_RCD_PDEBUGLS0STAT); + lsaddr = REG_READ(ASSIST_DEBUG_PRO_RCD_PDEBUGLS0ADDR); + lsdata = REG_READ(ASSIST_DEBUG_PRO_RCD_PDEBUGLS0DATA); + + if (DPORT_RECORD_PDEBUGINST_SZ(inst) == 0 && + DPORT_RECORD_PDEBUGSTATUS_BBCAUSE(dstat) == DPORT_RECORD_PDEBUGSTATUS_BBCAUSE_WAITI) { + ESP_LOGW(TAG, "WDT reset info: %s CPU PC=0x%x (waiti mode)", cpu_name, pc); + } else { + ESP_LOGW(TAG, "WDT reset info: %s CPU PC=0x%x", cpu_name, pc); + } + ESP_LOGD(TAG, "WDT reset info: %s CPU STATUS 0x%08x", cpu_name, stat); + ESP_LOGD(TAG, "WDT reset info: %s CPU PID 0x%08x", cpu_name, pid); + ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGINST 0x%08x", cpu_name, inst); + ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGSTATUS 0x%08x", cpu_name, dstat); + ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGDATA 0x%08x", cpu_name, data); + ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGPC 0x%08x", cpu_name, pc); + ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGLS0STAT 0x%08x", cpu_name, lsstat); + ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGLS0ADDR 0x%08x", cpu_name, lsaddr); + ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGLS0DATA 0x%08x", cpu_name, lsdata); +} + +static void bootloader_check_wdt_reset(void) +{ + int wdt_rst = 0; + RESET_REASON rst_reas[2]; + + rst_reas[0] = rtc_get_reset_reason(0); + if (rst_reas[0] == RTCWDT_SYS_RESET || rst_reas[0] == TG0WDT_SYS_RESET || rst_reas[0] == TG1WDT_SYS_RESET || + rst_reas[0] == TG0WDT_CPU_RESET || rst_reas[0] == TG1WDT_CPU_RESET || rst_reas[0] == RTCWDT_CPU_RESET) { + ESP_LOGW(TAG, "PRO CPU has been reset by WDT."); + wdt_rst = 1; + } + if (wdt_rst) { + // if reset by WDT dump info from trace port + wdt_reset_info_dump(0); + } + wdt_reset_cpu0_info_enable(); +} + +void abort(void) +{ +#if !CONFIG_ESP32S2_PANIC_SILENT_REBOOT + ets_printf("abort() was called at PC 0x%08x\r\n", (intptr_t)__builtin_return_address(0) - 3); +#endif + if (esp_cpu_in_ocd_debug_mode()) { + __asm__("break 0,0"); + } + while (1) { + } +} + +esp_err_t bootloader_init(void) +{ + esp_err_t ret = ESP_OK; + // protect memory region + cpu_configure_region_protection(); + /* check that static RAM is after the stack */ +#ifndef NDEBUG + { + assert(&_bss_start <= &_bss_end); + assert(&_data_start <= &_data_end); + } +#endif + // clear bss section + bootloader_clear_bss_section(); + // reset MMU + bootloader_reset_mmu(); + // config clock + bootloader_clock_configure(); + // initialize uart console, from now on, we can use esp_log + bootloader_init_uart_console(); + /* print 2nd bootloader banner */ + bootloader_print_banner(); + // update flash ID + bootloader_flash_update_id(); + // read bootloader header + if ((ret = bootloader_read_bootloader_header()) != ESP_OK) { + goto err; + } + // read chip revision and check if it's compatible to bootloader + if ((ret = bootloader_check_bootloader_validity()) != ESP_OK) { + goto err; + } + // initialize spi flash + if ((ret = bootloader_init_spi_flash()) != ESP_OK) { + goto err; + } + // check whether a WDT reset happend + bootloader_check_wdt_reset(); + // config WDT + bootloader_config_wdt(); + // enable RNG early entropy source + bootloader_enable_random(); +err: + return ret; +} diff --git a/components/soc/esp32s2beta/include/soc/cpu.h b/components/soc/esp32s2beta/include/soc/cpu.h index 420350cdb9..c73b16f24c 100644 --- a/components/soc/esp32s2beta/include/soc/cpu.h +++ b/components/soc/esp32s2beta/include/soc/cpu.h @@ -51,13 +51,6 @@ static inline void cpu_write_itlb(unsigned vpn, unsigned attr) asm volatile ("witlb %1, %0; isync\n" :: "r" (vpn), "r" (attr)); } -static inline void cpu_init_memctl(void) -{ -#if XCHAL_ERRATUM_572 -#error "Shouldn't have this errata or need this call on esp32s2beta" -#endif -} - /** * @brief Configure memory region protection *