From 3f287800eb99867c17022608fbf29bbf40843cd4 Mon Sep 17 00:00:00 2001 From: morris Date: Tue, 1 Dec 2020 21:34:53 +0800 Subject: [PATCH] bootloader_support: added esp32-c3 support --- components/bootloader_support/component.mk | 5 +- .../src/bootloader_console.c | 6 +- .../src/bootloader_efuse_esp32c3.c | 28 ++ .../bootloader_support/src/bootloader_flash.c | 7 +- .../src/bootloader_flash_config_esp32c3.c | 83 +++++ .../src/bootloader_random_esp32c3.c | 31 ++ .../src/esp32c3/bootloader_esp32c3.c | 313 ++++++++++++++++++ .../src/esp32c3/bootloader_sha.c | 48 +++ .../src/esp32c3/flash_encrypt.c | 296 +++++++++++++++++ .../src/esp32c3/secure_boot.c | 45 +++ .../src/esp32c3/secure_boot_signatures.c | 93 ++++++ .../bootloader_support/src/esp_image_format.c | 5 + .../test/test_verify_image.c | 1 - 13 files changed, 952 insertions(+), 9 deletions(-) create mode 100644 components/bootloader_support/src/bootloader_efuse_esp32c3.c create mode 100644 components/bootloader_support/src/bootloader_flash_config_esp32c3.c create mode 100644 components/bootloader_support/src/bootloader_random_esp32c3.c create mode 100644 components/bootloader_support/src/esp32c3/bootloader_esp32c3.c create mode 100644 components/bootloader_support/src/esp32c3/bootloader_sha.c create mode 100644 components/bootloader_support/src/esp32c3/flash_encrypt.c create mode 100644 components/bootloader_support/src/esp32c3/secure_boot.c create mode 100644 components/bootloader_support/src/esp32c3/secure_boot_signatures.c diff --git a/components/bootloader_support/component.mk b/components/bootloader_support/component.mk index b24336fef1..26b2a59b8b 100644 --- a/components/bootloader_support/component.mk +++ b/components/bootloader_support/component.mk @@ -25,10 +25,13 @@ endif COMPONENT_OBJEXCLUDE += src/bootloader_flash_config_esp32s2.o \ src/bootloader_flash_config_esp32s3.o \ + src/bootloader_flash_config_esp32c3.o \ src/bootloader_efuse_esp32s2.o \ src/bootloader_efuse_esp32s3.o \ + src/bootloader_efuse_esp32c3.o \ src/bootloader_random_esp32s2.o \ - src/bootloader_random_esp32s3.o + src/bootloader_random_esp32s3.o \ + src/bootloader_random_esp32c3.o ifndef CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME ifndef CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME diff --git a/components/bootloader_support/src/bootloader_console.c b/components/bootloader_support/src/bootloader_console.c index b6730cebdc..7d80957648 100644 --- a/components/bootloader_support/src/bootloader_console.c +++ b/components/bootloader_support/src/bootloader_console.c @@ -42,7 +42,7 @@ void bootloader_console_init(void) { const int uart_num = CONFIG_ESP_CONSOLE_UART_NUM; - esp_rom_install_channel_putc(1, esp_rom_uart_putc); + esp_rom_install_uart_printf(); // Wait for UART FIFO to be empty. esp_rom_uart_tx_wait_idle(0); @@ -52,7 +52,9 @@ void bootloader_console_init(void) 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 esp_rom_printf in ROM code). +#if ESP_ROM_SUPPORT_MULTIPLE_UART esp_rom_uart_set_as_console(uart_num); +#endif // If console is attached to UART1 or if non-default pins are used, // need to reconfigure pins using GPIO matrix if (uart_num != 0 || @@ -75,7 +77,7 @@ void bootloader_console_init(void) // Set configured UART console baud rate uint32_t clock_hz = rtc_clk_apb_freq_get(); -#if CONFIG_IDF_TARGET_ESP32S3 +#if ESP_ROM_UART_CLK_IS_XTAL clock_hz = UART_CLK_FREQ_ROM; // From esp32-s3 on, UART clock source is selected to XTAL in ROM #endif esp_rom_uart_set_clock_baudrate(uart_num, clock_hz, CONFIG_ESP_CONSOLE_UART_BAUDRATE); diff --git a/components/bootloader_support/src/bootloader_efuse_esp32c3.c b/components/bootloader_support/src/bootloader_efuse_esp32c3.c new file mode 100644 index 0000000000..196825a007 --- /dev/null +++ b/components/bootloader_support/src/bootloader_efuse_esp32c3.c @@ -0,0 +1,28 @@ +// Copyright 2020 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. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// 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 + +uint8_t bootloader_common_get_chip_revision(void) +{ + // should return the same value as esp_efuse_get_chip_ver() + /* No other revisions for ESP32-C3 */ + return 0; +} + +uint32_t bootloader_common_get_chip_ver_pkg(void) +{ + // should return the same value as esp_efuse_get_pkg_ver() + return 0; +} diff --git a/components/bootloader_support/src/bootloader_flash.c b/components/bootloader_support/src/bootloader_flash.c index 905945309e..7a7d0ba4b7 100644 --- a/components/bootloader_support/src/bootloader_flash.c +++ b/components/bootloader_support/src/bootloader_flash.c @@ -404,12 +404,7 @@ esp_err_t bootloader_flash_write(size_t dest_addr, void *src, size_t size, bool } if (write_encrypted) { -#if CONFIG_IDF_TARGET_ESP32 return spi_to_esp_err(esp_rom_spiflash_write_encrypted(dest_addr, src, size)); -#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 - // TODO: use the same ROM API here - return spi_to_esp_err(SPI_Encrypt_Write(dest_addr, src, size)); -#endif } else { return spi_to_esp_err(esp_rom_spiflash_write(dest_addr, src, size)); } @@ -447,7 +442,9 @@ esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size) #endif +#ifndef g_rom_spiflash_dummy_len_plus // ESP32-C3 uses a macro to access ROM data here extern uint8_t g_rom_spiflash_dummy_len_plus[]; +#endif uint32_t bootloader_execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len) { uint32_t old_ctrl_reg = SPIFLASH.ctrl.val; diff --git a/components/bootloader_support/src/bootloader_flash_config_esp32c3.c b/components/bootloader_support/src/bootloader_flash_config_esp32c3.c new file mode 100644 index 0000000000..d140fa0ff6 --- /dev/null +++ b/components/bootloader_support/src/bootloader_flash_config_esp32c3.c @@ -0,0 +1,83 @@ +// Copyright 2020 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. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// 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 "string.h" +#include "sdkconfig.h" +#include "esp_err.h" +#include "esp_log.h" +#include "esp32c3/rom/gpio.h" +#include "esp32c3/rom/spi_flash.h" +#include "esp32c3/rom/efuse.h" +#include "soc/gpio_periph.h" +#include "soc/efuse_reg.h" +#include "soc/spi_reg.h" +#include "soc/spi_mem_reg.h" +#include "soc/spi_caps.h" +#include "flash_qio_mode.h" +#include "bootloader_flash_config.h" +#include "bootloader_common.h" + +#define FLASH_IO_MATRIX_DUMMY_40M 0 +#define FLASH_IO_MATRIX_DUMMY_80M 0 + +void bootloader_flash_update_id() +{ + esp_rom_spiflash_chip_t *chip = &rom_spiflash_legacy_data->chip; + chip->device_id = bootloader_read_flash_id(); +} + +void IRAM_ATTR bootloader_flash_cs_timing_config() +{ + SET_PERI_REG_MASK(SPI_MEM_USER_REG(0), SPI_MEM_CS_HOLD_M | SPI_MEM_CS_SETUP_M); + SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_HOLD_TIME_V, 0, SPI_MEM_CS_HOLD_TIME_S); + SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_SETUP_TIME_V, 0, SPI_MEM_CS_SETUP_TIME_S); + SET_PERI_REG_MASK(SPI_MEM_USER_REG(1), SPI_MEM_CS_HOLD_M | SPI_MEM_CS_SETUP_M); + SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(1), SPI_MEM_CS_HOLD_TIME_V, 1, SPI_MEM_CS_HOLD_TIME_S); + SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(1), SPI_MEM_CS_SETUP_TIME_V, 0, SPI_MEM_CS_SETUP_TIME_S); +} + +void IRAM_ATTR bootloader_flash_clock_config(const esp_image_header_t *pfhdr) +{ + uint32_t spi_clk_div = 0; + switch (pfhdr->spi_speed) { + case ESP_IMAGE_SPI_SPEED_80M: + spi_clk_div = 1; + break; + case ESP_IMAGE_SPI_SPEED_40M: + spi_clk_div = 2; + break; + case ESP_IMAGE_SPI_SPEED_26M: + spi_clk_div = 3; + break; + case ESP_IMAGE_SPI_SPEED_20M: + spi_clk_div = 4; + break; + default: + break; + } + esp_rom_spiflash_config_clk(spi_clk_div, 0); +} + +void IRAM_ATTR bootloader_flash_set_dummy_out(void) +{ + REG_SET_BIT(SPI_MEM_CTRL_REG(0), SPI_MEM_FDUMMY_OUT | SPI_MEM_D_POL | SPI_MEM_Q_POL); + REG_SET_BIT(SPI_MEM_CTRL_REG(1), SPI_MEM_FDUMMY_OUT | SPI_MEM_D_POL | SPI_MEM_Q_POL); +} + +void IRAM_ATTR bootloader_flash_dummy_config(const esp_image_header_t *pfhdr) +{ + bootloader_configure_spi_pins(1); + bootloader_flash_set_dummy_out(); +} diff --git a/components/bootloader_support/src/bootloader_random_esp32c3.c b/components/bootloader_support/src/bootloader_random_esp32c3.c new file mode 100644 index 0000000000..4ab2e38981 --- /dev/null +++ b/components/bootloader_support/src/bootloader_random_esp32c3.c @@ -0,0 +1,31 @@ +// Copyright 2020 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. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// 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 "sdkconfig.h" +#include "bootloader_random.h" +#include "esp_log.h" + +static const char *TAG = "bootloader_random"; + +void bootloader_random_enable(void) +{ + ESP_LOGW(TAG, "RNG for ESP32-C3 not currently supported"); // IDF-2305 + // Don't forget to remove the following line + // *libbootloader_support.a:bootloader_random*.*(.literal.bootloader_random_enable .text.bootloader_random_enable) + // In the bootloader.ld when RNG support is ready for ESP32-C3 +} + +void bootloader_random_disable(void) +{ + ESP_LOGW(TAG, "RNG for ESP32-C3 not currently supported"); // IDF-2305 +} diff --git a/components/bootloader_support/src/esp32c3/bootloader_esp32c3.c b/components/bootloader_support/src/esp32c3/bootloader_esp32c3.c new file mode 100644 index 0000000000..0219da916b --- /dev/null +++ b/components/bootloader_support/src/esp32c3/bootloader_esp32c3.c @@ -0,0 +1,313 @@ +// Copyright 2020 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. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// 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 "sdkconfig.h" +#include "esp_attr.h" +#include "esp_log.h" +#include "esp_image_format.h" +#include "flash_qio_mode.h" +#include "esp_rom_gpio.h" +#include "esp_rom_efuse.h" +#include "esp_rom_uart.h" +#include "esp_rom_sys.h" +#include "soc/efuse_reg.h" +#include "soc/gpio_sig_map.h" +#include "soc/io_mux_reg.h" +#include "soc/assist_debug_reg.h" +#include "soc/cpu.h" +#include "soc/rtc.h" +#include "soc/spi_periph.h" +#include "soc/extmem_reg.h" +#include "soc/io_mux_reg.h" +#include "soc/system_reg.h" +#include "esp32c3/rom/efuse.h" +#include "esp32c3/rom/spi_flash.h" +#include "esp32c3/rom/cache.h" +#include "esp32c3/rom/ets_sys.h" +#include "esp32c3/rom/spi_flash.h" +#include "esp32c3/rom/rtc.h" +#include "bootloader_common.h" +#include "bootloader_init.h" +#include "bootloader_clock.h" +#include "bootloader_flash_config.h" +#include "bootloader_mem.h" +#include "regi2c_ctrl.h" +#include "bootloader_console.h" + +static const char *TAG = "boot.esp32c3"; + +void IRAM_ATTR bootloader_configure_spi_pins(int drv) +{ + const uint32_t spiconfig = esp_rom_efuse_get_flash_gpio_info(); + uint8_t wp_pin = esp_rom_efuse_get_flash_wp_gpio(); + uint8_t clk_gpio_num = SPI_CLK_GPIO_NUM; + uint8_t q_gpio_num = SPI_Q_GPIO_NUM; + uint8_t d_gpio_num = SPI_D_GPIO_NUM; + uint8_t cs0_gpio_num = SPI_CS0_GPIO_NUM; + uint8_t hd_gpio_num = SPI_HD_GPIO_NUM; + uint8_t wp_gpio_num = SPI_WP_GPIO_NUM; + if (spiconfig == 0) { + + } else { + clk_gpio_num = spiconfig & 0x3f; + q_gpio_num = (spiconfig >> 6) & 0x3f; + d_gpio_num = (spiconfig >> 12) & 0x3f; + cs0_gpio_num = (spiconfig >> 18) & 0x3f; + hd_gpio_num = (spiconfig >> 24) & 0x3f; + wp_gpio_num = wp_pin; + } + esp_rom_gpio_pad_set_drv(clk_gpio_num, drv); + esp_rom_gpio_pad_set_drv(q_gpio_num, drv); + esp_rom_gpio_pad_set_drv(d_gpio_num, drv); + esp_rom_gpio_pad_set_drv(cs0_gpio_num, drv); + if (hd_gpio_num <= MAX_PAD_GPIO_NUM) { + esp_rom_gpio_pad_set_drv(hd_gpio_num, drv); + } + if (wp_gpio_num <= MAX_PAD_GPIO_NUM) { + esp_rom_gpio_pad_set_drv(wp_gpio_num, drv); + } +} + +static void bootloader_reset_mmu(void) +{ + Cache_Suspend_ICache(); + Cache_Invalidate_ICache_All(); + Cache_MMU_Init(); + + REG_CLR_BIT(EXTMEM_ICACHE_CTRL1_REG, EXTMEM_ICACHE_SHUT_IBUS); + REG_CLR_BIT(EXTMEM_ICACHE_CTRL1_REG, EXTMEM_ICACHE_SHUT_DBUS); +} + +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(rom_spiflash_legacy_data->chip.device_id, size * 0x100000, 0x10000, 0x1000, 0x100, 0xffff); // TODO: set mode + 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_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 = esp_rom_efuse_get_flash_gpio_info(); + if (spiconfig != ESP_ROM_EFUSE_FLASH_DEFAULT_SPI && spiconfig != ESP_ROM_EFUSE_FLASH_DEFAULT_HSPI) { + 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); + //ensure the flash is write-protected + bootloader_enable_wp(); + return ESP_OK; +} + +static void wdt_reset_cpu0_info_enable(void) +{ + REG_SET_BIT(SYSTEM_CPU_PERI_CLK_EN_REG, SYSTEM_CLK_EN_ASSIST_DEBUG); + REG_CLR_BIT(SYSTEM_CPU_PERI_RST_EN_REG, SYSTEM_RST_EN_ASSIST_DEBUG); + REG_WRITE(ASSIST_DEBUG_CORE_0_RCD_EN_REG, ASSIST_DEBUG_CORE_0_RCD_PDEBUGEN | ASSIST_DEBUG_CORE_0_RCD_RECORDEN); +} + +static void wdt_reset_info_dump(int cpu) +{ + // TODO ESP32-C3 IDF-2118 + ESP_LOGE(TAG, "WDT reset info dump is not supported yet", cpu_name); +} + +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(); +} + +static void bootloader_super_wdt_auto_feed(void) +{ + REG_WRITE(RTC_CNTL_SWD_WPROTECT_REG, RTC_CNTL_SWD_WKEY_VALUE); + REG_SET_BIT(RTC_CNTL_SWD_CONF_REG, RTC_CNTL_SWD_AUTO_FEED_EN); + REG_WRITE(RTC_CNTL_SWD_WPROTECT_REG, 0); +} + +static inline void bootloader_hardware_init(void) +{ + // TODO ESP32-C3 IDF-2452 + REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_FORCE_XPD_IPH, 1); + REGI2C_WRITE_MASK(I2C_BIAS, I2C_BIAS_DREG_1P1_PVT, 12); +} + +static inline void bootloader_glitch_reset_disable(void) +{ + // TODO ESP32-C3 IDF-2453 + REG_SET_FIELD(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_SEL, 0); +} + +esp_err_t bootloader_init(void) +{ + esp_err_t ret = ESP_OK; + bootloader_hardware_init(); + bootloader_glitch_reset_disable(); + bootloader_super_wdt_auto_feed(); + // protect memory region + bootloader_init_mem(); + /* check that static RAM is after the stack */ + assert(&_bss_start <= &_bss_end); + assert(&_data_start <= &_data_end); + // clear bss section + bootloader_clear_bss_section(); + // reset MMU + bootloader_reset_mmu(); + // config clock + bootloader_clock_configure(); + // initialize console, from now on, we can use esp_log + bootloader_console_init(); + /* 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/esp32c3/bootloader_sha.c b/components/bootloader_support/src/esp32c3/bootloader_sha.c new file mode 100644 index 0000000000..9388626e89 --- /dev/null +++ b/components/bootloader_support/src/esp32c3/bootloader_sha.c @@ -0,0 +1,48 @@ +// Copyright 2020 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. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// 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_sha.h" +#include +#include +#include +#include + +#include "esp32c3/rom/sha.h" + +static SHA_CTX ctx; + +bootloader_sha256_handle_t bootloader_sha256_start() +{ + // Enable SHA hardware + ets_sha_enable(); + ets_sha_init(&ctx, SHA2_256); + return &ctx; // Meaningless non-NULL value +} + +void bootloader_sha256_data(bootloader_sha256_handle_t handle, const void *data, size_t data_len) +{ + assert(handle != NULL); + assert(data_len % 4 == 0); + ets_sha_update(&ctx, data, data_len, false); +} + +void bootloader_sha256_finish(bootloader_sha256_handle_t handle, uint8_t *digest) +{ + assert(handle != NULL); + + if (digest == NULL) { + bzero(&ctx, sizeof(ctx)); + return; + } + ets_sha_finish(&ctx, digest); +} diff --git a/components/bootloader_support/src/esp32c3/flash_encrypt.c b/components/bootloader_support/src/esp32c3/flash_encrypt.c new file mode 100644 index 0000000000..cc45a5fbf3 --- /dev/null +++ b/components/bootloader_support/src/esp32c3/flash_encrypt.c @@ -0,0 +1,296 @@ +// Copyright 2015-2020 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. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// 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 "bootloader_flash_priv.h" +#include "bootloader_random.h" +#include "bootloader_utility.h" +#include "esp_image_format.h" +#include "esp_flash_encrypt.h" +#include "esp_flash_partitions.h" +#include "esp_secure_boot.h" +#include "esp_log.h" +#include "esp32c3/rom/secure_boot.h" +#include "esp32c3/rom/cache.h" +#include "esp32c3/rom/efuse.h" + +static const char *TAG = "flash_encrypt"; + +/* Static functions for stages of flash encryption */ +static esp_err_t initialise_flash_encryption(void); +static esp_err_t encrypt_flash_contents(uint32_t flash_crypt_cnt, bool flash_crypt_wr_dis); +static esp_err_t encrypt_bootloader(void); +static esp_err_t encrypt_and_load_partition_table(esp_partition_info_t *partition_table, int *num_partitions); +static esp_err_t encrypt_partition(int index, const esp_partition_info_t *partition); + +esp_err_t esp_flash_encrypt_check_and_update(void) +{ + // TODO ESP32-C3 IDF-2116 + uint32_t cnt = REG_GET_FIELD(EFUSE_RD_REPEAT_DATA1_REG, EFUSE_SPI_BOOT_CRYPT_CNT); + ESP_LOGV(TAG, "SPI_BOOT_CRYPT_CNT 0x%x", cnt); + + bool flash_crypt_wr_dis = false; // TODO: check if CRYPT_CNT is write disabled + + _Static_assert(EFUSE_SPI_BOOT_CRYPT_CNT == 0x7, "assuming CRYPT_CNT is only 3 bits wide"); + + if (cnt == 1 || cnt == 3 || cnt == 7) { + /* Flash is already encrypted */ + int left; + if (cnt == 7 /* || disabled */) { + left = 0; + } else if (cnt == 3) { + left = 1; + } else { + left = 2; + } + ESP_LOGI(TAG, "flash encryption is enabled (%d plaintext flashes left)", left); + return ESP_OK; + } else { + /* Flash is not encrypted, so encrypt it! */ + return encrypt_flash_contents(cnt, flash_crypt_wr_dis); + } +} + +static esp_err_t initialise_flash_encryption(void) +{ + /* Before first flash encryption pass, need to initialise key & crypto config */ + + /* Find out if a key is already set */ + bool has_aes128 = ets_efuse_find_purpose(ETS_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY, NULL); + bool has_aes256_1 = ets_efuse_find_purpose(ETS_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_1, NULL); + bool has_aes256_2 = ets_efuse_find_purpose(ETS_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_2, NULL); + + bool has_key = has_aes128 || (has_aes256_1 && has_aes256_2); + + if (!has_key && (has_aes256_1 || has_aes256_2)) { + ESP_LOGE(TAG, "Invalid efuse key blocks: Both AES-256 key blocks must be set."); + return ESP_ERR_INVALID_STATE; + } + + if (has_key) { + ESP_LOGI(TAG, "Using pre-existing key in efuse"); + + ESP_LOGE(TAG, "TODO: Check key is read & write protected"); // TODO + } else { + ESP_LOGI(TAG, "Generating new flash encryption key..."); +#ifdef CONFIG_SECURE_FLASH_ENCRYPTION_AES256 + const unsigned BLOCKS_NEEDED = 2; + const ets_efuse_purpose_t PURPOSE_START = ETS_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_1; + const ets_efuse_purpose_t PURPOSE_END = ETS_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_2; +#else + const unsigned BLOCKS_NEEDED = 1; + const ets_efuse_purpose_t PURPOSE_START = ETS_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY; + const ets_efuse_purpose_t PURPOSE_END = ETS_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY; +#endif + + if (ets_efuse_count_unused_key_blocks() < BLOCKS_NEEDED) { + ESP_LOGE(TAG, "Not enough free efuse key blocks (need %d) to continue", BLOCKS_NEEDED); + return ESP_ERR_INVALID_STATE; + } + + for (ets_efuse_purpose_t purpose = PURPOSE_START; purpose <= PURPOSE_END; purpose++) { + uint32_t buf[8] = {0}; + bootloader_fill_random(buf, sizeof(buf)); + ets_efuse_block_t block = ets_efuse_find_unused_key_block(); + ESP_LOGD(TAG, "Writing ETS_EFUSE_BLOCK_KEY%d with purpose %d", + block - ETS_EFUSE_BLOCK_KEY0, purpose); + bootloader_debug_buffer(buf, sizeof(buf), "Key content"); + int r = ets_efuse_write_key(block, purpose, buf, sizeof(buf)); + bzero(buf, sizeof(buf)); + if (r != 0) { + ESP_LOGE(TAG, "Failed to write efuse block %d with purpose %d. Can't continue."); + return ESP_FAIL; + } + } + ESP_LOGD(TAG, "Key generation complete"); + } + + ESP_LOGE(TAG, "TODO: burn remaining security protection bits"); + + return ESP_OK; +} + +/* Encrypt all flash data that should be encrypted */ +static esp_err_t encrypt_flash_contents(uint32_t spi_boot_crypt_cnt, bool flash_crypt_wr_dis) +{ + esp_err_t err; + esp_partition_info_t partition_table[ESP_PARTITION_TABLE_MAX_ENTRIES]; + int num_partitions; + + /* If the last spi_boot_crypt_cnt bit is burned or write-disabled, the + device can't re-encrypt itself. */ + if (flash_crypt_wr_dis || spi_boot_crypt_cnt == EFUSE_SPI_BOOT_CRYPT_CNT) { + ESP_LOGE(TAG, "Cannot re-encrypt data (SPI_BOOT_CRYPT_CNT 0x%02x write disabled %d", spi_boot_crypt_cnt, flash_crypt_wr_dis); + return ESP_FAIL; + } + + if (spi_boot_crypt_cnt == 0) { + /* Very first flash of encrypted data: generate keys, etc. */ + err = initialise_flash_encryption(); + if (err != ESP_OK) { + return err; + } + } + + err = encrypt_bootloader(); + if (err != ESP_OK) { + return err; + } + + err = encrypt_and_load_partition_table(partition_table, &num_partitions); + if (err != ESP_OK) { + return err; + } + + /* Now iterate the just-loaded partition table, looking for entries to encrypt + */ + + /* Go through each partition and encrypt if necessary */ + for (int i = 0; i < num_partitions; i++) { + err = encrypt_partition(i, &partition_table[i]); + if (err != ESP_OK) { + return err; + } + } + + ESP_LOGD(TAG, "All flash regions checked for encryption pass"); + + /* Set least significant 0-bit in spi_boot_crypt_cnt */ + int ffs_inv = __builtin_ffs((~spi_boot_crypt_cnt) & 0x7); + /* ffs_inv shouldn't be zero, as zero implies spi_boot_crypt_cnt == 0xFF */ + uint32_t new_spi_boot_crypt_cnt = spi_boot_crypt_cnt + (1 << (ffs_inv - 1)); + ESP_LOGD(TAG, "SPI_BOOT_CRYPT_CNT 0x%x -> 0x%x", spi_boot_crypt_cnt, new_spi_boot_crypt_cnt); + + ets_efuse_clear_program_registers(); + REG_SET_FIELD(EFUSE_PGM_DATA2_REG, EFUSE_SPI_BOOT_CRYPT_CNT, new_spi_boot_crypt_cnt); + ets_efuse_program(ETS_EFUSE_BLOCK0); + + ESP_LOGI(TAG, "Flash encryption completed"); + + return ESP_OK; +} + +static esp_err_t encrypt_bootloader(void) +{ + esp_err_t err; + uint32_t image_length; + /* Check for plaintext bootloader (verification will fail if it's already encrypted) */ + if (esp_image_verify_bootloader(&image_length) == ESP_OK) { + ESP_LOGD(TAG, "bootloader is plaintext. Encrypting..."); + err = esp_flash_encrypt_region(ESP_BOOTLOADER_OFFSET, image_length); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to encrypt bootloader in place: 0x%x", err); + return err; + } + + if (esp_secure_boot_enabled()) { + // TODO: anything different for secure boot? + } + } else { + ESP_LOGW(TAG, "no valid bootloader was found"); + } + + return ESP_OK; +} + +static esp_err_t encrypt_and_load_partition_table(esp_partition_info_t *partition_table, int *num_partitions) +{ + esp_err_t err; + /* Check for plaintext partition table */ + err = bootloader_flash_read(ESP_PARTITION_TABLE_OFFSET, partition_table, ESP_PARTITION_TABLE_MAX_LEN, false); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to read partition table data"); + return err; + } + if (esp_partition_table_verify(partition_table, false, num_partitions) == ESP_OK) { + ESP_LOGD(TAG, "partition table is plaintext. Encrypting..."); + esp_err_t err = esp_flash_encrypt_region(ESP_PARTITION_TABLE_OFFSET, + FLASH_SECTOR_SIZE); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to encrypt partition table in place. %x", err); + return err; + } + } else { + ESP_LOGE(TAG, "Failed to read partition table data - not plaintext?"); + return ESP_ERR_INVALID_STATE; + } + + /* Valid partition table loaded */ + return ESP_OK; +} + +static esp_err_t encrypt_partition(int index, const esp_partition_info_t *partition) +{ + esp_err_t err; + bool should_encrypt = (partition->flags & PART_FLAG_ENCRYPTED); + + if (partition->type == PART_TYPE_APP) { + /* check if the partition holds a valid unencrypted app */ + esp_image_metadata_t data_ignored; + err = esp_image_verify(ESP_IMAGE_VERIFY, + &partition->pos, + &data_ignored); + should_encrypt = (err == ESP_OK); + } else if (partition->type == PART_TYPE_DATA && partition->subtype == PART_SUBTYPE_DATA_OTA) { + /* check if we have ota data partition and the partition should be encrypted unconditionally */ + should_encrypt = true; + } + + if (!should_encrypt) { + return ESP_OK; + } else { + /* should_encrypt */ + ESP_LOGI(TAG, "Encrypting partition %d at offset 0x%x (length 0x%x)...", index, partition->pos.offset, partition->pos.size); + + err = esp_flash_encrypt_region(partition->pos.offset, partition->pos.size); + ESP_LOGI(TAG, "Done encrypting"); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to encrypt partition %d", index); + } + return err; + } +} + +esp_err_t esp_flash_encrypt_region(uint32_t src_addr, size_t data_length) +{ + esp_err_t err; + uint32_t buf[FLASH_SECTOR_SIZE / sizeof(uint32_t)]; + + if (src_addr % FLASH_SECTOR_SIZE != 0) { + ESP_LOGE(TAG, "esp_flash_encrypt_region bad src_addr 0x%x", src_addr); + return ESP_FAIL; + } + + for (size_t i = 0; i < data_length; i += FLASH_SECTOR_SIZE) { + uint32_t sec_start = i + src_addr; + err = bootloader_flash_read(sec_start, buf, FLASH_SECTOR_SIZE, false); + if (err != ESP_OK) { + goto flash_failed; + } + err = bootloader_flash_erase_sector(sec_start / FLASH_SECTOR_SIZE); + if (err != ESP_OK) { + goto flash_failed; + } + err = bootloader_flash_write(sec_start, buf, FLASH_SECTOR_SIZE, true); + if (err != ESP_OK) { + goto flash_failed; + } + } + return ESP_OK; + +flash_failed: + ESP_LOGE(TAG, "flash operation failed: 0x%x", err); + return err; +} diff --git a/components/bootloader_support/src/esp32c3/secure_boot.c b/components/bootloader_support/src/esp32c3/secure_boot.c new file mode 100644 index 0000000000..ae3e2bdc1f --- /dev/null +++ b/components/bootloader_support/src/esp32c3/secure_boot.c @@ -0,0 +1,45 @@ +// Copyright 2015-2020 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. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// 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 "esp_secure_boot.h" +#include "esp_log.h" +#include "esp32c3/rom/secure_boot.h" +#include "esp_rom_efuse.h" + +static const char *TAG = "secure_boot"; + +esp_err_t esp_secure_boot_permanently_enable(void) +{ + uint8_t hash[32]; + + if (esp_rom_efuse_is_secure_boot_enabled()) { + ESP_LOGI(TAG, "secure boot is already enabled, continuing.."); + return ESP_OK; + } + + ESP_LOGI(TAG, "Verifying bootloader signature...\n"); + int r = ets_secure_boot_verify_bootloader(hash, false); + if (r != ESP_OK) { + ESP_LOGE(TAG, "Failed to verify bootloader signature"); + return r; + } + + ets_efuse_clear_program_registers(); + REG_SET_BIT(EFUSE_PGM_DATA3_REG, EFUSE_SECURE_BOOT_EN); + ets_efuse_program(ETS_EFUSE_BLOCK0); + + assert(esp_rom_efuse_is_secure_boot_enabled()); + ESP_LOGI(TAG, "Secure boot permanently enabled"); + + return ESP_OK; +} diff --git a/components/bootloader_support/src/esp32c3/secure_boot_signatures.c b/components/bootloader_support/src/esp32c3/secure_boot_signatures.c new file mode 100644 index 0000000000..458ced12ae --- /dev/null +++ b/components/bootloader_support/src/esp32c3/secure_boot_signatures.c @@ -0,0 +1,93 @@ +// Copyright 2015-2020 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. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// 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 "sdkconfig.h" + +#include "bootloader_flash.h" +#include "bootloader_sha.h" +#include "esp_log.h" +#include "esp_image_format.h" +#include "esp32c3/rom/secure_boot.h" + +static const char *TAG = "secure_boot"; + +#define DIGEST_LEN 32 + +esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length) +{ + ets_secure_boot_key_digests_t trusted_keys = { 0 }; + uint8_t digest[DIGEST_LEN]; + const uint8_t *data; + + ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length); + + if ((src_addr + length) % 4096 != 0) { + ESP_LOGE(TAG, "addr 0x%x length 0x%x doesn't end on a sector boundary", src_addr, length); + return ESP_ERR_INVALID_ARG; + } + + data = bootloader_mmap(src_addr, length + sizeof(struct ets_secure_boot_sig_block)); + if (data == NULL) { + ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", src_addr, length + sizeof(ets_secure_boot_signature_t)); + return ESP_FAIL; + } + + // Calculate digest of main image +#ifdef BOOTLOADER_BUILD + bootloader_sha256_handle_t handle = bootloader_sha256_start(); + bootloader_sha256_data(handle, data, length); + bootloader_sha256_finish(handle, digest); +#else + /* Use thread-safe esp-idf SHA function */ + esp_sha(SHA2_256, data, length, digest); +#endif + + int r = ets_secure_boot_read_key_digests(&trusted_keys); + + if (r == ETS_OK) { + const ets_secure_boot_signature_t *sig = (const ets_secure_boot_signature_t *)(data + length); + // TODO: calling this function in IDF app context is unsafe + r = ets_secure_boot_verify_signature(sig, digest, &trusted_keys); + } + bootloader_munmap(data); + + return (r == ETS_OK) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_secure_boot_verify_signature_block(uint32_t sig_block_flash_offs, const uint8_t *image_digest) +{ + ets_secure_boot_key_digests_t trusted_keys; + + assert(sig_block_flash_offs % 4096 == 0); // TODO: enforce this in a better way + + const ets_secure_boot_signature_t *sig = bootloader_mmap(sig_block_flash_offs, sizeof(ets_secure_boot_signature_t)); + + if (sig == NULL) { + ESP_LOGE(TAG, "Failed to mmap data at offset 0x%x", sig_block_flash_offs); + return ESP_FAIL; + } + + int r = ets_secure_boot_read_key_digests(&trusted_keys); + if (r != 0) { + ESP_LOGE(TAG, "No trusted key digests were found in efuse!"); + } else { + ESP_LOGD(TAG, "Verifying with RSA-PSS..."); + // TODO: calling this function in IDF app context is unsafe + r = ets_secure_boot_verify_signature(sig, image_digest, &trusted_keys); + } + + bootloader_munmap(sig); + + return (r == 0) ? ESP_OK : ESP_ERR_IMAGE_INVALID; +} diff --git a/components/bootloader_support/src/esp_image_format.c b/components/bootloader_support/src/esp_image_format.c index e61972f573..9ed8b140c1 100644 --- a/components/bootloader_support/src/esp_image_format.c +++ b/components/bootloader_support/src/esp_image_format.c @@ -607,6 +607,11 @@ static esp_err_t process_segment_data(intptr_t load_addr, uint32_t data_addr, ui // Set up the obfuscation value to use for loading while (ram_obfs_value[0] == 0 || ram_obfs_value[1] == 0) { bootloader_fill_random(ram_obfs_value, sizeof(ram_obfs_value)); +#if CONFIG_IDF_ENV_FPGA + /* FPGA doesn't always emulate the RNG */ + ram_obfs_value[0] ^= 0x33; + ram_obfs_value[1] ^= 0x66; +#endif } uint32_t *dest = (uint32_t *)load_addr; #endif diff --git a/components/bootloader_support/test/test_verify_image.c b/components/bootloader_support/test/test_verify_image.c index fd6cef02ff..cd87c719ab 100644 --- a/components/bootloader_support/test/test_verify_image.c +++ b/components/bootloader_support/test/test_verify_image.c @@ -10,7 +10,6 @@ #include "freertos/task.h" #include "freertos/semphr.h" #include "freertos/queue.h" -#include "freertos/xtensa_api.h" #include "unity.h" #include "bootloader_common.h" #include "bootloader_util.h"