chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2017-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#include "soc/soc.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/chip_revision.h"
|
||||
#include "hal/efuse_hal.h"
|
||||
|
||||
#include "soc/rtc_cntl_periph.h"
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#include "hal/clk_tree_ll.h"
|
||||
#endif
|
||||
#include "esp_rom_sys.h"
|
||||
#include "esp_rom_serial_output.h"
|
||||
|
||||
__attribute__((weak)) void bootloader_clock_configure(void)
|
||||
{
|
||||
// ROM bootloader may have put a lot of text into UART0 FIFO.
|
||||
// Wait for it to be printed.
|
||||
// This is not needed on power on reset, when ROM bootloader is running at
|
||||
// 40 MHz. But in case of TG WDT reset, CPU may still be running at >80 MHZ,
|
||||
// and will be done with the bootloader much earlier than UART FIFO is empty.
|
||||
esp_rom_output_tx_wait_idle(0);
|
||||
|
||||
/* Set CPU to a higher certain frequency. Keep other clocks unmodified. */
|
||||
int cpu_freq_mhz = CONFIG_BOOTLOADER_CPU_CLK_FREQ_MHZ;
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
/* On ESP32 rev 0, switching to 80/160 MHz if clock was previously set to
|
||||
* 240 MHz may cause the chip to lock up (see CPU-3.5 of the errata
|
||||
* document). For rev. 0, switch to 240 instead if it has been enabled
|
||||
* previously.
|
||||
*/
|
||||
if (!ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 100) &&
|
||||
clk_ll_cpu_get_freq_mhz_from_pll() == CLK_LL_PLL_240M_FREQ_MHZ) {
|
||||
cpu_freq_mhz = 240;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (esp_rom_get_reset_reason(0) != RESET_REASON_CPU0_SW || rtc_clk_apb_freq_get() < APB_CLK_FREQ) {
|
||||
rtc_clk_config_t clk_cfg = RTC_CLK_CONFIG_DEFAULT();
|
||||
|
||||
clk_cfg.cpu_freq_mhz = cpu_freq_mhz;
|
||||
|
||||
// Use RTC_SLOW clock source sel register field's default value, RC_SLOW, for 2nd stage bootloader
|
||||
// RTC_SLOW clock source will be switched according to Kconfig selection at application startup
|
||||
clk_cfg.slow_clk_src = rtc_clk_slow_src_get();
|
||||
if (clk_cfg.slow_clk_src == SOC_RTC_SLOW_CLK_SRC_INVALID) {
|
||||
clk_cfg.slow_clk_src = SOC_RTC_SLOW_CLK_SRC_DEFAULT;
|
||||
}
|
||||
|
||||
// Use RTC_FAST clock source sel register field's default value, XTAL_DIV, for 2nd stage bootloader
|
||||
// RTC_FAST clock source will be switched to RC_FAST at application startup
|
||||
clk_cfg.fast_clk_src = rtc_clk_fast_src_get();
|
||||
if (clk_cfg.fast_clk_src == SOC_RTC_FAST_CLK_SRC_INVALID) {
|
||||
clk_cfg.fast_clk_src = SOC_RTC_FAST_CLK_SRC_DEFAULT;
|
||||
}
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32C6
|
||||
if (efuse_hal_chip_revision() == 0) {
|
||||
// Some of ESP32C6-ECO0 chip's SOC_RTC_FAST_CLK_SRC_XTAL_D2 rtc_fast clock has timing issue,
|
||||
// which will cause the chip to be unable to capture the reset reason when it is reset.
|
||||
// Force to use SOC_RTC_FAST_CLK_SRC_RC_FAST since 2nd stage bootloader
|
||||
clk_cfg.fast_clk_src = SOC_RTC_FAST_CLK_SRC_RC_FAST;
|
||||
}
|
||||
#endif
|
||||
|
||||
rtc_clk_init(clk_cfg);
|
||||
}
|
||||
|
||||
/* As a slight optimization, if 32k XTAL was enabled in sdkconfig, we enable
|
||||
* it here. Usually it needs some time to start up, so we amortize at least
|
||||
* part of the start up time by enabling 32k XTAL early.
|
||||
* App startup code will wait until the oscillator has started up.
|
||||
*/
|
||||
#if CONFIG_ESP_SYSTEM_RTC_EXT_XTAL
|
||||
if (!rtc_clk_32k_enabled()) {
|
||||
rtc_clk_32k_bootstrap(CONFIG_ESP_SYSTEM_RTC_EXT_XTAL_BOOTSTRAP_CYCLES);
|
||||
}
|
||||
#endif // CONFIG_ESP_SYSTEM_RTC_EXT_XTAL
|
||||
|
||||
// TODO: IDF-8938 Need refactor! Does not belong to clock configuration.
|
||||
#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C61
|
||||
#if CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C61
|
||||
#define LP_ANALOG_PERI_LP_ANA_LP_INT_ENA_REG LP_ANA_LP_INT_ENA_REG
|
||||
#define LP_ANALOG_PERI_LP_ANA_BOD_MODE0_LP_INT_ENA LP_ANA_BOD_MODE0_LP_INT_ENA
|
||||
#define LP_ANALOG_PERI_LP_ANA_LP_INT_CLR_REG LP_ANA_LP_INT_CLR_REG
|
||||
#define LP_ANALOG_PERI_LP_ANA_BOD_MODE0_LP_INT_CLR LP_ANA_BOD_MODE0_LP_INT_CLR
|
||||
#endif
|
||||
// CLR ENA
|
||||
CLEAR_PERI_REG_MASK(LP_WDT_INT_ENA_REG, LP_WDT_SUPER_WDT_INT_ENA); /* SWD */
|
||||
CLEAR_PERI_REG_MASK(LP_ANALOG_PERI_LP_ANA_LP_INT_ENA_REG, LP_ANALOG_PERI_LP_ANA_BOD_MODE0_LP_INT_ENA); /* BROWN_OUT */
|
||||
CLEAR_PERI_REG_MASK(LP_WDT_INT_ENA_REG, LP_WDT_LP_WDT_INT_ENA); /* WDT */
|
||||
CLEAR_PERI_REG_MASK(PMU_HP_INT_ENA_REG, PMU_SOC_WAKEUP_INT_ENA); /* SLP_REJECT */
|
||||
CLEAR_PERI_REG_MASK(PMU_HP_INT_ENA_REG, PMU_SOC_SLEEP_REJECT_INT_ENA); /* SLP_WAKEUP */
|
||||
// SET CLR
|
||||
SET_PERI_REG_MASK(LP_WDT_INT_CLR_REG, LP_WDT_SUPER_WDT_INT_CLR); /* SWD */
|
||||
SET_PERI_REG_MASK(LP_ANALOG_PERI_LP_ANA_LP_INT_CLR_REG, LP_ANALOG_PERI_LP_ANA_BOD_MODE0_LP_INT_CLR); /* BROWN_OUT */
|
||||
SET_PERI_REG_MASK(LP_WDT_INT_CLR_REG, LP_WDT_LP_WDT_INT_CLR); /* WDT */
|
||||
#elif CONFIG_IDF_TARGET_ESP32H2
|
||||
// CLR ENA
|
||||
CLEAR_PERI_REG_MASK(LP_WDT_INT_ENA_REG, LP_WDT_SUPER_WDT_INT_ENA); /* SWD */
|
||||
CLEAR_PERI_REG_MASK(LP_ANALOG_PERI_LP_ANA_LP_INT_ENA_REG, LP_ANALOG_PERI_LP_ANA_BOD_MODE0_LP_INT_ENA); /* BROWN_OUT */
|
||||
CLEAR_PERI_REG_MASK(LP_WDT_INT_ENA_REG, LP_WDT_LP_WDT_INT_ENA); /* WDT */
|
||||
CLEAR_PERI_REG_MASK(PMU_HP_INT_ENA_REG, PMU_SOC_WAKEUP_INT_ENA); /* SLP_REJECT */
|
||||
CLEAR_PERI_REG_MASK(PMU_HP_INT_ENA_REG, PMU_SOC_SLEEP_REJECT_INT_ENA); /* SLP_WAKEUP */
|
||||
// SET CLR
|
||||
SET_PERI_REG_MASK(LP_WDT_INT_CLR_REG, LP_WDT_SUPER_WDT_INT_CLR); /* SWD */
|
||||
SET_PERI_REG_MASK(LP_ANALOG_PERI_LP_ANA_LP_INT_CLR_REG, LP_ANALOG_PERI_LP_ANA_BOD_MODE0_LP_INT_CLR); /* BROWN_OUT */
|
||||
SET_PERI_REG_MASK(LP_WDT_INT_CLR_REG, LP_WDT_LP_WDT_INT_CLR); /* WDT */
|
||||
SET_PERI_REG_MASK(PMU_HP_INT_CLR_REG, PMU_SOC_WAKEUP_INT_CLR); /* SLP_REJECT */
|
||||
SET_PERI_REG_MASK(PMU_HP_INT_CLR_REG, PMU_SOC_SLEEP_REJECT_INT_CLR); /* SLP_WAKEUP */
|
||||
#elif CONFIG_IDF_TARGET_ESP32H21
|
||||
// CLR ENA
|
||||
CLEAR_PERI_REG_MASK(LP_WDT_INT_ENA_REG, LP_WDT_SUPER_WDT_INT_ENA); /* SWD */
|
||||
CLEAR_PERI_REG_MASK(LP_ANA_LP_INT_ENA_REG, LP_ANA_BOD_MODE0_LP_INT_ENA); /* BROWN_OUT */
|
||||
CLEAR_PERI_REG_MASK(LP_WDT_INT_ENA_REG, LP_WDT_LP_WDT_INT_ENA); /* WDT */
|
||||
CLEAR_PERI_REG_MASK(PMU_HP_INT_ENA_REG, PMU_SOC_WAKEUP_INT_ENA); /* SLP_REJECT */
|
||||
CLEAR_PERI_REG_MASK(PMU_HP_INT_ENA_REG, PMU_SOC_SLEEP_REJECT_INT_ENA); /* SLP_WAKEUP */
|
||||
// SET CLR
|
||||
SET_PERI_REG_MASK(LP_WDT_INT_CLR_REG, LP_WDT_SUPER_WDT_INT_CLR); /* SWD */
|
||||
SET_PERI_REG_MASK(LP_ANA_LP_INT_CLR_REG, LP_ANA_BOD_MODE0_LP_INT_CLR); /* BROWN_OUT */
|
||||
SET_PERI_REG_MASK(LP_WDT_INT_CLR_REG, LP_WDT_LP_WDT_INT_CLR); /* WDT */
|
||||
SET_PERI_REG_MASK(PMU_HP_INT_CLR_REG, PMU_SOC_WAKEUP_INT_CLR); /* SLP_REJECT */
|
||||
SET_PERI_REG_MASK(PMU_HP_INT_CLR_REG, PMU_SOC_SLEEP_REJECT_INT_CLR);
|
||||
#elif CONFIG_IDF_TARGET_ESP32H4
|
||||
// CLR ENA
|
||||
CLEAR_PERI_REG_MASK(LP_WDT_INT_ENA_REG, LP_WDT_SUPER_WDT_INT_ENA); /* SWD */
|
||||
CLEAR_PERI_REG_MASK(LP_ANA_LP_INT_ENA_REG, LP_ANA_BOD_MODE0_LP_INT_ENA); /* BROWN_OUT */
|
||||
CLEAR_PERI_REG_MASK(LP_WDT_INT_ENA_REG, LP_WDT_LP_WDT_INT_ENA); /* WDT */
|
||||
CLEAR_PERI_REG_MASK(PMU_HP_INT_ENA_REG, PMU_SOC_WAKEUP_INT_ENA); /* SLP_REJECT */
|
||||
CLEAR_PERI_REG_MASK(PMU_HP_INT_ENA_REG, PMU_SOC_SLEEP_REJECT_INT_ENA); /* SLP_WAKEUP */
|
||||
// SET CLR
|
||||
SET_PERI_REG_MASK(LP_WDT_INT_CLR_REG, LP_WDT_SUPER_WDT_INT_CLR); /* SWD */
|
||||
SET_PERI_REG_MASK(LP_ANA_LP_INT_CLR_REG, LP_ANA_BOD_MODE0_LP_INT_CLR); /* BROWN_OUT */
|
||||
SET_PERI_REG_MASK(LP_WDT_INT_CLR_REG, LP_WDT_LP_WDT_INT_CLR); /* WDT */
|
||||
SET_PERI_REG_MASK(PMU_HP_INT_CLR_REG, PMU_SOC_WAKEUP_INT_CLR); /* SLP_REJECT */
|
||||
SET_PERI_REG_MASK(PMU_HP_INT_CLR_REG, PMU_SOC_SLEEP_REJECT_INT_CLR);
|
||||
#elif CONFIG_IDF_TARGET_ESP32P4
|
||||
// CLR ENA
|
||||
CLEAR_PERI_REG_MASK(LP_WDT_INT_ENA_REG, LP_WDT_SUPER_WDT_INT_ENA); /* SWD */
|
||||
CLEAR_PERI_REG_MASK(LP_ANALOG_PERI_LP_INT_ENA_REG, LP_ANALOG_PERI_BOD_MODE0_LP_INT_ENA); /* BROWN_OUT */
|
||||
CLEAR_PERI_REG_MASK(LP_WDT_INT_ENA_REG, LP_WDT_LP_WDT_INT_ENA); /* WDT */
|
||||
CLEAR_PERI_REG_MASK(PMU_HP_INT_ENA_REG, PMU_SOC_WAKEUP_INT_ENA); /* SLP_REJECT */
|
||||
CLEAR_PERI_REG_MASK(PMU_HP_INT_ENA_REG, PMU_SOC_SLEEP_REJECT_INT_ENA); /* SLP_WAKEUP */
|
||||
// SET CLR
|
||||
SET_PERI_REG_MASK(LP_WDT_INT_CLR_REG, LP_WDT_SUPER_WDT_INT_CLR); /* SWD */
|
||||
SET_PERI_REG_MASK(LP_ANALOG_PERI_LP_INT_CLR_REG, LP_ANALOG_PERI_LP_INT_CLR_REG); /* BROWN_OUT */
|
||||
SET_PERI_REG_MASK(LP_WDT_INT_CLR_REG, LP_WDT_LP_WDT_INT_CLR); /* WDT */
|
||||
#elif CONFIG_IDF_TARGET_ESP32S31
|
||||
// CLR ENA
|
||||
CLEAR_PERI_REG_MASK(RTC_WDT_INT_ENA_REG, RTC_WDT_SUPER_WDT_INT_ENA); /* SWD */
|
||||
CLEAR_PERI_REG_MASK(LP_ANA_LP_INT_ENA_REG, LP_ANA_BOD_MODE0_LP_INT_ENA); /* BROWN_OUT */
|
||||
CLEAR_PERI_REG_MASK(RTC_WDT_INT_ENA_REG, RTC_WDT_LP_WDT_INT_ENA); /* WDT */
|
||||
CLEAR_PERI_REG_MASK(PMU_HP_INT_ENA_REG, PMU_SOC_WAKEUP_INT_ENA); /* SLP_REJECT */
|
||||
CLEAR_PERI_REG_MASK(PMU_HP_INT_ENA_REG, PMU_SOC_SLEEP_REJECT_INT_ENA); /* SLP_WAKEUP */
|
||||
// SET CLR
|
||||
SET_PERI_REG_MASK(RTC_WDT_INT_CLR_REG, RTC_WDT_SUPER_WDT_INT_CLR); /* SWD */
|
||||
SET_PERI_REG_MASK(LP_ANA_LP_INT_CLR_REG, LP_ANA_BOD_MODE0_LP_INT_ENA); /* BROWN_OUT */
|
||||
SET_PERI_REG_MASK(RTC_WDT_INT_CLR_REG, RTC_WDT_LP_WDT_INT_CLR); /* WDT */
|
||||
#else
|
||||
REG_WRITE(RTC_CNTL_INT_ENA_REG, 0);
|
||||
REG_WRITE(RTC_CNTL_INT_CLR_REG, UINT32_MAX);
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "soc/rtc.h"
|
||||
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
|
||||
int esp_clk_apb_freq(void)
|
||||
{
|
||||
return rtc_clk_apb_freq_get();
|
||||
}
|
||||
|
||||
#endif // BOOTLOADER_BUILD
|
||||
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include "string.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_rom_spiflash.h"
|
||||
#include "esp_rom_crc.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
#include "esp_rom_sys.h"
|
||||
#include "esp_flash_partitions.h"
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "bootloader_common.h"
|
||||
#include "bootloader_utility.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/efuse_reg.h"
|
||||
#include "hal/gpio_ll.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "bootloader_sha.h"
|
||||
#include "sys/param.h"
|
||||
|
||||
#define ESP_PARTITION_HASH_LEN 32 /* SHA-256 digest length */
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "boot_comm");
|
||||
|
||||
esp_comm_gpio_hold_t bootloader_common_check_long_hold_gpio(uint32_t num_pin, uint32_t delay_sec)
|
||||
{
|
||||
return bootloader_common_check_long_hold_gpio_level(num_pin, delay_sec, false);
|
||||
}
|
||||
|
||||
esp_comm_gpio_hold_t bootloader_common_check_long_hold_gpio_level(uint32_t num_pin, uint32_t delay_sec, bool level)
|
||||
{
|
||||
esp_rom_gpio_pad_select_gpio(num_pin);
|
||||
if (((1ULL << num_pin) & SOC_GPIO_VALID_GPIO_MASK) != 0) {
|
||||
gpio_ll_input_enable(&GPIO, num_pin);
|
||||
}
|
||||
esp_rom_gpio_pad_pullup_only(num_pin);
|
||||
uint32_t tm_start = esp_log_early_timestamp();
|
||||
if (gpio_ll_get_level(&GPIO, num_pin) != level) {
|
||||
return GPIO_NOT_HOLD;
|
||||
}
|
||||
do {
|
||||
if (gpio_ll_get_level(&GPIO, num_pin) != level) {
|
||||
return GPIO_SHORT_HOLD;
|
||||
}
|
||||
} while (delay_sec > ((esp_log_early_timestamp() - tm_start) / 1000L));
|
||||
return GPIO_LONG_HOLD;
|
||||
}
|
||||
|
||||
// Search for a label in the list. list = "nvs1, nvs2, otadata, nvs"; label = "nvs".
|
||||
bool bootloader_common_label_search(const char *list, char *label)
|
||||
{
|
||||
if (list == NULL || label == NULL) {
|
||||
return false;
|
||||
}
|
||||
const char *sub_list_start_like_label = strstr(list, label);
|
||||
while (sub_list_start_like_label != NULL) {
|
||||
|
||||
// ["," or " "] + label + ["," or " " or "\0"]
|
||||
// first character before the label found there must be a delimiter ["," or " "].
|
||||
int idx_first = sub_list_start_like_label - list;
|
||||
if (idx_first == 0 || (idx_first != 0 && (list[idx_first - 1] == ',' || list[idx_first - 1] == ' '))) {
|
||||
// next character after the label found there must be a delimiter ["," or " " or "\0"].
|
||||
int len_label = strlen(label);
|
||||
if (sub_list_start_like_label[len_label] == 0 ||
|
||||
sub_list_start_like_label[len_label] == ',' ||
|
||||
sub_list_start_like_label[len_label] == ' ') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// [start_delim] + label + [end_delim] was not found.
|
||||
// Position is moving to next delimiter if it is not the end of list.
|
||||
size_t pos_delim = strcspn(sub_list_start_like_label, ", ");
|
||||
if (pos_delim == strlen(sub_list_start_like_label)) {
|
||||
break;
|
||||
}
|
||||
sub_list_start_like_label = strstr(&sub_list_start_like_label[pos_delim], label);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//This function erases while mmap is not unmapped yet. Can't be called in the app while XIP on PSRAM.
|
||||
bool bootloader_common_erase_part_type_data(const char *list_erase, bool ota_data_erase)
|
||||
{
|
||||
const esp_partition_info_t *partitions;
|
||||
const char *marker;
|
||||
esp_err_t err;
|
||||
int num_partitions;
|
||||
bool ret = true;
|
||||
|
||||
partitions = bootloader_mmap(ESP_PARTITION_TABLE_OFFSET, ESP_PARTITION_TABLE_MAX_LEN);
|
||||
if (!partitions) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", ESP_PARTITION_TABLE_OFFSET, ESP_PARTITION_TABLE_MAX_LEN);
|
||||
return false;
|
||||
}
|
||||
ESP_LOGD(TAG, "mapped partition table 0x%x at 0x%x", ESP_PARTITION_TABLE_OFFSET, (intptr_t)partitions);
|
||||
|
||||
err = esp_partition_table_verify(partitions, true, &num_partitions);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to verify partition table");
|
||||
ret = false;
|
||||
} else {
|
||||
ESP_LOGI(TAG, "## Label Usage Offset Length Cleaned");
|
||||
for (int i = 0; i < num_partitions; i++) {
|
||||
const esp_partition_info_t *partition = &partitions[i];
|
||||
char label[sizeof(partition->label) + 1] = {0};
|
||||
if (partition->type == PART_TYPE_DATA) {
|
||||
bool fl_ota_data_erase = false;
|
||||
if (ota_data_erase == true && partition->subtype == PART_SUBTYPE_DATA_OTA) {
|
||||
fl_ota_data_erase = true;
|
||||
}
|
||||
// partition->label is not null-terminated string.
|
||||
strncpy(label, (char *)&partition->label, sizeof(label) - 1);
|
||||
if (fl_ota_data_erase == true || (bootloader_common_label_search(list_erase, label) == true)) {
|
||||
err = bootloader_flash_erase_range(partition->pos.offset, partition->pos.size);
|
||||
if (err != ESP_OK) {
|
||||
ret = false;
|
||||
marker = "err";
|
||||
} else {
|
||||
marker = "yes";
|
||||
}
|
||||
} else {
|
||||
marker = "no";
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "%2d %-16s data %08"PRIx32" %08"PRIx32" [%s]", i, partition->label,
|
||||
partition->pos.offset, partition->pos.size, marker);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bootloader_munmap(partitions);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t bootloader_common_get_sha256_of_partition(uint32_t address, uint32_t size, int type, uint8_t *out_sha_256)
|
||||
{
|
||||
if (out_sha_256 == NULL || size == 0) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (type == PART_TYPE_APP || type == PART_TYPE_BOOTLOADER) {
|
||||
const esp_partition_pos_t partition_pos = {
|
||||
.offset = address,
|
||||
.size = size,
|
||||
};
|
||||
esp_image_metadata_t data;
|
||||
if (esp_image_get_metadata(&partition_pos, &data) != ESP_OK) {
|
||||
return ESP_ERR_IMAGE_INVALID;
|
||||
}
|
||||
if (data.image.hash_appended) {
|
||||
memcpy(out_sha_256, data.image_digest, ESP_PARTITION_HASH_LEN);
|
||||
uint8_t calc_sha256[ESP_PARTITION_HASH_LEN];
|
||||
// The hash is verified before returning, if app content is invalid then the function returns ESP_ERR_IMAGE_INVALID.
|
||||
esp_err_t error = bootloader_sha256_flash_contents(address, data.image_len - ESP_PARTITION_HASH_LEN, calc_sha256);
|
||||
if (error || memcmp(data.image_digest, calc_sha256, ESP_PARTITION_HASH_LEN) != 0) {
|
||||
return ESP_ERR_IMAGE_INVALID;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
// If image doesn't have a appended hash then hash calculates for entire image.
|
||||
size = data.image_len;
|
||||
}
|
||||
// If image is type by data then hash is calculated for entire image.
|
||||
return bootloader_sha256_flash_contents(address, size, out_sha_256);
|
||||
}
|
||||
|
||||
void bootloader_common_vddsdio_configure(void)
|
||||
{
|
||||
#if CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V
|
||||
rtc_vddsdio_config_t cfg = rtc_vddsdio_get_config();
|
||||
if (cfg.enable == 1 && cfg.tieh == RTC_VDDSDIO_TIEH_1_8V) { // VDDSDIO regulator is enabled @ 1.8V
|
||||
cfg.drefh = 3;
|
||||
cfg.drefm = 3;
|
||||
cfg.drefl = 3;
|
||||
cfg.force = 1;
|
||||
rtc_vddsdio_set_config(cfg);
|
||||
esp_rom_delay_us(10); // wait for regulator to become stable
|
||||
}
|
||||
#endif // CONFIG_BOOTLOADER_VDDSDIO_BOOST
|
||||
}
|
||||
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "string.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_rom_spiflash.h"
|
||||
#include "esp_rom_crc.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
#include "esp_flash_partitions.h"
|
||||
#if CONFIG_SECURE_BOOT
|
||||
#include "esp_secure_boot.h"
|
||||
#endif
|
||||
#include "bootloader_flash.h"
|
||||
#include "bootloader_common.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/efuse_reg.h"
|
||||
#include "soc/chip_revision.h"
|
||||
#include "hal/efuse_hal.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "bootloader_sha.h"
|
||||
#include "sys/param.h"
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "esp_rom_caps.h"
|
||||
#include "esp_macros.h"
|
||||
|
||||
#define ESP_PARTITION_HASH_LEN 32 /* SHA-256 digest length */
|
||||
#define IS_FIELD_SET(rev_full) (((rev_full) != 65535) && ((rev_full) != 0))
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "boot_comm");
|
||||
|
||||
bool bootloader_common_check_chip_revision_validity(const esp_image_header_t *img_hdr, bool check_max_revision)
|
||||
{
|
||||
if (!img_hdr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned revision = efuse_hal_chip_revision();
|
||||
unsigned min_rev = img_hdr->min_chip_rev_full;
|
||||
|
||||
bool is_min_rev_invalid = !ESP_CHIP_REV_ABOVE(revision, min_rev);
|
||||
if (is_min_rev_invalid) {
|
||||
ESP_LOGE(TAG, "chip revision check failed. Required >= v%d.%d, found v%d.%d.",
|
||||
min_rev / 100, min_rev % 100,
|
||||
revision / 100, revision % 100);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (check_max_revision) {
|
||||
unsigned int max_rev = img_hdr->max_chip_rev_full;
|
||||
bool is_max_rev_invalid = IS_FIELD_SET(max_rev) && revision > max_rev && !efuse_hal_get_disable_wafer_version_major();
|
||||
if (is_max_rev_invalid) {
|
||||
ESP_LOGE(TAG, "chip revision check failed. Required <= v%d.%d, found v%d.%d.",
|
||||
max_rev / 100, max_rev % 100,
|
||||
revision / 100, revision % 100);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t bootloader_common_ota_select_crc(const esp_ota_select_entry_t *s)
|
||||
{
|
||||
return esp_rom_crc32_le(UINT32_MAX, (uint8_t*)&s->ota_seq, 4);
|
||||
}
|
||||
|
||||
bool bootloader_common_ota_select_invalid(const esp_ota_select_entry_t *s)
|
||||
{
|
||||
return s->ota_seq == UINT32_MAX || s->ota_state == ESP_OTA_IMG_INVALID || s->ota_state == ESP_OTA_IMG_ABORTED;
|
||||
}
|
||||
|
||||
bool bootloader_common_ota_select_valid(const esp_ota_select_entry_t *s)
|
||||
{
|
||||
return bootloader_common_ota_select_invalid(s) == false && s->crc == bootloader_common_ota_select_crc(s);
|
||||
}
|
||||
|
||||
int bootloader_common_get_active_otadata(esp_ota_select_entry_t *two_otadata)
|
||||
{
|
||||
if (two_otadata == NULL) {
|
||||
return -1;
|
||||
}
|
||||
bool valid_two_otadata[2];
|
||||
valid_two_otadata[0] = bootloader_common_ota_select_valid(&two_otadata[0]);
|
||||
valid_two_otadata[1] = bootloader_common_ota_select_valid(&two_otadata[1]);
|
||||
return bootloader_common_select_otadata(two_otadata, valid_two_otadata, true);
|
||||
}
|
||||
|
||||
#if !CONFIG_IDF_TARGET_ESP32
|
||||
esp_err_t bootloader_common_check_efuse_blk_validity(uint32_t min_rev_full, uint32_t max_rev_full)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
#ifndef CONFIG_IDF_ENV_FPGA
|
||||
// Check whether the efuse block version satisfy the requirements of current image.
|
||||
uint32_t revision = efuse_hal_blk_version();
|
||||
uint32_t major_rev = revision / 100;
|
||||
uint32_t minor_rev = revision % 100;
|
||||
if (IS_FIELD_SET(min_rev_full) && !ESP_EFUSE_BLK_REV_ABOVE(revision, min_rev_full)) {
|
||||
ESP_LOGE(TAG, "Image requires efuse blk rev >= v%"PRIu32".%"PRIu32", but chip is v%"PRIu32".%"PRIu32,
|
||||
min_rev_full / 100, min_rev_full % 100, major_rev, minor_rev);
|
||||
err = ESP_FAIL;
|
||||
}
|
||||
// If burnt `disable_blk_version_major` bit, skip the max version check
|
||||
if ((IS_FIELD_SET(max_rev_full) && (revision > max_rev_full) && !efuse_hal_get_disable_blk_version_major())) {
|
||||
ESP_LOGE(TAG, "Image requires efuse blk rev <= v%"PRIu32".%"PRIu32", but chip is v%"PRIu32".%"PRIu32,
|
||||
max_rev_full / 100, max_rev_full % 100, major_rev, minor_rev);
|
||||
err = ESP_FAIL;
|
||||
}
|
||||
#endif
|
||||
return err;
|
||||
}
|
||||
#endif // !CONFIG_IDF_TARGET_ESP32
|
||||
|
||||
esp_err_t bootloader_common_check_chip_validity(const esp_image_header_t* img_hdr, esp_image_type type)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
esp_chip_id_t chip_id = CONFIG_IDF_FIRMWARE_CHIP_ID;
|
||||
if (chip_id != img_hdr->chip_id) {
|
||||
ESP_LOGE(TAG, "mismatch chip ID, expected %d, found %d", chip_id, img_hdr->chip_id);
|
||||
err = ESP_FAIL;
|
||||
} else {
|
||||
#ifndef CONFIG_IDF_ENV_FPGA
|
||||
if (type == ESP_IMAGE_APPLICATION) {
|
||||
if (!bootloader_common_check_chip_revision_validity(img_hdr, true)) {
|
||||
err = ESP_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
// Maximum revision check is skipped for bootloader images
|
||||
if (type == ESP_IMAGE_BOOTLOADER) {
|
||||
if (!bootloader_common_check_chip_revision_validity(img_hdr, false)) {
|
||||
err = ESP_FAIL;
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_IDF_ENV_FPGA
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int bootloader_common_select_otadata(const esp_ota_select_entry_t *two_otadata, bool *valid_two_otadata, bool max)
|
||||
{
|
||||
if (two_otadata == NULL || valid_two_otadata == NULL) {
|
||||
return -1;
|
||||
}
|
||||
int active_otadata = -1;
|
||||
if (valid_two_otadata[0] && valid_two_otadata[1]) {
|
||||
uint32_t condition = (max == true) ? MAX(two_otadata[0].ota_seq, two_otadata[1].ota_seq) : MIN(two_otadata[0].ota_seq, two_otadata[1].ota_seq);
|
||||
if (condition == two_otadata[0].ota_seq) {
|
||||
active_otadata = 0;
|
||||
} else {
|
||||
active_otadata = 1;
|
||||
}
|
||||
ESP_LOGD(TAG, "Both OTA copies are valid");
|
||||
} else {
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
if (valid_two_otadata[i]) {
|
||||
active_otadata = i;
|
||||
ESP_LOGD(TAG, "Only otadata[%d] is valid", i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return active_otadata;
|
||||
}
|
||||
|
||||
#if CONFIG_BOOTLOADER_RESERVE_RTC_MEM
|
||||
|
||||
static uint32_t rtc_retain_mem_size(void) {
|
||||
#if CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC && !CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC_IN_CRC
|
||||
/* A custom memory has been reserved by the user, do not consider this memory into CRC calculation as it may change without
|
||||
* the have the user updating the CRC. Return the offset of the custom field, which is equivalent to size of the structure
|
||||
* minus the size of everything after (including) `custom` */
|
||||
return offsetof(rtc_retain_mem_t, custom);
|
||||
#else
|
||||
return sizeof(rtc_retain_mem_t) - sizeof(bootloader_common_get_rtc_retain_mem()->crc);
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool is_retain_mem_valid(void)
|
||||
{
|
||||
rtc_retain_mem_t* rtc_retain_mem = bootloader_common_get_rtc_retain_mem();
|
||||
return esp_rom_crc32_le(UINT32_MAX, (uint8_t*)rtc_retain_mem, rtc_retain_mem_size()) == rtc_retain_mem->crc && rtc_retain_mem->crc != UINT32_MAX;
|
||||
}
|
||||
|
||||
static void update_rtc_retain_mem_crc(void)
|
||||
{
|
||||
rtc_retain_mem_t* rtc_retain_mem = bootloader_common_get_rtc_retain_mem();
|
||||
rtc_retain_mem->crc = esp_rom_crc32_le(UINT32_MAX, (uint8_t*)rtc_retain_mem, rtc_retain_mem_size());
|
||||
}
|
||||
|
||||
NOINLINE_ATTR void bootloader_common_reset_rtc_retain_mem(void)
|
||||
{
|
||||
hal_memset(bootloader_common_get_rtc_retain_mem(), 0, sizeof(rtc_retain_mem_t));
|
||||
}
|
||||
|
||||
uint16_t bootloader_common_get_rtc_retain_mem_reboot_counter(void)
|
||||
{
|
||||
if (is_retain_mem_valid()) {
|
||||
return bootloader_common_get_rtc_retain_mem()->reboot_counter;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bootloader_common_set_rtc_retain_mem_factory_reset_state(void)
|
||||
{
|
||||
if (!is_retain_mem_valid()) {
|
||||
bootloader_common_reset_rtc_retain_mem();
|
||||
}
|
||||
bootloader_common_get_rtc_retain_mem()->flags.factory_reset_state = true;
|
||||
update_rtc_retain_mem_crc();
|
||||
}
|
||||
|
||||
bool bootloader_common_get_rtc_retain_mem_factory_reset_state(void)
|
||||
{
|
||||
rtc_retain_mem_t* rtc_retain_mem = bootloader_common_get_rtc_retain_mem();
|
||||
if (is_retain_mem_valid()) {
|
||||
bool factory_reset_state = rtc_retain_mem->flags.factory_reset_state;
|
||||
if (factory_reset_state == true) {
|
||||
rtc_retain_mem->flags.factory_reset_state = false;
|
||||
update_rtc_retain_mem_crc();
|
||||
}
|
||||
return factory_reset_state;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
esp_partition_pos_t* bootloader_common_get_rtc_retain_mem_partition(void)
|
||||
{
|
||||
if (is_retain_mem_valid()) {
|
||||
return &bootloader_common_get_rtc_retain_mem()->partition;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void bootloader_common_update_rtc_retain_mem(esp_partition_pos_t* partition, bool reboot_counter)
|
||||
{
|
||||
rtc_retain_mem_t* rtc_retain_mem = bootloader_common_get_rtc_retain_mem();
|
||||
if (reboot_counter) {
|
||||
if (!is_retain_mem_valid()) {
|
||||
bootloader_common_reset_rtc_retain_mem();
|
||||
}
|
||||
if (++rtc_retain_mem->reboot_counter == 0) {
|
||||
// do not allow to overflow. Stop it.
|
||||
--rtc_retain_mem->reboot_counter;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (partition != NULL) {
|
||||
rtc_retain_mem->partition.offset = partition->offset;
|
||||
rtc_retain_mem->partition.size = partition->size;
|
||||
}
|
||||
|
||||
update_rtc_retain_mem_crc();
|
||||
}
|
||||
|
||||
rtc_retain_mem_t* bootloader_common_get_rtc_retain_mem(void)
|
||||
{
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
|
||||
#if ESP_ROM_HAS_LP_ROM
|
||||
#if CONFIG_IDF_TARGET_ESP32P4
|
||||
#define RTC_RETAIN_MEM_ADDR (SOC_RTC_DRAM_LOW + CONFIG_P4_REV3_MSPI_WORKAROUND_SIZE)
|
||||
#else
|
||||
#define RTC_RETAIN_MEM_ADDR (SOC_RTC_DRAM_LOW)
|
||||
#endif
|
||||
#else
|
||||
/* Since the structure containing the retain_mem_t is aligned on 8 by the linker, make sure we align this
|
||||
* structure size here too */
|
||||
#define RETAIN_MEM_SIZE ESP_ALIGN_UP(sizeof(rtc_retain_mem_t), 8)
|
||||
#define RTC_RETAIN_MEM_ADDR (SOC_RTC_DRAM_HIGH - RETAIN_MEM_SIZE)
|
||||
#endif //ESP_ROM_HAS_LP_ROM
|
||||
|
||||
#if CONFIG_SECURE_BOOT && ESP_ROM_SUPPORT_SECURE_BOOT_FAST_WAKEUP
|
||||
static rtc_retain_mem_t *const s_bootloader_retain_mem = (rtc_retain_mem_t *)RTC_RETAIN_MEM_ADDR - ESP_SECURE_BOOT_DIGEST_LEN;
|
||||
#else
|
||||
static rtc_retain_mem_t *const s_bootloader_retain_mem = (rtc_retain_mem_t *)RTC_RETAIN_MEM_ADDR;
|
||||
#endif
|
||||
return s_bootloader_retain_mem;
|
||||
#else
|
||||
static __attribute__((section(".bootloader_data_rtc_mem"))) rtc_retain_mem_t s_bootloader_retain_mem;
|
||||
return &s_bootloader_retain_mem;
|
||||
#endif // !BOOTLOADER_BUILD
|
||||
}
|
||||
|
||||
|
||||
#endif // CONFIG_BOOTLOADER_RESERVE_RTC_MEM
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "bootloader_console.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "hal/uart_periph.h"
|
||||
#include "soc/uart_pins.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "hal/gpio_ll.h"
|
||||
#include "hal/uart_ll.h"
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/usb/cdc_acm.h"
|
||||
#include "esp32s2/rom/usb/usb_common.h"
|
||||
#endif
|
||||
#if CONFIG_ESP_CONSOLE_USB_CDC
|
||||
#include "hal/usb_wrap_ll.h"
|
||||
#endif
|
||||
#include "esp_rom_gpio.h"
|
||||
#include "esp_rom_serial_output.h"
|
||||
#include "esp_rom_sys.h"
|
||||
#include "esp_rom_caps.h"
|
||||
|
||||
static void __attribute__((unused)) release_default_console_io(void)
|
||||
{
|
||||
// Default console is UART0 with TX and RX on their IOMUX pins
|
||||
gpio_ll_output_disable(&GPIO, U0TXD_GPIO_NUM);
|
||||
gpio_ll_func_sel(&GPIO, U0TXD_GPIO_NUM, PIN_FUNC_GPIO); // Set TX pin to GPIO function to truly disable output
|
||||
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, UART_PERIPH_SIGNAL(UART_NUM_0, SOC_UART_PERIPH_SIGNAL_RX), 0);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ESP_CONSOLE_NONE
|
||||
void bootloader_console_init(void)
|
||||
{
|
||||
// Wait for UART FIFO to be empty.
|
||||
esp_rom_output_tx_wait_idle(0);
|
||||
release_default_console_io();
|
||||
|
||||
esp_rom_install_channel_putc(1, NULL);
|
||||
esp_rom_install_channel_putc(2, NULL);
|
||||
}
|
||||
#endif // CONFIG_ESP_CONSOLE_NONE
|
||||
|
||||
#ifdef CONFIG_ESP_CONSOLE_UART
|
||||
void bootloader_console_init(void)
|
||||
{
|
||||
const int uart_num = CONFIG_ESP_CONSOLE_UART_NUM;
|
||||
int __DECLARE_RCC_ATOMIC_ENV __attribute__ ((unused)); // To avoid build errors/warnings about __DECLARE_RCC_ATOMIC_ENV
|
||||
|
||||
// Install rom uart printf as console.
|
||||
esp_rom_install_uart_printf();
|
||||
|
||||
// Wait for UART FIFO to be empty.
|
||||
esp_rom_output_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 >= 0) ? CONFIG_ESP_CONSOLE_UART_TX_GPIO : U0TXD_GPIO_NUM;
|
||||
const int uart_rx_gpio = (CONFIG_ESP_CONSOLE_UART_RX_GPIO >= 0) ? CONFIG_ESP_CONSOLE_UART_RX_GPIO : U0RXD_GPIO_NUM;
|
||||
|
||||
// Switch to the new UART
|
||||
esp_rom_output_set_as_console(uart_num); // changes UART number used for esp_rom_printf in ROM code
|
||||
esp_rom_output_switch_buffer(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 != U0TXD_GPIO_NUM ||
|
||||
uart_rx_gpio != U0RXD_GPIO_NUM) {
|
||||
release_default_console_io();
|
||||
// Route GPIO signals to/from pins
|
||||
const uint32_t tx_idx = UART_PERIPH_SIGNAL(uart_num, SOC_UART_PERIPH_SIGNAL_TX);
|
||||
const uint32_t rx_idx = UART_PERIPH_SIGNAL(uart_num, SOC_UART_PERIPH_SIGNAL_RX);
|
||||
gpio_ll_func_sel(&GPIO, uart_rx_gpio, PIN_FUNC_GPIO);
|
||||
gpio_ll_input_enable(&GPIO, uart_rx_gpio);
|
||||
esp_rom_gpio_pad_pullup_only(uart_rx_gpio);
|
||||
esp_rom_gpio_connect_out_signal(uart_tx_gpio, tx_idx, 0, 0);
|
||||
esp_rom_gpio_connect_in_signal(uart_rx_gpio, rx_idx, 0);
|
||||
gpio_ll_func_sel(&GPIO, uart_tx_gpio, PIN_FUNC_GPIO);
|
||||
// Enable the peripheral
|
||||
uart_ll_enable_bus_clock(uart_num, true);
|
||||
uart_ll_reset_register(uart_num);
|
||||
// Set clock source
|
||||
#if SOC_UART_SUPPORT_XTAL_CLK
|
||||
uart_ll_set_sclk(UART_LL_GET_HW(uart_num), (soc_module_clk_t)UART_SCLK_XTAL);
|
||||
#else
|
||||
uart_ll_set_sclk(UART_LL_GET_HW(uart_num), (soc_module_clk_t)UART_SCLK_APB);
|
||||
#endif
|
||||
// Reset TX and RX FIFOs
|
||||
uart_ll_txfifo_rst(UART_LL_GET_HW(uart_num));
|
||||
uart_ll_rxfifo_rst(UART_LL_GET_HW(uart_num));
|
||||
}
|
||||
#endif // CONFIG_ESP_CONSOLE_UART_CUSTOM
|
||||
|
||||
// Set configured UART console baud rate
|
||||
uint32_t clock_hz = rtc_clk_apb_freq_get();
|
||||
#if ESP_ROM_UART_CLK_IS_XTAL
|
||||
clock_hz = (uint32_t)rtc_clk_xtal_freq_get() * MHZ; // From esp32-s3 on, UART clk source is selected to XTAL in ROM
|
||||
#endif
|
||||
_uart_ll_set_baudrate(UART_LL_GET_HW(uart_num), CONFIG_ESP_CONSOLE_UART_BAUDRATE, clock_hz);
|
||||
}
|
||||
#endif // CONFIG_ESP_CONSOLE_UART
|
||||
|
||||
#ifdef CONFIG_ESP_CONSOLE_USB_CDC
|
||||
/* Buffer for CDC data structures. No RX buffer allocated. */
|
||||
static char s_usb_cdc_buf[ESP_ROM_CDC_ACM_WORK_BUF_MIN];
|
||||
|
||||
void bootloader_console_init(void)
|
||||
{
|
||||
// Wait for UART FIFO to be empty.
|
||||
esp_rom_output_tx_wait_idle(0);
|
||||
release_default_console_io();
|
||||
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32S2
|
||||
/* ESP32-S2 specific patch to set the correct serial number in the descriptor.
|
||||
* Later chips don't need this.
|
||||
*/
|
||||
rom_usb_cdc_set_descriptor_patch();
|
||||
#endif
|
||||
|
||||
esp_rom_output_usb_acm_init(s_usb_cdc_buf, sizeof(s_usb_cdc_buf));
|
||||
esp_rom_output_set_as_console(ESP_ROM_USB_OTG_NUM);
|
||||
esp_rom_install_channel_putc(1, bootloader_console_write_char_usb);
|
||||
// Ensure that the USB FSLS PHY is mapped to the USB WRAP
|
||||
usb_wrap_ll_phy_enable_pad(&USB_WRAP, true);
|
||||
usb_wrap_ll_phy_enable_external(&USB_WRAP, false);
|
||||
}
|
||||
#endif //CONFIG_ESP_CONSOLE_USB_CDC
|
||||
|
||||
#ifdef CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
|
||||
void bootloader_console_init(void)
|
||||
{
|
||||
// Wait for UART FIFO to be empty.
|
||||
esp_rom_output_tx_wait_idle(0);
|
||||
release_default_console_io();
|
||||
|
||||
esp_rom_output_switch_buffer(ESP_ROM_USB_SERIAL_DEVICE_NUM);
|
||||
|
||||
/* Switch console channel to avoid output on UART and allow */
|
||||
esp_rom_output_set_as_console(ESP_ROM_USB_SERIAL_DEVICE_NUM);
|
||||
|
||||
/* ROM printf by default also prints to USB-Serial-JTAG on channel 2
|
||||
need to disable to not print twice */
|
||||
esp_rom_install_channel_putc(2, NULL);
|
||||
}
|
||||
#endif //CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* This file contains console-related functions which should be located in iram_loader_seg,
|
||||
* to be available in the "loader" phase, when iram_seg may be overwritten.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "bootloader_console.h"
|
||||
#include "esp_rom_serial_output.h"
|
||||
#include "esp_rom_sys.h"
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/usb/chip_usb_dw_wrapper.h"
|
||||
#include "esp32s2/rom/usb/usb_dc.h"
|
||||
#include "esp32s2/rom/usb/cdc_acm.h"
|
||||
#include "esp32s2/rom/usb/usb_persist.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
#include "esp32s3/rom/usb/chip_usb_dw_wrapper.h"
|
||||
#include "esp32s3/rom/usb/usb_dc.h"
|
||||
#include "esp32s3/rom/usb/cdc_acm.h"
|
||||
#include "esp32s3/rom/usb/usb_persist.h"
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ESP_CONSOLE_USB_CDC
|
||||
/* The following functions replace esp_rom_uart_putc, esp_rom_uart_tx_one_char,
|
||||
* and uart_tx_one_char_uart ROM functions. The main difference is that
|
||||
* uart_tx_one_char_uart calls cdc_acm_fifo_fill for each byte passed to it,
|
||||
* which results in very slow console output. The version here uses a TX buffer.
|
||||
* It also doesn't handle UART output, only works with USB.
|
||||
*/
|
||||
static char cdc_txbuf[ACM_BYTES_PER_TX];
|
||||
static size_t cdc_txpos;
|
||||
|
||||
static void bootloader_console_flush_usb(void)
|
||||
{
|
||||
cdc_acm_fifo_fill(uart_acm_dev, (const uint8_t *) cdc_txbuf, cdc_txpos);
|
||||
/* return value ignored — if bootloader fails to log something, proceed anyway */
|
||||
cdc_txpos = 0;
|
||||
}
|
||||
|
||||
static void bootloader_console_write_one_char_usb(char ch)
|
||||
{
|
||||
cdc_txbuf[cdc_txpos++] = ch;
|
||||
if (ch == '\n' || cdc_txpos == sizeof(cdc_txbuf)) {
|
||||
bootloader_console_flush_usb();
|
||||
}
|
||||
}
|
||||
|
||||
void bootloader_console_write_char_usb(char c)
|
||||
{
|
||||
if (c == '\n') {
|
||||
bootloader_console_write_one_char_usb('\r');
|
||||
bootloader_console_write_one_char_usb('\n');
|
||||
} else if (c == '\r') {
|
||||
} else {
|
||||
bootloader_console_write_one_char_usb(c);
|
||||
}
|
||||
}
|
||||
#endif //CONFIG_ESP_CONSOLE_USB_CDC
|
||||
|
||||
void bootloader_console_deinit(void)
|
||||
{
|
||||
#ifdef CONFIG_ESP_CONSOLE_UART
|
||||
/* Ensure any buffered log output is displayed */
|
||||
esp_rom_output_flush_tx(CONFIG_ESP_CONSOLE_ROM_SERIAL_PORT_NUM);
|
||||
#endif // CONFIG_ESP_CONSOLE_UART
|
||||
|
||||
#ifdef CONFIG_ESP_CONSOLE_USB_CDC
|
||||
bootloader_console_flush_usb();
|
||||
usb_dc_prepare_persist();
|
||||
chip_usb_set_persist_flags(USBDC_PERSIST_ENA);
|
||||
esp_rom_delay_us(100);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
usb_dc_check_poll_for_interrupts();
|
||||
}
|
||||
esp_rom_install_channel_putc(1, NULL);
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "bootloader_common.h"
|
||||
#include "hal/efuse_ll.h"
|
||||
#include "hal/efuse_hal.h"
|
||||
#include "esp_attr.h"
|
||||
|
||||
IRAM_ATTR uint32_t bootloader_common_get_chip_ver_pkg(void)
|
||||
{
|
||||
return efuse_ll_get_chip_ver_pkg();
|
||||
}
|
||||
|
||||
int bootloader_clock_get_rated_freq_mhz(void)
|
||||
{
|
||||
//TODO: IDF-6570, need refactor
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
return efuse_hal_get_rated_freq_mhz();
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32C2
|
||||
return 120;
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
return 160;
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32C6
|
||||
return 160;
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32C61
|
||||
return 160;
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32C5
|
||||
return 160;
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32H2
|
||||
//IDF-6570
|
||||
return 96;
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32H21
|
||||
return 96;
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32H4
|
||||
return 96;
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32P4
|
||||
return 400;
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
return 240;
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
return 240;
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32S31
|
||||
return 300;
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_log.h"
|
||||
#include "bootloader_init.h"
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "bootloader_flash_config.h"
|
||||
#include "bootloader_random.h"
|
||||
#include "bootloader_clock.h"
|
||||
#include "bootloader_common.h"
|
||||
#include "esp_cpu.h"
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#include "soc/rtc.h"
|
||||
#if SOC_WDT_SUPPORTED || SOC_RTC_WDT_SUPPORTED
|
||||
#include "hal/wdt_hal.h"
|
||||
#endif
|
||||
#include "hal/efuse_hal.h"
|
||||
#include "hal/cache_hal.h"
|
||||
#include "hal/mmu_hal.h"
|
||||
#include "esp_bootloader_desc.h"
|
||||
#include "esp_rom_sys.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "boot");
|
||||
|
||||
#if !CONFIG_APP_BUILD_TYPE_RAM
|
||||
esp_image_header_t WORD_ALIGNED_ATTR bootloader_image_hdr;
|
||||
#endif
|
||||
|
||||
void bootloader_clear_bss_section(void)
|
||||
{
|
||||
memset(&_bss_start, 0, (uintptr_t)&_bss_end - (uintptr_t)&_bss_start);
|
||||
}
|
||||
|
||||
esp_err_t bootloader_read_bootloader_header(void)
|
||||
{
|
||||
/* load bootloader image header */
|
||||
#if SOC_RECOVERY_BOOTLOADER_SUPPORTED
|
||||
const uint32_t bootloader_flash_offset = esp_rom_get_bootloader_offset();
|
||||
#else
|
||||
const uint32_t bootloader_flash_offset = ESP_PRIMARY_BOOTLOADER_OFFSET;
|
||||
#endif
|
||||
if (bootloader_flash_read(bootloader_flash_offset, &bootloader_image_hdr, sizeof(esp_image_header_t), true) != ESP_OK) {
|
||||
ESP_EARLY_LOGE(TAG, "failed to load bootloader image header!");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t bootloader_check_bootloader_validity(void)
|
||||
{
|
||||
unsigned int chip_revision = efuse_hal_chip_revision();
|
||||
unsigned int chip_major_rev = chip_revision / 100;
|
||||
unsigned int chip_minor_rev = chip_revision % 100;
|
||||
ESP_EARLY_LOGI(TAG, "chip revision: v%d.%d", chip_major_rev, chip_minor_rev);
|
||||
/* ESP32 doesn't have more memory and more efuse bits for block major version. */
|
||||
#if !CONFIG_IDF_TARGET_ESP32
|
||||
unsigned int efuse_revision = efuse_hal_blk_version();
|
||||
unsigned int efuse_major_rev = efuse_revision / 100;
|
||||
unsigned int efuse_minor_rev = efuse_revision % 100;
|
||||
ESP_EARLY_LOGI(TAG, "efuse block revision: v%d.%d", efuse_major_rev, efuse_minor_rev);
|
||||
#endif // !CONFIG_IDF_TARGET_ESP32
|
||||
/* 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;
|
||||
}
|
||||
|
||||
void bootloader_config_wdt(void)
|
||||
{
|
||||
#if SOC_RTC_WDT_SUPPORTED
|
||||
/*
|
||||
* At this point, the flashboot protection of RWDT and MWDT0 will have been
|
||||
* automatically enabled. We can disable flashboot protection as it's not
|
||||
* needed anymore. If configured to do so, we also initialize the RWDT to
|
||||
* protect the remainder of the bootloader process.
|
||||
*/
|
||||
//Disable RWDT flashboot protection.
|
||||
wdt_hal_context_t rwdt_ctx = RWDT_HAL_CONTEXT_DEFAULT();
|
||||
wdt_hal_write_protect_disable(&rwdt_ctx);
|
||||
wdt_hal_set_flashboot_en(&rwdt_ctx, false);
|
||||
wdt_hal_write_protect_enable(&rwdt_ctx);
|
||||
|
||||
#ifdef CONFIG_BOOTLOADER_WDT_ENABLE
|
||||
//Initialize and start RWDT to protect the for bootloader if configured to do so
|
||||
ESP_EARLY_LOGD(TAG, "Enabling RTCWDT(%d ms)", CONFIG_BOOTLOADER_WDT_TIME_MS);
|
||||
wdt_hal_init(&rwdt_ctx, WDT_RWDT, 0, false);
|
||||
uint32_t stage_timeout_ticks = (uint32_t)((uint64_t)CONFIG_BOOTLOADER_WDT_TIME_MS * rtc_clk_slow_freq_get_hz() / 1000);
|
||||
wdt_hal_write_protect_disable(&rwdt_ctx);
|
||||
wdt_hal_config_stage(&rwdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC);
|
||||
wdt_hal_enable(&rwdt_ctx);
|
||||
wdt_hal_write_protect_enable(&rwdt_ctx);
|
||||
#endif
|
||||
|
||||
#endif /* SOC_RTC_WDT_SUPPORTED */
|
||||
|
||||
#if SOC_WDT_SUPPORTED
|
||||
//Disable MWDT0 flashboot protection. When RTC WDT is present, run this after RWDT
|
||||
//setup above so there is no gap in WDT protection during bootloader.
|
||||
wdt_hal_context_t mwdt_ctx = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0};
|
||||
wdt_hal_write_protect_disable(&mwdt_ctx);
|
||||
wdt_hal_set_flashboot_en(&mwdt_ctx, false);
|
||||
wdt_hal_write_protect_enable(&mwdt_ctx);
|
||||
#endif /* SOC_WDT_SUPPORTED */
|
||||
}
|
||||
|
||||
void bootloader_enable_random(void)
|
||||
{
|
||||
ESP_EARLY_LOGI(TAG, "Enabling RNG early entropy source...");
|
||||
bootloader_random_enable();
|
||||
}
|
||||
|
||||
void bootloader_print_banner(void)
|
||||
{
|
||||
#if BOOTLOADER_BUILD
|
||||
if (CONFIG_BOOTLOADER_LOG_LEVEL >= ESP_LOG_INFO) {
|
||||
const esp_bootloader_desc_t *desc = esp_bootloader_get_description();
|
||||
ESP_EARLY_LOGI(TAG, "ESP-IDF %s 2nd stage bootloader", desc->idf_ver);
|
||||
#ifdef CONFIG_BOOTLOADER_COMPILE_TIME_DATE
|
||||
ESP_EARLY_LOGI(TAG, "compile time %s", desc->date_time);
|
||||
#endif
|
||||
}
|
||||
#endif // BOOTLOADER_BUILD
|
||||
|
||||
#if CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
|
||||
#if (SOC_CPU_CORES_NUM > 1)
|
||||
ESP_EARLY_LOGW(TAG, "Unicore bootloader");
|
||||
#endif
|
||||
#else
|
||||
ESP_EARLY_LOGI(TAG, "Multicore bootloader");
|
||||
#endif
|
||||
}
|
||||
|
||||
void bootloader_init_ext_mem(void)
|
||||
{
|
||||
//init cache hal
|
||||
cache_hal_config_t cache_config = {
|
||||
#if CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
|
||||
.core_nums = 1,
|
||||
#else
|
||||
.core_nums = SOC_CPU_CORES_NUM,
|
||||
#endif
|
||||
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||
.l2_cache_size = CONFIG_CACHE_L2_CACHE_SIZE,
|
||||
.l2_cache_line_size = CONFIG_CACHE_L2_CACHE_LINE_SIZE,
|
||||
#endif
|
||||
};
|
||||
cache_hal_init(&cache_config);
|
||||
//reset mmu
|
||||
mmu_hal_config_t mmu_config = {
|
||||
#if CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
|
||||
.core_nums = 1,
|
||||
#else
|
||||
.core_nums = SOC_CPU_CORES_NUM,
|
||||
#endif
|
||||
.mmu_page_size = CONFIG_MMU_PAGE_SIZE,
|
||||
};
|
||||
mmu_hal_init(&mmu_config);
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "hal/mpu_hal.h"
|
||||
#include "hal/mpu_types.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "bootloader_mem.h"
|
||||
#include "esp_cpu.h"
|
||||
|
||||
#include "hal/apm_hal.h"
|
||||
#if CONFIG_IDF_TARGET_ESP32S31
|
||||
#include "soc/hp_peri0_pms_reg.h"
|
||||
#include "soc/hp_peri1_pms_reg.h"
|
||||
#include "soc/lp_peri_pms_reg.h"
|
||||
#endif
|
||||
|
||||
void bootloader_init_mem(void)
|
||||
{
|
||||
|
||||
#if !defined(BOOTLOADER_BUILD)
|
||||
/* By default, these access path filters are enable and allow the
|
||||
* access to masters only if they are in TEE mode. Since all masters
|
||||
* except HP CPU boots in REE mode, default setting of these filters
|
||||
* will deny the access to all masters except HP CPU.
|
||||
* So, at boot disabling these filters. They will enable as per the
|
||||
* use case by TEE initialization code.
|
||||
*/
|
||||
#if SOC_APM_CTRL_FILTER_SUPPORTED
|
||||
apm_hal_enable_ctrl_filter_all(false);
|
||||
/* [APM] On power-up, only the HP CPU starts in TEE mode; others
|
||||
* default to REE2. APM blocks REE0–REE2 access by default.
|
||||
* Thus, all masters are set to TEE mode.
|
||||
*/
|
||||
#if SOC_APM_SUPPORT_TEE_PERI_ACCESS_CTRL
|
||||
apm_hal_set_master_sec_mode_all(APM_SEC_MODE_TEE);
|
||||
#endif // SOC_APM_SUPPORT_TEE_PERI_ACCESS_CTRL
|
||||
#endif // SOC_APM_CTRL_FILTER_SUPPORTED
|
||||
#endif
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32S31
|
||||
/* TODO: [ESP32S31] IDF-14620
|
||||
As a temp. fix to allow ULP access to all peripherals during bringup.
|
||||
Open all LP/HP peripheral PMS control registers for all security modes.
|
||||
*/
|
||||
for (uint32_t reg = LP_PERI_PMS_LP_SYSREG_CTRL_REG; reg <= LP_PERI_PMS_LP_DAC_CTRL_REG; reg += 4) {
|
||||
REG_WRITE(reg, 0xFF);
|
||||
}
|
||||
for (uint32_t reg = HP_PERI0_PMS_TRACE0_CTRL_REG; reg <= HP_PERI0_PMS_AXI_PERF_MON_CTRL_REG; reg += 4) {
|
||||
REG_WRITE(reg, 0xFF);
|
||||
}
|
||||
for (uint32_t reg = HP_PERI1_PMS_HP_USBOTG_PHY_CTRL_REG; reg <= HP_PERI1_PMS_HP_PERI1_PMS_CTRL_REG; reg += 4) {
|
||||
REG_WRITE(reg, 0xFF);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CONFIG_BOOTLOADER_REGION_PROTECTION_ENABLE
|
||||
// protect memory region
|
||||
esp_cpu_configure_region_protection();
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "esp_cpu.h"
|
||||
#include "esp_log.h"
|
||||
#include "bootloader_common.h"
|
||||
#include "esp_rom_sys.h"
|
||||
|
||||
|
||||
void __assert_func(const char *file, int line, const char *func, const char *expr)
|
||||
{
|
||||
|
||||
#if !CONFIG_OPTIMIZATION_ASSERTIONS_SILENT
|
||||
esp_rom_printf("Assert failed in %s, %s:%d (%s)\r\n", func, file, line, expr);
|
||||
#endif
|
||||
|
||||
ESP_INFINITE_LOOP();
|
||||
}
|
||||
|
||||
void abort(void)
|
||||
{
|
||||
#if !CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT
|
||||
esp_rom_printf("abort() was called at PC 0x%08x\r\n", (intptr_t)__builtin_return_address(0) - 3);
|
||||
#endif
|
||||
#if CONFIG_ESP_DEBUG_OCDAWARE
|
||||
if (esp_cpu_dbgr_is_attached()) {
|
||||
esp_cpu_dbgr_break();
|
||||
}
|
||||
#endif
|
||||
ESP_INFINITE_LOOP();
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2010-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_log.h"
|
||||
#include "bootloader_random.h"
|
||||
#include "esp_cpu.h"
|
||||
#include "hal/rng_ll.h"
|
||||
|
||||
#include "hal/rtc_timer_hal.h"
|
||||
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
#include "esp_random.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
|
||||
__attribute__((weak)) void bootloader_fill_random(void *buffer, size_t length)
|
||||
{
|
||||
return esp_fill_random(buffer, length);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#if !defined CONFIG_IDF_TARGET_ESP32S3
|
||||
#if (defined CONFIG_IDF_TARGET_ESP32C6 || defined CONFIG_IDF_TARGET_ESP32H2)
|
||||
#define RNG_CPU_WAIT_CYCLE_NUM (CONFIG_BOOTLOADER_CPU_CLK_FREQ_MHZ * 16) // Keep the byte sampling frequency in the ~62KHz range which has been
|
||||
// tested.
|
||||
#elif CONFIG_IDF_TARGET_ESP32P4
|
||||
// bootloader tested with around 63 KHz bytes reading frequency
|
||||
#define RNG_CPU_WAIT_CYCLE_NUM (CONFIG_BOOTLOADER_CPU_CLK_FREQ_MHZ * 16)
|
||||
#else
|
||||
#define RNG_CPU_WAIT_CYCLE_NUM (CONFIG_BOOTLOADER_CPU_CLK_FREQ_MHZ * 32 * 2) /* extra factor of 2 is precautionary */
|
||||
#endif
|
||||
#else
|
||||
#define RNG_CPU_WAIT_CYCLE_NUM (CONFIG_BOOTLOADER_CPU_CLK_FREQ_MHZ * 23) /* 45 KHz reading frequency is the maximum we have tested so far on S3 */
|
||||
#endif
|
||||
|
||||
__attribute__((weak)) void bootloader_fill_random(void *buffer, size_t length)
|
||||
{
|
||||
uint8_t *buffer_bytes = (uint8_t *)buffer;
|
||||
uint32_t random;
|
||||
uint32_t start, now;
|
||||
|
||||
assert(buffer != NULL);
|
||||
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
#if !SOC_RTC_TIMER_V1
|
||||
random = rng_ll_read_data();
|
||||
start = esp_cpu_get_cycle_count();
|
||||
do {
|
||||
random ^= rng_ll_read_data();
|
||||
now = esp_cpu_get_cycle_count();
|
||||
} while (now - start < RNG_CPU_WAIT_CYCLE_NUM);
|
||||
|
||||
// XOR the RT slow clock, which is asynchronous, to add some entropy and improve
|
||||
// the distribution
|
||||
uint32_t current_rtc_timer_counter = (rtc_timer_hal_get_cycle_count(0) & 0xFF);
|
||||
random = random ^ current_rtc_timer_counter;
|
||||
|
||||
buffer_bytes[i] = random & 0xFF;
|
||||
#else
|
||||
if (i == 0 || i % 4 == 0) { /* redundant check is for a compiler warning */
|
||||
/* in bootloader with ADC feeding HWRNG, we accumulate 1
|
||||
bit of entropy per 40 APB cycles (==80 CPU cycles.)
|
||||
|
||||
To avoid reading the entire RNG hardware state out
|
||||
as-is, we repeatedly read the RNG register and XOR all
|
||||
values.
|
||||
*/
|
||||
random = rng_ll_read_data();
|
||||
start = esp_cpu_get_cycle_count();
|
||||
do {
|
||||
random ^= rng_ll_read_data();
|
||||
now = esp_cpu_get_cycle_count();
|
||||
} while (now - start < RNG_CPU_WAIT_CYCLE_NUM);
|
||||
}
|
||||
buffer_bytes[i] = random >> ((i % 4) * 8);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif // BOOTLOADER_BUILD
|
||||
|
||||
#if CONFIG_ESP_BRINGUP_BYPASS_RANDOM_SETTING
|
||||
static void s_non_functional(const char *func)
|
||||
{
|
||||
ESP_EARLY_LOGW("rand", "%s non-functional as RNG has not been supported yet", func);
|
||||
}
|
||||
|
||||
void bootloader_random_enable()
|
||||
{
|
||||
s_non_functional(__func__);
|
||||
}
|
||||
|
||||
void bootloader_random_disable()
|
||||
{
|
||||
s_non_functional(__func__);
|
||||
}
|
||||
#endif // CONFIG_ESP_BRINGUP_BYPASS_RANDOM_SETTING
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#include "bootloader_random.h"
|
||||
#include "hal/rng_ll.h"
|
||||
#include "soc/rtc_periph.h"
|
||||
#include "soc/sens_reg.h"
|
||||
#include "soc/syscon_reg.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/i2s_reg.h"
|
||||
#include "soc/periph_defs.h"
|
||||
#include "esp_log.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#endif
|
||||
|
||||
void bootloader_random_enable(void)
|
||||
{
|
||||
/* Ensure the hardware RNG is enabled following a soft reset. This should always be the case already (this clock is
|
||||
never disabled while the CPU is running), this is a "belts and braces" type check.
|
||||
*/
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, DPORT_WIFI_CLK_RNG_EN);
|
||||
#else
|
||||
periph_module_enable(PERIPH_RNG_MODULE);
|
||||
#endif // BOOTLOADER_BUILD
|
||||
|
||||
/* Enable SAR ADC in test mode to feed ADC readings of the 1.1V
|
||||
reference via I2S into the RNG entropy input.
|
||||
|
||||
Note: I2S requires the PLL to be running, so the call to rtc_set_cpu_freq(CPU_80M)
|
||||
in early bootloader startup must have been made.
|
||||
*/
|
||||
SET_PERI_REG_BITS(RTC_CNTL_TEST_MUX_REG, RTC_CNTL_DTEST_RTC, 2, RTC_CNTL_DTEST_RTC_S);
|
||||
SET_PERI_REG_MASK(RTC_CNTL_TEST_MUX_REG, RTC_CNTL_ENT_RTC);
|
||||
SET_PERI_REG_MASK(SENS_SAR_START_FORCE_REG, SENS_SAR2_EN_TEST);
|
||||
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN);
|
||||
#else
|
||||
periph_module_enable(PERIPH_I2S0_MODULE);
|
||||
#endif // BOOTLOADER_BUILD
|
||||
CLEAR_PERI_REG_MASK(SENS_SAR_START_FORCE_REG, SENS_ULP_CP_FORCE_START_TOP);
|
||||
CLEAR_PERI_REG_MASK(SENS_SAR_START_FORCE_REG, SENS_ULP_CP_START_TOP);
|
||||
|
||||
// Test pattern configuration byte 0xAD:
|
||||
//--[7:4] channel_sel: 10-->en_test
|
||||
//--[3:2] bit_width : 3-->12bit
|
||||
//--[1:0] atten : 1-->3dB attenuation
|
||||
WRITE_PERI_REG(SYSCON_SARADC_SAR2_PATT_TAB1_REG, 0xADADADAD);
|
||||
WRITE_PERI_REG(SYSCON_SARADC_SAR2_PATT_TAB2_REG, 0xADADADAD);
|
||||
WRITE_PERI_REG(SYSCON_SARADC_SAR2_PATT_TAB3_REG, 0xADADADAD);
|
||||
WRITE_PERI_REG(SYSCON_SARADC_SAR2_PATT_TAB4_REG, 0xADADADAD);
|
||||
SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_SAR, 3, SENS_FORCE_XPD_SAR_S);
|
||||
SET_PERI_REG_MASK(SENS_SAR_READ_CTRL_REG, SENS_SAR1_DIG_FORCE);
|
||||
SET_PERI_REG_MASK(SENS_SAR_READ_CTRL2_REG, SENS_SAR2_DIG_FORCE);
|
||||
|
||||
SET_PERI_REG_MASK(SYSCON_SARADC_CTRL_REG, SYSCON_SARADC_SAR2_MUX);
|
||||
SET_PERI_REG_BITS(SYSCON_SARADC_CTRL_REG, SYSCON_SARADC_SAR_CLK_DIV, 4, SYSCON_SARADC_SAR_CLK_DIV_S);
|
||||
SET_PERI_REG_BITS(SYSCON_SARADC_FSM_REG, SYSCON_SARADC_RSTB_WAIT, 8, SYSCON_SARADC_RSTB_WAIT_S); /* was 1 */
|
||||
SET_PERI_REG_BITS(SYSCON_SARADC_FSM_REG, SYSCON_SARADC_START_WAIT, 10, SYSCON_SARADC_START_WAIT_S);
|
||||
SET_PERI_REG_BITS(SYSCON_SARADC_CTRL_REG, SYSCON_SARADC_WORK_MODE, 0, SYSCON_SARADC_WORK_MODE_S);
|
||||
SET_PERI_REG_MASK(SYSCON_SARADC_CTRL_REG, SYSCON_SARADC_SAR_SEL);
|
||||
CLEAR_PERI_REG_MASK(SYSCON_SARADC_CTRL_REG, SYSCON_SARADC_DATA_SAR_SEL);
|
||||
SET_PERI_REG_BITS(I2S_SAMPLE_RATE_CONF_REG(0), I2S_RX_BCK_DIV_NUM, 20, I2S_RX_BCK_DIV_NUM_S);
|
||||
SET_PERI_REG_MASK(SYSCON_SARADC_CTRL_REG, SYSCON_SARADC_DATA_TO_I2S);
|
||||
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF2_REG(0), I2S_CAMERA_EN);
|
||||
SET_PERI_REG_MASK(I2S_CONF2_REG(0), I2S_LCD_EN);
|
||||
SET_PERI_REG_MASK(I2S_CONF2_REG(0), I2S_DATA_ENABLE);
|
||||
SET_PERI_REG_MASK(I2S_CONF2_REG(0), I2S_DATA_ENABLE_TEST_EN);
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_START);
|
||||
rng_ll_enable();
|
||||
}
|
||||
|
||||
void bootloader_random_disable(void)
|
||||
{
|
||||
rng_ll_disable();
|
||||
|
||||
/* Reset some i2s configuration (possibly redundant as we reset entire
|
||||
I2S peripheral further down). */
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_START);
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET);
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET);
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF2_REG(0), I2S_CAMERA_EN);
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF2_REG(0), I2S_LCD_EN);
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF2_REG(0), I2S_DATA_ENABLE_TEST_EN);
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF2_REG(0), I2S_DATA_ENABLE);
|
||||
|
||||
/* Disable i2s clock */
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN);
|
||||
#else
|
||||
periph_module_disable(PERIPH_I2S0_MODULE);
|
||||
#endif // BOOTLOADER_BUILD
|
||||
|
||||
/* Restore SYSCON mode registers */
|
||||
CLEAR_PERI_REG_MASK(SENS_SAR_READ_CTRL_REG, SENS_SAR1_DIG_FORCE);
|
||||
CLEAR_PERI_REG_MASK(SENS_SAR_READ_CTRL2_REG, SENS_SAR2_DIG_FORCE);
|
||||
|
||||
/* Restore SAR ADC mode */
|
||||
CLEAR_PERI_REG_MASK(SENS_SAR_START_FORCE_REG, SENS_SAR2_EN_TEST);
|
||||
CLEAR_PERI_REG_MASK(SYSCON_SARADC_CTRL_REG, SYSCON_SARADC_SAR2_MUX
|
||||
| SYSCON_SARADC_SAR_SEL | SYSCON_SARADC_DATA_TO_I2S);
|
||||
SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_SAR, 0, SENS_FORCE_XPD_SAR_S);
|
||||
|
||||
SET_PERI_REG_BITS(SYSCON_SARADC_FSM_REG, SYSCON_SARADC_START_WAIT, 8, SYSCON_SARADC_START_WAIT_S);
|
||||
|
||||
/* Reset i2s peripheral */
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST);
|
||||
#else
|
||||
periph_module_reset(PERIPH_I2S0_MODULE);
|
||||
#endif
|
||||
|
||||
/* Disable pull supply voltage to SAR ADC */
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_TEST_MUX_REG, RTC_CNTL_ENT_RTC);
|
||||
SET_PERI_REG_BITS(RTC_CNTL_TEST_MUX_REG, RTC_CNTL_DTEST_RTC, 0, RTC_CNTL_DTEST_RTC_S);
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#include "bootloader_random.h"
|
||||
#include "hal/rng_ll.h"
|
||||
#include "esp_log.h"
|
||||
#include "soc/syscon_reg.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "soc/apb_saradc_reg.h"
|
||||
#include "soc/system_reg.h"
|
||||
#include "esp_private/regi2c_ctrl.h"
|
||||
#include "esp_private/sar_periph_ctrl.h"
|
||||
#include "soc/regi2c_saradc.h"
|
||||
#include "hal/adc_ll.h"
|
||||
#include "hal/sar_ctrl_ll.h"
|
||||
#include "hal/clk_gate_ll.h"
|
||||
|
||||
#define ADC_RNG_CLKM_DIV_NUM 15
|
||||
#define ADC_RNG_CLKM_DIV_B 0
|
||||
#define ADC_RNG_CLKM_DIV_A 0
|
||||
|
||||
void bootloader_random_enable(void)
|
||||
{
|
||||
sar_ctrl_ll_set_power_mode(SAR_CTRL_LL_POWER_ON);
|
||||
SET_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_SAR_I2C_PU_M);
|
||||
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
regi2c_saradc_enable();
|
||||
#else
|
||||
regi2c_ctrl_ll_i2c_sar_periph_enable();
|
||||
#endif
|
||||
ANALOG_CLOCK_ENABLE();
|
||||
adc_ll_regi2c_init();
|
||||
|
||||
_adc_ll_enable_bus_clock(true);
|
||||
_adc_ll_reset_register();
|
||||
adc_ll_digi_clk_sel(ADC_DIGI_CLK_SRC_PLL_F80M);
|
||||
adc_ll_digi_controller_clk_div(ADC_RNG_CLKM_DIV_NUM, ADC_RNG_CLKM_DIV_B, ADC_RNG_CLKM_DIV_A);
|
||||
adc_ll_digi_set_power_manage(ADC_LL_POWER_SW_ON);
|
||||
adc_ll_digi_set_clk_div(1);
|
||||
|
||||
adc_ll_digi_set_fsm_time(ADC_LL_FSM_RSTB_WAIT_DEFAULT, ADC_LL_FSM_START_WAIT_DEFAULT,
|
||||
ADC_LL_FSM_STANDBY_WAIT_DEFAULT);
|
||||
|
||||
adc_digi_pattern_config_t pattern_config = {};
|
||||
pattern_config.unit = ADC_UNIT_2;
|
||||
pattern_config.atten = ADC_ATTEN_DB_12;
|
||||
pattern_config.channel = ADC_CHANNEL_1; //Use reserved channel 1 to get internal voltage
|
||||
adc_ll_digi_set_pattern_table(ADC_UNIT_2, 0, pattern_config);
|
||||
adc_ll_digi_set_pattern_table_len(ADC_UNIT_2, 1);
|
||||
|
||||
|
||||
adc_ll_digi_set_trigger_interval(100);
|
||||
adc_ll_digi_convert_limit_enable(false);
|
||||
adc_ll_digi_dma_enable();
|
||||
adc_ll_digi_trigger_enable();
|
||||
rng_ll_enable();
|
||||
}
|
||||
|
||||
void bootloader_random_disable(void)
|
||||
{
|
||||
rng_ll_disable();
|
||||
|
||||
_adc_ll_enable_bus_clock(false);
|
||||
adc_ll_digi_trigger_disable();
|
||||
adc_ll_digi_reset_pattern_table();
|
||||
adc_ll_regi2c_adc_deinit();
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
regi2c_saradc_disable();
|
||||
#endif
|
||||
// disable analog i2c master clock
|
||||
ANALOG_CLOCK_DISABLE();
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#include "bootloader_random.h"
|
||||
#include "hal/rng_ll.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "esp_private/regi2c_ctrl.h"
|
||||
#include "esp_private/sar_periph_ctrl.h"
|
||||
#include "hal/adc_ll.h"
|
||||
#include "hal/temperature_sensor_ll.h"
|
||||
#include "esp_private/sar_periph_ctrl.h"
|
||||
|
||||
#define ADC_RNG_CLKM_DIV_NUM 15
|
||||
#define ADC_RNG_CLKM_DIV_B 0
|
||||
#define ADC_RNG_CLKM_DIV_A 0
|
||||
|
||||
void bootloader_random_enable(void)
|
||||
{
|
||||
/* RNG module is always clock enabled */
|
||||
REG_SET_FIELD(RTC_CNTL_SENSOR_CTRL_REG, RTC_CNTL_FORCE_XPD_SAR, 0x3);
|
||||
SET_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_SAR_I2C_PU_M);
|
||||
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
sar_periph_ctrl_adc_reset();
|
||||
#else
|
||||
tsens_ll_reg_values_t saved_tsens_regs = {};
|
||||
tsens_ll_backup_registers(&saved_tsens_regs);
|
||||
_adc_ll_reset_register();
|
||||
// Restore temperature sensor related register values after ADC reset
|
||||
_temperature_sensor_ll_reset_module();
|
||||
tsens_ll_restore_registers(&saved_tsens_regs);
|
||||
#endif
|
||||
|
||||
_adc_ll_enable_bus_clock(true);
|
||||
adc_ll_enable_func_clock(true);
|
||||
adc_ll_digi_clk_sel(ADC_DIGI_CLK_SRC_APB);
|
||||
adc_ll_digi_controller_clk_div(ADC_RNG_CLKM_DIV_NUM, ADC_RNG_CLKM_DIV_B, ADC_RNG_CLKM_DIV_A);
|
||||
adc_ll_digi_set_power_manage(ADC_LL_POWER_SW_ON);
|
||||
adc_ll_digi_set_fsm_time(ADC_LL_FSM_RSTB_WAIT_DEFAULT, ADC_LL_FSM_START_WAIT_DEFAULT,
|
||||
ADC_LL_FSM_STANDBY_WAIT_DEFAULT);
|
||||
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
regi2c_saradc_enable();
|
||||
#else
|
||||
regi2c_ctrl_ll_i2c_sar_periph_enable();
|
||||
#endif
|
||||
// enable analog i2c master clock for RNG runtime
|
||||
ANALOG_CLOCK_ENABLE();
|
||||
adc_ll_regi2c_init();
|
||||
|
||||
adc_digi_pattern_config_t pattern_config = {};
|
||||
pattern_config.unit = ADC_UNIT_2;
|
||||
pattern_config.atten = ADC_ATTEN_DB_12;
|
||||
pattern_config.channel = ADC_CHANNEL_1; //Use reserved channel 10 to get internal voltage
|
||||
adc_ll_digi_set_pattern_table(ADC_UNIT_2, 0, pattern_config);
|
||||
adc_ll_digi_set_pattern_table_len(ADC_UNIT_2, 1);
|
||||
|
||||
adc_ll_digi_dma_enable();
|
||||
|
||||
adc_ll_digi_set_clk_div(1);
|
||||
adc_ll_digi_set_trigger_interval(100);
|
||||
adc_ll_digi_trigger_enable();
|
||||
rng_ll_enable();
|
||||
}
|
||||
|
||||
void bootloader_random_disable(void)
|
||||
{
|
||||
rng_ll_disable();
|
||||
|
||||
_adc_ll_enable_bus_clock(false);
|
||||
adc_ll_digi_trigger_disable();
|
||||
adc_ll_digi_reset_pattern_table();
|
||||
adc_ll_regi2c_adc_deinit();
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
regi2c_saradc_disable();
|
||||
#endif
|
||||
// disable analog i2c master clock
|
||||
ANALOG_CLOCK_DISABLE();
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#include "bootloader_random.h"
|
||||
#include "hal/regi2c_ctrl_ll.h"
|
||||
#include "hal/adc_ll.h"
|
||||
#include "hal/adc_types.h"
|
||||
#include "hal/rng_ll.h"
|
||||
#include "esp_private/regi2c_ctrl.h"
|
||||
#include "hal/temperature_sensor_ll.h"
|
||||
#include "esp_private/sar_periph_ctrl.h"
|
||||
|
||||
#define I2C_SAR_ADC_INIT_CODE_VAL 2150
|
||||
#define ADC_RNG_CLKM_DIV_NUM 0
|
||||
#define ADC_RNG_CLKM_DIV_B 0
|
||||
#define ADC_RNG_CLKM_DIV_A 0
|
||||
|
||||
void bootloader_random_enable(void)
|
||||
{
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
sar_periph_ctrl_adc_reset();
|
||||
#else
|
||||
// Save temperature sensor related register values before ADC reset
|
||||
tsens_ll_reg_values_t saved_tsens_regs = {};
|
||||
tsens_ll_backup_registers(&saved_tsens_regs);
|
||||
adc_ll_reset_register();
|
||||
// Restore temperature sensor related register values after ADC reset
|
||||
temperature_sensor_ll_reset_module();
|
||||
tsens_ll_restore_registers(&saved_tsens_regs);
|
||||
#endif
|
||||
|
||||
adc_ll_enable_bus_clock(true);
|
||||
adc_ll_enable_func_clock(true);
|
||||
adc_ll_digi_clk_sel(ADC_DIGI_CLK_SRC_XTAL);
|
||||
adc_ll_digi_controller_clk_div(ADC_RNG_CLKM_DIV_NUM, ADC_RNG_CLKM_DIV_B, ADC_RNG_CLKM_DIV_A);
|
||||
|
||||
// some ADC sensor registers are in power group PERIF_I2C and need to be enabled via PMU
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
regi2c_saradc_enable();
|
||||
#else
|
||||
regi2c_ctrl_ll_i2c_sar_periph_enable();
|
||||
#endif
|
||||
|
||||
// enable analog i2c master clock for RNG runtime
|
||||
ANALOG_CLOCK_ENABLE();
|
||||
|
||||
adc_ll_regi2c_init();
|
||||
adc_ll_set_calibration_param(ADC_UNIT_1, I2C_SAR_ADC_INIT_CODE_VAL);
|
||||
adc_ll_set_calibration_param(ADC_UNIT_2, I2C_SAR_ADC_INIT_CODE_VAL);
|
||||
|
||||
adc_digi_pattern_config_t pattern_config = {};
|
||||
pattern_config.unit = ADC_UNIT_1;
|
||||
pattern_config.atten = ADC_ATTEN_DB_12;
|
||||
pattern_config.channel = ADC_CHANNEL_7; //Use reserved channel to get internal voltage
|
||||
adc_ll_digi_set_pattern_table(ADC_UNIT_1, 0, pattern_config);
|
||||
pattern_config.unit = ADC_UNIT_2;
|
||||
pattern_config.atten = ADC_ATTEN_DB_12;
|
||||
pattern_config.channel = ADC_CHANNEL_1; //Use reserved ADC2 and reserved channel to get internal voltage
|
||||
adc_ll_digi_set_pattern_table(ADC_UNIT_2, 1, pattern_config);
|
||||
|
||||
adc_ll_digi_set_pattern_table_len(ADC_UNIT_1, 2);
|
||||
|
||||
adc_ll_digi_set_clk_div(15);
|
||||
adc_ll_digi_set_trigger_interval(200);
|
||||
adc_ll_digi_trigger_enable();
|
||||
|
||||
rng_ll_enable();
|
||||
}
|
||||
|
||||
void bootloader_random_disable(void)
|
||||
{
|
||||
rng_ll_disable();
|
||||
adc_ll_digi_trigger_disable();
|
||||
adc_ll_digi_reset_pattern_table();
|
||||
adc_ll_set_calibration_param(ADC_UNIT_1, 0x0);
|
||||
adc_ll_set_calibration_param(ADC_UNIT_2, 0x0);
|
||||
adc_ll_regi2c_adc_deinit();
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
regi2c_saradc_disable();
|
||||
#endif
|
||||
|
||||
// disable analog i2c master clock
|
||||
ANALOG_CLOCK_DISABLE();
|
||||
adc_ll_digi_controller_clk_div(4, 0, 0);
|
||||
adc_ll_digi_clk_sel(ADC_DIGI_CLK_SRC_XTAL);
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#include "bootloader_random.h"
|
||||
#include "hal/rng_ll.h"
|
||||
#include "hal/regi2c_ctrl_ll.h"
|
||||
#include "hal/adc_ll.h"
|
||||
#include "hal/adc_types.h"
|
||||
#include "esp_private/regi2c_ctrl.h"
|
||||
#include "hal/temperature_sensor_ll.h"
|
||||
#include "esp_private/sar_periph_ctrl.h"
|
||||
|
||||
#define I2C_SAR_ADC_INIT_CODE_VAL 2150
|
||||
#define ADC_RNG_CLKM_DIV_NUM 0
|
||||
#define ADC_RNG_CLKM_DIV_B 0
|
||||
#define ADC_RNG_CLKM_DIV_A 0
|
||||
|
||||
void bootloader_random_enable(void)
|
||||
{
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
sar_periph_ctrl_adc_reset();
|
||||
#else
|
||||
tsens_ll_reg_values_t saved_tsens_regs = {};
|
||||
tsens_ll_backup_registers(&saved_tsens_regs);
|
||||
adc_ll_reset_register();
|
||||
// Restore temperature sensor related register values after ADC reset
|
||||
temperature_sensor_ll_reset_module();
|
||||
tsens_ll_restore_registers(&saved_tsens_regs);
|
||||
#endif
|
||||
|
||||
adc_ll_enable_bus_clock(true);
|
||||
adc_ll_enable_func_clock(true);
|
||||
adc_ll_digi_clk_sel(ADC_DIGI_CLK_SRC_XTAL);
|
||||
adc_ll_digi_controller_clk_div(ADC_RNG_CLKM_DIV_NUM, ADC_RNG_CLKM_DIV_B, ADC_RNG_CLKM_DIV_A);
|
||||
|
||||
// some ADC sensor registers are in power group PERIF_I2C and need to be enabled via PMU
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
regi2c_saradc_enable();
|
||||
#else
|
||||
regi2c_ctrl_ll_i2c_sar_periph_enable();
|
||||
#endif
|
||||
|
||||
// enable analog i2c master clock for RNG runtime
|
||||
ANALOG_CLOCK_ENABLE();
|
||||
|
||||
adc_ll_regi2c_init();
|
||||
adc_ll_set_calibration_param(ADC_UNIT_1, I2C_SAR_ADC_INIT_CODE_VAL);
|
||||
adc_ll_set_calibration_param(ADC_UNIT_2, I2C_SAR_ADC_INIT_CODE_VAL);
|
||||
|
||||
adc_digi_pattern_config_t pattern_config = {};
|
||||
pattern_config.unit = ADC_UNIT_2;
|
||||
pattern_config.atten = ADC_ATTEN_DB_2_5;
|
||||
pattern_config.channel = ADC_CHANNEL_1; //Use reserved channel to get internal voltage
|
||||
adc_ll_digi_set_pattern_table(ADC_UNIT_1, 0, pattern_config);
|
||||
pattern_config.unit = ADC_UNIT_2;
|
||||
pattern_config.atten = ADC_ATTEN_DB_2_5;
|
||||
pattern_config.channel = ADC_CHANNEL_1; //Use reserved ADC2 and reserved channel to get internal voltage
|
||||
adc_ll_digi_set_pattern_table(ADC_UNIT_2, 1, pattern_config);
|
||||
adc_ll_digi_set_pattern_table_len(ADC_UNIT_2, 2);
|
||||
|
||||
adc_ll_digi_set_clk_div(15);
|
||||
adc_ll_digi_set_trigger_interval(200);
|
||||
adc_ll_digi_trigger_enable();
|
||||
rng_ll_enable();
|
||||
}
|
||||
|
||||
void bootloader_random_disable(void)
|
||||
{
|
||||
rng_ll_disable();
|
||||
|
||||
adc_ll_digi_trigger_disable();
|
||||
adc_ll_digi_reset_pattern_table();
|
||||
adc_ll_set_calibration_param(ADC_UNIT_1, 0x0);
|
||||
adc_ll_set_calibration_param(ADC_UNIT_2, 0x0);
|
||||
adc_ll_regi2c_adc_deinit();
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
regi2c_saradc_disable();
|
||||
#endif
|
||||
|
||||
// disable analog i2c master clock
|
||||
ANALOG_CLOCK_DISABLE();
|
||||
adc_ll_digi_controller_clk_div(4, 0, 0);
|
||||
adc_ll_digi_clk_sel(ADC_DIGI_CLK_SRC_XTAL);
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#include "bootloader_random.h"
|
||||
#include "hal/rng_ll.h"
|
||||
#include "hal/regi2c_ctrl_ll.h"
|
||||
#include "hal/adc_ll.h"
|
||||
#include "hal/adc_types.h"
|
||||
#include "esp_private/regi2c_ctrl.h"
|
||||
#include "hal/temperature_sensor_ll.h"
|
||||
#include "esp_private/sar_periph_ctrl.h"
|
||||
|
||||
#define I2C_SAR_ADC_INIT_CODE_VAL 2150
|
||||
#define ADC_RNG_CLKM_DIV_NUM 0
|
||||
#define ADC_RNG_CLKM_DIV_B 0
|
||||
#define ADC_RNG_CLKM_DIV_A 0
|
||||
|
||||
void bootloader_random_enable(void)
|
||||
{
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
sar_periph_ctrl_adc_reset();
|
||||
#else
|
||||
// Save temperature sensor related register values before ADC reset
|
||||
tsens_ll_reg_values_t saved_tsens_regs = {};
|
||||
tsens_ll_backup_registers(&saved_tsens_regs);
|
||||
adc_ll_reset_register();
|
||||
// Restore temperature sensor related register values after ADC reset
|
||||
temperature_sensor_ll_reset_module();
|
||||
tsens_ll_restore_registers(&saved_tsens_regs);
|
||||
#endif
|
||||
|
||||
adc_ll_enable_bus_clock(true);
|
||||
adc_ll_enable_func_clock(true);
|
||||
adc_ll_digi_clk_sel(ADC_DIGI_CLK_SRC_XTAL);
|
||||
adc_ll_digi_controller_clk_div(ADC_RNG_CLKM_DIV_NUM, ADC_RNG_CLKM_DIV_B, ADC_RNG_CLKM_DIV_A);
|
||||
|
||||
// some ADC sensor registers are in power group PERIF_I2C and need to be enabled via PMU
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
regi2c_saradc_enable();
|
||||
#else
|
||||
regi2c_ctrl_ll_i2c_sar_periph_enable();
|
||||
#endif
|
||||
|
||||
// enable analog i2c master clock for RNG runtime
|
||||
ANALOG_CLOCK_ENABLE();
|
||||
|
||||
adc_ll_regi2c_init();
|
||||
adc_ll_set_calibration_param(ADC_UNIT_1, I2C_SAR_ADC_INIT_CODE_VAL);
|
||||
adc_ll_set_calibration_param(ADC_UNIT_2, I2C_SAR_ADC_INIT_CODE_VAL);
|
||||
|
||||
adc_digi_pattern_config_t pattern_config = {};
|
||||
pattern_config.unit = ADC_UNIT_1;
|
||||
pattern_config.atten = ADC_ATTEN_DB_12;
|
||||
pattern_config.channel = ADC_CHANNEL_7; //Use reserved channel to get internal voltage
|
||||
adc_ll_digi_set_pattern_table(ADC_UNIT_1, 0, pattern_config);
|
||||
pattern_config.unit = ADC_UNIT_2;
|
||||
pattern_config.atten = ADC_ATTEN_DB_12;
|
||||
pattern_config.channel = ADC_CHANNEL_1; //Use reserved ADC2 and reserved channel to get internal voltage
|
||||
adc_ll_digi_set_pattern_table(ADC_UNIT_2, 1, pattern_config);
|
||||
adc_ll_digi_set_pattern_table_len(ADC_UNIT_1, 2);
|
||||
|
||||
adc_ll_digi_set_clk_div(15);
|
||||
adc_ll_digi_set_trigger_interval(200);
|
||||
adc_ll_digi_trigger_enable();
|
||||
rng_ll_enable();
|
||||
}
|
||||
|
||||
void bootloader_random_disable(void)
|
||||
{
|
||||
rng_ll_disable();
|
||||
|
||||
adc_ll_digi_trigger_disable();
|
||||
adc_ll_digi_reset_pattern_table();
|
||||
adc_ll_set_calibration_param(ADC_UNIT_1, 0x0);
|
||||
adc_ll_set_calibration_param(ADC_UNIT_2, 0x0);
|
||||
adc_ll_regi2c_adc_deinit();
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
regi2c_saradc_disable();
|
||||
#endif
|
||||
|
||||
// disable analog i2c master clock
|
||||
ANALOG_CLOCK_DISABLE();
|
||||
adc_ll_digi_controller_clk_div(4, 0, 0);
|
||||
adc_ll_digi_clk_sel(ADC_DIGI_CLK_SRC_XTAL);
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#include "bootloader_random.h"
|
||||
#include "hal/rng_ll.h"
|
||||
#include "hal/regi2c_ctrl_ll.h"
|
||||
#include "hal/adc_ll.h"
|
||||
#include "hal/adc_types.h"
|
||||
#include "esp_private/regi2c_ctrl.h"
|
||||
#include "hal/temperature_sensor_ll.h"
|
||||
#include "esp_private/sar_periph_ctrl.h"
|
||||
|
||||
#define I2C_SAR_ADC_INIT_CODE_VAL 2150
|
||||
#define ADC_RNG_CLKM_DIV_NUM 0
|
||||
#define ADC_RNG_CLKM_DIV_B 0
|
||||
#define ADC_RNG_CLKM_DIV_A 0
|
||||
|
||||
void bootloader_random_enable(void)
|
||||
{
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
sar_periph_ctrl_adc_reset();
|
||||
#else
|
||||
// Save temperature sensor related register values before ADC reset
|
||||
tsens_ll_reg_values_t saved_tsens_regs = {};
|
||||
tsens_ll_backup_registers(&saved_tsens_regs);
|
||||
adc_ll_reset_register();
|
||||
// Restore temperature sensor related register values after ADC reset
|
||||
temperature_sensor_ll_reset_module();
|
||||
tsens_ll_restore_registers(&saved_tsens_regs);
|
||||
#endif
|
||||
|
||||
adc_ll_enable_bus_clock(true);
|
||||
adc_ll_enable_func_clock(true);
|
||||
adc_ll_digi_clk_sel(ADC_DIGI_CLK_SRC_XTAL);
|
||||
adc_ll_digi_controller_clk_div(ADC_RNG_CLKM_DIV_NUM, ADC_RNG_CLKM_DIV_B, ADC_RNG_CLKM_DIV_A);
|
||||
|
||||
// some ADC sensor registers are in power group PERIF_I2C and need to be enabled via PMU
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
regi2c_saradc_enable();
|
||||
#else
|
||||
regi2c_ctrl_ll_i2c_sar_periph_enable();
|
||||
#endif
|
||||
|
||||
// enable analog i2c master clock for RNG runtime
|
||||
ANALOG_CLOCK_ENABLE();
|
||||
|
||||
adc_ll_regi2c_init();
|
||||
adc_ll_set_calibration_param(ADC_UNIT_1, I2C_SAR_ADC_INIT_CODE_VAL);
|
||||
adc_ll_set_calibration_param(ADC_UNIT_2, I2C_SAR_ADC_INIT_CODE_VAL);
|
||||
|
||||
adc_digi_pattern_config_t pattern_config = {};
|
||||
pattern_config.atten = ADC_ATTEN_DB_2_5;
|
||||
adc_ll_digi_set_pattern_table(ADC_UNIT_1, 0, pattern_config);
|
||||
pattern_config.unit = ADC_UNIT_2;
|
||||
pattern_config.atten = ADC_ATTEN_DB_2_5;
|
||||
pattern_config.channel = ADC_CHANNEL_1; //Use reserved ADC2 and reserved channel to get internal voltage
|
||||
adc_ll_digi_set_pattern_table(ADC_UNIT_2, 1, pattern_config);
|
||||
adc_ll_digi_set_pattern_table_len(ADC_UNIT_1, 1);
|
||||
|
||||
adc_ll_digi_set_clk_div(15);
|
||||
adc_ll_digi_set_trigger_interval(200);
|
||||
adc_ll_digi_trigger_enable();
|
||||
rng_ll_enable();
|
||||
}
|
||||
|
||||
void bootloader_random_disable(void)
|
||||
{
|
||||
rng_ll_disable();
|
||||
|
||||
adc_ll_digi_trigger_disable();
|
||||
adc_ll_digi_reset_pattern_table();
|
||||
adc_ll_set_calibration_param(ADC_UNIT_1, 0x0);
|
||||
adc_ll_set_calibration_param(ADC_UNIT_2, 0x0);
|
||||
adc_ll_regi2c_adc_deinit();
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
regi2c_saradc_disable();
|
||||
#endif
|
||||
|
||||
// disable analog i2c master clock
|
||||
ANALOG_CLOCK_DISABLE();
|
||||
adc_ll_digi_controller_clk_div(4, 0, 0);
|
||||
adc_ll_digi_clk_sel(ADC_DIGI_CLK_SRC_XTAL);
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#include "bootloader_random.h"
|
||||
#include "hal/regi2c_ctrl_ll.h"
|
||||
#include "hal/adc_ll.h"
|
||||
#include "hal/adc_types.h"
|
||||
#include "hal/rng_ll.h"
|
||||
#include "esp_private/regi2c_ctrl.h"
|
||||
#include "hal/temperature_sensor_ll.h"
|
||||
#include "esp_private/sar_periph_ctrl.h"
|
||||
|
||||
#define I2C_SAR_ADC_INIT_CODE_VAL 2150
|
||||
#define ADC_RNG_CLKM_DIV_NUM 0
|
||||
#define ADC_RNG_CLKM_DIV_B 0
|
||||
#define ADC_RNG_CLKM_DIV_A 0
|
||||
|
||||
void bootloader_random_enable(void)
|
||||
{
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
sar_periph_ctrl_adc_reset();
|
||||
#else
|
||||
// Save temperature sensor related register values before ADC reset
|
||||
tsens_ll_reg_values_t saved_tsens_regs = {};
|
||||
tsens_ll_backup_registers(&saved_tsens_regs);
|
||||
adc_ll_reset_register();
|
||||
// Restore temperature sensor related register values after ADC reset
|
||||
temperature_sensor_ll_reset_module();
|
||||
tsens_ll_restore_registers(&saved_tsens_regs);
|
||||
#endif
|
||||
|
||||
adc_ll_enable_bus_clock(true);
|
||||
adc_ll_enable_func_clock(false);
|
||||
adc_ll_digi_clk_sel(ADC_DIGI_CLK_SRC_XTAL);
|
||||
adc_ll_digi_controller_clk_div(ADC_RNG_CLKM_DIV_NUM, ADC_RNG_CLKM_DIV_B, ADC_RNG_CLKM_DIV_A);
|
||||
|
||||
// some ADC sensor registers are in power group PERIF_I2C and need to be enabled via PMU
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
regi2c_saradc_enable();
|
||||
#else
|
||||
regi2c_ctrl_ll_i2c_sar_periph_enable();
|
||||
#endif
|
||||
|
||||
// enable analog i2c master clock for RNG runtime
|
||||
ANALOG_CLOCK_ENABLE();
|
||||
|
||||
adc_ll_regi2c_init();
|
||||
adc_ll_set_calibration_param(ADC_UNIT_1, I2C_SAR_ADC_INIT_CODE_VAL);
|
||||
adc_ll_set_calibration_param(ADC_UNIT_2, I2C_SAR_ADC_INIT_CODE_VAL);
|
||||
|
||||
adc_digi_pattern_config_t pattern_config = {};
|
||||
pattern_config.unit = ADC_UNIT_1;
|
||||
pattern_config.atten = ADC_ATTEN_DB_12;
|
||||
pattern_config.channel = ADC_CHANNEL_7; // Use reserved channel to get internal voltage
|
||||
adc_ll_digi_set_pattern_table(ADC_UNIT_1, 0, pattern_config);
|
||||
pattern_config.unit = ADC_UNIT_2;
|
||||
pattern_config.atten = ADC_ATTEN_DB_12;
|
||||
pattern_config.channel = ADC_CHANNEL_1; // Use reserved ADC2 and reserved channel to get internal voltage
|
||||
adc_ll_digi_set_pattern_table(ADC_UNIT_2, 1, pattern_config);
|
||||
adc_ll_digi_set_pattern_table_len(ADC_UNIT_1, 2);
|
||||
|
||||
adc_ll_digi_set_clk_div(15);
|
||||
adc_ll_digi_set_trigger_interval(200);
|
||||
adc_ll_digi_trigger_enable();
|
||||
|
||||
rng_ll_enable();
|
||||
}
|
||||
|
||||
void bootloader_random_disable(void)
|
||||
{
|
||||
rng_ll_disable();
|
||||
adc_ll_digi_trigger_disable();
|
||||
adc_ll_digi_reset_pattern_table();
|
||||
adc_ll_set_calibration_param(ADC_UNIT_1, 0x0);
|
||||
adc_ll_set_calibration_param(ADC_UNIT_2, 0x0);
|
||||
adc_ll_regi2c_adc_deinit();
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
regi2c_saradc_disable();
|
||||
#endif
|
||||
|
||||
// disable analog i2c master clock
|
||||
ANALOG_CLOCK_DISABLE();
|
||||
adc_ll_digi_controller_clk_div(4, 0, 0);
|
||||
adc_ll_digi_clk_sel(ADC_DIGI_CLK_SRC_XTAL);
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#include "bootloader_random.h"
|
||||
#include "hal/regi2c_ctrl_ll.h"
|
||||
#include "hal/adc_ll.h"
|
||||
#include "hal/adc_types.h"
|
||||
#include "hal/rng_ll.h"
|
||||
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "esp_private/adc_share_hw_ctrl.h"
|
||||
#include "esp_private/sar_periph_ctrl.h"
|
||||
|
||||
#define I2C_SAR_ADC_INIT_CODE_VAL 2166
|
||||
#define ADC_RNG_CLKM_DIV_NUM 0
|
||||
#define ADC_RNG_CLKM_DIV_B 0
|
||||
#define ADC_RNG_CLKM_DIV_A 0
|
||||
|
||||
void bootloader_random_enable(void)
|
||||
{
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
sar_periph_ctrl_adc_reset();
|
||||
#else
|
||||
_adc_ll_reset_register();
|
||||
#endif
|
||||
|
||||
_adc_ll_enable_bus_clock(true);
|
||||
|
||||
adc_ll_digi_clk_sel(ADC_DIGI_CLK_SRC_XTAL);
|
||||
adc_ll_digi_controller_clk_div(ADC_RNG_CLKM_DIV_NUM, ADC_RNG_CLKM_DIV_B, ADC_RNG_CLKM_DIV_A);
|
||||
|
||||
// some ADC sensor registers are in power group PERIF_I2C and need to be enabled via PMU
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
regi2c_saradc_enable();
|
||||
#else
|
||||
regi2c_ctrl_ll_i2c_sar_periph_enable();
|
||||
#endif
|
||||
|
||||
// enable analog i2c master clock for RNG runtime
|
||||
ANALOG_CLOCK_ENABLE();
|
||||
|
||||
adc_ll_regi2c_init();
|
||||
adc_ll_set_calibration_param(ADC_UNIT_1, I2C_SAR_ADC_INIT_CODE_VAL);
|
||||
|
||||
adc_digi_pattern_config_t pattern_config = {};
|
||||
pattern_config.unit = ADC_UNIT_1;
|
||||
pattern_config.atten = ADC_ATTEN_DB_12;
|
||||
pattern_config.channel = ADC_CHANNEL_10;
|
||||
adc_ll_digi_set_pattern_table(ADC_UNIT_1, 0, pattern_config);
|
||||
adc_ll_digi_set_pattern_table(ADC_UNIT_1, 1, pattern_config);
|
||||
adc_ll_digi_set_pattern_table(ADC_UNIT_1, 2, pattern_config);
|
||||
adc_ll_digi_set_pattern_table(ADC_UNIT_1, 3, pattern_config);
|
||||
adc_ll_digi_set_pattern_table_len(ADC_UNIT_1, 1);
|
||||
|
||||
adc_ll_set_controller(ADC_UNIT_1, ADC_LL_CTRL_DIG);
|
||||
adc_ll_digi_set_power_manage(ADC_UNIT_1, ADC_LL_POWER_SW_ON);
|
||||
|
||||
adc_ll_digi_set_clk_div(15);
|
||||
adc_ll_digi_set_trigger_interval(100);
|
||||
adc_ll_digi_trigger_enable();
|
||||
rng_ll_enable();
|
||||
}
|
||||
|
||||
void bootloader_random_disable(void)
|
||||
{
|
||||
rng_ll_disable();
|
||||
|
||||
adc_ll_digi_trigger_disable();
|
||||
adc_ll_digi_reset_pattern_table();
|
||||
adc_ll_set_calibration_param(ADC_UNIT_1, 0x0);
|
||||
adc_ll_set_calibration_param(ADC_UNIT_2, 0x0);
|
||||
adc_ll_regi2c_adc_deinit();
|
||||
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
regi2c_saradc_disable();
|
||||
#endif
|
||||
|
||||
// disable analog i2c master clock
|
||||
ANALOG_CLOCK_DISABLE();
|
||||
adc_ll_digi_controller_clk_div(4, 0, 0);
|
||||
adc_ll_digi_clk_sel(ADC_DIGI_CLK_SRC_XTAL);
|
||||
|
||||
adc_ll_set_controller(ADC_UNIT_1, ADC_LL_CTRL_ULP);
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#include "bootloader_random.h"
|
||||
#include "hal/rng_ll.h"
|
||||
#include "soc/rtc_periph.h"
|
||||
#include "soc/sens_reg.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/syscon_reg.h"
|
||||
#include "esp_log.h"
|
||||
#include "soc/apb_saradc_reg.h"
|
||||
#include "esp_private/regi2c_ctrl.h"
|
||||
#include "esp_private/sar_periph_ctrl.h"
|
||||
#include "hal/adc_ll.h"
|
||||
|
||||
#include "esp_rom_sys.h"
|
||||
#include "hal/clk_tree_ll.h"
|
||||
#include "hal/sar_ctrl_ll.h"
|
||||
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#endif
|
||||
|
||||
void bootloader_random_enable(void)
|
||||
{
|
||||
/* Ensure the Wifi clock for RNG modiule is enabled following a soft reset. This should always be the case already
|
||||
(this clock is never disabled while the CPU is running), this is a "belt and braces" type check.
|
||||
*/
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, DPORT_WIFI_CLK_RNG_EN);
|
||||
#else
|
||||
periph_module_enable(PERIPH_RNG_MODULE);
|
||||
#endif // BOOTLOADER_BUILD
|
||||
|
||||
// Enable 8M clock source for RNG (this is actually enough to produce strong random results,
|
||||
// but enabling the SAR ADC as well adds some insurance.)
|
||||
clk_ll_rc_fast_digi_enable();
|
||||
|
||||
// Enable SAR ADC to read a disconnected input for additional entropy
|
||||
_adc_ll_reset_register();
|
||||
_adc_ll_enable_bus_clock(true);
|
||||
|
||||
adc_ll_digi_clk_sel(ADC_DIGI_CLK_SRC_APB);
|
||||
adc_ll_calibration_prepare(ADC_UNIT_1, false);
|
||||
adc_ll_calibration_prepare(ADC_UNIT_2, false);
|
||||
adc_ll_calibration_init(ADC_UNIT_1);
|
||||
adc_ll_calibration_init(ADC_UNIT_2);
|
||||
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
regi2c_saradc_enable();
|
||||
#else
|
||||
regi2c_ctrl_ll_i2c_sar_periph_enable();
|
||||
#endif
|
||||
// enable analog i2c master clock for RNG runtime
|
||||
ANALOG_CLOCK_ENABLE();
|
||||
|
||||
adc_ll_regi2c_init();
|
||||
sar_ctrl_ll_set_power_mode(SAR_CTRL_LL_POWER_ON);
|
||||
|
||||
adc_digi_pattern_config_t pattern_config = {};
|
||||
pattern_config.unit = ADC_UNIT_1;
|
||||
pattern_config.atten = ADC_ATTEN_DB_12;
|
||||
pattern_config.channel = ADC_CHANNEL_10; //Use reserved channel 10 to get internal voltage
|
||||
adc_ll_digi_set_pattern_table(ADC_UNIT_1, 0, pattern_config);
|
||||
pattern_config.unit = ADC_UNIT_2;
|
||||
pattern_config.atten = ADC_ATTEN_DB_12;
|
||||
pattern_config.channel = ADC_CHANNEL_10; //Use reserved channel 10 to get internal voltage
|
||||
adc_ll_digi_set_pattern_table(ADC_UNIT_2, 0, pattern_config);
|
||||
adc_ll_digi_set_pattern_table_len(ADC_UNIT_1, 1);
|
||||
adc_ll_digi_set_pattern_table_len(ADC_UNIT_2, 1);
|
||||
|
||||
adc_ll_digi_set_convert_mode(ADC_LL_DIGI_CONV_BOTH_UNIT);
|
||||
|
||||
adc_ll_set_controller(ADC_UNIT_1, ADC_LL_CTRL_DIG);
|
||||
|
||||
adc_ll_digi_set_clk_div(4);
|
||||
adc_ll_digi_set_trigger_interval(100);
|
||||
adc_ll_digi_trigger_enable();
|
||||
rng_ll_enable();
|
||||
}
|
||||
|
||||
void bootloader_random_disable(void)
|
||||
{
|
||||
rng_ll_disable();
|
||||
|
||||
adc_ll_calibration_clear();
|
||||
_adc_ll_enable_bus_clock(false);
|
||||
adc_ll_digi_trigger_disable();
|
||||
adc_ll_digi_reset_pattern_table();
|
||||
|
||||
adc_ll_regi2c_adc_deinit();
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
regi2c_saradc_disable();
|
||||
#endif
|
||||
|
||||
ANALOG_CLOCK_DISABLE();
|
||||
|
||||
/* Note: the 8M CLK entropy source continues running even after this function is called,
|
||||
but as mentioned above it's better to enable Wi-Fi or BT or call bootloader_random_enable()
|
||||
in order to get a secondary entropy source.
|
||||
*/
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#include "bootloader_random.h"
|
||||
#include "hal/rng_ll.h"
|
||||
#include "soc/syscon_reg.h"
|
||||
#include "esp_private/regi2c_ctrl.h"
|
||||
#include "esp_private/sar_periph_ctrl.h"
|
||||
#include "hal/adc_ll.h"
|
||||
#include "hal/adc_types.h"
|
||||
#include "hal/regi2c_ctrl_ll.h"
|
||||
|
||||
#define ADC_RNG_CLKM_DIV_NUM 3
|
||||
#define ADC_RNG_CLKM_DIV_B 0
|
||||
#define ADC_RNG_CLKM_DIV_A 0
|
||||
|
||||
void bootloader_random_enable(void)
|
||||
{
|
||||
SET_PERI_REG_MASK(SYSTEM_WIFI_CLK_EN_REG, SYSTEM_WIFI_CLK_RNG_EN);
|
||||
|
||||
// Enable 8M clock source for RNG (this is actually enough to produce strong random results,
|
||||
// but enabling the SAR ADC as well adds some insurance.)
|
||||
REG_SET_BIT(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN);
|
||||
|
||||
_adc_ll_reset_register();
|
||||
_adc_ll_enable_bus_clock(true);
|
||||
_adc_ll_enable_bus_clock(false);
|
||||
|
||||
adc_ll_digi_clk_sel(ADC_DIGI_CLK_SRC_APB);
|
||||
adc_ll_digi_controller_clk_div(ADC_RNG_CLKM_DIV_NUM, ADC_RNG_CLKM_DIV_B, ADC_RNG_CLKM_DIV_A);
|
||||
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
regi2c_saradc_enable();
|
||||
#else
|
||||
regi2c_ctrl_ll_i2c_sar_periph_enable();
|
||||
#endif
|
||||
// enable analog i2c master clock for RNG runtime
|
||||
ANALOG_CLOCK_ENABLE();
|
||||
|
||||
adc_ll_regi2c_init();
|
||||
|
||||
adc_digi_pattern_config_t pattern_config = {};
|
||||
pattern_config.unit = ADC_UNIT_1;
|
||||
pattern_config.atten = ADC_ATTEN_DB_12;
|
||||
pattern_config.channel = ADC_CHANNEL_10; //Use reserved channel to get internal voltage
|
||||
adc_ll_digi_set_pattern_table(ADC_UNIT_1, 0, pattern_config);
|
||||
pattern_config.unit = ADC_UNIT_2;
|
||||
pattern_config.atten = ADC_ATTEN_DB_12;
|
||||
pattern_config.channel = ADC_CHANNEL_10; //Use reserved ADC2 and reserved channel to get internal voltage
|
||||
adc_ll_digi_set_pattern_table(ADC_UNIT_2, 1, pattern_config);
|
||||
adc_ll_digi_set_pattern_table_len(ADC_UNIT_1, 1);
|
||||
adc_ll_digi_set_pattern_table_len(ADC_UNIT_2, 1);
|
||||
|
||||
adc_ll_digi_set_convert_mode(ADC_LL_DIGI_CONV_BOTH_UNIT);
|
||||
|
||||
adc_ll_set_controller(ADC_UNIT_1, ADC_LL_CTRL_DIG);
|
||||
adc_ll_disable_sleep_controller();
|
||||
adc_ll_set_arbiter_work_mode(ADC_ARB_MODE_LOOP);
|
||||
|
||||
adc_ll_digi_set_clk_div(3);
|
||||
adc_ll_digi_set_trigger_interval(70);
|
||||
adc_ll_digi_trigger_enable();
|
||||
rng_ll_enable();
|
||||
}
|
||||
|
||||
void bootloader_random_disable(void)
|
||||
{
|
||||
rng_ll_disable();
|
||||
|
||||
adc_ll_digi_trigger_disable();
|
||||
adc_ll_digi_reset_pattern_table();
|
||||
|
||||
adc_ll_regi2c_adc_deinit();
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
regi2c_saradc_disable();
|
||||
#endif
|
||||
|
||||
// disable analog i2c master clock
|
||||
ANALOG_CLOCK_DISABLE();
|
||||
adc_ll_digi_controller_clk_div(4, 0, 0);
|
||||
adc_ll_digi_clk_sel(ADC_DIGI_CLK_SRC_APB);
|
||||
|
||||
adc_ll_set_controller(ADC_UNIT_1, ADC_LL_CTRL_ULP);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#include "bootloader_random.h"
|
||||
#include "hal/rng_ll.h"
|
||||
|
||||
void bootloader_random_enable(void)
|
||||
{
|
||||
rng_ll_enable();
|
||||
}
|
||||
|
||||
void bootloader_random_disable(void)
|
||||
{
|
||||
rng_ll_disable();
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <inttypes.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_rom_sys.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#if SOC_CPU_LOCKUP_DEBUG_SUPPORTED
|
||||
#include "hal/assist_debug_ll.h"
|
||||
#include "esp_rom_caps.h"
|
||||
#endif
|
||||
#include "bootloader_init.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "boot");
|
||||
|
||||
#if SOC_CPU_LOCKUP_DEBUG_SUPPORTED && !ESP_ROM_PRINTS_LOCKUP_STATUS
|
||||
static void lockup_info_dump(int cpu)
|
||||
{
|
||||
const char *cpu_name = cpu ? "APP" : "PRO";
|
||||
|
||||
ESP_LOGW(TAG, "%s CPU reset due to CPU lockup (exception inside exception handler).", cpu_name);
|
||||
ESP_LOGW(TAG, "%s CPU trap chain:", cpu_name);
|
||||
for (int i = 0; i < 2; i++) {
|
||||
uint32_t cause = assist_debug_ll_lockup_get_cause(cpu, i);
|
||||
uint32_t tval = assist_debug_ll_lockup_get_tval(cpu, i);
|
||||
uint32_t iaddr = assist_debug_ll_lockup_get_iaddr(cpu, i);
|
||||
uint32_t priv = assist_debug_ll_lockup_get_priv(cpu, i);
|
||||
const char *label = i == 0 ? "latest" : "previous";
|
||||
|
||||
ESP_LOGW(TAG, " [%s trap] cause=0x%02"PRIx32" PCAddr=0x%08"PRIx32" tval=0x%08"PRIx32" priv=%"PRIu32,
|
||||
label, cause, iaddr, tval, priv);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void bootloader_check_reset(void)
|
||||
{
|
||||
bool any_wdt_reset = false;
|
||||
soc_reset_reason_t reset_reason;
|
||||
|
||||
reset_reason = esp_rom_get_reset_reason(0);
|
||||
any_wdt_reset |= bootloader_check_if_wdt_reset(0, reset_reason);
|
||||
#if SOC_CPU_LOCKUP_DEBUG_SUPPORTED && !ESP_ROM_PRINTS_LOCKUP_STATUS
|
||||
if (reset_reason == RESET_REASON_CPU_LOCKUP) {
|
||||
lockup_info_dump(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
|
||||
reset_reason = esp_rom_get_reset_reason(1);
|
||||
any_wdt_reset |= bootloader_check_if_wdt_reset(1, reset_reason);
|
||||
#if SOC_CPU_LOCKUP_DEBUG_SUPPORTED && !ESP_ROM_PRINTS_LOCKUP_STATUS
|
||||
if (reset_reason == RESET_REASON_CPU_LOCKUP) {
|
||||
lockup_info_dump(1);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (any_wdt_reset) {
|
||||
bootloader_dump_wdt_reset_info(0);
|
||||
#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
|
||||
bootloader_dump_wdt_reset_info(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
bootloader_enable_cpu_reset_info();
|
||||
}
|
||||
@@ -0,0 +1,296 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include "bootloader_sha.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "rom/sha.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if NON_OS_BUILD || CONFIG_APP_BUILD_TYPE_RAM
|
||||
#if !CONFIG_IDF_TARGET_ESP32
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
#if SOC_SHA_SUPPORT_SHA512
|
||||
bootloader_sha_handle_t bootloader_sha512_start(bool is384)
|
||||
{
|
||||
// Enable SHA hardware
|
||||
ets_sha_enable();
|
||||
ets_sha_init(&ctx, is384 ? SHA2_384 : SHA2_512);
|
||||
return &ctx; // Meaningless non-NULL value
|
||||
}
|
||||
|
||||
void bootloader_sha512_data(bootloader_sha_handle_t handle, const void *data, size_t data_len)
|
||||
{
|
||||
assert(handle != NULL);
|
||||
ets_sha_update(&ctx, data, data_len, false);
|
||||
}
|
||||
|
||||
void bootloader_sha512_finish(bootloader_sha_handle_t handle, uint8_t *digest)
|
||||
{
|
||||
assert(handle != NULL);
|
||||
|
||||
if (digest == NULL) {
|
||||
bzero(&ctx, sizeof(ctx));
|
||||
return;
|
||||
}
|
||||
ets_sha_finish(&ctx, digest);
|
||||
}
|
||||
#endif /* SOC_SHA_SUPPORT_SHA512 */
|
||||
#else /* !CONFIG_IDF_TARGET_ESP32 */
|
||||
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/hwcrypto_periph.h"
|
||||
|
||||
static uint32_t words_hashed;
|
||||
|
||||
// Words per SHA256 block
|
||||
static const size_t BLOCK_WORDS = (64 / sizeof(uint32_t));
|
||||
// Words in final SHA256 digest
|
||||
static const size_t DIGEST_WORDS = (32 / sizeof(uint32_t));
|
||||
|
||||
bootloader_sha256_handle_t bootloader_sha256_start(void)
|
||||
{
|
||||
// Enable SHA hardware
|
||||
ets_sha_enable();
|
||||
words_hashed = 0;
|
||||
return (bootloader_sha256_handle_t)&words_hashed; // 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);
|
||||
|
||||
const uint32_t *w = (const uint32_t *)data;
|
||||
size_t word_len = data_len / 4;
|
||||
uint32_t *sha_text_reg = (uint32_t *)(SHA_TEXT_BASE);
|
||||
|
||||
while (word_len > 0) {
|
||||
size_t block_count = words_hashed % BLOCK_WORDS;
|
||||
size_t copy_words = (BLOCK_WORDS - block_count);
|
||||
|
||||
copy_words = MIN(word_len, copy_words);
|
||||
|
||||
// Wait for SHA engine idle
|
||||
while (_DPORT_REG_READ(SHA_256_BUSY_REG) != 0) { }
|
||||
|
||||
// Copy to memory block
|
||||
for (size_t i = 0; i < copy_words; i++) {
|
||||
sha_text_reg[block_count + i] = __builtin_bswap32(w[i]);
|
||||
}
|
||||
asm volatile ("memw");
|
||||
|
||||
// Update counters
|
||||
words_hashed += copy_words;
|
||||
block_count += copy_words;
|
||||
word_len -= copy_words;
|
||||
w += copy_words;
|
||||
|
||||
// If we loaded a full block, run the SHA engine
|
||||
if (block_count == BLOCK_WORDS) {
|
||||
if (words_hashed == BLOCK_WORDS) {
|
||||
_DPORT_REG_WRITE(SHA_256_START_REG, 1);
|
||||
} else {
|
||||
_DPORT_REG_WRITE(SHA_256_CONTINUE_REG, 1);
|
||||
}
|
||||
block_count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bootloader_sha256_finish(bootloader_sha256_handle_t handle, uint8_t *digest)
|
||||
{
|
||||
assert(handle != NULL);
|
||||
|
||||
if (digest == NULL) {
|
||||
return; // We'd free resources here, but there are none to free
|
||||
}
|
||||
|
||||
uint32_t data_words = words_hashed;
|
||||
|
||||
// Pad to a 55 byte long block loaded in the engine
|
||||
// (leaving 1 byte 0x80 plus variable padding plus 8 bytes of length,
|
||||
// to fill a 64 byte block.)
|
||||
int block_bytes = (words_hashed % BLOCK_WORDS) * 4;
|
||||
int pad_bytes = 55 - block_bytes;
|
||||
if (pad_bytes < 0) {
|
||||
pad_bytes += 64;
|
||||
}
|
||||
static const uint8_t padding[64] = { 0x80, 0, };
|
||||
|
||||
pad_bytes += 5; // 1 byte for 0x80 plus first 4 bytes of the 64-bit length
|
||||
assert(pad_bytes % 4 == 0); // should be, as (block_bytes % 4 == 0)
|
||||
|
||||
bootloader_sha256_data(handle, padding, pad_bytes);
|
||||
|
||||
assert(words_hashed % BLOCK_WORDS == 60 / 4); // 32-bits left in block
|
||||
|
||||
// Calculate 32-bit length for final 32 bits of data
|
||||
uint32_t bit_count = __builtin_bswap32( data_words * 32 );
|
||||
bootloader_sha256_data(handle, &bit_count, sizeof(bit_count));
|
||||
|
||||
assert(words_hashed % BLOCK_WORDS == 0);
|
||||
|
||||
while (_DPORT_REG_READ(SHA_256_BUSY_REG) == 1) { }
|
||||
_DPORT_REG_WRITE(SHA_256_LOAD_REG, 1);
|
||||
while (_DPORT_REG_READ(SHA_256_BUSY_REG) == 1) { }
|
||||
|
||||
uint32_t *digest_words = (uint32_t *)digest;
|
||||
uint32_t *sha_text_reg = (uint32_t *)(SHA_TEXT_BASE);
|
||||
for (size_t i = 0; i < DIGEST_WORDS; i++) {
|
||||
digest_words[i] = __builtin_bswap32(sha_text_reg[i]);
|
||||
}
|
||||
asm volatile ("memw");
|
||||
}
|
||||
#endif /* CONFIG_IDF_TARGET_ESP32 */
|
||||
#else /* NON_OS_BUILD || CONFIG_APP_BUILD_TYPE_RAM */
|
||||
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "psa/crypto.h"
|
||||
|
||||
bootloader_sha256_handle_t bootloader_sha256_start(void)
|
||||
{
|
||||
psa_hash_operation_t *op = (psa_hash_operation_t *)malloc(sizeof(psa_hash_operation_t));
|
||||
if (!op) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*op = psa_hash_operation_init();
|
||||
psa_status_t status = psa_hash_setup(op, PSA_ALG_SHA_256);
|
||||
if (status != PSA_SUCCESS) {
|
||||
free(op);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (bootloader_sha256_handle_t)op;
|
||||
}
|
||||
|
||||
void bootloader_sha256_data(bootloader_sha256_handle_t handle, const void *data, size_t data_len)
|
||||
{
|
||||
assert(handle != NULL);
|
||||
psa_hash_operation_t *op = (psa_hash_operation_t *)handle;
|
||||
|
||||
psa_status_t status = psa_hash_update(op, data, data_len);
|
||||
assert(status == PSA_SUCCESS);
|
||||
(void)status; // Suppress unused variable warning in release builds
|
||||
}
|
||||
|
||||
void bootloader_sha256_finish(bootloader_sha256_handle_t handle, uint8_t *digest)
|
||||
{
|
||||
assert(handle != NULL);
|
||||
psa_hash_operation_t *op = (psa_hash_operation_t *)handle;
|
||||
|
||||
if (digest != NULL) {
|
||||
size_t hash_len;
|
||||
psa_status_t status = psa_hash_finish(op, digest, PSA_HASH_LENGTH(PSA_ALG_SHA_256), &hash_len);
|
||||
assert(status == PSA_SUCCESS);
|
||||
assert(hash_len == PSA_HASH_LENGTH(PSA_ALG_SHA_256));
|
||||
(void)status; // Suppress unused variable warning in release builds
|
||||
(void)hash_len; // Suppress unused variable warning in release builds
|
||||
} else {
|
||||
psa_hash_abort(op);
|
||||
}
|
||||
|
||||
free(handle);
|
||||
handle = NULL;
|
||||
}
|
||||
|
||||
#if SOC_SHA_SUPPORT_SHA512
|
||||
|
||||
typedef struct {
|
||||
psa_hash_operation_t *hash_op;
|
||||
int psa_alg;
|
||||
} bootloader_psa_sha_handle_t;
|
||||
|
||||
bootloader_sha_handle_t bootloader_sha512_start(bool is384)
|
||||
{
|
||||
psa_status_t status;
|
||||
bootloader_psa_sha_handle_t *op = (bootloader_psa_sha_handle_t *)malloc(sizeof(bootloader_psa_sha_handle_t));
|
||||
if (!op) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
op->hash_op = (psa_hash_operation_t *)malloc(sizeof(psa_hash_operation_t));
|
||||
if (!op->hash_op) {
|
||||
free(op);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
op->psa_alg = is384 ? PSA_ALG_SHA_384 : PSA_ALG_SHA_512;
|
||||
|
||||
*op->hash_op = psa_hash_operation_init();
|
||||
status = psa_hash_setup(op->hash_op, op->psa_alg);
|
||||
if (status != PSA_SUCCESS) {
|
||||
free(op->hash_op);
|
||||
free(op);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (bootloader_psa_sha_handle_t *)op;
|
||||
}
|
||||
|
||||
void bootloader_sha512_data(bootloader_sha_handle_t handle, const void *data, size_t data_len)
|
||||
{
|
||||
assert(handle != NULL);
|
||||
bootloader_psa_sha_handle_t *op = (bootloader_psa_sha_handle_t *)handle;
|
||||
|
||||
psa_status_t status = psa_hash_update(op->hash_op, data, data_len);
|
||||
assert(status == PSA_SUCCESS);
|
||||
(void)status; // Suppress unused variable warning in release builds
|
||||
}
|
||||
|
||||
void bootloader_sha512_finish(bootloader_sha_handle_t handle, uint8_t *digest)
|
||||
{
|
||||
assert(handle != NULL);
|
||||
bootloader_psa_sha_handle_t *op = (bootloader_psa_sha_handle_t *)handle;
|
||||
|
||||
if (digest != NULL) {
|
||||
size_t hash_len;
|
||||
psa_status_t status = psa_hash_finish(op->hash_op, digest, PSA_HASH_LENGTH(op->psa_alg), &hash_len);
|
||||
assert(status == PSA_SUCCESS);
|
||||
assert(hash_len == PSA_HASH_LENGTH(op->psa_alg));
|
||||
(void)status; // Suppress unused variable warning in release builds
|
||||
(void)hash_len; // Suppress unused variable warning in release builds
|
||||
} else {
|
||||
psa_hash_abort(op->hash_op);
|
||||
}
|
||||
|
||||
free(op->hash_op);
|
||||
free(op);
|
||||
handle = NULL;
|
||||
}
|
||||
#endif /* SOC_SHA_SUPPORT_SHA512 */
|
||||
#endif /* !(NON_OS_BUILD || CONFIG_APP_BUILD_TYPE_RAM) */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "esp_attr.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "esp_rom_sys.h"
|
||||
#include "esp_rom_crc.h"
|
||||
|
||||
#include "hal/efuse_hal.h"
|
||||
|
||||
#include "esp_image_format.h"
|
||||
#include "bootloader_config.h"
|
||||
#include "bootloader_flash_priv.h"
|
||||
|
||||
#include "bootloader_utility.h"
|
||||
#include "bootloader_utility_tee.h"
|
||||
#include "esp_tee_ota_utils.h"
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "boot_tee");
|
||||
|
||||
static esp_err_t write_tee_otadata_sector(esp_tee_ota_select_entry_t *tee_otadata, uint32_t offset)
|
||||
{
|
||||
if (tee_otadata == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_err_t err = bootloader_flash_erase_sector(offset / FLASH_SECTOR_SIZE);
|
||||
if (err == ESP_OK) {
|
||||
bool write_encrypted = false;
|
||||
#if !CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
write_encrypted = efuse_hal_flash_encryption_enabled();
|
||||
#endif
|
||||
err = bootloader_flash_write(offset, tee_otadata, sizeof(esp_tee_ota_select_entry_t), write_encrypted);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to write otadata sector, 0x%x", err);
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static esp_err_t read_tee_otadata(const esp_partition_pos_t *tee_ota_info, esp_tee_ota_select_entry_t *two_otadata)
|
||||
{
|
||||
if (tee_ota_info == NULL || two_otadata == NULL || tee_ota_info->offset == 0) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (tee_ota_info->size < 2 * FLASH_SECTOR_SIZE) {
|
||||
return ESP_ERR_INVALID_SIZE;
|
||||
}
|
||||
|
||||
ESP_LOGV(TAG, "TEE OTA data offset 0x%"PRIx32, tee_ota_info->offset);
|
||||
|
||||
const esp_tee_ota_select_entry_t *ota_select_map = bootloader_mmap(tee_ota_info->offset, tee_ota_info->size);
|
||||
if (!ota_select_map) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%"PRIx32", 0x%"PRIx32") failed", tee_ota_info->offset, tee_ota_info->size);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
memcpy(&two_otadata[0], (uint8_t *)ota_select_map, sizeof(esp_tee_ota_select_entry_t));
|
||||
memcpy(&two_otadata[1], (uint8_t *)ota_select_map + FLASH_SECTOR_SIZE, sizeof(esp_tee_ota_select_entry_t));
|
||||
|
||||
bootloader_munmap(ota_select_map);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t write_tee_otadata(esp_tee_ota_select_entry_t *tee_otadata, const esp_partition_pos_t *tee_ota_info)
|
||||
{
|
||||
esp_err_t err = write_tee_otadata_sector(tee_otadata, tee_ota_info->offset);
|
||||
if (err == ESP_OK) {
|
||||
err = write_tee_otadata_sector(tee_otadata, tee_ota_info->offset + FLASH_SECTOR_SIZE);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to update otadata sector, 0x%x", err);
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static esp_err_t get_valid_tee_otadata(const esp_partition_pos_t *tee_ota_info, esp_tee_ota_select_entry_t *tee_otadata)
|
||||
{
|
||||
esp_tee_ota_select_entry_t two_otadata[2] = {0};
|
||||
if (read_tee_otadata(tee_ota_info, two_otadata) != ESP_OK) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
esp_tee_ota_select_entry_t blank_otadata;
|
||||
memset(&blank_otadata, 0xff, sizeof(esp_tee_ota_select_entry_t));
|
||||
|
||||
// Check if the contents of both the otadata sectors match
|
||||
bool sectors_match = (memcmp(&two_otadata[0], &two_otadata[1], sizeof(esp_tee_ota_select_entry_t)) == 0);
|
||||
if (sectors_match) {
|
||||
if (memcmp(&two_otadata[0], &blank_otadata, sizeof(esp_tee_ota_select_entry_t)) != 0) {
|
||||
uint32_t crc = esp_rom_crc32_le(0, (uint8_t const *)two_otadata, (sizeof(esp_tee_ota_select_entry_t) - sizeof(uint32_t)));
|
||||
if (two_otadata[0].magic != TEE_OTADATA_MAGIC || crc != two_otadata[0].crc) {
|
||||
ESP_LOGE(TAG, "TEE otadata[0] magic or CRC verification failed");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
memcpy(tee_otadata, &two_otadata[0], sizeof(esp_tee_ota_select_entry_t));
|
||||
ESP_LOGV(TAG, "Both tee_otadata sectors are the same");
|
||||
} else {
|
||||
uint32_t crc_otadata0 = esp_rom_crc32_le(0, (uint8_t const *)&two_otadata[0], (sizeof(esp_tee_ota_select_entry_t) - sizeof(uint32_t)));
|
||||
uint32_t crc_otadata1 = esp_rom_crc32_le(0, (uint8_t const *)&two_otadata[1], (sizeof(esp_tee_ota_select_entry_t) - sizeof(uint32_t)));
|
||||
|
||||
if (crc_otadata0 == two_otadata[0].crc) {
|
||||
ESP_LOGV(TAG, "Second tee_otadata sector is invalid - copying contents from first sector");
|
||||
// Copy contents of first tee_otadata sector into second
|
||||
write_tee_otadata_sector(&two_otadata[0], tee_ota_info->offset + FLASH_SECTOR_SIZE);
|
||||
memcpy(tee_otadata, &two_otadata[0], sizeof(esp_tee_ota_select_entry_t));
|
||||
} else if (crc_otadata1 == two_otadata[1].crc) {
|
||||
ESP_LOGV(TAG, "First tee_otadata sector is invalid - copying contents from second sector");
|
||||
// Copy contents of second tee_otadata sector into first
|
||||
write_tee_otadata_sector(&two_otadata[1], tee_ota_info->offset);
|
||||
memcpy(tee_otadata, &two_otadata[1], sizeof(esp_tee_ota_select_entry_t));
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Both tee_otadata sectors are invalid!");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t update_tee_otadata(const esp_partition_pos_t *tee_ota_info, uint8_t boot_partition, uint8_t ota_state)
|
||||
{
|
||||
esp_tee_ota_select_entry_t otadata = {
|
||||
.magic = TEE_OTADATA_MAGIC,
|
||||
.boot_partition = boot_partition,
|
||||
.ota_state = ota_state,
|
||||
};
|
||||
otadata.crc = esp_rom_crc32_le(0, (uint8_t const *)&otadata, (sizeof(esp_tee_ota_select_entry_t) - sizeof(uint32_t)));
|
||||
return write_tee_otadata(&otadata, tee_ota_info);
|
||||
}
|
||||
|
||||
int bootloader_utility_tee_get_boot_partition(const esp_partition_pos_t *tee_ota_info)
|
||||
{
|
||||
esp_tee_ota_select_entry_t otadata = {}, blank_otadata;
|
||||
const int default_tee_app_slot = PART_SUBTYPE_TEE_0;
|
||||
|
||||
esp_err_t err = get_valid_tee_otadata(tee_ota_info, &otadata);
|
||||
if (err == ESP_ERR_NOT_FOUND) {
|
||||
ESP_LOGV(TAG, "otadata partition not found, booting from first partition");
|
||||
return default_tee_app_slot;
|
||||
}
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to get valid otadata, 0x%x", err);
|
||||
return -1;
|
||||
}
|
||||
memset(&blank_otadata, 0xff, sizeof(esp_tee_ota_select_entry_t));
|
||||
if (!memcmp(&blank_otadata, &otadata, sizeof(esp_tee_ota_select_entry_t))) {
|
||||
ESP_LOGV(TAG, "otadata partition empty, booting from first partition");
|
||||
/* NOTE: The first TEE partition will always be valid as it is flashed manually */
|
||||
if (update_tee_otadata(tee_ota_info, default_tee_app_slot, ESP_TEE_OTA_IMG_VALID) != ESP_OK) {
|
||||
ESP_LOGW(TAG, "Failed to setup TEE otadata as per the first partition!");
|
||||
}
|
||||
return default_tee_app_slot;
|
||||
}
|
||||
|
||||
int boot_partition = 0;
|
||||
|
||||
#if BOOTLOADER_BUILD
|
||||
switch(otadata.ota_state) {
|
||||
case ESP_TEE_OTA_IMG_NEW:
|
||||
ESP_LOGD(TAG, "TEE otadata - Current image state: NEW");
|
||||
boot_partition = otadata.boot_partition;
|
||||
if (update_tee_otadata(tee_ota_info, otadata.boot_partition, ESP_TEE_OTA_IMG_PENDING_VERIFY) != ESP_OK) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case ESP_TEE_OTA_IMG_UNDEFINED:
|
||||
case ESP_TEE_OTA_IMG_PENDING_VERIFY:
|
||||
ESP_LOGD(TAG, "TEE otadata - Current image state: PENDING_VERIFY/UNDEFINED");
|
||||
boot_partition = (otadata.boot_partition == PART_SUBTYPE_TEE_0) ? PART_SUBTYPE_TEE_1 : PART_SUBTYPE_TEE_0;
|
||||
if (update_tee_otadata(tee_ota_info, boot_partition, ESP_TEE_OTA_IMG_INVALID) != ESP_OK) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case ESP_TEE_OTA_IMG_INVALID:
|
||||
ESP_LOGD(TAG, "TEE otadata - Current image state: INVALID");
|
||||
bootloader_reset();
|
||||
break;
|
||||
case ESP_TEE_OTA_IMG_VALID:
|
||||
ESP_LOGD(TAG, "TEE otadata - Current image state: VALID");
|
||||
boot_partition = otadata.boot_partition;
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#else
|
||||
boot_partition = otadata.boot_partition;
|
||||
#endif
|
||||
|
||||
return boot_partition;
|
||||
}
|
||||
|
||||
esp_err_t bootloader_utility_tee_set_boot_partition(const esp_partition_pos_t *tee_ota_info, const esp_partition_info_t *tee_try_part)
|
||||
{
|
||||
if (tee_ota_info == NULL || tee_try_part == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (tee_try_part->subtype != PART_SUBTYPE_TEE_0 && tee_try_part->subtype != PART_SUBTYPE_TEE_1) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_image_metadata_t data = {};
|
||||
if (esp_image_verify(ESP_IMAGE_VERIFY, &tee_try_part->pos, &data) != ESP_OK) {
|
||||
return ESP_ERR_IMAGE_INVALID;
|
||||
}
|
||||
|
||||
return update_tee_otadata(tee_ota_info, tee_try_part->subtype, ESP_TEE_OTA_IMG_NEW);
|
||||
}
|
||||
|
||||
int bootloader_utility_tee_get_next_update_partition(const esp_partition_pos_t *tee_ota_info)
|
||||
{
|
||||
esp_tee_ota_select_entry_t otadata = {}, blank_otadata;
|
||||
const int default_tee_next_app_slot = PART_SUBTYPE_TEE_1;
|
||||
|
||||
esp_err_t err = get_valid_tee_otadata(tee_ota_info, &otadata);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to get valid otadata, 0x%x", err);
|
||||
return -1;
|
||||
}
|
||||
memset(&blank_otadata, 0xff, sizeof(esp_tee_ota_select_entry_t));
|
||||
if (!memcmp(&blank_otadata, &otadata, sizeof(esp_tee_ota_select_entry_t))) {
|
||||
return default_tee_next_app_slot;
|
||||
}
|
||||
|
||||
return (otadata.boot_partition == PART_SUBTYPE_TEE_0) ? PART_SUBTYPE_TEE_1 : PART_SUBTYPE_TEE_0;
|
||||
}
|
||||
|
||||
esp_err_t bootloader_utility_tee_mark_app_valid_and_cancel_rollback(const esp_partition_pos_t *tee_ota_info)
|
||||
{
|
||||
esp_tee_ota_select_entry_t two_otadata[2];
|
||||
|
||||
esp_err_t err = read_tee_otadata(tee_ota_info, two_otadata);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to fetch TEE otadata!");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (two_otadata[0].ota_state == ESP_TEE_OTA_IMG_VALID) {
|
||||
ESP_LOGD(TAG, "TEE otadata - Current image already has been marked VALID");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
int tee_app_slot = bootloader_utility_tee_get_boot_partition(tee_ota_info);
|
||||
return update_tee_otadata(tee_ota_info, (uint8_t)tee_app_slot, ESP_TEE_OTA_IMG_VALID);
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#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 "bootloader_mem.h"
|
||||
#include "bootloader_console.h"
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "esp_private/bootloader_flash_internal.h"
|
||||
#include "esp_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/soc_caps.h"
|
||||
|
||||
#include "hal/gpio_hal.h"
|
||||
#include "hal/mmu_hal.h"
|
||||
#include "xtensa/config/core.h"
|
||||
#include "xt_instr_macros.h"
|
||||
|
||||
#include "esp32/rom/cache.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
#include "esp_rom_efuse.h"
|
||||
#include "esp_rom_sys.h"
|
||||
#include "esp_rom_spiflash.h"
|
||||
#include "esp_efuse.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "boot.esp32");
|
||||
|
||||
#if !CONFIG_APP_BUILD_TYPE_RAM
|
||||
static void bootloader_reset_mmu(void)
|
||||
{
|
||||
/* completely reset MMU in case serial bootloader was running */
|
||||
Cache_Read_Disable(0);
|
||||
#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
|
||||
Cache_Read_Disable(1);
|
||||
#endif
|
||||
Cache_Flush(0);
|
||||
#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
|
||||
Cache_Flush(1);
|
||||
#endif
|
||||
mmu_init(0);
|
||||
#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
|
||||
/* 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
|
||||
|
||||
mmu_hal_config_t mmu_config = {
|
||||
#if CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
|
||||
.core_nums = 1,
|
||||
#else
|
||||
.core_nums = SOC_CPU_CORES_NUM,
|
||||
#endif
|
||||
};
|
||||
mmu_hal_ctx_init(&mmu_config);
|
||||
|
||||
/* 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_ESP_SYSTEM_SINGLE_CORE_MODE
|
||||
DPORT_REG_CLR_BIT(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MASK_DROM0);
|
||||
#endif
|
||||
}
|
||||
#endif //#if !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
|
||||
|
||||
static inline esp_err_t bootloader_check_rated_cpu_clock(void)
|
||||
{
|
||||
int rated_freq = bootloader_clock_get_rated_freq_mhz();
|
||||
if (rated_freq < CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ) {
|
||||
ESP_LOGE(TAG, "Chip CPU freq rated for %dMHz, configured for %dMHz. Modify CPU freq in menuconfig",
|
||||
rated_freq, CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#if SOC_RTC_WDT_SUPPORTED
|
||||
void bootloader_enable_cpu_reset_info(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);
|
||||
}
|
||||
|
||||
void bootloader_dump_wdt_reset_info(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 ? ESP_LOG_ATTR_STR("APP") : ESP_LOG_ATTR_STR("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_ESP_SYSTEM_SINGLE_CORE_MODE
|
||||
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);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (DPORT_RECORD_PDEBUGINST_SZ(inst) == 0 &&
|
||||
DPORT_RECORD_PDEBUGSTATUS_BBCAUSE(dstat) == DPORT_RECORD_PDEBUGSTATUS_BBCAUSE_WAITI) {
|
||||
ESP_LOGW(TAG, "WDT rst info: %s CPU PC=0x%"PRIx32" (waiti mode)", cpu_name, pc);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "WDT rst info: %s CPU PC=0x%"PRIx32, cpu_name, pc);
|
||||
}
|
||||
ESP_LOGD(TAG, "WDT rst info: %s CPU STATUS 0x%08"PRIx32, cpu_name, stat);
|
||||
ESP_LOGD(TAG, "WDT rst info: %s CPU PID 0x%08"PRIx32, cpu_name, pid);
|
||||
ESP_LOGD(TAG, "WDT rst info: %s CPU PDEBUGINST 0x%08"PRIx32, cpu_name, inst);
|
||||
ESP_LOGD(TAG, "WDT rst info: %s CPU PDEBUGSTATUS 0x%08"PRIx32, cpu_name, dstat);
|
||||
ESP_LOGD(TAG, "WDT rst info: %s CPU PDEBUGDATA 0x%08"PRIx32, cpu_name, data);
|
||||
ESP_LOGD(TAG, "WDT rst info: %s CPU PDEBUGPC 0x%08"PRIx32, cpu_name, pc);
|
||||
ESP_LOGD(TAG, "WDT rst info: %s CPU PDEBUGLS0STAT 0x%08"PRIx32, cpu_name, lsstat);
|
||||
ESP_LOGD(TAG, "WDT rst info: %s CPU PDEBUGLS0ADDR 0x%08"PRIx32, cpu_name, lsaddr);
|
||||
ESP_LOGD(TAG, "WDT rst info: %s CPU PDEBUGLS0DATA 0x%08"PRIx32, cpu_name, lsdata);
|
||||
}
|
||||
|
||||
bool bootloader_check_if_wdt_reset(int cpu, soc_reset_reason_t rst_reason)
|
||||
{
|
||||
if (cpu == 0 && (rst_reason == RESET_REASON_CORE_RTC_WDT || rst_reason == RESET_REASON_CORE_MWDT0 ||
|
||||
rst_reason == RESET_REASON_CORE_MWDT1 || rst_reason == RESET_REASON_CPU0_MWDT0 ||
|
||||
rst_reason == RESET_REASON_CPU0_RTC_WDT)) {
|
||||
ESP_LOGW(TAG, "PRO CPU has been reset by WDT");
|
||||
return true;
|
||||
}
|
||||
if (cpu == 1 && (rst_reason == RESET_REASON_CORE_RTC_WDT || rst_reason == RESET_REASON_CORE_MWDT0 ||
|
||||
rst_reason == RESET_REASON_CORE_MWDT1 || rst_reason == RESET_REASON_CPU1_MWDT1 ||
|
||||
rst_reason == RESET_REASON_CPU1_RTC_WDT)) {
|
||||
ESP_LOGW(TAG, "APP CPU has been reset by WDT");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif // SOC_RTC_WDT_SUPPORTED
|
||||
|
||||
esp_err_t bootloader_init(void)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
#if XCHAL_ERRATUM_572
|
||||
uint32_t memctl = XCHAL_CACHE_MEMCTL_DEFAULT;
|
||||
WSR(XT_REG_MEMCTL, memctl);
|
||||
#endif // XCHAL_ERRATUM_572
|
||||
|
||||
// In RAM_APP, memory will be initialized in `call_start_cpu0`
|
||||
#if !CONFIG_APP_BUILD_TYPE_RAM
|
||||
bootloader_init_mem();
|
||||
|
||||
// check that static RAM is after the stack
|
||||
#ifndef NDEBUG
|
||||
{
|
||||
assert(&_bss_start <= &_bss_end);
|
||||
assert(&_data_start <= &_data_end);
|
||||
int *sp = esp_cpu_get_sp();
|
||||
assert(sp < &_bss_start);
|
||||
assert(sp < &_data_start);
|
||||
}
|
||||
#endif
|
||||
// clear bss section
|
||||
bootloader_clear_bss_section();
|
||||
#endif // !CONFIG_APP_BUILD_TYPE_RAM
|
||||
|
||||
// init eFuse virtual mode (read eFuses to RAM)
|
||||
#ifdef CONFIG_EFUSE_VIRTUAL
|
||||
ESP_EARLY_LOGW(TAG, "eFuse virtual mode is enabled. If Secure boot or Flash encryption is enabled then it does not provide any security. FOR TESTING ONLY!");
|
||||
#ifndef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
esp_efuse_init_virtual_mode_in_ram();
|
||||
#endif
|
||||
#endif
|
||||
// bootst up vddsdio
|
||||
bootloader_common_vddsdio_configure();
|
||||
// check rated CPU clock
|
||||
if ((ret = bootloader_check_rated_cpu_clock()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
// config clock
|
||||
bootloader_clock_configure();
|
||||
// initialize uart console, from now on, we can use esp_log
|
||||
bootloader_console_init();
|
||||
/* print 2nd bootloader banner */
|
||||
bootloader_print_banner();
|
||||
|
||||
#if !CONFIG_APP_BUILD_TYPE_RAM
|
||||
// reset MMU
|
||||
bootloader_reset_mmu();
|
||||
// update flash ID
|
||||
bootloader_flash_update_id();
|
||||
// Check and run XMC startup flow
|
||||
if ((ret = bootloader_flash_xmc_startup()) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "XMC startup flow failed, reboot!");
|
||||
return ret;
|
||||
}
|
||||
// read bootloader header
|
||||
if ((ret = bootloader_read_bootloader_header()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
// read chip revision and check if it's compatible to bootloader
|
||||
if ((ret = bootloader_check_bootloader_validity()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
// initialize spi flash
|
||||
if ((ret = bootloader_init_spi_flash()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
#endif // #if !CONFIG_APP_BUILD_TYPE_RAM
|
||||
|
||||
// check reset reason and dump diagnostic info
|
||||
bootloader_check_reset();
|
||||
#if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED
|
||||
// config WDT
|
||||
bootloader_config_wdt();
|
||||
#endif
|
||||
// enable RNG early entropy source
|
||||
bootloader_enable_random();
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
//Not supported but common bootloader calls the function. Do nothing
|
||||
void bootloader_ana_clock_glitch_reset_config(bool enable)
|
||||
{
|
||||
(void)enable;
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <strings.h>
|
||||
#include "esp_flash_encrypt.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "esp_log.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "flash_encrypt");
|
||||
|
||||
esp_err_t esp_flash_encryption_enable_secure_features(void)
|
||||
{
|
||||
|
||||
/* CRYPT_CONFIG determines which bits of the AES block key are XORed
|
||||
with bits from the flash address, to provide the key tweak.
|
||||
|
||||
CRYPT_CONFIG == 0 is effectively AES ECB mode (NOT SUPPORTED)
|
||||
|
||||
For now this is hardcoded to XOR all 256 bits of the key.
|
||||
|
||||
If you need to override it, you can pre-burn this efuse to the
|
||||
desired value and then write-protect it, in which case this
|
||||
operation does nothing. Please note this is not recommended!
|
||||
*/
|
||||
ESP_LOGI(TAG, "Setting CRYPT_CONFIG efuse to 0xF");
|
||||
uint32_t crypt_config = 0;
|
||||
esp_efuse_read_field_blob(ESP_EFUSE_ENCRYPT_CONFIG, &crypt_config, 4);
|
||||
if (crypt_config == 0) {
|
||||
crypt_config = EFUSE_FLASH_CRYPT_CONFIG;
|
||||
esp_efuse_write_field_blob(ESP_EFUSE_ENCRYPT_CONFIG, &crypt_config, 4);
|
||||
} else if (crypt_config != EFUSE_FLASH_CRYPT_CONFIG) {
|
||||
ESP_LOGE(TAG, "EFUSE_ENCRYPT_CONFIG should be set 0xF but it is 0x%" PRIx32, crypt_config);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC
|
||||
ESP_LOGI(TAG, "Disable UART bootloader encryption...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DISABLE_DL_ENCRYPT);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling UART bootloader encryption");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_DEC
|
||||
ESP_LOGI(TAG, "Disable UART bootloader decryption...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DISABLE_DL_DECRYPT);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling UART bootloader decryption - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE
|
||||
ESP_LOGI(TAG, "Disable UART bootloader MMU cache...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DISABLE_DL_CACHE);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling UART bootloader MMU cache - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
|
||||
ESP_LOGI(TAG, "Disable JTAG...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DISABLE_JTAG);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_ROM_BASIC
|
||||
ESP_LOGI(TAG, "Disable ROM BASIC interpreter fallback...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_CONSOLE_DEBUG_DISABLE);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling ROM BASIC fallback - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SECURE_BOOT_V2_ENABLED) && !defined(CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS)
|
||||
// This bit is set when enabling Secure Boot V2, but we can't enable it until this later point in the first boot
|
||||
// otherwise the Flash Encryption key cannot be read protected
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_EFUSE_RD_DISABLE);
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_FLASH_SKIP_WRITE_PROTECTION_CACHE
|
||||
// Set write-protection for DIS_ICACHE to prevent bricking chip in case it will be set accidentally.
|
||||
// esp32 has DIS_ICACHE. Write-protection bit = 3.
|
||||
// List of eFuses with the same write protection bit:
|
||||
// MAC, MAC_CRC, DISABLE_APP_CPU, DISABLE_BT, DIS_CACHE, VOL_LEVEL_HP_INV.
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_DIS_CACHE);
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <strings.h>
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "esp_log.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "secure_boot");
|
||||
|
||||
esp_err_t esp_secure_boot_enable_secure_features(void)
|
||||
{
|
||||
#ifdef CONFIG_SECURE_BOOT_V1_ENABLED
|
||||
ESP_LOGI(TAG, "Read & write protecting new key...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_RD_DIS_BLK2);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_BLK2);
|
||||
|
||||
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_ABS_DONE_0);
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
|
||||
ESP_LOGI(TAG, "Disable JTAG...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DISABLE_JTAG);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_ROM_BASIC
|
||||
ESP_LOGI(TAG, "Disable ROM BASIC interpreter fallback...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_CONSOLE_DEBUG_DISABLE);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling ROM BASIC fallback - SECURITY COMPROMISED");
|
||||
#endif
|
||||
#endif // CONFIG_SECURE_BOOT_V1_ENABLED
|
||||
|
||||
|
||||
|
||||
#ifdef CONFIG_SECURE_BOOT_V2_ENABLED
|
||||
esp_err_t err;
|
||||
err = esp_efuse_write_field_bit(ESP_EFUSE_ABS_DONE_1);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Blowing secure boot efuse...failed.");
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
|
||||
ESP_LOGI(TAG, "Disable JTAG...");
|
||||
err = esp_efuse_write_field_bit(ESP_EFUSE_DISABLE_JTAG);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Disable JTAG...failed.");
|
||||
return err;
|
||||
}
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_ROM_BASIC
|
||||
ESP_LOGI(TAG, "Disable ROM BASIC interpreter fallback...");
|
||||
err = esp_efuse_write_field_bit(ESP_EFUSE_CONSOLE_DEBUG_DISABLE);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Disable ROM BASIC interpreter fallback...failed.");
|
||||
return err;
|
||||
}
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling ROM BASIC fallback - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SECURE_DISABLE_ROM_DL_MODE
|
||||
ESP_LOGI(TAG, "Disable ROM Download mode...");
|
||||
err = esp_efuse_disable_rom_download_mode();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Could not disable ROM Download mode...");
|
||||
return err;
|
||||
}
|
||||
#else
|
||||
ESP_LOGW(TAG, "UART ROM Download mode kept enabled - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS
|
||||
bool rd_dis_now = true;
|
||||
#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
|
||||
/* If flash encryption is not enabled yet then don't read-disable efuses yet, do it later in the boot
|
||||
when Flash Encryption is being enabled */
|
||||
rd_dis_now = esp_efuse_is_flash_encryption_enabled();
|
||||
#endif
|
||||
if (rd_dis_now) {
|
||||
ESP_LOGI(TAG, "Prevent read disabling of additional efuses...");
|
||||
err = esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_EFUSE_RD_DISABLE);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Prevent read disabling of additional efuses...failed.");
|
||||
return err;
|
||||
}
|
||||
}
|
||||
#else
|
||||
ESP_LOGW(TAG, "Allowing read disabling of additional efuses - SECURITY COMPROMISED");
|
||||
#endif
|
||||
#endif // CONFIG_SECURE_BOOT_V2_ENABLED
|
||||
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#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_serial_output.h"
|
||||
#include "esp_rom_sys.h"
|
||||
#include "esp_rom_spiflash.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/assist_debug_reg.h"
|
||||
#include "esp_cpu.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#include "soc/extmem_reg.h"
|
||||
#include "soc/system_reg.h"
|
||||
#include "esp32c2/rom/ets_sys.h"
|
||||
#include "esp32c2/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 "bootloader_console.h"
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "bootloader_soc.h"
|
||||
#include "esp_private/bootloader_flash_internal.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "hal/mmu_hal.h"
|
||||
#include "hal/cache_hal.h"
|
||||
#include "hal/rwdt_ll.h"
|
||||
#include "hal/brownout_ll.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "boot.esp32c2");
|
||||
|
||||
#if SOC_RTC_WDT_SUPPORTED
|
||||
void bootloader_enable_cpu_reset_info(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);
|
||||
}
|
||||
|
||||
void bootloader_dump_wdt_reset_info(int cpu)
|
||||
{
|
||||
(void) cpu;
|
||||
// saved PC was already printed by the ROM bootloader.
|
||||
// nothing to do here.
|
||||
}
|
||||
|
||||
bool bootloader_check_if_wdt_reset(int cpu, soc_reset_reason_t rst_reason)
|
||||
{
|
||||
(void) cpu;
|
||||
if (rst_reason == RESET_REASON_CORE_RTC_WDT || rst_reason == RESET_REASON_CORE_MWDT0 ||
|
||||
rst_reason == RESET_REASON_CPU0_MWDT0 || rst_reason == RESET_REASON_CPU0_RTC_WDT) {
|
||||
ESP_LOGW(TAG, "PRO CPU has been reset by WDT.");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
#endif // SOC_RTC_WDT_SUPPORTED
|
||||
|
||||
static inline void bootloader_ana_reset_config(void)
|
||||
{
|
||||
//Enable super WDT reset.
|
||||
bootloader_ana_super_wdt_reset_config(true);
|
||||
//Enable BOD reset (mode1)
|
||||
brownout_ll_ana_reset_enable(true);
|
||||
}
|
||||
|
||||
esp_err_t bootloader_init(void)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
bootloader_ana_reset_config();
|
||||
#if SOC_RTC_WDT_SUPPORTED
|
||||
bootloader_super_wdt_auto_feed();
|
||||
#endif
|
||||
|
||||
// In RAM_APP, memory will be initialized in `call_start_cpu0`
|
||||
#if !CONFIG_APP_BUILD_TYPE_RAM
|
||||
// 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();
|
||||
#endif // !CONFIG_APP_BUILD_TYPE_RAM
|
||||
|
||||
// init eFuse virtual mode (read eFuses to RAM)
|
||||
#ifdef CONFIG_EFUSE_VIRTUAL
|
||||
ESP_EARLY_LOGW(TAG, "eFuse virtual mode is enabled. If Secure boot or Flash encryption is enabled then it does not provide any security. FOR TESTING ONLY!");
|
||||
#ifndef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
esp_efuse_init_virtual_mode_in_ram();
|
||||
#endif
|
||||
#endif
|
||||
// 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();
|
||||
|
||||
#if !CONFIG_APP_BUILD_TYPE_RAM
|
||||
// init cache and mmu
|
||||
bootloader_init_ext_mem();
|
||||
// update flash ID
|
||||
bootloader_flash_update_id();
|
||||
// read bootloader header
|
||||
if ((ret = bootloader_read_bootloader_header()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
// read chip revision and check if it's compatible to bootloader
|
||||
if ((ret = bootloader_check_bootloader_validity()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
// initialize spi flash
|
||||
if ((ret = bootloader_init_spi_flash()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
#endif // !CONFIG_APP_BUILD_TYPE_RAM
|
||||
|
||||
// check reset reason and dump diagnostic info
|
||||
bootloader_check_reset();
|
||||
#if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED
|
||||
// config WDT
|
||||
bootloader_config_wdt();
|
||||
#endif
|
||||
// enable RNG early entropy source
|
||||
bootloader_enable_random();
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
|
||||
void bootloader_ana_super_wdt_reset_config(bool enable)
|
||||
{
|
||||
REG_CLR_BIT(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_SUPER_WDT_RST);
|
||||
|
||||
if (enable) {
|
||||
REG_CLR_BIT(RTC_CNTL_SWD_CONF_REG, RTC_CNTL_SWD_BYPASS_RST);
|
||||
} else {
|
||||
REG_SET_BIT(RTC_CNTL_SWD_CONF_REG, RTC_CNTL_SWD_BYPASS_RST);
|
||||
}
|
||||
}
|
||||
|
||||
//Not supported but common bootloader calls the function. Do nothing
|
||||
void bootloader_ana_clock_glitch_reset_config(bool enable)
|
||||
{
|
||||
(void)enable;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <strings.h>
|
||||
#include "esp_flash_encrypt.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "esp_log.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "flash_encrypt");
|
||||
|
||||
esp_err_t esp_flash_encryption_enable_secure_features(void)
|
||||
{
|
||||
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC
|
||||
ESP_LOGI(TAG, "Disable UART bootloader encryption...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling UART bootloader encryption");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE
|
||||
ESP_LOGI(TAG, "Disable UART bootloader cache...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_ICACHE);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling UART bootloader cache - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
|
||||
ESP_LOGI(TAG, "Disable JTAG...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_PAD_JTAG);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DIRECT_BOOT);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <strings.h>
|
||||
#include "esp_flash_encrypt.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "esp_log.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "secure_boot");
|
||||
|
||||
esp_err_t esp_secure_boot_enable_secure_features(void)
|
||||
{
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DIRECT_BOOT);
|
||||
|
||||
#ifdef CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE
|
||||
ESP_LOGI(TAG, "Enabling Security download mode...");
|
||||
esp_err_t err = esp_efuse_enable_rom_secure_download_mode();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Could not enable Security download mode...");
|
||||
return err;
|
||||
}
|
||||
#elif CONFIG_SECURE_DISABLE_ROM_DL_MODE
|
||||
ESP_LOGI(TAG, "Disable ROM Download mode...");
|
||||
esp_err_t err = esp_efuse_disable_rom_download_mode();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Could not disable ROM Download mode...");
|
||||
return err;
|
||||
}
|
||||
#else
|
||||
ESP_LOGW(TAG, "UART ROM Download mode kept enabled - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
|
||||
ESP_LOGI(TAG, "Disable hardware & software JTAG...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_PAD_JTAG);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_EN);
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS
|
||||
// Secure boot and Flash encryption share one eFuse key block so they can not be set separately.
|
||||
// CONFIG_SECURE_BOOT_FLASH_ENC_KEYS_BURN_TOGETHER option is used to burn SB and FE at the same time.
|
||||
// SB key is readable, the corresponding bit in RD_DIS is unset.
|
||||
// We set write-protection for RD_DIS to ensure that the SB key is always readable.
|
||||
// FE key is read-protected, the corresponding bit in RD_DIS is set.
|
||||
ESP_LOGI(TAG, "Prevent read disabling of additional efuses...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Allowing read disabling of additional efuses - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#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_serial_output.h"
|
||||
#include "esp_rom_sys.h"
|
||||
#include "esp_rom_spiflash.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/assist_debug_reg.h"
|
||||
#include "esp_cpu.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#include "soc/extmem_reg.h"
|
||||
#include "soc/system_reg.h"
|
||||
#include "soc/chip_revision.h"
|
||||
#include "esp32c3/rom/ets_sys.h"
|
||||
#include "bootloader_common.h"
|
||||
#include "bootloader_init.h"
|
||||
#include "bootloader_clock.h"
|
||||
#include "bootloader_flash_config.h"
|
||||
#include "bootloader_mem.h"
|
||||
#include "esp_private/regi2c_ctrl.h"
|
||||
#include "soc/regi2c_lp_bias.h"
|
||||
#include "soc/regi2c_bias.h"
|
||||
#include "bootloader_console.h"
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "esp_private/bootloader_flash_internal.h"
|
||||
#include "bootloader_soc.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "hal/mmu_hal.h"
|
||||
#include "hal/cache_hal.h"
|
||||
#include "hal/efuse_hal.h"
|
||||
#include "hal/rwdt_ll.h"
|
||||
#include "hal/brownout_ll.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "boot.esp32c3");
|
||||
|
||||
#if SOC_RTC_WDT_SUPPORTED
|
||||
void bootloader_enable_cpu_reset_info(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);
|
||||
}
|
||||
|
||||
void bootloader_dump_wdt_reset_info(int cpu)
|
||||
{
|
||||
(void) cpu;
|
||||
// saved PC was already printed by the ROM bootloader.
|
||||
// nothing to do here.
|
||||
}
|
||||
|
||||
bool bootloader_check_if_wdt_reset(int cpu, soc_reset_reason_t rst_reason)
|
||||
{
|
||||
(void) cpu;
|
||||
if (rst_reason == RESET_REASON_CORE_RTC_WDT || rst_reason == RESET_REASON_CORE_MWDT0 || rst_reason == RESET_REASON_CORE_MWDT1 ||
|
||||
rst_reason == RESET_REASON_CPU0_MWDT0 || rst_reason == RESET_REASON_CPU0_MWDT1 || rst_reason == RESET_REASON_CPU0_RTC_WDT) {
|
||||
ESP_LOGW(TAG, "PRO CPU has been reset by WDT.");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
#endif // SOC_RTC_WDT_SUPPORTED
|
||||
|
||||
static inline void bootloader_hardware_init(void)
|
||||
{
|
||||
// This check is always included in the bootloader so it can
|
||||
// print the minimum revision error message later in the boot
|
||||
if (!ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 3)) {
|
||||
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_ana_reset_config(void)
|
||||
{
|
||||
//Enable super WDT reset.
|
||||
bootloader_ana_super_wdt_reset_config(true);
|
||||
|
||||
/*
|
||||
For origin chip & ECO1: brownout & clock glitch reset not available
|
||||
For ECO2: fix brownout reset bug
|
||||
For ECO3: fix clock glitch reset bug
|
||||
*/
|
||||
switch (efuse_hal_chip_revision()) {
|
||||
case 0:
|
||||
case 1:
|
||||
//Disable BOD and GLITCH reset
|
||||
brownout_ll_ana_reset_enable(false);
|
||||
bootloader_ana_clock_glitch_reset_config(false);
|
||||
break;
|
||||
case 2:
|
||||
//Enable BOD reset. Disable GLITCH reset
|
||||
brownout_ll_ana_reset_enable(true);
|
||||
bootloader_ana_clock_glitch_reset_config(false);
|
||||
break;
|
||||
case 3:
|
||||
default:
|
||||
//Enable BOD, and GLITCH reset
|
||||
brownout_ll_ana_reset_enable(true);
|
||||
bootloader_ana_clock_glitch_reset_config(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t bootloader_init(void)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
bootloader_hardware_init();
|
||||
bootloader_ana_reset_config();
|
||||
#if SOC_RTC_WDT_SUPPORTED
|
||||
bootloader_super_wdt_auto_feed();
|
||||
#endif
|
||||
|
||||
// In RAM_APP, memory will be initialized in `call_start_cpu0`
|
||||
#if !CONFIG_APP_BUILD_TYPE_RAM
|
||||
// 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();
|
||||
#endif // !CONFIG_APP_BUILD_TYPE_RAM
|
||||
|
||||
// init eFuse virtual mode (read eFuses to RAM)
|
||||
#ifdef CONFIG_EFUSE_VIRTUAL
|
||||
ESP_EARLY_LOGW(TAG, "eFuse virtual mode is enabled. If Secure boot or Flash encryption is enabled then it does not provide any security. FOR TESTING ONLY!");
|
||||
#ifndef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
esp_efuse_init_virtual_mode_in_ram();
|
||||
#endif
|
||||
#endif
|
||||
// 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();
|
||||
|
||||
#if !CONFIG_APP_BUILD_TYPE_RAM
|
||||
// init cache and mmu
|
||||
bootloader_init_ext_mem();
|
||||
// update flash ID
|
||||
bootloader_flash_update_id();
|
||||
// Check and run XMC startup flow
|
||||
if ((ret = bootloader_flash_xmc_startup()) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "failed when running XMC startup flow, reboot!");
|
||||
return ret;
|
||||
}
|
||||
// read bootloader header
|
||||
if ((ret = bootloader_read_bootloader_header()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
// read chip revision and check if it's compatible to bootloader
|
||||
if ((ret = bootloader_check_bootloader_validity()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
// initialize spi flash
|
||||
if ((ret = bootloader_init_spi_flash()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
#endif //#if !CONFIG_APP_BUILD_TYPE_RAM
|
||||
|
||||
// check reset reason and dump diagnostic info
|
||||
bootloader_check_reset();
|
||||
#if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED
|
||||
// config WDT
|
||||
bootloader_config_wdt();
|
||||
#endif
|
||||
// enable RNG early entropy source
|
||||
bootloader_enable_random();
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include "soc/soc.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
|
||||
void bootloader_ana_super_wdt_reset_config(bool enable)
|
||||
{
|
||||
REG_CLR_BIT(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_SUPER_WDT_RST);
|
||||
|
||||
if (enable) {
|
||||
REG_CLR_BIT(RTC_CNTL_SWD_CONF_REG, RTC_CNTL_SWD_BYPASS_RST);
|
||||
} else {
|
||||
REG_SET_BIT(RTC_CNTL_SWD_CONF_REG, RTC_CNTL_SWD_BYPASS_RST);
|
||||
}
|
||||
}
|
||||
|
||||
void bootloader_ana_clock_glitch_reset_config(bool enable)
|
||||
{
|
||||
REG_CLR_BIT(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_GLITCH_RST);
|
||||
|
||||
if (enable) {
|
||||
REG_SET_BIT(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_GLITCH_RST_EN);
|
||||
} else {
|
||||
REG_CLR_BIT(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_GLITCH_RST_EN);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <strings.h>
|
||||
#include "esp_flash_encrypt.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "esp_log.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "flash_encrypt");
|
||||
|
||||
esp_err_t esp_flash_encryption_enable_secure_features(void)
|
||||
{
|
||||
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC
|
||||
ESP_LOGI(TAG, "Disable UART bootloader encryption...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling UART bootloader encryption");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE
|
||||
ESP_LOGI(TAG, "Disable UART bootloader cache...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_ICACHE);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling UART bootloader cache - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
|
||||
ESP_LOGI(TAG, "Disable JTAG...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_PAD_JTAG);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_JTAG);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DIRECT_BOOT);
|
||||
|
||||
#if defined(CONFIG_SECURE_BOOT_V2_ENABLED) && !defined(CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS)
|
||||
// This bit is set when enabling Secure Boot V2, but we can't enable it until this later point in the first boot
|
||||
// otherwise the Flash Encryption key cannot be read protected
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_FLASH_SKIP_WRITE_PROTECTION_CACHE
|
||||
// Set write-protection for DIS_ICACHE to prevent bricking chip in case it will be set accidentally.
|
||||
// esp32c3 has DIS_ICACHE. Write-protection bit = 2.
|
||||
// List of eFuses with the same write protection bit:
|
||||
// DIS_ICACHE, DIS_USB_JTAG, DIS_DOWNLOAD_ICACHE, DIS_USB_SERIAL_JTAG,
|
||||
// DIS_FORCE_DOWNLOAD, DIS_TWAI, JTAG_SEL_ENABLE, DIS_PAD_JTAG, DIS_DOWNLOAD_MANUAL_ENCRYPT.
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_DIS_ICACHE);
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <strings.h>
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "esp_log.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "secure_boot");
|
||||
|
||||
esp_err_t esp_secure_boot_enable_secure_features(void)
|
||||
{
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DIRECT_BOOT);
|
||||
|
||||
#ifdef CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE
|
||||
ESP_LOGI(TAG, "Enabling Security download mode...");
|
||||
esp_err_t err = esp_efuse_enable_rom_secure_download_mode();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Could not enable Security download mode...");
|
||||
return err;
|
||||
}
|
||||
#elif CONFIG_SECURE_DISABLE_ROM_DL_MODE
|
||||
ESP_LOGI(TAG, "Disable ROM Download mode...");
|
||||
esp_err_t err = esp_efuse_disable_rom_download_mode();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Could not disable ROM Download mode...");
|
||||
return err;
|
||||
}
|
||||
#else
|
||||
ESP_LOGW(TAG, "UART ROM Download mode kept enabled - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
|
||||
ESP_LOGI(TAG, "Disable hardware & software JTAG...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_PAD_JTAG);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_JTAG);
|
||||
esp_efuse_write_field_cnt(ESP_EFUSE_SOFT_DIS_JTAG, ESP_EFUSE_SOFT_DIS_JTAG[0]->bit_count);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SECURE_BOOT_ENABLE_AGGRESSIVE_KEY_REVOKE
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_AGGRESSIVE_REVOKE);
|
||||
#endif
|
||||
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_EN);
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS
|
||||
bool rd_dis_now = true;
|
||||
#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
|
||||
/* If flash encryption is not enabled yet then don't read-disable efuses yet, do it later in the boot
|
||||
when Flash Encryption is being enabled */
|
||||
rd_dis_now = esp_efuse_is_flash_encryption_enabled();
|
||||
#endif
|
||||
if (rd_dis_now) {
|
||||
ESP_LOGI(TAG, "Prevent read disabling of additional efuses...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
|
||||
}
|
||||
#else
|
||||
ESP_LOGW(TAG, "Allowing read disabling of additional efuses - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#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_serial_output.h"
|
||||
#include "esp_rom_sys.h"
|
||||
#include "esp_rom_spiflash.h"
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/assist_debug_reg.h"
|
||||
#include "esp_cpu.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/cache_reg.h"
|
||||
#include "soc/pcr_reg.h"
|
||||
#include "esp32c5/rom/ets_sys.h"
|
||||
#include "esp32c5/rom/spi_flash.h"
|
||||
#include "bootloader_common.h"
|
||||
#include "bootloader_init.h"
|
||||
#include "bootloader_clock.h"
|
||||
#include "bootloader_flash_config.h"
|
||||
#include "bootloader_mem.h"
|
||||
#include "esp_private/regi2c_ctrl.h"
|
||||
#include "bootloader_console.h"
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "bootloader_soc.h"
|
||||
#include "esp_private/bootloader_flash_internal.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "hal/mmu_hal.h"
|
||||
#include "hal/cache_hal.h"
|
||||
#include "soc/lp_wdt_reg.h"
|
||||
#include "hal/efuse_hal.h"
|
||||
#include "hal/lpwdt_ll.h"
|
||||
#include "hal/regi2c_ctrl_ll.h"
|
||||
#include "hal/brownout_ll.h"
|
||||
#include "hal/axi_icm_ll.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "boot.esp32c5");
|
||||
|
||||
#if SOC_RTC_WDT_SUPPORTED
|
||||
void bootloader_enable_cpu_reset_info(void)
|
||||
{
|
||||
REG_SET_BIT(PCR_ASSIST_CONF_REG, PCR_ASSIST_CLK_EN);
|
||||
REG_CLR_BIT(PCR_ASSIST_CONF_REG, PCR_ASSIST_RST_EN);
|
||||
REG_WRITE(ASSIST_DEBUG_CORE_0_RCD_EN_REG, ASSIST_DEBUG_CORE_0_RCD_PDEBUGEN | ASSIST_DEBUG_CORE_0_RCD_RECORDEN);
|
||||
}
|
||||
|
||||
void bootloader_dump_wdt_reset_info(int cpu)
|
||||
{
|
||||
(void) cpu;
|
||||
// saved PC was already printed by the ROM bootloader.
|
||||
// nothing to do here.
|
||||
}
|
||||
|
||||
bool bootloader_check_if_wdt_reset(int cpu, soc_reset_reason_t rst_reason)
|
||||
{
|
||||
(void) cpu;
|
||||
if (rst_reason == RESET_REASON_CORE_RTC_WDT || rst_reason == RESET_REASON_CORE_MWDT0 || rst_reason == RESET_REASON_CORE_MWDT1 ||
|
||||
rst_reason == RESET_REASON_CPU0_MWDT0 || rst_reason == RESET_REASON_CPU0_MWDT1 || rst_reason == RESET_REASON_CPU0_RTC_WDT) {
|
||||
ESP_LOGW(TAG, "PRO CPU has been reset by WDT.");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void bootloader_super_wdt_auto_feed(void)
|
||||
{
|
||||
REG_WRITE(LP_WDT_SWD_WPROTECT_REG, LP_WDT_SWD_WKEY_VALUE);
|
||||
REG_SET_BIT(LP_WDT_SWD_CONFIG_REG, LP_WDT_SWD_AUTO_FEED_EN);
|
||||
REG_WRITE(LP_WDT_SWD_WPROTECT_REG, 0);
|
||||
}
|
||||
#endif // SOC_RTC_WDT_SUPPORTED
|
||||
|
||||
static inline void bootloader_hardware_init(void)
|
||||
{
|
||||
// Clear bit reset_event_bypass to ensure that the system bus is also reset during a core reset (WDT),
|
||||
// preventing bus freezing caused by an incorrect MSPI core reset in ROM.
|
||||
axi_icm_ll_reset_with_core_reset(true);
|
||||
_regi2c_ctrl_ll_master_enable_clock(true); // keep ana i2c mst clock always enabled in bootloader
|
||||
regi2c_ctrl_ll_master_configure_clock();
|
||||
}
|
||||
|
||||
static inline void bootloader_ana_reset_config(void)
|
||||
{
|
||||
//Enable BOD reset (mode1)
|
||||
brownout_ll_ana_reset_enable(true);
|
||||
bootloader_power_glitch_reset_config(true);
|
||||
}
|
||||
|
||||
esp_err_t bootloader_init(void)
|
||||
{
|
||||
#if CONFIG_SECURE_BOOT
|
||||
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
if (efuse_hal_chip_revision() == 0) {
|
||||
ESP_LOGE(TAG, "Chip version 0.0 is not supported with RSA secure boot scheme. Please select the ECDSA scheme.");
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
#endif /* CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME */
|
||||
#endif /* CONFIG_SECURE_BOOT */
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
bootloader_hardware_init();
|
||||
bootloader_ana_reset_config();
|
||||
#if SOC_RTC_WDT_SUPPORTED
|
||||
bootloader_super_wdt_auto_feed();
|
||||
#endif
|
||||
|
||||
// In RAM_APP, memory will be initialized in `call_start_cpu0`
|
||||
#if !CONFIG_APP_BUILD_TYPE_RAM
|
||||
// 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();
|
||||
#endif // !CONFIG_APP_BUILD_TYPE_RAM
|
||||
|
||||
// init eFuse virtual mode (read eFuses to RAM)
|
||||
#ifdef CONFIG_EFUSE_VIRTUAL
|
||||
ESP_EARLY_LOGW(TAG, "eFuse virtual mode is enabled. If Secure boot or Flash encryption is enabled then it does not provide any security. FOR TESTING ONLY!");
|
||||
#ifndef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
esp_efuse_init_virtual_mode_in_ram();
|
||||
#endif
|
||||
#endif
|
||||
// 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();
|
||||
|
||||
#if !CONFIG_APP_BUILD_TYPE_RAM
|
||||
// init cache and mmu
|
||||
bootloader_init_ext_mem();
|
||||
// update flash ID
|
||||
bootloader_flash_update_id();
|
||||
// Check and run XMC startup flow
|
||||
if ((ret = bootloader_flash_xmc_startup()) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "failed when running XMC startup flow, reboot!");
|
||||
return ret;
|
||||
}
|
||||
// read bootloader header
|
||||
if ((ret = bootloader_read_bootloader_header()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
// read chip revision and check if it's compatible to bootloader
|
||||
if ((ret = bootloader_check_bootloader_validity()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
// initialize spi flash
|
||||
if ((ret = bootloader_init_spi_flash()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
#endif // !CONFIG_APP_BUILD_TYPE_RAM
|
||||
|
||||
// check reset reason and dump diagnostic info
|
||||
bootloader_check_reset();
|
||||
#if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED
|
||||
// config WDT
|
||||
bootloader_config_wdt();
|
||||
#endif
|
||||
// enable RNG early entropy source
|
||||
bootloader_enable_random();
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include "soc/soc.h"
|
||||
#include "soc/lp_analog_peri_reg.h"
|
||||
#include "soc/pmu_reg.h"
|
||||
#include "hal/regi2c_ctrl.h"
|
||||
#include "soc/regi2c_saradc.h"
|
||||
|
||||
//Not supported but common bootloader calls the function. Do nothing
|
||||
void bootloader_ana_clock_glitch_reset_config(bool enable)
|
||||
{
|
||||
(void)enable;
|
||||
}
|
||||
|
||||
void bootloader_power_glitch_reset_config(bool enable)
|
||||
{
|
||||
//only detect VDDPST POWER GLITCH
|
||||
SET_PERI_REG_MASK(PMU_RF_PWC_REG, PMU_PERIF_I2C_RSTB);
|
||||
SET_PERI_REG_MASK(PMU_RF_PWC_REG, PMU_XPD_PERIF_I2C);
|
||||
REGI2C_WRITE_MASK(I2C_SAR_ADC, POWER_GLITCH_XPD_VDET_PERIF, 0);
|
||||
REGI2C_WRITE_MASK(I2C_SAR_ADC, POWER_GLITCH_XPD_VDET_XTAL, 0);
|
||||
REGI2C_WRITE_MASK(I2C_SAR_ADC, POWER_GLITCH_XPD_VDET_PLL, 0);
|
||||
|
||||
REG_SET_FIELD(LP_ANA_FIB_ENABLE_REG, LP_ANA_ANA_FIB_PWR_GLITCH_ENA, 0);//default val for chip from ECO1
|
||||
if (enable) {
|
||||
REG_SET_FIELD(LP_ANA_POWER_GLITCH_CNTL_REG, LP_ANA_PWR_GLITCH_RESET_ENA, 0xf);//default val for chip from ECO1
|
||||
} else {
|
||||
REG_SET_FIELD(LP_ANA_POWER_GLITCH_CNTL_REG, LP_ANA_PWR_GLITCH_RESET_ENA, 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <strings.h>
|
||||
#include "esp_flash_encrypt.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_crypto_periph_clk.h"
|
||||
#include "esp_key_mgr.h"
|
||||
#include "hal/key_mgr_hal.h"
|
||||
#include "hal/mspi_ll.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "hal/key_mgr_ll.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "flash_encrypt");
|
||||
|
||||
esp_err_t esp_flash_encryption_enable_secure_features(void)
|
||||
{
|
||||
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC
|
||||
ESP_LOGI(TAG, "Disable UART bootloader encryption...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling UART bootloader encryption");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE
|
||||
ESP_LOGI(TAG, "Disable UART bootloader cache...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SPI_DOWNLOAD_MSPI_DIS);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling UART bootloader cache - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
|
||||
ESP_LOGI(TAG, "Disable JTAG...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_PAD_JTAG);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_JTAG);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DIRECT_BOOT);
|
||||
|
||||
#if CONFIG_SECURE_FLASH_PSEUDO_ROUND_FUNC
|
||||
ESP_LOGI(TAG, "Enable XTS-AES pseudo rounds function...");
|
||||
uint8_t xts_pseudo_level = CONFIG_SECURE_FLASH_PSEUDO_ROUND_FUNC_STRENGTH;
|
||||
esp_efuse_write_field_blob(ESP_EFUSE_XTS_DPA_PSEUDO_LEVEL, &xts_pseudo_level, ESP_EFUSE_XTS_DPA_PSEUDO_LEVEL[0]->bit_count);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SECURE_BOOT_V2_ENABLED) && !defined(CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS)
|
||||
// This bit is set when enabling Secure Boot V2, but we can't enable it until this later point in the first boot
|
||||
// otherwise the Flash Encryption key cannot be read protected
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_FLASH_SKIP_WRITE_PROTECTION_CACHE
|
||||
// Set write-protection for DIS_ICACHE to prevent bricking chip in case it will be set accidentally.
|
||||
// esp32c5 has DIS_ICACHE. Write-protection bit = 2.
|
||||
// List of eFuses with the same write protection bit:
|
||||
// SWAP_UART_SDIO_EN, DIS_ICACHE, DIS_USB_JTAG, DIS_DOWNLOAD_ICACHE,
|
||||
// DIS_USB_SERIAL_JTAG, DIS_FORCE_DOWNLOAD, DIS_TWAI, JTAG_SEL_ENABLE,
|
||||
// DIS_PAD_JTAG, DIS_DOWNLOAD_MANUAL_ENCRYPT.
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_DIS_ICACHE);
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_flash_encryption_use_efuse_key(void)
|
||||
{
|
||||
esp_crypto_key_mgr_enable_periph_clk(true);
|
||||
|
||||
// Force Key Manager to use eFuse key for XTS-AES operation
|
||||
key_mgr_hal_set_key_usage(ESP_KEY_MGR_FLASH_XTS_AES_KEY, ESP_KEY_MGR_USE_EFUSE_KEY);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <strings.h>
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "esp_log.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "secure_boot");
|
||||
|
||||
esp_err_t esp_secure_boot_enable_secure_features(void)
|
||||
{
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DIRECT_BOOT);
|
||||
|
||||
#ifdef CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE
|
||||
ESP_LOGI(TAG, "Enabling Security download mode...");
|
||||
esp_err_t err = esp_efuse_enable_rom_secure_download_mode();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Could not enable Security download mode...");
|
||||
return err;
|
||||
}
|
||||
#elif CONFIG_SECURE_DISABLE_ROM_DL_MODE
|
||||
ESP_LOGI(TAG, "Disable ROM Download mode...");
|
||||
esp_err_t err = esp_efuse_disable_rom_download_mode();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Could not disable ROM Download mode...");
|
||||
return err;
|
||||
}
|
||||
#else
|
||||
ESP_LOGW(TAG, "UART ROM Download mode kept enabled - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
|
||||
ESP_LOGI(TAG, "Disable hardware & software JTAG...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_PAD_JTAG);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_JTAG);
|
||||
esp_efuse_write_field_cnt(ESP_EFUSE_SOFT_DIS_JTAG, ESP_EFUSE_SOFT_DIS_JTAG[0]->bit_count);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SECURE_BOOT_ENABLE_AGGRESSIVE_KEY_REVOKE
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_AGGRESSIVE_REVOKE);
|
||||
#endif
|
||||
|
||||
#if CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_SHA384_EN);
|
||||
#endif
|
||||
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_EN);
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS
|
||||
bool rd_dis_now = true;
|
||||
#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
|
||||
/* If flash encryption is not enabled yet then don't read-disable efuses yet, do it later in the boot
|
||||
when Flash Encryption is being enabled */
|
||||
rd_dis_now = esp_efuse_is_flash_encryption_enabled();
|
||||
#endif
|
||||
if (rd_dis_now) {
|
||||
ESP_LOGI(TAG, "Prevent read disabling of additional efuses...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
|
||||
}
|
||||
#else
|
||||
ESP_LOGW(TAG, "Allowing read disabling of additional efuses - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
#include "rom/ecdsa.h"
|
||||
|
||||
#define ROM_FUNC_TYPECAST int(*)(const uint8_t*, const uint8_t*, int, const uint8_t*, uint8_t*)
|
||||
|
||||
extern uint32_t _rom_eco_version;
|
||||
int (*_rom_ets_ecdsa_verify)(const uint8_t*, const uint8_t*, int, const uint8_t*, uint8_t*);
|
||||
|
||||
/* On ESP32-C6 ECO 0, the ROM interface hasn't exposed ets_ecdsa_verify symbol, so for that we have defined
|
||||
* the function here and then jump to the absolute address in ROM.
|
||||
*
|
||||
* There is a possibility of updating the ROM in the future chip revisions without any major upgrades,
|
||||
* in that case, the same binary should work as is on the new chip revision. For that, we check the _rom_eco_version
|
||||
* and if its a newer one, we jump to the new ROM interface. These addresses won't change in the future
|
||||
*
|
||||
* ets_ecdsa_verify symbol will be present in the upcoming ROM ECO versions so even though we have defined it here,
|
||||
* linker will pick the symbol address from rom.ld file
|
||||
*/
|
||||
int ets_ecdsa_verify(const uint8_t *key, const uint8_t *sig, ECDSA_CURVE curve_id, const uint8_t *image_digest, uint8_t *verified_digest)
|
||||
{
|
||||
if (_rom_eco_version == 0) {
|
||||
_rom_ets_ecdsa_verify = (ROM_FUNC_TYPECAST)0x4001a824;
|
||||
return _rom_ets_ecdsa_verify(key, sig, curve_id, image_digest, verified_digest);
|
||||
} else {
|
||||
_rom_ets_ecdsa_verify = (ROM_FUNC_TYPECAST)0x40001490;
|
||||
return _rom_ets_ecdsa_verify(key, sig, curve_id, image_digest, verified_digest);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#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_serial_output.h"
|
||||
#include "esp_rom_sys.h"
|
||||
#include "esp_rom_spiflash.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/assist_debug_reg.h"
|
||||
#include "esp_cpu.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#include "soc/extmem_reg.h"
|
||||
#include "soc/pcr_reg.h"
|
||||
#include "esp32c6/rom/ets_sys.h"
|
||||
#include "esp32c6/rom/spi_flash.h"
|
||||
#include "bootloader_common.h"
|
||||
#include "bootloader_init.h"
|
||||
#include "bootloader_clock.h"
|
||||
#include "bootloader_flash_config.h"
|
||||
#include "bootloader_mem.h"
|
||||
#include "esp_private/regi2c_ctrl.h"
|
||||
#include "soc/regi2c_lp_bias.h"
|
||||
#include "soc/regi2c_bias.h"
|
||||
#include "bootloader_console.h"
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "bootloader_soc.h"
|
||||
#include "esp_private/bootloader_flash_internal.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "hal/mmu_hal.h"
|
||||
#include "hal/cache_hal.h"
|
||||
#include "hal/clk_tree_ll.h"
|
||||
#include "soc/lp_wdt_reg.h"
|
||||
#include "hal/efuse_hal.h"
|
||||
#include "hal/lpwdt_ll.h"
|
||||
#include "hal/regi2c_ctrl_ll.h"
|
||||
#include "hal/brownout_ll.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "boot.esp32c6");
|
||||
|
||||
#if SOC_RTC_WDT_SUPPORTED
|
||||
void bootloader_enable_cpu_reset_info(void)
|
||||
{
|
||||
REG_SET_BIT(PCR_ASSIST_CONF_REG, PCR_ASSIST_CLK_EN);
|
||||
REG_CLR_BIT(PCR_ASSIST_CONF_REG, PCR_ASSIST_RST_EN);
|
||||
REG_WRITE(ASSIST_DEBUG_CORE_0_RCD_EN_REG, ASSIST_DEBUG_CORE_0_RCD_PDEBUGEN | ASSIST_DEBUG_CORE_0_RCD_RECORDEN);
|
||||
}
|
||||
|
||||
void bootloader_dump_wdt_reset_info(int cpu)
|
||||
{
|
||||
(void) cpu;
|
||||
// saved PC was already printed by the ROM bootloader.
|
||||
// nothing to do here.
|
||||
}
|
||||
|
||||
bool bootloader_check_if_wdt_reset(int cpu, soc_reset_reason_t rst_reason)
|
||||
{
|
||||
(void) cpu;
|
||||
if (rst_reason == RESET_REASON_CORE_RTC_WDT || rst_reason == RESET_REASON_CORE_MWDT0 || rst_reason == RESET_REASON_CORE_MWDT1 ||
|
||||
rst_reason == RESET_REASON_CPU0_MWDT0 || rst_reason == RESET_REASON_CPU0_MWDT1 || rst_reason == RESET_REASON_CPU0_RTC_WDT) {
|
||||
ESP_LOGW(TAG, "PRO CPU has been reset by WDT.");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void bootloader_super_wdt_auto_feed(void)
|
||||
{
|
||||
REG_WRITE(LP_WDT_SWD_WPROTECT_REG, LP_WDT_SWD_WKEY_VALUE);
|
||||
REG_SET_BIT(LP_WDT_SWD_CONFIG_REG, LP_WDT_SWD_AUTO_FEED_EN);
|
||||
REG_WRITE(LP_WDT_SWD_WPROTECT_REG, 0);
|
||||
}
|
||||
#endif // SOC_RTC_WDT_SUPPORTED
|
||||
|
||||
static inline void bootloader_hardware_init(void)
|
||||
{
|
||||
// In 80MHz flash mode, ROM sets the mspi module clk divider to 2, fix it here
|
||||
#if CONFIG_ESPTOOLPY_FLASHFREQ_80M && !CONFIG_APP_BUILD_TYPE_RAM
|
||||
clk_ll_mspi_fast_set_hs_divider(6);
|
||||
esp_rom_spiflash_config_clk(1, 0);
|
||||
esp_rom_spiflash_config_clk(1, 1);
|
||||
esp_rom_spiflash_fix_dummylen(0, 1);
|
||||
esp_rom_spiflash_fix_dummylen(1, 1);
|
||||
#endif
|
||||
|
||||
_regi2c_ctrl_ll_master_enable_clock(true); // keep ana i2c mst clock always enabled in bootloader
|
||||
regi2c_ctrl_ll_master_configure_clock();
|
||||
}
|
||||
|
||||
static inline void bootloader_ana_reset_config(void)
|
||||
{
|
||||
//Enable super WDT reset.
|
||||
bootloader_ana_super_wdt_reset_config(true);
|
||||
//Enable BOD mode1 hardware reset
|
||||
brownout_ll_ana_reset_enable(true);
|
||||
}
|
||||
|
||||
esp_err_t bootloader_init(void)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
bootloader_hardware_init();
|
||||
bootloader_ana_reset_config();
|
||||
#if SOC_RTC_WDT_SUPPORTED
|
||||
bootloader_super_wdt_auto_feed();
|
||||
#endif
|
||||
|
||||
// In RAM_APP, memory will be initialized in `call_start_cpu0`
|
||||
#if !CONFIG_APP_BUILD_TYPE_RAM
|
||||
// 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();
|
||||
#endif // !CONFIG_APP_BUILD_TYPE_RAM
|
||||
|
||||
// init eFuse virtual mode (read eFuses to RAM)
|
||||
#ifdef CONFIG_EFUSE_VIRTUAL
|
||||
ESP_EARLY_LOGW(TAG, "eFuse virtual mode is enabled. If Secure boot or Flash encryption is enabled then it does not provide any security. FOR TESTING ONLY!");
|
||||
#ifndef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
esp_efuse_init_virtual_mode_in_ram();
|
||||
#endif
|
||||
#endif
|
||||
// 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();
|
||||
|
||||
#if !CONFIG_APP_BUILD_TYPE_RAM
|
||||
// init cache and mmu
|
||||
bootloader_init_ext_mem();
|
||||
// update flash ID
|
||||
bootloader_flash_update_id();
|
||||
// Check and run XMC startup flow
|
||||
if ((ret = bootloader_flash_xmc_startup()) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "failed when running XMC startup flow, reboot!");
|
||||
return ret;
|
||||
}
|
||||
// read bootloader header
|
||||
if ((ret = bootloader_read_bootloader_header()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
// read chip revision and check if it's compatible to bootloader
|
||||
if ((ret = bootloader_check_bootloader_validity()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
// initialize spi flash
|
||||
if ((ret = bootloader_init_spi_flash()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
#endif // !CONFIG_APP_BUILD_TYPE_RAM
|
||||
|
||||
// check reset reason and dump diagnostic info
|
||||
bootloader_check_reset();
|
||||
#if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED
|
||||
// config WDT
|
||||
bootloader_config_wdt();
|
||||
#endif
|
||||
// enable RNG early entropy source
|
||||
bootloader_enable_random();
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include "soc/soc.h"
|
||||
#include "soc/lp_analog_peri_reg.h"
|
||||
|
||||
void bootloader_ana_super_wdt_reset_config(bool enable)
|
||||
{
|
||||
//C6 doesn't support bypass super WDT reset
|
||||
assert(enable);
|
||||
REG_CLR_BIT(LP_ANALOG_PERI_LP_ANA_FIB_ENABLE_REG, LP_ANALOG_PERI_LP_ANA_FIB_SUPER_WDT_RST);
|
||||
}
|
||||
|
||||
//Not supported but common bootloader calls the function. Do nothing
|
||||
void bootloader_ana_clock_glitch_reset_config(bool enable)
|
||||
{
|
||||
(void)enable;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <strings.h>
|
||||
#include "esp_flash_encrypt.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "esp_log.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "flash_encrypt");
|
||||
|
||||
esp_err_t esp_flash_encryption_enable_secure_features(void)
|
||||
{
|
||||
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC
|
||||
ESP_LOGI(TAG, "Disable UART bootloader encryption...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling UART bootloader encryption");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE
|
||||
ESP_LOGI(TAG, "Disable UART bootloader cache...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_ICACHE);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling UART bootloader cache - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
|
||||
ESP_LOGI(TAG, "Disable JTAG...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_PAD_JTAG);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_JTAG);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DIRECT_BOOT);
|
||||
|
||||
#if defined(CONFIG_SECURE_BOOT_V2_ENABLED) && !defined(CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS)
|
||||
// This bit is set when enabling Secure Boot V2, but we can't enable it until this later point in the first boot
|
||||
// otherwise the Flash Encryption key cannot be read protected
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_FLASH_SKIP_WRITE_PROTECTION_CACHE
|
||||
// Set write-protection for DIS_ICACHE to prevent bricking chip in case it will be set accidentally.
|
||||
// esp32c6 has DIS_ICACHE. Write-protection bit = 2.
|
||||
// List of eFuses with the same write protection bit:
|
||||
// SWAP_UART_SDIO_EN, DIS_ICACHE, DIS_USB_JTAG, DIS_DOWNLOAD_ICACHE,
|
||||
// DIS_USB_SERIAL_JTAG, DIS_FORCE_DOWNLOAD, DIS_TWAI, JTAG_SEL_ENABLE,
|
||||
// DIS_PAD_JTAG, DIS_DOWNLOAD_MANUAL_ENCRYPT.
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_DIS_ICACHE);
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <strings.h>
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "esp_log.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "secure_boot");
|
||||
|
||||
esp_err_t esp_secure_boot_enable_secure_features(void)
|
||||
{
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DIRECT_BOOT);
|
||||
|
||||
#ifdef CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE
|
||||
ESP_LOGI(TAG, "Enabling Security download mode...");
|
||||
esp_err_t err = esp_efuse_enable_rom_secure_download_mode();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Could not enable Security download mode...");
|
||||
return err;
|
||||
}
|
||||
#elif CONFIG_SECURE_DISABLE_ROM_DL_MODE
|
||||
ESP_LOGI(TAG, "Disable ROM Download mode...");
|
||||
esp_err_t err = esp_efuse_disable_rom_download_mode();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Could not disable ROM Download mode...");
|
||||
return err;
|
||||
}
|
||||
#else
|
||||
ESP_LOGW(TAG, "UART ROM Download mode kept enabled - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
|
||||
ESP_LOGI(TAG, "Disable hardware & software JTAG...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_PAD_JTAG);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_JTAG);
|
||||
esp_efuse_write_field_cnt(ESP_EFUSE_SOFT_DIS_JTAG, ESP_EFUSE_SOFT_DIS_JTAG[0]->bit_count);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SECURE_BOOT_ENABLE_AGGRESSIVE_KEY_REVOKE
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_AGGRESSIVE_REVOKE);
|
||||
#endif
|
||||
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_EN);
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS
|
||||
bool rd_dis_now = true;
|
||||
#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
|
||||
/* If flash encryption is not enabled yet then don't read-disable efuses yet, do it later in the boot
|
||||
when Flash Encryption is being enabled */
|
||||
rd_dis_now = esp_efuse_is_flash_encryption_enabled();
|
||||
#endif
|
||||
if (rd_dis_now) {
|
||||
ESP_LOGI(TAG, "Prevent read disabling of additional efuses...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
|
||||
}
|
||||
#else
|
||||
ESP_LOGW(TAG, "Allowing read disabling of additional efuses - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#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_serial_output.h"
|
||||
#include "esp_rom_sys.h"
|
||||
#include "esp_rom_spiflash.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/assist_debug_reg.h"
|
||||
#include "esp_cpu.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#include "soc/cache_reg.h"
|
||||
#include "soc/pcr_reg.h"
|
||||
#include "esp32c61/rom/ets_sys.h"
|
||||
#include "esp32c61/rom/spi_flash.h"
|
||||
#include "bootloader_common.h"
|
||||
#include "bootloader_init.h"
|
||||
#include "bootloader_clock.h"
|
||||
#include "bootloader_flash_config.h"
|
||||
#include "bootloader_mem.h"
|
||||
#include "esp_private/regi2c_ctrl.h"
|
||||
#include "soc/regi2c_lp_bias.h"
|
||||
#include "soc/regi2c_bias.h"
|
||||
#include "bootloader_console.h"
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "bootloader_soc.h"
|
||||
#include "esp_private/bootloader_flash_internal.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "hal/mmu_hal.h"
|
||||
#include "hal/cache_hal.h"
|
||||
#include "soc/lp_wdt_reg.h"
|
||||
#include "hal/efuse_hal.h"
|
||||
#include "hal/lpwdt_ll.h"
|
||||
#include "hal/regi2c_ctrl_ll.h"
|
||||
#include "hal/brownout_ll.h"
|
||||
#include "hal/axi_icm_ll.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "boot.esp32c61");
|
||||
|
||||
#if SOC_RTC_WDT_SUPPORTED
|
||||
void bootloader_enable_cpu_reset_info(void)
|
||||
{
|
||||
REG_SET_BIT(PCR_ASSIST_CONF_REG, PCR_ASSIST_CLK_EN);
|
||||
REG_CLR_BIT(PCR_ASSIST_CONF_REG, PCR_ASSIST_RST_EN);
|
||||
REG_WRITE(ASSIST_DEBUG_CORE_0_RCD_EN_REG, ASSIST_DEBUG_CORE_0_RCD_PDEBUGEN | ASSIST_DEBUG_CORE_0_RCD_RECORDEN);
|
||||
}
|
||||
|
||||
void bootloader_dump_wdt_reset_info(int cpu)
|
||||
{
|
||||
(void) cpu;
|
||||
// saved PC was already printed by the ROM bootloader.
|
||||
// nothing to do here.
|
||||
}
|
||||
|
||||
bool bootloader_check_if_wdt_reset(int cpu, soc_reset_reason_t rst_reason)
|
||||
{
|
||||
(void) cpu;
|
||||
if (rst_reason == RESET_REASON_CORE_RTC_WDT || rst_reason == RESET_REASON_CORE_MWDT0 || rst_reason == RESET_REASON_CORE_MWDT1 ||
|
||||
rst_reason == RESET_REASON_CPU0_MWDT0 || rst_reason == RESET_REASON_CPU0_MWDT1 || rst_reason == RESET_REASON_CPU0_RTC_WDT) {
|
||||
ESP_LOGW(TAG, "PRO CPU has been reset by WDT.");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void bootloader_super_wdt_auto_feed(void)
|
||||
{
|
||||
REG_WRITE(LP_WDT_SWD_WPROTECT_REG, LP_WDT_SWD_WKEY_VALUE);
|
||||
REG_SET_BIT(LP_WDT_SWD_CONFIG_REG, LP_WDT_SWD_AUTO_FEED_EN);
|
||||
REG_WRITE(LP_WDT_SWD_WPROTECT_REG, 0);
|
||||
}
|
||||
#endif // SOC_RTC_WDT_SUPPORTED
|
||||
|
||||
static inline void bootloader_hardware_init(void)
|
||||
{
|
||||
// Clear bit reset_event_bypass to ensure that the system bus is also reset during a core reset (WDT),
|
||||
// preventing bus freezing caused by an incorrect MSPI core reset in ROM.
|
||||
axi_icm_ll_reset_with_core_reset(true);
|
||||
_regi2c_ctrl_ll_master_enable_clock(true); // keep ana i2c mst clock always enabled in bootloader
|
||||
regi2c_ctrl_ll_master_configure_clock();
|
||||
}
|
||||
|
||||
static inline void bootloader_ana_reset_config(void)
|
||||
{
|
||||
//Enable BOD reset (mode1)
|
||||
brownout_ll_ana_reset_enable(true);
|
||||
bootloader_power_glitch_reset_config(true);
|
||||
}
|
||||
|
||||
esp_err_t bootloader_init(void)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
bootloader_hardware_init();
|
||||
bootloader_ana_reset_config();
|
||||
#if SOC_RTC_WDT_SUPPORTED
|
||||
bootloader_super_wdt_auto_feed();
|
||||
#endif
|
||||
|
||||
// In RAM_APP, memory will be initialized in `call_start_cpu0`
|
||||
#if !CONFIG_APP_BUILD_TYPE_RAM
|
||||
// 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();
|
||||
#endif // !CONFIG_APP_BUILD_TYPE_RAM
|
||||
|
||||
// init eFuse virtual mode (read eFuses to RAM)
|
||||
#ifdef CONFIG_EFUSE_VIRTUAL
|
||||
ESP_EARLY_LOGW(TAG, "eFuse virtual mode is enabled. If Secure boot or Flash encryption is enabled then it does not provide any security. FOR TESTING ONLY!");
|
||||
#ifndef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
esp_efuse_init_virtual_mode_in_ram();
|
||||
#endif
|
||||
#endif
|
||||
// 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();
|
||||
|
||||
#if !CONFIG_APP_BUILD_TYPE_RAM
|
||||
// init cache and mmu
|
||||
bootloader_init_ext_mem();
|
||||
// update flash ID
|
||||
bootloader_flash_update_id();
|
||||
// Check and run XMC startup flow
|
||||
if ((ret = bootloader_flash_xmc_startup()) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "failed when running XMC startup flow, reboot!");
|
||||
return ret;
|
||||
}
|
||||
// read bootloader header
|
||||
if ((ret = bootloader_read_bootloader_header()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
// read chip revision and check if it's compatible to bootloader
|
||||
if ((ret = bootloader_check_bootloader_validity()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
// initialize spi flash
|
||||
if ((ret = bootloader_init_spi_flash()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
#endif // !CONFIG_APP_BUILD_TYPE_RAM
|
||||
|
||||
// check reset reason and dump diagnostic info
|
||||
bootloader_check_reset();
|
||||
#if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED
|
||||
// config WDT
|
||||
bootloader_config_wdt();
|
||||
#endif
|
||||
// enable RNG early entropy source
|
||||
bootloader_enable_random();
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include "soc/soc.h"
|
||||
#include "soc/lp_analog_peri_reg.h"
|
||||
#include "soc/pmu_reg.h"
|
||||
#include "hal/regi2c_ctrl.h"
|
||||
#include "soc/regi2c_saradc.h"
|
||||
|
||||
//Not supported but common bootloader calls the function. Do nothing
|
||||
void bootloader_ana_clock_glitch_reset_config(bool enable)
|
||||
{
|
||||
(void)enable;
|
||||
}
|
||||
|
||||
void bootloader_power_glitch_reset_config(bool enable)
|
||||
{
|
||||
//only detect VDDPST POWER GLITCH
|
||||
SET_PERI_REG_MASK(PMU_RF_PWC_REG, PMU_PERIF_I2C_RSTB);
|
||||
SET_PERI_REG_MASK(PMU_RF_PWC_REG, PMU_XPD_PERIF_I2C);
|
||||
REGI2C_WRITE_MASK(I2C_SAR_ADC, POWER_GLITCH_XPD_VDET_PERIF, 0);
|
||||
REGI2C_WRITE_MASK(I2C_SAR_ADC, POWER_GLITCH_XPD_VDET_PLLBB, 0);
|
||||
REGI2C_WRITE_MASK(I2C_SAR_ADC, POWER_GLITCH_XPD_VDET_PLL, 0);
|
||||
|
||||
REG_SET_FIELD(LP_ANA_FIB_ENABLE_REG, LP_ANA_ANA_FIB_PWR_GLITCH_ENA, 0);//default val for chip from ECO2
|
||||
if (enable) {
|
||||
REG_SET_FIELD(LP_ANA_POWER_GLITCH_CNTL_REG, LP_ANA_POWER_GLITCH_RESET_ENA, 0xf);//default val for chip from ECO2
|
||||
} else {
|
||||
REG_SET_FIELD(LP_ANA_POWER_GLITCH_CNTL_REG, LP_ANA_POWER_GLITCH_RESET_ENA, 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <strings.h>
|
||||
#include "esp_flash_encrypt.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "esp_log.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "flash_encrypt");
|
||||
|
||||
esp_err_t esp_flash_encryption_enable_secure_features(void)
|
||||
{
|
||||
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC
|
||||
ESP_LOGI(TAG, "Disable UART bootloader encryption...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling UART bootloader encryption");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE
|
||||
ESP_LOGI(TAG, "Disable UART bootloader cache...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SPI_DOWNLOAD_MSPI_DIS);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling UART bootloader cache - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
|
||||
ESP_LOGI(TAG, "Disable JTAG...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_PAD_JTAG);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_JTAG);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DIRECT_BOOT);
|
||||
|
||||
#if CONFIG_SECURE_FLASH_PSEUDO_ROUND_FUNC
|
||||
ESP_LOGI(TAG, "Enable XTS-AES pseudo rounds function...");
|
||||
uint8_t xts_pseudo_level = CONFIG_SECURE_FLASH_PSEUDO_ROUND_FUNC_STRENGTH;
|
||||
esp_efuse_write_field_blob(ESP_EFUSE_XTS_DPA_PSEUDO_LEVEL, &xts_pseudo_level, ESP_EFUSE_XTS_DPA_PSEUDO_LEVEL[0]->bit_count);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SECURE_BOOT_V2_ENABLED) && !defined(CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS)
|
||||
// This bit is set when enabling Secure Boot V2, but we can't enable it until this later point in the first boot
|
||||
// otherwise the Flash Encryption key cannot be read protected
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_FLASH_SKIP_WRITE_PROTECTION_CACHE
|
||||
// Set write-protection for DIS_ICACHE to prevent bricking chip in case it will be set accidentally.
|
||||
// esp32c61 has DIS_ICACHE. Write-protection bit = 2.
|
||||
// List of eFuses with the same write protection bit:
|
||||
// SWAP_UART_SDIO_EN, DIS_ICACHE, DIS_USB_JTAG, DIS_DOWNLOAD_ICACHE,
|
||||
// DIS_USB_SERIAL_JTAG, DIS_FORCE_DOWNLOAD, DIS_TWAI, JTAG_SEL_ENABLE,
|
||||
// DIS_PAD_JTAG, DIS_DOWNLOAD_MANUAL_ENCRYPT.
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_DIS_ICACHE);
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <strings.h>
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "esp_log.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "secure_boot");
|
||||
|
||||
esp_err_t esp_secure_boot_enable_secure_features(void)
|
||||
{
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DIRECT_BOOT);
|
||||
|
||||
#ifdef CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE
|
||||
ESP_LOGI(TAG, "Enabling Security download mode...");
|
||||
esp_err_t err = esp_efuse_enable_rom_secure_download_mode();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Could not enable Security download mode...");
|
||||
return err;
|
||||
}
|
||||
#elif CONFIG_SECURE_DISABLE_ROM_DL_MODE
|
||||
ESP_LOGI(TAG, "Disable ROM Download mode...");
|
||||
esp_err_t err = esp_efuse_disable_rom_download_mode();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Could not disable ROM Download mode...");
|
||||
return err;
|
||||
}
|
||||
#else
|
||||
ESP_LOGW(TAG, "UART ROM Download mode kept enabled - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
|
||||
ESP_LOGI(TAG, "Disable hardware & software JTAG...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_PAD_JTAG);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_JTAG);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SECURE_BOOT_ENABLE_AGGRESSIVE_KEY_REVOKE
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_AGGRESSIVE_REVOKE);
|
||||
#endif
|
||||
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_EN);
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS
|
||||
bool rd_dis_now = true;
|
||||
#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
|
||||
/* If flash encryption is not enabled yet then don't read-disable efuses yet, do it later in the boot
|
||||
when Flash Encryption is being enabled */
|
||||
rd_dis_now = esp_efuse_is_flash_encryption_enabled();
|
||||
#endif
|
||||
if (rd_dis_now) {
|
||||
ESP_LOGI(TAG, "Prevent read disabling of additional efuses...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
|
||||
}
|
||||
#else
|
||||
ESP_LOGW(TAG, "Allowing read disabling of additional efuses - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#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_serial_output.h"
|
||||
#include "esp_rom_sys.h"
|
||||
#include "esp_rom_spiflash.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/assist_debug_reg.h"
|
||||
#include "esp_cpu.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#include "soc/extmem_reg.h"
|
||||
#include "soc/pcr_reg.h"
|
||||
#include "esp32h2/rom/ets_sys.h"
|
||||
#include "bootloader_common.h"
|
||||
#include "bootloader_init.h"
|
||||
#include "bootloader_clock.h"
|
||||
#include "bootloader_flash_config.h"
|
||||
#include "bootloader_mem.h"
|
||||
#include "esp_private/regi2c_ctrl.h"
|
||||
#include "soc/regi2c_lp_bias.h"
|
||||
#include "soc/regi2c_bias.h"
|
||||
#include "bootloader_console.h"
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "bootloader_soc.h"
|
||||
#include "esp_private/bootloader_flash_internal.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "hal/mmu_hal.h"
|
||||
#include "hal/cache_hal.h"
|
||||
#include "hal/lpwdt_ll.h"
|
||||
#include "soc/lp_wdt_reg.h"
|
||||
#include "soc/pmu_reg.h"
|
||||
#include "hal/efuse_hal.h"
|
||||
#include "hal/regi2c_ctrl_ll.h"
|
||||
#include "hal/brownout_ll.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "boot.esp32h2");
|
||||
|
||||
#if SOC_RTC_WDT_SUPPORTED
|
||||
void bootloader_enable_cpu_reset_info(void)
|
||||
{
|
||||
REG_SET_BIT(PCR_ASSIST_CONF_REG, PCR_ASSIST_CLK_EN);
|
||||
REG_CLR_BIT(PCR_ASSIST_CONF_REG, PCR_ASSIST_RST_EN);
|
||||
REG_WRITE(ASSIST_DEBUG_CORE_0_RCD_EN_REG, ASSIST_DEBUG_CORE_0_RCD_PDEBUGEN | ASSIST_DEBUG_CORE_0_RCD_RECORDEN);
|
||||
}
|
||||
|
||||
void bootloader_dump_wdt_reset_info(int cpu)
|
||||
{
|
||||
(void) cpu;
|
||||
// saved PC was already printed by the ROM bootloader.
|
||||
// nothing to do here.
|
||||
}
|
||||
|
||||
bool bootloader_check_if_wdt_reset(int cpu, soc_reset_reason_t rst_reason)
|
||||
{
|
||||
(void) cpu;
|
||||
if (rst_reason == RESET_REASON_CORE_RTC_WDT || rst_reason == RESET_REASON_CORE_MWDT0 || rst_reason == RESET_REASON_CORE_MWDT1 ||
|
||||
rst_reason == RESET_REASON_CPU0_MWDT0 || rst_reason == RESET_REASON_CPU0_MWDT1 || rst_reason == RESET_REASON_CPU0_RTC_WDT) {
|
||||
ESP_EARLY_LOGW(TAG, "PRO CPU has been reset by WDT.");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void bootloader_super_wdt_auto_feed(void)
|
||||
{
|
||||
REG_WRITE(LP_WDT_SWD_WPROTECT_REG, LP_WDT_SWD_WKEY_VALUE);
|
||||
REG_SET_BIT(LP_WDT_SWD_CONFIG_REG, LP_WDT_SWD_AUTO_FEED_EN);
|
||||
REG_WRITE(LP_WDT_SWD_WPROTECT_REG, 0);
|
||||
}
|
||||
#endif // SOC_RTC_WDT_SUPPORTED
|
||||
|
||||
static inline void bootloader_hardware_init(void)
|
||||
{
|
||||
/* Disable RF pll by default */
|
||||
CLEAR_PERI_REG_MASK(PMU_RF_PWC_REG, PMU_XPD_RFPLL);
|
||||
SET_PERI_REG_MASK(PMU_RF_PWC_REG, PMU_XPD_FORCE_RFPLL);
|
||||
|
||||
_regi2c_ctrl_ll_master_enable_clock(true); // keep ana i2c mst clock always enabled in bootloader
|
||||
regi2c_ctrl_ll_master_configure_clock();
|
||||
|
||||
REGI2C_WRITE_MASK(I2C_BIAS, I2C_BIAS_DREG_0P8, 8); // fix low temp issue, need to increase this internal voltage
|
||||
|
||||
}
|
||||
|
||||
static inline void bootloader_ana_reset_config(void)
|
||||
{
|
||||
//Enable super WDT reset.
|
||||
bootloader_ana_super_wdt_reset_config(true);
|
||||
//Enable BOD reset (mode1)
|
||||
brownout_ll_ana_reset_enable(true);
|
||||
}
|
||||
|
||||
esp_err_t bootloader_init(void)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
bootloader_hardware_init();
|
||||
bootloader_ana_reset_config();
|
||||
#if SOC_RTC_WDT_SUPPORTED
|
||||
bootloader_super_wdt_auto_feed();
|
||||
#endif
|
||||
|
||||
// In RAM_APP, memory will be initialized in `call_start_cpu0`
|
||||
#if !CONFIG_APP_BUILD_TYPE_RAM
|
||||
// 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();
|
||||
#endif // !CONFIG_APP_BUILD_TYPE_RAM
|
||||
|
||||
// init eFuse virtual mode (read eFuses to RAM)
|
||||
#ifdef CONFIG_EFUSE_VIRTUAL
|
||||
ESP_EARLY_LOGW(TAG, "eFuse virtual mode is enabled. If Secure boot or Flash encryption is enabled then it does not provide any security. FOR TESTING ONLY!");
|
||||
#ifndef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
esp_efuse_init_virtual_mode_in_ram();
|
||||
#endif
|
||||
#endif
|
||||
// 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();
|
||||
|
||||
#if !CONFIG_APP_BUILD_TYPE_RAM
|
||||
// init cache and mmu
|
||||
bootloader_init_ext_mem();
|
||||
// update flash ID
|
||||
bootloader_flash_update_id();
|
||||
// Check and run XMC startup flow
|
||||
if ((ret = bootloader_flash_xmc_startup()) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "failed when running XMC startup flow, reboot!");
|
||||
return ret;
|
||||
}
|
||||
// read bootloader header
|
||||
if ((ret = bootloader_read_bootloader_header()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
// read chip revision and check if it's compatible to bootloader
|
||||
if ((ret = bootloader_check_bootloader_validity()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
// initialize spi flash
|
||||
if ((ret = bootloader_init_spi_flash()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
#endif // !CONFIG_APP_BUILD_TYPE_RAM
|
||||
|
||||
// check reset reason and dump diagnostic info
|
||||
bootloader_check_reset();
|
||||
#if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED
|
||||
// config WDT
|
||||
bootloader_config_wdt();
|
||||
#endif
|
||||
// enable RNG early entropy source
|
||||
bootloader_enable_random();
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include "soc/lp_analog_peri_reg.h"
|
||||
|
||||
void bootloader_ana_super_wdt_reset_config(bool enable)
|
||||
{
|
||||
//H2 doesn't support bypass super WDT reset
|
||||
assert(enable);
|
||||
REG_CLR_BIT(LP_ANALOG_PERI_LP_ANA_FIB_ENABLE_REG, LP_ANALOG_PERI_LP_ANA_FIB_SUPER_WDT_RST);
|
||||
}
|
||||
|
||||
//Not supported but common bootloader calls the function. Do nothing
|
||||
void bootloader_ana_clock_glitch_reset_config(bool enable)
|
||||
{
|
||||
(void)enable;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <strings.h>
|
||||
#include "esp_flash_encrypt.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "esp_log.h"
|
||||
#include "hal/spi_flash_encrypted_ll.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "flash_encrypt");
|
||||
|
||||
esp_err_t esp_flash_encryption_enable_secure_features(void)
|
||||
{
|
||||
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC
|
||||
ESP_LOGI(TAG, "Disable UART bootloader encryption...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling UART bootloader encryption");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
|
||||
ESP_LOGI(TAG, "Disable JTAG...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_PAD_JTAG);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_JTAG);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DIRECT_BOOT);
|
||||
|
||||
#if CONFIG_SECURE_FLASH_PSEUDO_ROUND_FUNC
|
||||
if (spi_flash_encrypt_ll_is_pseudo_rounds_function_supported()) {
|
||||
ESP_LOGI(TAG, "Enable XTS-AES pseudo rounds function...");
|
||||
uint8_t xts_pseudo_level = CONFIG_SECURE_FLASH_PSEUDO_ROUND_FUNC_STRENGTH;
|
||||
esp_efuse_write_field_blob(ESP_EFUSE_XTS_DPA_PSEUDO_LEVEL, &xts_pseudo_level, ESP_EFUSE_XTS_DPA_PSEUDO_LEVEL[0]->bit_count);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SECURE_BOOT_V2_ENABLED) && !defined(CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS)
|
||||
// This bit is set when enabling Secure Boot V2, but we can't enable it until this later point in the first boot
|
||||
// otherwise the Flash Encryption key cannot be read protected
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_FLASH_SKIP_WRITE_PROTECTION_CACHE
|
||||
// Set write-protection for DIS_ICACHE to prevent bricking chip in case it will be set accidentally.
|
||||
// esp32h2 has DIS_ICACHE. Write-protection bit = 2.
|
||||
// List of eFuses with the same write protection bit:
|
||||
// DIS_ICACHE, DIS_USB_JTAG, POWERGLITCH_EN, DIS_FORCE_DOWNLOAD, SPI_DOWNLOAD_MSPI_DIS,
|
||||
// DIS_TWAI, JTAG_SEL_ENABLE, DIS_PAD_JTAG, DIS_DOWNLOAD_MANUAL_ENCRYPT, DIS_USB_SERIAL_JTAG
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_DIS_ICACHE);
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <strings.h>
|
||||
#include "hal/ecdsa_ll.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "esp_log.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "secure_boot");
|
||||
|
||||
esp_err_t esp_secure_boot_enable_secure_features(void)
|
||||
{
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DIRECT_BOOT);
|
||||
|
||||
#ifdef CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE
|
||||
ESP_LOGI(TAG, "Enabling Security download mode...");
|
||||
esp_err_t err = esp_efuse_enable_rom_secure_download_mode();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Could not enable Security download mode...");
|
||||
return err;
|
||||
}
|
||||
#elif CONFIG_SECURE_DISABLE_ROM_DL_MODE
|
||||
ESP_LOGI(TAG, "Disable ROM Download mode...");
|
||||
esp_err_t err = esp_efuse_disable_rom_download_mode();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Could not disable ROM Download mode...");
|
||||
return err;
|
||||
}
|
||||
#else
|
||||
ESP_LOGW(TAG, "UART ROM Download mode kept enabled - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
|
||||
ESP_LOGI(TAG, "Disable hardware & software JTAG...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_PAD_JTAG);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_JTAG);
|
||||
esp_efuse_write_field_cnt(ESP_EFUSE_SOFT_DIS_JTAG, ESP_EFUSE_SOFT_DIS_JTAG[0]->bit_count);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SECURE_BOOT_ENABLE_AGGRESSIVE_KEY_REVOKE
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_AGGRESSIVE_REVOKE);
|
||||
#endif
|
||||
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_EN);
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS
|
||||
bool rd_dis_now = true;
|
||||
#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
|
||||
/* If flash encryption is not enabled yet then don't read-disable efuses yet, do it later in the boot
|
||||
when Flash Encryption is being enabled */
|
||||
rd_dis_now = esp_efuse_is_flash_encryption_enabled();
|
||||
#endif
|
||||
if (rd_dis_now) {
|
||||
ESP_LOGI(TAG, "Prevent read disabling of additional efuses...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
|
||||
}
|
||||
#else
|
||||
ESP_LOGW(TAG, "Allowing read disabling of additional efuses - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#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_serial_output.h"
|
||||
#include "esp_rom_sys.h"
|
||||
#include "esp_rom_spiflash.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/assist_debug_reg.h"
|
||||
#include "esp_cpu.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#include "soc/cache_reg.h"
|
||||
#include "soc/pcr_reg.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "bootloader_common.h"
|
||||
#include "bootloader_init.h"
|
||||
#include "bootloader_clock.h"
|
||||
#include "bootloader_flash_config.h"
|
||||
#include "bootloader_mem.h"
|
||||
#include "esp_private/regi2c_ctrl.h"
|
||||
#include "soc/regi2c_lp_bias.h"
|
||||
#include "soc/regi2c_bias.h"
|
||||
#include "bootloader_console.h"
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "bootloader_soc.h"
|
||||
#include "esp_private/bootloader_flash_internal.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "hal/mmu_hal.h"
|
||||
#include "hal/cache_hal.h"
|
||||
#include "hal/lpwdt_ll.h"
|
||||
#include "hal/brownout_ll.h"
|
||||
#include "soc/lp_wdt_reg.h"
|
||||
#include "soc/pmu_reg.h"
|
||||
#include "hal/efuse_hal.h"
|
||||
#include "hal/regi2c_ctrl_ll.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "boot.esp32h21");
|
||||
|
||||
#if SOC_RTC_WDT_SUPPORTED
|
||||
void bootloader_enable_cpu_reset_info(void)
|
||||
{
|
||||
REG_SET_BIT(PCR_ASSIST_CONF_REG, PCR_ASSIST_CLK_EN);
|
||||
REG_CLR_BIT(PCR_ASSIST_CONF_REG, PCR_ASSIST_RST_EN);
|
||||
REG_WRITE(ASSIST_DEBUG_CORE_0_RCD_EN_REG, ASSIST_DEBUG_CORE_0_RCD_PDEBUGEN | ASSIST_DEBUG_CORE_0_RCD_RECORDEN);
|
||||
}
|
||||
|
||||
void bootloader_dump_wdt_reset_info(int cpu)
|
||||
{
|
||||
(void) cpu;
|
||||
// saved PC was already printed by the ROM bootloader.
|
||||
// nothing to do here.
|
||||
}
|
||||
|
||||
bool bootloader_check_if_wdt_reset(int cpu, soc_reset_reason_t rst_reason)
|
||||
{
|
||||
(void) cpu;
|
||||
if (rst_reason == RESET_REASON_CORE_RTC_WDT || rst_reason == RESET_REASON_CORE_MWDT0 || rst_reason == RESET_REASON_CORE_MWDT1 ||
|
||||
rst_reason == RESET_REASON_CPU0_MWDT0 || rst_reason == RESET_REASON_CPU0_MWDT1 || rst_reason == RESET_REASON_CPU0_RTC_WDT) {
|
||||
ESP_EARLY_LOGW(TAG, "PRO CPU has been reset by WDT.");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void bootloader_super_wdt_auto_feed(void)
|
||||
{
|
||||
REG_WRITE(LP_WDT_SWD_WPROTECT_REG, LP_WDT_SWD_WKEY_VALUE);
|
||||
REG_SET_BIT(LP_WDT_SWD_CONFIG_REG, LP_WDT_SWD_AUTO_FEED_EN);
|
||||
REG_WRITE(LP_WDT_SWD_WPROTECT_REG, 0);
|
||||
}
|
||||
#endif // SOC_RTC_WDT_SUPPORTED
|
||||
|
||||
static inline void bootloader_hardware_init(void)
|
||||
{
|
||||
/* Disable RF pll by default */
|
||||
CLEAR_PERI_REG_MASK(PMU_RF_PWC_REG, PMU_XPD_RFPLL);
|
||||
SET_PERI_REG_MASK(PMU_RF_PWC_REG, PMU_XPD_FORCE_RFPLL);
|
||||
|
||||
_regi2c_ctrl_ll_master_enable_clock(true); // keep ana i2c mst clock always enabled in bootloader
|
||||
regi2c_ctrl_ll_master_configure_clock();
|
||||
}
|
||||
|
||||
static inline void bootloader_ana_reset_config(void)
|
||||
{
|
||||
//Enable super WDT reset.
|
||||
bootloader_ana_super_wdt_reset_config(true);
|
||||
//Enable BOD reset (mode1)
|
||||
brownout_ll_ana_reset_enable(true);
|
||||
}
|
||||
|
||||
esp_err_t bootloader_init(void)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
bootloader_hardware_init();
|
||||
bootloader_ana_reset_config();
|
||||
#if SOC_RTC_WDT_SUPPORTED
|
||||
bootloader_super_wdt_auto_feed();
|
||||
#endif
|
||||
|
||||
// In RAM_APP, memory will be initialized in `call_start_cpu0`
|
||||
#if !CONFIG_APP_BUILD_TYPE_RAM
|
||||
// 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();
|
||||
#endif // !CONFIG_APP_BUILD_TYPE_RAM
|
||||
|
||||
// init eFuse virtual mode (read eFuses to RAM)
|
||||
#ifdef CONFIG_EFUSE_VIRTUAL
|
||||
ESP_EARLY_LOGW(TAG, "eFuse virtual mode is enabled. If Secure boot or Flash encryption is enabled then it does not provide any security. FOR TESTING ONLY!");
|
||||
#ifndef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
esp_efuse_init_virtual_mode_in_ram();
|
||||
#endif
|
||||
#endif
|
||||
// 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();
|
||||
|
||||
#if !CONFIG_APP_BUILD_TYPE_RAM
|
||||
// init cache and mmu
|
||||
bootloader_init_ext_mem();
|
||||
// update flash ID
|
||||
bootloader_flash_update_id();
|
||||
// Check and run XMC startup flow
|
||||
if ((ret = bootloader_flash_xmc_startup()) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "failed when running XMC startup flow, reboot!");
|
||||
return ret;
|
||||
}
|
||||
// read bootloader header
|
||||
if ((ret = bootloader_read_bootloader_header()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
// read chip revision and check if it's compatible to bootloader
|
||||
if ((ret = bootloader_check_bootloader_validity()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
// initialize spi flash
|
||||
if ((ret = bootloader_init_spi_flash()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
#endif // !CONFIG_APP_BUILD_TYPE_RAM
|
||||
|
||||
// check reset reason and dump diagnostic info
|
||||
bootloader_check_reset();
|
||||
#if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED
|
||||
// config WDT
|
||||
bootloader_config_wdt();
|
||||
#endif
|
||||
// enable RNG early entropy source
|
||||
bootloader_enable_random();
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include "soc/lp_analog_peri_reg.h"
|
||||
|
||||
void bootloader_ana_super_wdt_reset_config(bool enable)
|
||||
{
|
||||
//H21 doesn't support bypass super WDT reset
|
||||
assert(enable);
|
||||
REG_CLR_BIT(LP_ANA_FIB_ENABLE_REG, LP_ANALOG_PERI_LP_ANA_FIB_SUPER_WDT_RST);
|
||||
}
|
||||
|
||||
//Not supported but common bootloader calls the function. Do nothing
|
||||
void bootloader_ana_clock_glitch_reset_config(bool enable)
|
||||
{
|
||||
(void)enable;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <strings.h>
|
||||
#include "esp_flash_encrypt.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "esp_log.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "flash_encrypt");
|
||||
|
||||
esp_err_t esp_flash_encryption_enable_secure_features(void)
|
||||
{
|
||||
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC
|
||||
ESP_LOGI(TAG, "Disable UART bootloader encryption...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling UART bootloader encryption");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
|
||||
ESP_LOGI(TAG, "Disable JTAG...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_PAD_JTAG);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_JTAG);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DIRECT_BOOT);
|
||||
|
||||
#if defined(CONFIG_SECURE_BOOT_V2_ENABLED) && !defined(CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS)
|
||||
// This bit is set when enabling Secure Boot V2, but we can't enable it until this later point in the first boot
|
||||
// otherwise the Flash Encryption key cannot be read protected
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_FLASH_SKIP_WRITE_PROTECTION_CACHE
|
||||
// Set write-protection for DIS_ICACHE to prevent bricking chip in case it will be set accidentally.
|
||||
// esp32h21 has DIS_ICACHE. Write-protection bit = 2.
|
||||
// List of eFuses with the same write protection bit:
|
||||
// DIS_ICACHE, DIS_USB_JTAG, POWERGLITCH_EN, DIS_FORCE_DOWNLOAD, SPI_DOWNLOAD_MSPI_DIS,
|
||||
// DIS_TWAI, JTAG_SEL_ENABLE, DIS_PAD_JTAG, DIS_DOWNLOAD_MANUAL_ENCRYPT, DIS_USB_SERIAL_JTAG
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_DIS_ICACHE);
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <strings.h>
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "esp_log.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "secure_boot");
|
||||
|
||||
esp_err_t esp_secure_boot_enable_secure_features(void)
|
||||
{
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DIRECT_BOOT);
|
||||
|
||||
#ifdef CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE
|
||||
ESP_LOGI(TAG, "Enabling Security download mode...");
|
||||
esp_err_t err = esp_efuse_enable_rom_secure_download_mode();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Could not enable Security download mode...");
|
||||
return err;
|
||||
}
|
||||
#elif CONFIG_SECURE_DISABLE_ROM_DL_MODE
|
||||
ESP_LOGI(TAG, "Disable ROM Download mode...");
|
||||
esp_err_t err = esp_efuse_disable_rom_download_mode();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Could not disable ROM Download mode...");
|
||||
return err;
|
||||
}
|
||||
#else
|
||||
ESP_LOGW(TAG, "UART ROM Download mode kept enabled - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
|
||||
ESP_LOGI(TAG, "Disable hardware & software JTAG...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_PAD_JTAG);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_JTAG);
|
||||
esp_efuse_write_field_cnt(ESP_EFUSE_SOFT_DIS_JTAG, ESP_EFUSE_SOFT_DIS_JTAG[0]->bit_count);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SECURE_BOOT_ENABLE_AGGRESSIVE_KEY_REVOKE
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_AGGRESSIVE_REVOKE);
|
||||
#endif
|
||||
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_EN);
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS
|
||||
bool rd_dis_now = true;
|
||||
#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
|
||||
/* If flash encryption is not enabled yet then don't read-disable efuses yet, do it later in the boot
|
||||
when Flash Encryption is being enabled */
|
||||
rd_dis_now = esp_efuse_is_flash_encryption_enabled();
|
||||
#endif
|
||||
if (rd_dis_now) {
|
||||
ESP_LOGI(TAG, "Prevent read disabling of additional efuses...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
|
||||
}
|
||||
#else
|
||||
ESP_LOGW(TAG, "Allowing read disabling of additional efuses - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#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_serial_output.h"
|
||||
#include "esp_rom_sys.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "esp_cpu.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#include "soc/cache_reg.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/pcr_reg.h"
|
||||
#include "soc/bus_monitor_reg.h"
|
||||
#include "bootloader_common.h"
|
||||
#include "bootloader_init.h"
|
||||
#include "bootloader_clock.h"
|
||||
#include "bootloader_flash_config.h"
|
||||
#include "bootloader_mem.h"
|
||||
#include "esp_private/regi2c_ctrl.h"
|
||||
#include "soc/hp_system_reg.h"
|
||||
#include "bootloader_console.h"
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "bootloader_soc.h"
|
||||
#include "esp_private/bootloader_flash_internal.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "hal/mmu_hal.h"
|
||||
#include "hal/cache_hal.h"
|
||||
#include "hal/clk_tree_ll.h"
|
||||
#include "soc/lp_wdt_reg.h"
|
||||
#include "hal/efuse_hal.h"
|
||||
#include "hal/lpwdt_ll.h"
|
||||
#include "hal/assist_debug_ll.h"
|
||||
#include "hal/brownout_ll.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "boot.esp32h4");
|
||||
|
||||
#if SOC_RTC_WDT_SUPPORTED || SOC_CPU_LOCKUP_DEBUG_SUPPORTED
|
||||
void bootloader_enable_cpu_reset_info(void)
|
||||
{
|
||||
assist_debug_ll_enable_bus_clock(0, true);
|
||||
assist_debug_ll_enable_pc_recording(0, true);
|
||||
assist_debug_ll_lockup_monitor_enable(0, true);
|
||||
assist_debug_ll_lockup_reset_enable(0);
|
||||
#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
|
||||
assist_debug_ll_enable_bus_clock(1, true);
|
||||
assist_debug_ll_enable_pc_recording(1, true);
|
||||
assist_debug_ll_lockup_monitor_enable(1, true);
|
||||
assist_debug_ll_lockup_reset_enable(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
void bootloader_dump_wdt_reset_info(int cpu)
|
||||
{
|
||||
(void) cpu;
|
||||
// saved PC was already printed by the ROM bootloader.
|
||||
// nothing to do here.
|
||||
}
|
||||
|
||||
bool bootloader_check_if_wdt_reset(int cpu, soc_reset_reason_t reset_reason)
|
||||
{
|
||||
if (cpu == 0 && (reset_reason == RESET_REASON_CORE_RTC_WDT || reset_reason == RESET_REASON_CORE_MWDT0 ||
|
||||
reset_reason == RESET_REASON_CORE_MWDT1 || reset_reason == RESET_REASON_CPU0_MWDT0 ||
|
||||
reset_reason == RESET_REASON_CPU0_MWDT1 || reset_reason == RESET_REASON_CPU0_RTC_WDT)) {
|
||||
ESP_LOGW(TAG, "PRO CPU has been reset by WDT.");
|
||||
return true;
|
||||
}
|
||||
if (cpu == 1 && (reset_reason == RESET_REASON_CORE_RTC_WDT || reset_reason == RESET_REASON_CORE_MWDT0 ||
|
||||
reset_reason == RESET_REASON_CORE_MWDT1 || reset_reason == RESET_REASON_CPU0_MWDT0 ||
|
||||
reset_reason == RESET_REASON_CPU0_MWDT1 || reset_reason == RESET_REASON_CPU0_RTC_WDT)) {
|
||||
ESP_LOGW(TAG, "APP CPU has been reset by WDT.");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#if SOC_RTC_WDT_SUPPORTED
|
||||
static void bootloader_super_wdt_auto_feed(void)
|
||||
{
|
||||
REG_WRITE(LP_WDT_SWD_WPROTECT_REG, LP_WDT_SWD_WKEY_VALUE);
|
||||
REG_SET_BIT(LP_WDT_SWD_CONFIG_REG, LP_WDT_SWD_AUTO_FEED_EN);
|
||||
REG_WRITE(LP_WDT_SWD_WPROTECT_REG, 0);
|
||||
}
|
||||
#endif
|
||||
#endif // SOC_RTC_WDT_SUPPORTED || SOC_CPU_LOCKUP_DEBUG_SUPPORTED
|
||||
|
||||
static inline void bootloader_hardware_init(void)
|
||||
{
|
||||
/* Disable RF pll by default */
|
||||
CLEAR_PERI_REG_MASK(PMU_RF_PWC_REG, PMU_XPD_RFPLL);
|
||||
SET_PERI_REG_MASK(PMU_RF_PWC_REG, PMU_XPD_FORCE_RFPLL);
|
||||
|
||||
#if !CONFIG_IDF_ENV_FPGA
|
||||
/* Enable analog i2c master clock */
|
||||
_regi2c_ctrl_ll_master_enable_clock(true); // keep ana i2c mst clock always enabled in bootloader
|
||||
regi2c_ctrl_ll_master_force_enable_clock(true); // TODO: IDF-12313 Remove this?
|
||||
regi2c_ctrl_ll_master_configure_clock();
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void bootloader_ana_reset_config(void)
|
||||
{
|
||||
//Enable super WDT reset.
|
||||
bootloader_ana_super_wdt_reset_config(true);
|
||||
//Enable BOD reset
|
||||
brownout_ll_ana_reset_enable(true);
|
||||
}
|
||||
|
||||
static inline void bootloader_config_dcache(void)
|
||||
{
|
||||
REG_SET_BIT(LP_AON_SRAM_USAGE_CONF_REG, LP_AON_DCACHE_USAGE);
|
||||
}
|
||||
|
||||
static inline void bootloader_config_icache1(void)
|
||||
{
|
||||
#if CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
|
||||
REG_CLR_BIT(LP_AON_SRAM_USAGE_CONF_REG, LP_AON_ICACHE1_USAGE);
|
||||
#else
|
||||
REG_SET_BIT(LP_AON_SRAM_USAGE_CONF_REG, LP_AON_ICACHE1_USAGE);
|
||||
#endif
|
||||
}
|
||||
|
||||
esp_err_t bootloader_init(void)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
bootloader_hardware_init();
|
||||
bootloader_ana_reset_config();
|
||||
#if SOC_RTC_WDT_SUPPORTED
|
||||
bootloader_super_wdt_auto_feed();
|
||||
#endif
|
||||
|
||||
// In RAM_APP, memory will be initialized in `call_start_cpu0`
|
||||
#if !CONFIG_APP_BUILD_TYPE_RAM
|
||||
// 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();
|
||||
#endif // !CONFIG_APP_BUILD_TYPE_RAM
|
||||
|
||||
// init eFuse virtual mode (read eFuses to RAM)
|
||||
#ifdef CONFIG_EFUSE_VIRTUAL
|
||||
ESP_EARLY_LOGW(TAG, "eFuse virtual mode is enabled. If Secure boot or Flash encryption is enabled then it does not provide any security. FOR TESTING ONLY!");
|
||||
#ifndef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
esp_efuse_init_virtual_mode_in_ram();
|
||||
#endif
|
||||
#endif
|
||||
// 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();
|
||||
|
||||
#if !CONFIG_APP_BUILD_TYPE_RAM
|
||||
// init cache and mmu
|
||||
bootloader_init_ext_mem();
|
||||
// update flash ID
|
||||
bootloader_flash_update_id();
|
||||
// Check and run XMC startup flow
|
||||
if ((ret = bootloader_flash_xmc_startup()) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "failed when running XMC startup flow, reboot!");
|
||||
return ret;
|
||||
}
|
||||
// read bootloader header
|
||||
if ((ret = bootloader_read_bootloader_header()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
// read chip revision and check if it's compatible to bootloader
|
||||
if ((ret = bootloader_check_bootloader_validity()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
// initialize spi flash
|
||||
if ((ret = bootloader_init_spi_flash()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
#endif // !CONFIG_APP_BUILD_TYPE_RAM
|
||||
bootloader_config_dcache();
|
||||
bootloader_config_icache1();
|
||||
// check reset reason and dump diagnostic info
|
||||
bootloader_check_reset();
|
||||
#if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED
|
||||
// config WDT
|
||||
bootloader_config_wdt();
|
||||
#endif
|
||||
// enable RNG early entropy source
|
||||
bootloader_enable_random();
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include "soc/soc.h"
|
||||
#include "soc/lp_analog_peri_reg.h"
|
||||
|
||||
//TODO: [ESP32H4] IDF-12313 inherited from verification branch, need check
|
||||
|
||||
void bootloader_ana_super_wdt_reset_config(bool enable)
|
||||
{
|
||||
//H4 doesn't support bypass super WDT reset
|
||||
// assert(enable);
|
||||
// REG_CLR_BIT(LP_ANA_FIB_ENABLE_REG, LP_ANALOG_PERI_LP_ANA_FIB_SUPER_WDT_RST);
|
||||
}
|
||||
|
||||
//Not supported but common bootloader calls the function. Do nothing
|
||||
void bootloader_ana_clock_glitch_reset_config(bool enable)
|
||||
{
|
||||
(void)enable;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <strings.h>
|
||||
#include "esp_flash_encrypt.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "esp_log.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "flash_encrypt");
|
||||
|
||||
esp_err_t esp_flash_encryption_enable_secure_features(void)
|
||||
{
|
||||
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC
|
||||
ESP_LOGI(TAG, "Disable UART bootloader encryption...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling UART bootloader encryption");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE
|
||||
ESP_LOGI(TAG, "Disable UART bootloader cache...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SPI_DOWNLOAD_MSPI_DIS);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling UART bootloader cache - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
|
||||
ESP_LOGI(TAG, "Disable JTAG...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_PAD_JTAG);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_JTAG);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DIRECT_BOOT);
|
||||
|
||||
#if defined(CONFIG_SECURE_FLASH_PSEUDO_ROUND_FUNC) && CONFIG_SECURE_FLASH_PSEUDO_ROUND_FUNC
|
||||
ESP_LOGI(TAG, "Enable XTS-AES pseudo rounds function...");
|
||||
uint8_t xts_pseudo_level = CONFIG_SECURE_FLASH_PSEUDO_ROUND_FUNC_STRENGTH;
|
||||
esp_efuse_write_field_blob(ESP_EFUSE_XTS_DPA_PSEUDO_LEVEL, &xts_pseudo_level, ESP_EFUSE_XTS_DPA_PSEUDO_LEVEL[0]->bit_count);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SECURE_BOOT_V2_ENABLED) && !defined(CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS)
|
||||
// This bit is set when enabling Secure Boot V2, but we can't enable it until this later point in the first boot
|
||||
// otherwise the Flash Encryption key cannot be read protected
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <strings.h>
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "esp_log.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "secure_boot");
|
||||
|
||||
esp_err_t esp_secure_boot_enable_secure_features(void)
|
||||
{
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DIRECT_BOOT);
|
||||
|
||||
#ifdef CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE
|
||||
ESP_LOGI(TAG, "Enabling Security download mode...");
|
||||
esp_err_t err = esp_efuse_enable_rom_secure_download_mode();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Could not enable Security download mode...");
|
||||
return err;
|
||||
}
|
||||
#elif CONFIG_SECURE_DISABLE_ROM_DL_MODE
|
||||
ESP_LOGI(TAG, "Disable ROM Download mode...");
|
||||
esp_err_t err = esp_efuse_disable_rom_download_mode();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Could not disable ROM Download mode...");
|
||||
return err;
|
||||
}
|
||||
#else
|
||||
ESP_LOGW(TAG, "UART ROM Download mode kept enabled - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
|
||||
ESP_LOGI(TAG, "Disable hardware & software JTAG...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_PAD_JTAG);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_JTAG);
|
||||
esp_efuse_write_field_cnt(ESP_EFUSE_SOFT_DIS_JTAG, ESP_EFUSE_SOFT_DIS_JTAG[0]->bit_count);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SECURE_BOOT_ENABLE_AGGRESSIVE_KEY_REVOKE
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_AGGRESSIVE_REVOKE);
|
||||
#endif
|
||||
|
||||
#if CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_SHA384_EN);
|
||||
#endif
|
||||
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_EN);
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS
|
||||
bool rd_dis_now = true;
|
||||
#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
|
||||
/* If flash encryption is not enabled yet then don't read-disable efuses yet, do it later in the boot
|
||||
when Flash Encryption is being enabled */
|
||||
rd_dis_now = esp_efuse_is_flash_encryption_enabled();
|
||||
#endif
|
||||
if (rd_dis_now) {
|
||||
ESP_LOGI(TAG, "Prevent read disabling of additional efuses...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
|
||||
}
|
||||
#else
|
||||
ESP_LOGW(TAG, "Allowing read disabling of additional efuses - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#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_serial_output.h"
|
||||
#include "esp_rom_sys.h"
|
||||
#include "esp_rom_spiflash.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/assist_debug_reg.h"
|
||||
#include "esp_cpu.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#include "soc/cache_reg.h"
|
||||
#include "esp32p4/rom/ets_sys.h"
|
||||
#include "esp32p4/rom/spi_flash.h"
|
||||
#include "bootloader_common.h"
|
||||
#include "bootloader_init.h"
|
||||
#include "bootloader_clock.h"
|
||||
#include "bootloader_flash_config.h"
|
||||
#include "bootloader_mem.h"
|
||||
#include "esp_private/regi2c_ctrl.h"
|
||||
#include "soc/chip_revision.h"
|
||||
#include "soc/regi2c_lp_bias.h"
|
||||
#include "soc/regi2c_bias.h"
|
||||
#include "bootloader_console.h"
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "bootloader_soc.h"
|
||||
#include "esp_private/bootloader_flash_internal.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "hal/assist_debug_ll.h"
|
||||
#include "hal/mmu_hal.h"
|
||||
#include "hal/cache_hal.h"
|
||||
#include "hal/clk_tree_ll.h"
|
||||
#include "hal/lpwdt_ll.h"
|
||||
#include "hal/spimem_flash_ll.h"
|
||||
#include "soc/lp_wdt_reg.h"
|
||||
#include "hal/efuse_hal.h"
|
||||
#include "soc/regi2c_syspll.h"
|
||||
#include "soc/regi2c_cpll.h"
|
||||
#include "soc/regi2c_bias.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "hal/regi2c_ctrl_ll.h"
|
||||
#include "hal/brownout_ll.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "boot.esp32p4");
|
||||
|
||||
#if SOC_RTC_WDT_SUPPORTED
|
||||
void bootloader_enable_cpu_reset_info(void)
|
||||
{
|
||||
_assist_debug_ll_enable_bus_clock(0, true);
|
||||
assist_debug_ll_enable_pc_recording(0, true);
|
||||
}
|
||||
|
||||
void bootloader_dump_wdt_reset_info(int cpu)
|
||||
{
|
||||
(void) cpu;
|
||||
// saved PC was already printed by the ROM bootloader.
|
||||
// nothing to do here.
|
||||
}
|
||||
|
||||
bool bootloader_check_if_wdt_reset(int cpu, soc_reset_reason_t rst_reason)
|
||||
{
|
||||
if (cpu == 0 && (rst_reason == RESET_REASON_CPU_MWDT || rst_reason == RESET_REASON_CPU_RWDT ||
|
||||
rst_reason == RESET_REASON_CORE_MWDT || rst_reason == RESET_REASON_CORE_RWDT ||
|
||||
rst_reason == RESET_REASON_SYS_RWDT)) {
|
||||
ESP_LOGW(TAG, "CPU has been reset by WDT.");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void bootloader_super_wdt_auto_feed(void)
|
||||
{
|
||||
REG_WRITE(LP_WDT_SWD_WPROTECT_REG, LP_WDT_SWD_WKEY_VALUE);
|
||||
REG_SET_BIT(LP_WDT_SWD_CONFIG_REG, LP_WDT_SWD_AUTO_FEED_EN);
|
||||
REG_WRITE(LP_WDT_SWD_WPROTECT_REG, 0);
|
||||
}
|
||||
#endif // SOC_RTC_WDT_SUPPORTED
|
||||
|
||||
static inline void bootloader_hardware_init(void)
|
||||
{
|
||||
_regi2c_ctrl_ll_master_enable_clock(true); // keep ana i2c mst clock always enabled in bootloader
|
||||
regi2c_ctrl_ll_master_configure_clock();
|
||||
|
||||
unsigned chip_version = efuse_hal_chip_revision();
|
||||
if (!ESP_CHIP_REV_ABOVE(chip_version, 1)) {
|
||||
// On ESP32P4 ECO0, the default (power on reset) CPLL and SPLL frequencies are very high, lower them to avoid bias may not be enough in bootloader
|
||||
// And we are fixing SPLL to be 480MHz after app is up
|
||||
REGI2C_WRITE_MASK(I2C_CPLL, I2C_CPLL_OC_DIV_7_0, 6); // lower default cpu_pll freq to 400M
|
||||
REGI2C_WRITE_MASK(I2C_SYSPLL, I2C_SYSPLL_OC_DIV_7_0, 8); // lower default sys_pll freq to 480M
|
||||
esp_rom_delay_us(100);
|
||||
}
|
||||
REGI2C_WRITE_MASK(I2C_BIAS, I2C_BIAS_DREG_1P1, 10);
|
||||
REGI2C_WRITE_MASK(I2C_BIAS, I2C_BIAS_DREG_1P1_PVT, 10);
|
||||
|
||||
#if !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
|
||||
// IDF-10019 TODO: This is temporarily for ESP32P4-ECO0, please remove it when eco0 is not widly used.
|
||||
if (likely(ESP_CHIP_REV_ABOVE(chip_version, 1))) {
|
||||
bootloader_init_mspi_clock();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void bootloader_ana_reset_config(void)
|
||||
{
|
||||
//Enable super WDT reset.
|
||||
bootloader_ana_super_wdt_reset_config(true);
|
||||
//Enable BOD reset (mode1)
|
||||
brownout_ll_ana_reset_enable(true);
|
||||
}
|
||||
|
||||
esp_err_t bootloader_init(void)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
bootloader_hardware_init();
|
||||
bootloader_ana_reset_config();
|
||||
#if SOC_RTC_WDT_SUPPORTED
|
||||
bootloader_super_wdt_auto_feed();
|
||||
#endif
|
||||
|
||||
// In RAM_APP, memory will be initialized in `call_start_cpu0`
|
||||
#if !CONFIG_APP_BUILD_TYPE_RAM
|
||||
// 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();
|
||||
#endif // !CONFIG_APP_BUILD_TYPE_RAM
|
||||
|
||||
// init eFuse virtual mode (read eFuses to RAM)
|
||||
#ifdef CONFIG_EFUSE_VIRTUAL
|
||||
ESP_EARLY_LOGW(TAG, "eFuse virtual mode is enabled. If Secure boot or Flash encryption is enabled then it does not provide any security. FOR TESTING ONLY!");
|
||||
#ifndef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
esp_efuse_init_virtual_mode_in_ram();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// 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();
|
||||
|
||||
#if !CONFIG_APP_BUILD_TYPE_RAM
|
||||
// init cache and mmu
|
||||
bootloader_init_ext_mem();
|
||||
// update flash ID
|
||||
bootloader_flash_update_id();
|
||||
// Check and run XMC startup flow
|
||||
if ((ret = bootloader_flash_xmc_startup()) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "failed when running XMC startup flow, reboot!");
|
||||
return ret;
|
||||
}
|
||||
// read bootloader header
|
||||
if ((ret = bootloader_read_bootloader_header()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
// read chip revision and check if it's compatible to bootloader
|
||||
if ((ret = bootloader_check_bootloader_validity()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
// initialize spi flash
|
||||
if ((ret = bootloader_init_spi_flash()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
#endif // !CONFIG_APP_BUILD_TYPE_RAM
|
||||
|
||||
// check reset reason and dump diagnostic info
|
||||
bootloader_check_reset();
|
||||
#if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED
|
||||
// config WDT
|
||||
bootloader_config_wdt();
|
||||
#endif
|
||||
// enable RNG early entropy source
|
||||
bootloader_enable_random();
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include "soc/lp_analog_peri_reg.h"
|
||||
|
||||
void bootloader_ana_super_wdt_reset_config(bool enable)
|
||||
{
|
||||
//TODO: IDF-7514
|
||||
}
|
||||
|
||||
void bootloader_ana_clock_glitch_reset_config(bool enable)
|
||||
{
|
||||
//TODO: IDF-7514
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <strings.h>
|
||||
#include "esp_flash_encrypt.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "esp_log.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_crypto_periph_clk.h"
|
||||
#include "esp_key_mgr.h"
|
||||
#include "hal/key_mgr_hal.h"
|
||||
#include "hal/key_mgr_ll.h"
|
||||
#include "hal/mspi_ll.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "flash_encrypt");
|
||||
|
||||
esp_err_t esp_flash_encryption_enable_secure_features(void)
|
||||
{
|
||||
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC
|
||||
ESP_LOGI(TAG, "Disable UART bootloader encryption...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling UART bootloader encryption");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE
|
||||
ESP_LOGI(TAG, "Disable UART bootloader cache...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SPI_DOWNLOAD_MSPI_DIS);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling UART bootloader cache - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
|
||||
ESP_LOGI(TAG, "Disable JTAG...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_PAD_JTAG);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_JTAG);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DIRECT_BOOT);
|
||||
|
||||
#if defined(CONFIG_SECURE_BOOT_V2_ENABLED) && !defined(CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS)
|
||||
// This bit is set when enabling Secure Boot V2, but we can't enable it until this later point in the first boot
|
||||
// otherwise the Flash Encryption key cannot be read protected
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_flash_encryption_use_efuse_key(void)
|
||||
{
|
||||
esp_crypto_key_mgr_enable_periph_clk(true);
|
||||
|
||||
// Force Key Manager to use eFuse key for XTS-AES operation
|
||||
key_mgr_hal_set_key_usage(ESP_KEY_MGR_FLASH_XTS_AES_KEY, ESP_KEY_MGR_USE_EFUSE_KEY);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <strings.h>
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "esp_log.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "secure_boot");
|
||||
|
||||
esp_err_t esp_secure_boot_enable_secure_features(void)
|
||||
{
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DIRECT_BOOT);
|
||||
|
||||
#ifdef CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE
|
||||
ESP_LOGI(TAG, "Enabling Security download mode...");
|
||||
esp_err_t err = esp_efuse_enable_rom_secure_download_mode();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Could not enable Security download mode...");
|
||||
return err;
|
||||
}
|
||||
#elif CONFIG_SECURE_DISABLE_ROM_DL_MODE
|
||||
ESP_LOGI(TAG, "Disable ROM Download mode...");
|
||||
esp_err_t err = esp_efuse_disable_rom_download_mode();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Could not disable ROM Download mode...");
|
||||
return err;
|
||||
}
|
||||
#else
|
||||
ESP_LOGW(TAG, "UART ROM Download mode kept enabled - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
|
||||
ESP_LOGI(TAG, "Disable hardware & software JTAG...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_PAD_JTAG);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_JTAG);
|
||||
esp_efuse_write_field_cnt(ESP_EFUSE_SOFT_DIS_JTAG, ESP_EFUSE_SOFT_DIS_JTAG[0]->bit_count);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SECURE_BOOT_ENABLE_AGGRESSIVE_KEY_REVOKE
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_AGGRESSIVE_REVOKE);
|
||||
#endif
|
||||
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_EN);
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS
|
||||
bool rd_dis_now = true;
|
||||
#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
|
||||
/* If flash encryption is not enabled yet then don't read-disable efuses yet, do it later in the boot
|
||||
when Flash Encryption is being enabled */
|
||||
rd_dis_now = esp_efuse_is_flash_encryption_enabled();
|
||||
#endif
|
||||
if (rd_dis_now) {
|
||||
ESP_LOGI(TAG, "Prevent read disabling of additional efuses...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
|
||||
}
|
||||
#else
|
||||
ESP_LOGW(TAG, "Allowing read disabling of additional efuses - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "bootloader_common.h"
|
||||
#include "soc/efuse_reg.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
|
||||
#include "bootloader_init.h"
|
||||
#include "bootloader_clock.h"
|
||||
#include "bootloader_flash_config.h"
|
||||
#include "bootloader_mem.h"
|
||||
#include "bootloader_console.h"
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "esp_private/bootloader_flash_internal.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
#include "esp_rom_efuse.h"
|
||||
#include "esp_rom_sys.h"
|
||||
#include "esp_rom_spiflash.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 "esp_cpu.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/extmem_reg.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#include "esp_efuse.h"
|
||||
#include "hal/mmu_hal.h"
|
||||
#include "hal/cache_hal.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "boot.esp32s2");
|
||||
|
||||
#if SOC_RTC_WDT_SUPPORTED
|
||||
void bootloader_enable_cpu_reset_info(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);
|
||||
}
|
||||
|
||||
void bootloader_dump_wdt_reset_info(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%"PRIx32" (waiti mode)", cpu_name, pc);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "WDT reset info: %s CPU PC=0x%"PRIx32, cpu_name, pc);
|
||||
}
|
||||
ESP_LOGD(TAG, "WDT reset info: %s CPU STATUS 0x%08"PRIx32, cpu_name, stat);
|
||||
ESP_LOGD(TAG, "WDT reset info: %s CPU PID 0x%08"PRIx32, cpu_name, pid);
|
||||
ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGINST 0x%08"PRIx32, cpu_name, inst);
|
||||
ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGSTATUS 0x%08"PRIx32, cpu_name, dstat);
|
||||
ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGDATA 0x%08"PRIx32, cpu_name, data);
|
||||
ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGPC 0x%08"PRIx32, cpu_name, pc);
|
||||
ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGLS0STAT 0x%08"PRIx32, cpu_name, lsstat);
|
||||
ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGLS0ADDR 0x%08"PRIx32, cpu_name, lsaddr);
|
||||
ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGLS0DATA 0x%08"PRIx32, cpu_name, lsdata);
|
||||
}
|
||||
|
||||
bool bootloader_check_if_wdt_reset(int cpu, soc_reset_reason_t rst_reason)
|
||||
{
|
||||
(void) cpu;
|
||||
if (rst_reason == RESET_REASON_CORE_RTC_WDT || rst_reason == RESET_REASON_CORE_MWDT0 || rst_reason == RESET_REASON_CORE_MWDT1 ||
|
||||
rst_reason == RESET_REASON_CPU0_MWDT0 || rst_reason == RESET_REASON_CPU0_MWDT1 || rst_reason == RESET_REASON_CPU0_RTC_WDT) {
|
||||
ESP_LOGW(TAG, "PRO CPU has been reset by WDT.");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void bootloader_super_wdt_auto_feed(void)
|
||||
{
|
||||
REG_SET_BIT(RTC_CNTL_SWD_CONF_REG, RTC_CNTL_SWD_AUTO_FEED_EN);
|
||||
}
|
||||
#endif // SOC_RTC_WDT_SUPPORTED
|
||||
|
||||
esp_err_t bootloader_init(void)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
#if SOC_RTC_WDT_SUPPORTED
|
||||
bootloader_super_wdt_auto_feed();
|
||||
#endif
|
||||
// protect memory region
|
||||
|
||||
// In RAM_APP, memory will be initialized in `call_start_cpu0`
|
||||
#if !CONFIG_APP_BUILD_TYPE_RAM
|
||||
bootloader_init_mem();
|
||||
|
||||
/* 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();
|
||||
#endif // !CONFIG_APP_BUILD_TYPE_RAM
|
||||
|
||||
// init eFuse virtual mode (read eFuses to RAM)
|
||||
#ifdef CONFIG_EFUSE_VIRTUAL
|
||||
ESP_EARLY_LOGW(TAG, "eFuse virtual mode is enabled. If Secure boot or Flash encryption is enabled then it does not provide any security. FOR TESTING ONLY!");
|
||||
#ifndef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
esp_efuse_init_virtual_mode_in_ram();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// 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();
|
||||
|
||||
#if !CONFIG_APP_BUILD_TYPE_RAM
|
||||
// init cache and mmu
|
||||
bootloader_init_ext_mem();
|
||||
// Workaround: normal ROM bootloader exits with DROM0 cache unmasked, but 2nd bootloader exits with it masked.
|
||||
REG_CLR_BIT(EXTMEM_PRO_ICACHE_CTRL1_REG, EXTMEM_PRO_ICACHE_MASK_DROM0);
|
||||
// update flash ID
|
||||
bootloader_flash_update_id();
|
||||
// Check and run XMC startup flow
|
||||
if ((ret = bootloader_flash_xmc_startup()) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "failed when running XMC startup flow, reboot!");
|
||||
return ret;
|
||||
}
|
||||
// read bootloader header
|
||||
if ((ret = bootloader_read_bootloader_header()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
// read chip revision and check if it's compatible to bootloader
|
||||
if ((ret = bootloader_check_bootloader_validity()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
// initialize spi flash
|
||||
if ((ret = bootloader_init_spi_flash()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
#endif // !CONFIG_APP_BUILD_TYPE_RAM
|
||||
|
||||
// check reset reason and dump diagnostic info
|
||||
bootloader_check_reset();
|
||||
#if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED
|
||||
// config WDT
|
||||
bootloader_config_wdt();
|
||||
#endif
|
||||
// enable RNG early entropy source
|
||||
bootloader_enable_random();
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
//Not supported but common bootloader calls the function. Do nothing
|
||||
void bootloader_ana_clock_glitch_reset_config(bool enable)
|
||||
{
|
||||
(void)enable;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <strings.h>
|
||||
#include "esp_flash_encrypt.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "esp_log.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "flash_encrypt");
|
||||
|
||||
esp_err_t esp_flash_encryption_enable_secure_features(void)
|
||||
{
|
||||
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC
|
||||
ESP_LOGI(TAG, "Disable UART bootloader encryption...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling UART bootloader encryption");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE
|
||||
ESP_LOGI(TAG, "Disable UART bootloader cache...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_DCACHE);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_ICACHE);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling UART bootloader cache - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
|
||||
ESP_LOGI(TAG, "Disable JTAG...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_HARD_DIS_JTAG);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_BOOT_REMAP);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_LEGACY_SPI_BOOT);
|
||||
|
||||
#if defined(CONFIG_SECURE_BOOT_V2_ENABLED) && !defined(CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS)
|
||||
// This bit is set when enabling Secure Boot V2, but we can't enable it until this later point in the first boot
|
||||
// otherwise the Flash Encryption key cannot be read protected
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_FLASH_SKIP_WRITE_PROTECTION_CACHE
|
||||
// Set write-protection for DIS_ICACHE and DIS_DCACHE to prevent bricking chip in case it will be set accidentally.
|
||||
// esp32s2 has DIS_ICACHE and DIS_DCACHE. Write-protection bit = 2 for both.
|
||||
// List of eFuses with the same write protection bit:
|
||||
// DIS_ICACHE, DIS_DCACHE, DIS_DOWNLOAD_ICACHE, DIS_DOWNLOAD_DCACHE,
|
||||
// DIS_FORCE_DOWNLOAD, DIS_USB, DIS_TWAI, DIS_BOOT_REMAP, SOFT_DIS_JTAG,
|
||||
// HARD_DIS_JTAG, DIS_DOWNLOAD_MANUAL_ENCRYPT.
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_DIS_ICACHE);
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <strings.h>
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "esp_log.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "secure_boot");
|
||||
|
||||
esp_err_t esp_secure_boot_enable_secure_features(void)
|
||||
{
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_BOOT_REMAP);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_LEGACY_SPI_BOOT);
|
||||
|
||||
#ifdef CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE
|
||||
ESP_LOGI(TAG, "Enabling Security download mode...");
|
||||
esp_err_t err = esp_efuse_enable_rom_secure_download_mode();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Could not enable Security download mode...");
|
||||
return err;
|
||||
}
|
||||
#elif CONFIG_SECURE_DISABLE_ROM_DL_MODE
|
||||
ESP_LOGI(TAG, "Disable ROM Download mode...");
|
||||
esp_err_t err = esp_efuse_disable_rom_download_mode();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Could not disable ROM Download mode...");
|
||||
return err;
|
||||
}
|
||||
#else
|
||||
ESP_LOGW(TAG, "UART ROM Download mode kept enabled - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
|
||||
ESP_LOGI(TAG, "Disable hardware & software JTAG...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_HARD_DIS_JTAG);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SOFT_DIS_JTAG);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SECURE_BOOT_ENABLE_AGGRESSIVE_KEY_REVOKE
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_AGGRESSIVE_REVOKE);
|
||||
#endif
|
||||
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_EN);
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS
|
||||
bool rd_dis_now = true;
|
||||
#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
|
||||
/* If flash encryption is not enabled yet then don't read-disable efuses yet, do it later in the boot
|
||||
when Flash Encryption is being enabled */
|
||||
rd_dis_now = esp_efuse_is_flash_encryption_enabled();
|
||||
#endif
|
||||
if (rd_dis_now) {
|
||||
ESP_LOGI(TAG, "Prevent read disabling of additional efuses...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
|
||||
}
|
||||
#else
|
||||
ESP_LOGW(TAG, "Allowing read disabling of additional efuses - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "flash_qio_mode.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 "esp_cpu.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "soc/extmem_reg.h"
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
|
||||
#include "esp_rom_gpio.h"
|
||||
#include "esp_rom_efuse.h"
|
||||
#include "esp_rom_sys.h"
|
||||
#include "esp_rom_spiflash.h"
|
||||
#include "esp32s3/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 "bootloader_console.h"
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "bootloader_soc.h"
|
||||
#include "esp_private/bootloader_flash_internal.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "hal/mmu_hal.h"
|
||||
#include "hal/cache_hal.h"
|
||||
#include "hal/rwdt_ll.h"
|
||||
#include "hal/brownout_ll.h"
|
||||
#include "xtensa/config/core.h"
|
||||
#include "xt_instr_macros.h"
|
||||
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "boot.esp32s3");
|
||||
|
||||
#if SOC_RTC_WDT_SUPPORTED
|
||||
void bootloader_enable_cpu_reset_info(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_PDEBUGENABLE_REG, 1);
|
||||
REG_WRITE(ASSIST_DEBUG_CORE_0_RCD_RECORDING_REG, 1);
|
||||
}
|
||||
|
||||
void bootloader_dump_wdt_reset_info(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 ? ESP_LOG_ATTR_STR("APP") : ESP_LOG_ATTR_STR("PRO");
|
||||
|
||||
stat = 0xdeadbeef;
|
||||
pid = 0;
|
||||
if (cpu == 0) {
|
||||
inst = REG_READ(ASSIST_DEBUG_CORE_0_RCD_PDEBUGINST_REG);
|
||||
dstat = REG_READ(ASSIST_DEBUG_CORE_0_RCD_PDEBUGSTATUS_REG);
|
||||
data = REG_READ(ASSIST_DEBUG_CORE_0_RCD_PDEBUGDATA_REG);
|
||||
pc = REG_READ(ASSIST_DEBUG_CORE_0_RCD_PDEBUGPC_REG);
|
||||
lsstat = REG_READ(ASSIST_DEBUG_CORE_0_RCD_PDEBUGLS0STAT_REG);
|
||||
lsaddr = REG_READ(ASSIST_DEBUG_CORE_0_RCD_PDEBUGLS0ADDR_REG);
|
||||
lsdata = REG_READ(ASSIST_DEBUG_CORE_0_RCD_PDEBUGLS0DATA_REG);
|
||||
} else {
|
||||
#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
|
||||
inst = REG_READ(ASSIST_DEBUG_CORE_1_RCD_PDEBUGINST_REG);
|
||||
dstat = REG_READ(ASSIST_DEBUG_CORE_1_RCD_PDEBUGSTATUS_REG);
|
||||
data = REG_READ(ASSIST_DEBUG_CORE_1_RCD_PDEBUGDATA_REG);
|
||||
pc = REG_READ(ASSIST_DEBUG_CORE_1_RCD_PDEBUGPC_REG);
|
||||
lsstat = REG_READ(ASSIST_DEBUG_CORE_1_RCD_PDEBUGLS0STAT_REG);
|
||||
lsaddr = REG_READ(ASSIST_DEBUG_CORE_1_RCD_PDEBUGLS0ADDR_REG);
|
||||
lsdata = REG_READ(ASSIST_DEBUG_CORE_1_RCD_PDEBUGLS0DATA_REG);
|
||||
#else
|
||||
ESP_LOGE(TAG, "WDT reset info: %s CPU not support!", cpu_name);
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "WDT reset info: %s CPU STATUS 0x%08"PRIx32, cpu_name, stat);
|
||||
ESP_LOGD(TAG, "WDT reset info: %s CPU PID 0x%08"PRIx32, cpu_name, pid);
|
||||
ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGINST 0x%08"PRIx32, cpu_name, inst);
|
||||
ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGSTATUS 0x%08"PRIx32, cpu_name, dstat);
|
||||
ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGDATA 0x%08"PRIx32, cpu_name, data);
|
||||
ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGPC 0x%08"PRIx32, cpu_name, pc);
|
||||
ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGLS0STAT 0x%08"PRIx32, cpu_name, lsstat);
|
||||
ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGLS0ADDR 0x%08"PRIx32, cpu_name, lsaddr);
|
||||
ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGLS0DATA 0x%08"PRIx32, cpu_name, lsdata);
|
||||
}
|
||||
|
||||
bool bootloader_check_if_wdt_reset(int cpu, soc_reset_reason_t rst_reason)
|
||||
{
|
||||
if (cpu == 0 && (rst_reason == RESET_REASON_CORE_RTC_WDT || rst_reason == RESET_REASON_CORE_MWDT0 ||
|
||||
rst_reason == RESET_REASON_CORE_MWDT1 || rst_reason == RESET_REASON_CPU0_MWDT0 ||
|
||||
rst_reason == RESET_REASON_CPU0_RTC_WDT)) {
|
||||
ESP_LOGW(TAG, "PRO CPU has been reset by WDT.");
|
||||
return true;
|
||||
}
|
||||
if (cpu == 1 && (rst_reason == RESET_REASON_CORE_RTC_WDT || rst_reason == RESET_REASON_CORE_MWDT0 ||
|
||||
rst_reason == RESET_REASON_CORE_MWDT1 || rst_reason == RESET_REASON_CPU1_MWDT1 ||
|
||||
rst_reason == RESET_REASON_CPU1_RTC_WDT)) {
|
||||
ESP_LOGW(TAG, "APP CPU has been reset by WDT.");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
#endif // SOC_RTC_WDT_SUPPORTED
|
||||
|
||||
static inline void bootloader_ana_reset_config(void)
|
||||
{
|
||||
//Enable WDT, BOD, and GLITCH reset
|
||||
bootloader_ana_super_wdt_reset_config(true);
|
||||
brownout_ll_ana_reset_enable(true);
|
||||
bootloader_ana_clock_glitch_reset_config(true);
|
||||
}
|
||||
|
||||
esp_err_t bootloader_init(void)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
#if XCHAL_ERRATUM_572
|
||||
uint32_t memctl = XCHAL_CACHE_MEMCTL_DEFAULT;
|
||||
WSR(XT_REG_MEMCTL, memctl);
|
||||
#endif // XCHAL_ERRATUM_572
|
||||
|
||||
bootloader_ana_reset_config();
|
||||
#if SOC_RTC_WDT_SUPPORTED
|
||||
bootloader_super_wdt_auto_feed();
|
||||
#endif
|
||||
|
||||
// In RAM_APP, memory will be initialized in `call_start_cpu0`
|
||||
#if !CONFIG_APP_BUILD_TYPE_RAM
|
||||
// protect memory region
|
||||
bootloader_init_mem();
|
||||
/* 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();
|
||||
#endif // !CONFIG_APP_BUILD_TYPE_RAM
|
||||
|
||||
// init eFuse virtual mode (read eFuses to RAM)
|
||||
#ifdef CONFIG_EFUSE_VIRTUAL
|
||||
ESP_EARLY_LOGW(TAG, "eFuse virtual mode is enabled. If Secure boot or Flash encryption is enabled then it does not provide any security. FOR TESTING ONLY!");
|
||||
#ifndef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
esp_efuse_init_virtual_mode_in_ram();
|
||||
#endif
|
||||
#endif
|
||||
// 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();
|
||||
|
||||
#if !CONFIG_APP_BUILD_TYPE_RAM
|
||||
// init cache and mmu
|
||||
bootloader_init_ext_mem();
|
||||
// update flash ID
|
||||
bootloader_flash_update_id();
|
||||
// Check and run XMC startup flow
|
||||
if ((ret = bootloader_flash_xmc_startup()) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "failed when running XMC startup flow, reboot!");
|
||||
return ret;
|
||||
}
|
||||
// read bootloader header
|
||||
if ((ret = bootloader_read_bootloader_header()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
// read chip revision and check if it's compatible to bootloader
|
||||
if ((ret = bootloader_check_bootloader_validity()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
// initialize spi flash
|
||||
if ((ret = bootloader_init_spi_flash()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
#endif // !CONFIG_APP_BUILD_TYPE_RAM
|
||||
|
||||
// check reset reason and dump diagnostic info
|
||||
bootloader_check_reset();
|
||||
#if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED
|
||||
// config WDT
|
||||
bootloader_config_wdt();
|
||||
#endif
|
||||
// enable RNG early entropy source
|
||||
bootloader_enable_random();
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include "soc/soc.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
|
||||
void bootloader_ana_super_wdt_reset_config(bool enable)
|
||||
{
|
||||
REG_CLR_BIT(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_SUPER_WDT_RST);
|
||||
|
||||
if (enable) {
|
||||
REG_CLR_BIT(RTC_CNTL_SWD_CONF_REG, RTC_CNTL_SWD_BYPASS_RST);
|
||||
} else {
|
||||
REG_SET_BIT(RTC_CNTL_SWD_CONF_REG, RTC_CNTL_SWD_BYPASS_RST);
|
||||
}
|
||||
}
|
||||
|
||||
void bootloader_ana_clock_glitch_reset_config(bool enable)
|
||||
{
|
||||
REG_CLR_BIT(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_GLITCH_RST);
|
||||
|
||||
if (enable) {
|
||||
REG_SET_BIT(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_GLITCH_RST_EN);
|
||||
} else {
|
||||
REG_CLR_BIT(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_GLITCH_RST_EN);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <strings.h>
|
||||
#include "esp_flash_encrypt.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "esp_log.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "flash_encrypt");
|
||||
|
||||
esp_err_t esp_flash_encryption_enable_secure_features(void)
|
||||
{
|
||||
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC
|
||||
ESP_LOGI(TAG, "Disable UART bootloader encryption...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling UART bootloader encryption");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE
|
||||
ESP_LOGI(TAG, "Disable UART bootloader cache...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_DCACHE);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_ICACHE);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling UART bootloader cache - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
|
||||
ESP_LOGI(TAG, "Disable JTAG...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_HARD_DIS_JTAG);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_JTAG);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DIRECT_BOOT);
|
||||
|
||||
#if defined(CONFIG_SECURE_BOOT_V2_ENABLED) && !defined(CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS)
|
||||
// This bit is set when enabling Secure Boot V2, but we can't enable it until this later point in the first boot
|
||||
// otherwise the Flash Encryption key cannot be read protected
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_FLASH_SKIP_WRITE_PROTECTION_CACHE
|
||||
// Set write-protection for DIS_ICACHE and DIS_DCACHE to prevent bricking chip in case it will be set accidentally.
|
||||
// esp32s3 has DIS_ICACHE and DIS_DCACHE. Write-protection bit = 2 for both.
|
||||
// List of eFuses with the same write protection bit:
|
||||
// DIS_ICACHE, DIS_DCACHE, DIS_DOWNLOAD_ICACHE, DIS_DOWNLOAD_DCACHE,
|
||||
// DIS_FORCE_DOWNLOAD, DIS_USB_OTG, DIS_TWAI, DIS_APP_CPU, DIS_PAD_JTAG,
|
||||
// DIS_DOWNLOAD_MANUAL_ENCRYPT, DIS_USB_JTAG, DIS_USB_SERIAL_JTAG, STRAP_JTAG_SEL, USB_PHY_SEL.
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_DIS_ICACHE);
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <strings.h>
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "esp_log.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "secure_boot");
|
||||
|
||||
esp_err_t esp_secure_boot_enable_secure_features(void)
|
||||
{
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DIRECT_BOOT);
|
||||
|
||||
#ifdef CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE
|
||||
ESP_LOGI(TAG, "Enabling Security download mode...");
|
||||
esp_err_t err = esp_efuse_enable_rom_secure_download_mode();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Could not enable Security download mode...");
|
||||
return err;
|
||||
}
|
||||
#elif CONFIG_SECURE_DISABLE_ROM_DL_MODE
|
||||
ESP_LOGI(TAG, "Disable ROM Download mode...");
|
||||
esp_err_t err = esp_efuse_disable_rom_download_mode();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Could not disable ROM Download mode...");
|
||||
return err;
|
||||
}
|
||||
#else
|
||||
ESP_LOGW(TAG, "UART ROM Download mode kept enabled - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
|
||||
ESP_LOGI(TAG, "Disable hardware & software JTAG...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_JTAG);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_HARD_DIS_JTAG);
|
||||
esp_efuse_write_field_cnt(ESP_EFUSE_SOFT_DIS_JTAG, ESP_EFUSE_SOFT_DIS_JTAG[0]->bit_count);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SECURE_BOOT_ENABLE_AGGRESSIVE_KEY_REVOKE
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_AGGRESSIVE_REVOKE);
|
||||
#endif
|
||||
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_EN);
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS
|
||||
bool rd_dis_now = true;
|
||||
#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
|
||||
/* If flash encryption is not enabled yet then don't read-disable efuses yet, do it later in the boot
|
||||
when Flash Encryption is being enabled */
|
||||
rd_dis_now = esp_efuse_is_flash_encryption_enabled();
|
||||
#endif
|
||||
if (rd_dis_now) {
|
||||
ESP_LOGI(TAG, "Prevent read disabling of additional efuses...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
|
||||
}
|
||||
#else
|
||||
ESP_LOGW(TAG, "Allowing read disabling of additional efuses - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "flash_qio_mode.h"
|
||||
#include "bootloader_common.h"
|
||||
#include "bootloader_init.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "bootloader_clock.h"
|
||||
#include "bootloader_flash_config.h"
|
||||
#include "bootloader_mem.h"
|
||||
#include "bootloader_console.h"
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "bootloader_soc.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_private/bootloader_flash_internal.h"
|
||||
#if SOC_RTC_WDT_SUPPORTED
|
||||
#include "soc/rtc_wdt_reg.h"
|
||||
#include "hal/rwdt_ll.h"
|
||||
#endif
|
||||
#include "hal/gpio_ll.h"
|
||||
#include "hal/brownout_ll.h"
|
||||
#include "soc/pmu_reg.h"
|
||||
#include "hal/regi2c_ctrl_ll.h"
|
||||
#include "hal/modem_lpcon_ll.h"
|
||||
#include "soc/reset_reasons.h"
|
||||
#include "hal/assist_debug_ll.h"
|
||||
#include "esp_rom_sys.h"
|
||||
#include "soc/regi2c_bias.h"
|
||||
#include "hal/regi2c_ctrl.h"
|
||||
#include "hal/clk_tree_ll.h"
|
||||
#include "hal/psram_ctrlr_ll.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "boot.esp32s31");
|
||||
|
||||
static inline void bootloader_hardware_init(void)
|
||||
{
|
||||
/* GPIO 41 is not bonded out to the package, Isolate it to suppress
|
||||
* floating leakage.*/
|
||||
gpio_ll_input_disable(&GPIO, 41);
|
||||
gpio_ll_output_disable(&GPIO, 41);
|
||||
gpio_ll_pullup_dis(&GPIO, 41);
|
||||
gpio_ll_pulldown_dis(&GPIO, 41);
|
||||
gpio_ll_func_sel(&GPIO, 41, PIN_FUNC_GPIO);
|
||||
|
||||
modem_lpcon_ll_enable_bus_clock(true);
|
||||
|
||||
#if !CONFIG_IDF_ENV_FPGA
|
||||
/* Enable analog i2c master clock */
|
||||
_regi2c_ctrl_ll_master_enable_clock(true); // keep ana i2c mst clock always enabled in bootloader
|
||||
regi2c_ctrl_ll_master_force_enable_clock(true); // TODO: IDF-14678 Remove this?
|
||||
regi2c_ctrl_ll_master_configure_clock();
|
||||
#endif
|
||||
|
||||
REGI2C_WRITE_MASK(I2C_BIAS, I2C_BIAS_DREG_1P1, 10);
|
||||
REGI2C_WRITE_MASK(I2C_BIAS, I2C_BIAS_DREG_1P1_PVT, 10);
|
||||
|
||||
/* Disable MPLL by default, during mmu_hal_init, a valid clock source is required for the PSRAM,
|
||||
so before shutting down mpll, the PSRAM clock source should be selected to an always-on source. */
|
||||
_psram_ctrlr_ll_select_clk_source(PSRAM_CTRLR_LL_MSPI_ID_2, PSRAM_CLK_SRC_XTAL);
|
||||
_psram_ctrlr_ll_select_clk_source(PSRAM_CTRLR_LL_MSPI_ID_3, PSRAM_CLK_SRC_XTAL);
|
||||
clk_ll_mpll_disable();
|
||||
}
|
||||
|
||||
void bootloader_enable_cpu_reset_info(void)
|
||||
{
|
||||
assist_debug_ll_enable_bus_clock(0, true);
|
||||
assist_debug_ll_enable_pc_recording(0, true);
|
||||
assist_debug_ll_lockup_monitor_enable(0, true);
|
||||
assist_debug_ll_lockup_reset_enable(0);
|
||||
#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
|
||||
assist_debug_ll_enable_bus_clock(1, true);
|
||||
assist_debug_ll_enable_pc_recording(1, true);
|
||||
assist_debug_ll_lockup_monitor_enable(1, true);
|
||||
assist_debug_ll_lockup_reset_enable(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
void bootloader_dump_wdt_reset_info(int cpu)
|
||||
{
|
||||
(void) cpu;
|
||||
// saved PC was already printed by the ROM bootloader.
|
||||
// nothing to do here.
|
||||
}
|
||||
|
||||
bool bootloader_check_if_wdt_reset(int cpu, soc_reset_reason_t reset_reason)
|
||||
{
|
||||
if (cpu == 0 && (reset_reason == RESET_REASON_CORE_MWDT0 || reset_reason == RESET_REASON_CORE_MWDT1 ||
|
||||
reset_reason == RESET_REASON_CORE_RWDT || reset_reason == RESET_REASON_CPU_MWDT ||
|
||||
reset_reason == RESET_REASON_CPU_RWDT || reset_reason == RESET_REASON_SYS_RWDT)) {
|
||||
ESP_LOGW(TAG, "PRO CPU has been reset by WDT.");
|
||||
return true;
|
||||
}
|
||||
if (cpu == 1 && (reset_reason == RESET_REASON_CORE_MWDT0 || reset_reason == RESET_REASON_CORE_MWDT1 ||
|
||||
reset_reason == RESET_REASON_CORE_RWDT || reset_reason == RESET_REASON_CPU_MWDT ||
|
||||
reset_reason == RESET_REASON_CPU_RWDT || reset_reason == RESET_REASON_SYS_RWDT)) {
|
||||
ESP_LOGW(TAG, "APP CPU has been reset by WDT.");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void bootloader_ana_reset_config(void)
|
||||
{
|
||||
//Enable BOD reset
|
||||
brownout_ll_ana_reset_enable(true);
|
||||
bootloader_power_glitch_reset_config(true);
|
||||
}
|
||||
|
||||
#if SOC_RTC_WDT_SUPPORTED
|
||||
static void bootloader_super_wdt_auto_feed(void)
|
||||
{
|
||||
REG_WRITE(RTC_WDT_SWD_WPROTECT_REG, RTC_WDT_SWD_WKEY_VALUE);
|
||||
REG_SET_BIT(RTC_WDT_SWD_CONFIG_REG, RTC_WDT_SWD_AUTO_FEED_EN);
|
||||
REG_WRITE(RTC_WDT_SWD_WPROTECT_REG, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
esp_err_t bootloader_init(void)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
bootloader_hardware_init();
|
||||
bootloader_ana_reset_config();
|
||||
#if SOC_RTC_WDT_SUPPORTED
|
||||
bootloader_super_wdt_auto_feed();
|
||||
#endif
|
||||
|
||||
// In RAM_APP, memory will be initialized in `call_start_cpu0`
|
||||
#if !CONFIG_APP_BUILD_TYPE_RAM
|
||||
// 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();
|
||||
#endif // !CONFIG_APP_BUILD_TYPE_RAM
|
||||
|
||||
// init eFuse virtual mode (read eFuses to RAM)
|
||||
#ifdef CONFIG_EFUSE_VIRTUAL
|
||||
ESP_EARLY_LOGW(TAG, "eFuse virtual mode is enabled. If Secure boot or Flash encryption is enabled then it does not provide any security. FOR TESTING ONLY!");
|
||||
#ifndef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
esp_efuse_init_virtual_mode_in_ram();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// 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();
|
||||
|
||||
#if !CONFIG_APP_BUILD_TYPE_RAM
|
||||
// init cache and mmu
|
||||
bootloader_init_ext_mem();
|
||||
// update flash ID
|
||||
bootloader_flash_update_id();
|
||||
// Check and run XMC startup flow
|
||||
if ((ret = bootloader_flash_xmc_startup()) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "failed when running XMC startup flow, reboot!");
|
||||
return ret;
|
||||
}
|
||||
// read bootloader header
|
||||
if ((ret = bootloader_read_bootloader_header()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
// read chip revision and check if it's compatible to bootloader
|
||||
if ((ret = bootloader_check_bootloader_validity()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
// initialize spi flash
|
||||
if ((ret = bootloader_init_spi_flash()) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
#endif // !CONFIG_APP_BUILD_TYPE_RAM
|
||||
|
||||
// check reset reason and dump diagnostic info
|
||||
bootloader_check_reset();
|
||||
#if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED
|
||||
// config WDT
|
||||
bootloader_config_wdt();
|
||||
#endif
|
||||
// enable RNG early entropy source
|
||||
bootloader_enable_random();
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include "soc/soc.h"
|
||||
#include "soc/lp_analog_peri_reg.h"
|
||||
#include "soc/pmu_reg.h"
|
||||
#include "hal/regi2c_ctrl.h"
|
||||
#include "soc/regi2c_saradc.h"
|
||||
|
||||
void bootloader_ana_super_wdt_reset_config(bool enable)
|
||||
{
|
||||
//TODO: IDF-14678
|
||||
}
|
||||
|
||||
void bootloader_ana_clock_glitch_reset_config(bool enable)
|
||||
{
|
||||
(void)enable;
|
||||
}
|
||||
|
||||
void bootloader_power_glitch_reset_config(bool enable)
|
||||
{
|
||||
//only detect VDDPST POWER GLITCH
|
||||
SET_PERI_REG_MASK(PMU_ANA_PERI_PWR_CTRL_REG, PMU_RSTB_PERIF_I2C);
|
||||
SET_PERI_REG_MASK(PMU_ANA_PERI_PWR_CTRL_REG, PMU_XPD_PERIF_I2C);
|
||||
REGI2C_WRITE_MASK(I2C_SARADC, POWER_GLITCH_XPD_VDET_PERIF, 0);
|
||||
REGI2C_WRITE_MASK(I2C_SARADC, POWER_GLITCH_XPD_VDET_PLLBB, 0);
|
||||
REGI2C_WRITE_MASK(I2C_SARADC, POWER_GLITCH_XPD_VDET_PLL, 0);
|
||||
|
||||
REG_SET_FIELD(LP_ANA_FIB_ENABLE_REG, LP_ANA_ANA_FIB_PWR_GLITCH_ENA, 0);
|
||||
if (enable) {
|
||||
REG_SET_FIELD(LP_ANA_PG_GLITCH_CNTL_REG, LP_ANA_POWER_GLITCH_RESET_ENA, 0xf);
|
||||
} else {
|
||||
REG_SET_FIELD(LP_ANA_PG_GLITCH_CNTL_REG, LP_ANA_POWER_GLITCH_RESET_ENA, 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <strings.h>
|
||||
#include "esp_flash_encrypt.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "esp_log.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_crypto_periph_clk.h"
|
||||
#include "esp_key_mgr.h"
|
||||
#include "hal/key_mgr_hal.h"
|
||||
#include "hal/key_mgr_ll.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "flash_encrypt");
|
||||
|
||||
esp_err_t esp_flash_encryption_enable_secure_features(void)
|
||||
{
|
||||
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC
|
||||
ESP_LOGI(TAG, "Disable UART bootloader encryption...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling UART bootloader encryption");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE
|
||||
ESP_LOGI(TAG, "Disable UART bootloader cache...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SPI_DOWNLOAD_MSPI_DIS);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling UART bootloader cache - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
|
||||
ESP_LOGI(TAG, "Disable JTAG...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_PAD_JTAG);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_JTAG);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DIRECT_BOOT);
|
||||
|
||||
#if CONFIG_SECURE_FLASH_PSEUDO_ROUND_FUNC
|
||||
ESP_LOGI(TAG, "Enable XTS-AES pseudo rounds function...");
|
||||
uint8_t xts_pseudo_level = CONFIG_SECURE_FLASH_PSEUDO_ROUND_FUNC_STRENGTH;
|
||||
esp_efuse_write_field_blob(ESP_EFUSE_XTS_DPA_PSEUDO_LEVEL, &xts_pseudo_level, ESP_EFUSE_XTS_DPA_PSEUDO_LEVEL[0]->bit_count);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SECURE_BOOT_V2_ENABLED) && !defined(CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS)
|
||||
// This bit is set when enabling Secure Boot V2, but we can't enable it until this later point in the first boot
|
||||
// otherwise the Flash Encryption key cannot be read protected
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_flash_encryption_use_efuse_key(void)
|
||||
{
|
||||
esp_crypto_key_mgr_enable_periph_clk(true);
|
||||
|
||||
// Force Key Manager to use eFuse key for XTS-AES operation
|
||||
key_mgr_hal_set_key_usage(ESP_KEY_MGR_FLASH_XTS_AES_KEY, ESP_KEY_MGR_USE_EFUSE_KEY);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <strings.h>
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "esp_log.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "secure_boot");
|
||||
|
||||
esp_err_t esp_secure_boot_enable_secure_features(void)
|
||||
{
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DIRECT_BOOT);
|
||||
|
||||
#ifdef CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE
|
||||
ESP_LOGI(TAG, "Enabling Security download mode...");
|
||||
esp_err_t err = esp_efuse_enable_rom_secure_download_mode();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Could not enable Security download mode...");
|
||||
return err;
|
||||
}
|
||||
#elif CONFIG_SECURE_DISABLE_ROM_DL_MODE
|
||||
ESP_LOGI(TAG, "Disable ROM Download mode...");
|
||||
esp_err_t err = esp_efuse_disable_rom_download_mode();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Could not disable ROM Download mode...");
|
||||
return err;
|
||||
}
|
||||
#else
|
||||
ESP_LOGW(TAG, "UART ROM Download mode kept enabled - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
|
||||
ESP_LOGI(TAG, "Disable hardware & software JTAG...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_PAD_JTAG);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_JTAG);
|
||||
esp_efuse_write_field_cnt(ESP_EFUSE_SOFT_DIS_JTAG, ESP_EFUSE_SOFT_DIS_JTAG[0]->bit_count);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SECURE_BOOT_ENABLE_AGGRESSIVE_KEY_REVOKE
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_AGGRESSIVE_REVOKE);
|
||||
#endif
|
||||
|
||||
#if CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_SHA384_EN);
|
||||
#endif
|
||||
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_EN);
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS
|
||||
bool rd_dis_now = true;
|
||||
#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
|
||||
/* If flash encryption is not enabled yet then don't read-disable efuses yet, do it later in the boot
|
||||
when Flash Encryption is being enabled */
|
||||
rd_dis_now = esp_efuse_is_flash_encryption_enabled();
|
||||
#endif
|
||||
if (rd_dis_now) {
|
||||
ESP_LOGI(TAG, "Prevent read disabling of additional efuses...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
|
||||
}
|
||||
#else
|
||||
ESP_LOGW(TAG, "Allowing read disabling of additional efuses - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,496 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <strings.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "esp_flash_encrypt.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "hal/efuse_hal.h"
|
||||
#include "hal/spi_flash_encrypted_ll.h"
|
||||
#include "hal/spi_flash_encrypt_hal.h"
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#if SOC_KEY_MANAGER_SUPPORTED
|
||||
#include "esp_key_mgr.h"
|
||||
#endif /* SOC_KEY_MANAGER_SUPPORTED */
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define CRYPT_CNT ESP_EFUSE_FLASH_CRYPT_CNT
|
||||
#define WR_DIS_CRYPT_CNT ESP_EFUSE_WR_DIS_FLASH_CRYPT_CNT
|
||||
#else
|
||||
#define CRYPT_CNT ESP_EFUSE_SPI_BOOT_CRYPT_CNT
|
||||
#define WR_DIS_CRYPT_CNT ESP_EFUSE_WR_DIS_SPI_BOOT_CRYPT_CNT
|
||||
#endif
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "flash_encrypt");
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
|
||||
void esp_flash_encryption_init_checks()
|
||||
{
|
||||
esp_flash_enc_mode_t mode;
|
||||
|
||||
#ifdef CONFIG_SECURE_FLASH_CHECK_ENC_EN_IN_APP
|
||||
if (!esp_efuse_is_flash_encryption_enabled()) {
|
||||
ESP_LOGE(TAG, "Flash encryption eFuse bit was not enabled in bootloader but CONFIG_SECURE_FLASH_ENC_ENABLED is on");
|
||||
abort();
|
||||
}
|
||||
#endif // CONFIG_SECURE_FLASH_CHECK_ENC_EN_IN_APP
|
||||
|
||||
// First check is: if Release mode flash encryption & secure boot are enabled then
|
||||
// FLASH_CRYPT_CNT *must* be write protected. This will have happened automatically
|
||||
// if bootloader is IDF V4.0 or newer but may not have happened for previous ESP-IDF bootloaders.
|
||||
#ifdef CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE
|
||||
#ifdef CONFIG_SECURE_BOOT
|
||||
if (esp_secure_boot_enabled() && esp_efuse_is_flash_encryption_enabled()) {
|
||||
bool flash_crypt_cnt_wr_dis = esp_efuse_read_field_bit(WR_DIS_CRYPT_CNT);
|
||||
if (!flash_crypt_cnt_wr_dis) {
|
||||
uint8_t flash_crypt_cnt = 0;
|
||||
esp_efuse_read_field_blob(CRYPT_CNT, &flash_crypt_cnt, CRYPT_CNT[0]->bit_count);
|
||||
if (flash_crypt_cnt == (1<<(CRYPT_CNT[0]->bit_count))-1) {
|
||||
// If encryption counter is already max, no need to write protect it
|
||||
// (this distinction is important on ESP32 ECO3 where write-protected FLASH_CRYPT_CNT also write-protects UART_DL_DIS)
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Flash encryption & Secure Boot together requires FLASH_CRYPT_CNT efuse to be write protected. Fixing now...");
|
||||
esp_flash_write_protect_crypt_cnt();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_SECURE_BOOT
|
||||
#endif // CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE
|
||||
|
||||
// Second check is to print a warning or error if the current running flash encryption mode
|
||||
// doesn't match the expectation from project config (due to mismatched bootloader and app, probably)
|
||||
mode = esp_get_flash_encryption_mode();
|
||||
if (mode == ESP_FLASH_ENC_MODE_DEVELOPMENT) {
|
||||
#ifdef CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE
|
||||
ESP_LOGE(TAG, "Flash encryption error: app is set for RELEASE, but efuses are DEVELOPMENT (device is not secure). See Flash Encryption docs to transition.");
|
||||
#else
|
||||
ESP_LOGW(TAG, "Flash encryption mode is DEVELOPMENT (not secure)");
|
||||
#endif // CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE
|
||||
} else if (mode == ESP_FLASH_ENC_MODE_RELEASE) {
|
||||
ESP_LOGI(TAG, "Flash encryption mode is RELEASE");
|
||||
}
|
||||
}
|
||||
#endif // BOOTLOADER_BUILD
|
||||
|
||||
|
||||
void esp_flash_write_protect_crypt_cnt(void)
|
||||
{
|
||||
esp_efuse_write_field_bit(WR_DIS_CRYPT_CNT);
|
||||
}
|
||||
|
||||
esp_flash_enc_mode_t esp_get_flash_encryption_mode(void)
|
||||
{
|
||||
bool flash_crypt_cnt_wr_dis = false;
|
||||
esp_flash_enc_mode_t mode = ESP_FLASH_ENC_MODE_DEVELOPMENT;
|
||||
|
||||
if (esp_efuse_is_flash_encryption_enabled()) {
|
||||
/* Check if FLASH CRYPT CNT is write protected */
|
||||
|
||||
flash_crypt_cnt_wr_dis = esp_efuse_read_field_bit(WR_DIS_CRYPT_CNT);
|
||||
if (!flash_crypt_cnt_wr_dis) {
|
||||
uint8_t flash_crypt_cnt = 0;
|
||||
esp_efuse_read_field_blob(CRYPT_CNT, &flash_crypt_cnt, CRYPT_CNT[0]->bit_count);
|
||||
if (flash_crypt_cnt == (1 << (CRYPT_CNT[0]->bit_count)) - 1) {
|
||||
flash_crypt_cnt_wr_dis = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (flash_crypt_cnt_wr_dis) {
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
bool dis_dl_cache = esp_efuse_read_field_bit(ESP_EFUSE_DISABLE_DL_CACHE);
|
||||
bool dis_dl_enc = esp_efuse_read_field_bit(ESP_EFUSE_DISABLE_DL_ENCRYPT);
|
||||
bool dis_dl_dec = esp_efuse_read_field_bit(ESP_EFUSE_DISABLE_DL_DECRYPT);
|
||||
/* Check if DISABLE_DL_DECRYPT, DISABLE_DL_ENCRYPT & DISABLE_DL_CACHE are set */
|
||||
if ( dis_dl_cache && dis_dl_enc && dis_dl_dec ) {
|
||||
mode = ESP_FLASH_ENC_MODE_RELEASE;
|
||||
}
|
||||
#else
|
||||
if (esp_efuse_read_field_bit(ESP_EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT)
|
||||
#if SOC_EFUSE_DIS_DOWNLOAD_MSPI
|
||||
&& esp_efuse_read_field_bit(ESP_EFUSE_SPI_DOWNLOAD_MSPI_DIS)
|
||||
#endif
|
||||
#if SOC_EFUSE_DIS_DOWNLOAD_ICACHE
|
||||
&& esp_efuse_read_field_bit(ESP_EFUSE_DIS_DOWNLOAD_ICACHE)
|
||||
#endif
|
||||
#if SOC_EFUSE_DIS_DOWNLOAD_DCACHE
|
||||
&& esp_efuse_read_field_bit(ESP_EFUSE_DIS_DOWNLOAD_DCACHE)
|
||||
#endif
|
||||
) {
|
||||
mode = ESP_FLASH_ENC_MODE_RELEASE;
|
||||
#ifdef CONFIG_SOC_FLASH_ENCRYPTION_XTS_AES_128_DERIVED
|
||||
// This chip supports two types of key: AES128_DERIVED and AES128.
|
||||
// To be in RELEASE mode, it is important for the AES128_DERIVED key that XTS_KEY_LENGTH_256 be write-protected.
|
||||
bool xts_key_len_256_wr_dis = esp_efuse_read_field_bit(WR_DIS_CRYPT_CNT);
|
||||
mode = (xts_key_len_256_wr_dis) ? ESP_FLASH_ENC_MODE_RELEASE : ESP_FLASH_ENC_MODE_DEVELOPMENT;
|
||||
#endif // CONFIG_SOC_FLASH_ENCRYPTION_XTS_AES_128_DERIVED
|
||||
}
|
||||
#endif // !CONFIG_IDF_TARGET_ESP32
|
||||
}
|
||||
} else {
|
||||
mode = ESP_FLASH_ENC_MODE_DISABLED;
|
||||
}
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
void esp_flash_encryption_set_release_mode(void)
|
||||
{
|
||||
esp_flash_enc_mode_t mode = esp_get_flash_encryption_mode();
|
||||
if (mode == ESP_FLASH_ENC_MODE_RELEASE) {
|
||||
return;
|
||||
}
|
||||
if (mode == ESP_FLASH_ENC_MODE_DISABLED) {
|
||||
ESP_LOGE(TAG, "Flash encryption eFuse is not enabled, abort..");
|
||||
abort();
|
||||
return;
|
||||
}
|
||||
// ESP_FLASH_ENC_MODE_DEVELOPMENT -> ESP_FLASH_ENC_MODE_RELEASE
|
||||
esp_efuse_batch_write_begin();
|
||||
if (!esp_efuse_read_field_bit(WR_DIS_CRYPT_CNT)) {
|
||||
size_t flash_crypt_cnt = 0;
|
||||
esp_efuse_read_field_cnt(CRYPT_CNT, &flash_crypt_cnt);
|
||||
if (flash_crypt_cnt != CRYPT_CNT[0]->bit_count) {
|
||||
esp_efuse_write_field_cnt(CRYPT_CNT, CRYPT_CNT[0]->bit_count - flash_crypt_cnt);
|
||||
}
|
||||
}
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DISABLE_DL_CACHE);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DISABLE_DL_ENCRYPT);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DISABLE_DL_DECRYPT);
|
||||
#else
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT);
|
||||
#if SOC_EFUSE_DIS_DOWNLOAD_MSPI
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SPI_DOWNLOAD_MSPI_DIS);
|
||||
#endif
|
||||
#if SOC_EFUSE_DIS_DOWNLOAD_ICACHE
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_ICACHE);
|
||||
#endif
|
||||
#if SOC_EFUSE_DIS_DOWNLOAD_DCACHE
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_DCACHE);
|
||||
#endif
|
||||
#ifdef CONFIG_SOC_FLASH_ENCRYPTION_XTS_AES_128_DERIVED
|
||||
// For AES128_DERIVED, FE key is 16 bytes and XTS_KEY_LENGTH_256 is 0.
|
||||
// It is important to protect XTS_KEY_LENGTH_256 from further changing it to 1. Set write protection for this bit.
|
||||
// Burning WR_DIS_CRYPT_CNT, blocks further changing of eFuses: DIS_DOWNLOAD_MANUAL_ENCRYPT, SPI_BOOT_CRYPT_CNT, [XTS_KEY_LENGTH_256], SECURE_BOOT_EN.
|
||||
esp_efuse_write_field_bit(WR_DIS_CRYPT_CNT);
|
||||
#endif // CONFIG_SOC_FLASH_ENCRYPTION_XTS_AES_128_DERIVED
|
||||
#endif // !CONFIG_IDF_TARGET_ESP32
|
||||
|
||||
#if SOC_FLASH_ENCRYPTION_XTS_AES_SUPPORT_PSEUDO_ROUND && !CONFIG_ESP32P4_SELECTS_REV_LESS_V3
|
||||
if (spi_flash_encrypt_ll_is_pseudo_rounds_function_supported()) {
|
||||
uint8_t xts_pseudo_level = 0;
|
||||
esp_efuse_read_field_blob(ESP_EFUSE_XTS_DPA_PSEUDO_LEVEL, &xts_pseudo_level, ESP_EFUSE_XTS_DPA_PSEUDO_LEVEL[0]->bit_count);
|
||||
|
||||
if (xts_pseudo_level == ESP_XTS_AES_PSEUDO_ROUNDS_DISABLE) {
|
||||
xts_pseudo_level = ESP_XTS_AES_PSEUDO_ROUNDS_LOW;
|
||||
esp_efuse_write_field_blob(ESP_EFUSE_XTS_DPA_PSEUDO_LEVEL, &xts_pseudo_level, ESP_EFUSE_XTS_DPA_PSEUDO_LEVEL[0]->bit_count);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_DIS_CACHE);
|
||||
#else
|
||||
#if SOC_EFUSE_DIS_ICACHE
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_DIS_ICACHE);
|
||||
#endif
|
||||
#endif // !CONFIG_IDF_TARGET_ESP32
|
||||
|
||||
#if CONFIG_SOC_SUPPORTS_SECURE_DL_MODE
|
||||
esp_efuse_enable_rom_secure_download_mode();
|
||||
#else
|
||||
esp_efuse_disable_rom_download_mode();
|
||||
#endif
|
||||
esp_efuse_batch_write_commit();
|
||||
|
||||
if (esp_get_flash_encryption_mode() != ESP_FLASH_ENC_MODE_RELEASE) {
|
||||
ESP_LOGE(TAG, "Flash encryption mode is DEVELOPMENT, abort..");
|
||||
abort();
|
||||
}
|
||||
ESP_LOGI(TAG, "Flash encryption mode is RELEASE");
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
bool esp_flash_encryption_cfg_verify_release_mode(void)
|
||||
{
|
||||
bool result = false;
|
||||
bool secure;
|
||||
|
||||
secure = esp_efuse_is_flash_encryption_enabled();
|
||||
result = secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not enabled Flash Encryption (FLASH_CRYPT_CNT->1 or max)");
|
||||
}
|
||||
|
||||
uint8_t crypt_config = 0;
|
||||
esp_efuse_read_field_blob(ESP_EFUSE_ENCRYPT_CONFIG, &crypt_config, 4);
|
||||
if (crypt_config != EFUSE_FLASH_CRYPT_CONFIG) {
|
||||
result &= false;
|
||||
ESP_LOGW(TAG, "ENCRYPT_CONFIG must be set 0xF (set ENCRYPT_CONFIG->0xF)");
|
||||
}
|
||||
|
||||
uint8_t flash_crypt_cnt = 0;
|
||||
esp_efuse_read_field_blob(ESP_EFUSE_FLASH_CRYPT_CNT, &flash_crypt_cnt, ESP_EFUSE_FLASH_CRYPT_CNT[0]->bit_count);
|
||||
if (flash_crypt_cnt != (1 << (ESP_EFUSE_FLASH_CRYPT_CNT[0]->bit_count)) - 1) {
|
||||
if (!esp_efuse_read_field_bit(ESP_EFUSE_WR_DIS_FLASH_CRYPT_CNT)) {
|
||||
result &= false;
|
||||
ESP_LOGW(TAG, "Not release mode of Flash Encryption (set FLASH_CRYPT_CNT->max or WR_DIS_FLASH_CRYPT_CNT->1)");
|
||||
}
|
||||
}
|
||||
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_DISABLE_DL_ENCRYPT);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not disabled UART bootloader encryption (set DISABLE_DL_ENCRYPT->1)");
|
||||
}
|
||||
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_DISABLE_DL_DECRYPT);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not disabled UART bootloader decryption (set DISABLE_DL_DECRYPT->1)");
|
||||
}
|
||||
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_DISABLE_DL_CACHE);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not disabled UART bootloader MMU cache (set DISABLE_DL_CACHE->1)");
|
||||
}
|
||||
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_DISABLE_JTAG);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not disabled JTAG (set DISABLE_JTAG->1)");
|
||||
}
|
||||
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_CONSOLE_DEBUG_DISABLE);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not disabled ROM BASIC interpreter fallback (set CONSOLE_DEBUG_DISABLE->1)");
|
||||
}
|
||||
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_WR_DIS_DIS_CACHE);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not write-protected DIS_CACHE (set WR_DIS_DIS_CACHE->1)");
|
||||
}
|
||||
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_RD_DIS_BLK1);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not read-protected flash encryption key (set RD_DIS_BLK1->1)");
|
||||
}
|
||||
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_WR_DIS_BLK1);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not write-protected flash encryption key (set WR_DIS_BLK1->1)");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#else // not CONFIG_IDF_TARGET_ESP32
|
||||
bool esp_flash_encryption_cfg_verify_release_mode(void)
|
||||
{
|
||||
bool result = false;
|
||||
bool secure;
|
||||
|
||||
secure = esp_efuse_is_flash_encryption_enabled();
|
||||
result = secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not enabled Flash Encryption (SPI_BOOT_CRYPT_CNT->1 or max)");
|
||||
}
|
||||
|
||||
uint8_t flash_crypt_cnt = 0;
|
||||
esp_efuse_read_field_blob(ESP_EFUSE_SPI_BOOT_CRYPT_CNT, &flash_crypt_cnt, ESP_EFUSE_SPI_BOOT_CRYPT_CNT[0]->bit_count);
|
||||
if (flash_crypt_cnt != (1 << (ESP_EFUSE_SPI_BOOT_CRYPT_CNT[0]->bit_count)) - 1) {
|
||||
if (!esp_efuse_read_field_bit(ESP_EFUSE_WR_DIS_SPI_BOOT_CRYPT_CNT)) {
|
||||
result &= false;
|
||||
ESP_LOGW(TAG, "Not release mode of Flash Encryption (set SPI_BOOT_CRYPT_CNT->max or WR_DIS_SPI_BOOT_CRYPT_CNT->1)");
|
||||
}
|
||||
}
|
||||
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not disabled UART bootloader encryption (set DIS_DOWNLOAD_MANUAL_ENCRYPT->1)");
|
||||
}
|
||||
|
||||
#if SOC_EFUSE_DIS_DOWNLOAD_DCACHE
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_DIS_DOWNLOAD_DCACHE);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not disabled UART bootloader Dcache (set DIS_DOWNLOAD_DCACHE->1)");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SOC_EFUSE_DIS_DOWNLOAD_MSPI
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_SPI_DOWNLOAD_MSPI_DIS);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not disabled UART bootloader download mspi (set DIS_DOWNLOAD_MSPI->1)");
|
||||
}
|
||||
#endif
|
||||
#if SOC_EFUSE_DIS_DOWNLOAD_ICACHE
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_DIS_DOWNLOAD_ICACHE);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not disabled UART bootloader cache (set DIS_DOWNLOAD_ICACHE->1)");
|
||||
}
|
||||
#endif
|
||||
bool soft_dis_jtag_complete = false;
|
||||
#if SOC_EFUSE_SOFT_DIS_JTAG
|
||||
size_t soft_dis_jtag_cnt_val = 0;
|
||||
esp_efuse_read_field_cnt(ESP_EFUSE_SOFT_DIS_JTAG, &soft_dis_jtag_cnt_val);
|
||||
soft_dis_jtag_complete = (soft_dis_jtag_cnt_val == ESP_EFUSE_SOFT_DIS_JTAG[0]->bit_count);
|
||||
if (soft_dis_jtag_complete) {
|
||||
bool hmac_key_found = false;
|
||||
hmac_key_found = esp_efuse_find_purpose(ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_JTAG, NULL);
|
||||
hmac_key_found |= esp_efuse_find_purpose(ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_ALL, NULL);
|
||||
if (!hmac_key_found) {
|
||||
ESP_LOGW(TAG, "SOFT_DIS_JTAG is set but HMAC key with respective purpose not found");
|
||||
soft_dis_jtag_complete = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!soft_dis_jtag_complete) {
|
||||
#if SOC_EFUSE_DIS_PAD_JTAG
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_DIS_PAD_JTAG);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not disabled JTAG PADs (set DIS_PAD_JTAG->1)");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SOC_EFUSE_DIS_USB_JTAG
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_DIS_USB_JTAG);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not disabled USB JTAG (set DIS_USB_JTAG->1)");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SOC_EFUSE_HARD_DIS_JTAG
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_HARD_DIS_JTAG);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not disabled JTAG (set HARD_DIS_JTAG->1)");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if SOC_EFUSE_DIS_DIRECT_BOOT
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_DIS_DIRECT_BOOT);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not disabled direct boot mode (set DIS_DIRECT_BOOT->1)");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SOC_EFUSE_DIS_BOOT_REMAP
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_DIS_BOOT_REMAP);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not disabled boot from RAM (set DIS_BOOT_REMAP->1)");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SOC_EFUSE_DIS_LEGACY_SPI_BOOT
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_DIS_LEGACY_SPI_BOOT);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not disabled Legacy SPI boot (set DIS_LEGACY_SPI_BOOT->1)");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SOC_EFUSE_DIS_ICACHE
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_WR_DIS_DIS_ICACHE);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not write-protected DIS_ICACHE (set WR_DIS_DIS_ICACHE->1)");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CONFIG_SECURE_FLASH_ENCRYPTION_KEY_SOURCE_EFUSES
|
||||
esp_efuse_purpose_t purposes[] = {
|
||||
#if SOC_EFUSE_XTS_AES_KEY_256
|
||||
ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_1,
|
||||
ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_2,
|
||||
#endif
|
||||
#if SOC_EFUSE_XTS_AES_KEY_128
|
||||
ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY,
|
||||
#endif
|
||||
};
|
||||
// S2 and S3 chips have both XTS_AES_128_KEY and XTS_AES_256_KEY_1/2.
|
||||
// The check below does not take into account that XTS_AES_128_KEY and XTS_AES_256_KEY_1/2
|
||||
// are mutually exclusive because this will make the chip not functional.
|
||||
// Only one type key must be configured in eFuses.
|
||||
secure = false;
|
||||
size_t purpose_count = sizeof(purposes) / sizeof(esp_efuse_purpose_t);
|
||||
for (size_t i = 0; i < purpose_count; i++) {
|
||||
esp_efuse_block_t block;
|
||||
if (esp_efuse_find_purpose(purposes[i], &block)) {
|
||||
secure = esp_efuse_get_key_dis_read(block);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not read-protected Flash encryption key in BLOCK%d (set RD_DIS_KEY%d->1)", block, block - EFUSE_BLK_KEY0);
|
||||
}
|
||||
secure = esp_efuse_get_key_dis_write(block);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not write-protected Flash encryption key in BLOCK%d (set WR_DIS_KEY%d->1)", block, block - EFUSE_BLK_KEY0);
|
||||
}
|
||||
|
||||
#if SOC_EFUSE_KEY_PURPOSE_FIELD
|
||||
secure = esp_efuse_get_keypurpose_dis_write(block);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not write-protected KEY_PURPOSE for BLOCK%d (set WR_DIS_KEY_PURPOSE%d->1)", block, block - EFUSE_BLK_KEY0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
result &= secure;
|
||||
#elif CONFIG_SECURE_FLASH_ENCRYPTION_KEY_SOURCE_KEY_MGR
|
||||
#if CONFIG_SECURE_FLASH_ENCRYPTION_AES128
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_KM_XTS_KEY_LENGTH_256);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not enabled Key Manager XTS-AES-128 key (set KM_XTS_KEY_LENGTH_256->1)");
|
||||
}
|
||||
#endif
|
||||
|
||||
const uint32_t force_key_mgr_key = esp_efuse_read_field_bit(ESP_EFUSE_FORCE_USE_KEY_MANAGER_KEY);
|
||||
secure = (force_key_mgr_key & (1 << ESP_KEY_MGR_FORCE_USE_KM_XTS_AES_KEY));
|
||||
result &= secure;
|
||||
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not forcing Key Manager to use XTS-AES key (set FORCE_USE_KEY_MANAGER_KEY->1)");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SOC_FLASH_ENCRYPTION_XTS_AES_SUPPORT_PSEUDO_ROUND && !CONFIG_ESP32P4_SELECTS_REV_LESS_V3
|
||||
if (spi_flash_encrypt_ll_is_pseudo_rounds_function_supported()) {
|
||||
uint8_t xts_pseudo_level = 0;
|
||||
esp_efuse_read_field_blob(ESP_EFUSE_XTS_DPA_PSEUDO_LEVEL, &xts_pseudo_level, ESP_EFUSE_XTS_DPA_PSEUDO_LEVEL[0]->bit_count);
|
||||
if (!xts_pseudo_level) {
|
||||
result &= false;
|
||||
ESP_LOGW(TAG, "Not enabled XTS-AES pseudo rounds function (set XTS_DPA_PSEUDO_LEVEL->1 or more)");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
#endif // not CONFIG_IDF_TARGET_ESP32
|
||||
|
||||
// Deprecated function
|
||||
bool IRAM_ATTR esp_flash_encryption_enabled(void)
|
||||
{
|
||||
return esp_efuse_is_flash_encryption_enabled();
|
||||
}
|
||||
@@ -0,0 +1,711 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <strings.h>
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "bootloader_random.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_flash_encrypt.h"
|
||||
#include "esp_flash_partitions.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "esp_log.h"
|
||||
#if SOC_RTC_WDT_SUPPORTED
|
||||
#include "hal/wdt_hal.h"
|
||||
#endif
|
||||
#include "sdkconfig.h"
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#if SOC_KEY_MANAGER_SUPPORTED
|
||||
#include "esp_key_mgr.h"
|
||||
#include "hal/key_mgr_ll.h"
|
||||
#include "rom/key_mgr.h"
|
||||
#include "esp_rom_crc.h"
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK
|
||||
#include "soc/sensitive_reg.h"
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define CRYPT_CNT ESP_EFUSE_FLASH_CRYPT_CNT
|
||||
#define WR_DIS_CRYPT_CNT ESP_EFUSE_WR_DIS_FLASH_CRYPT_CNT
|
||||
#else
|
||||
#define CRYPT_CNT ESP_EFUSE_SPI_BOOT_CRYPT_CNT
|
||||
#define WR_DIS_CRYPT_CNT ESP_EFUSE_WR_DIS_SPI_BOOT_CRYPT_CNT
|
||||
#endif
|
||||
|
||||
#define FLASH_ENC_CNT_MAX (CRYPT_CNT[0]->bit_count)
|
||||
|
||||
/* This file implements FLASH ENCRYPTION related APIs to perform
|
||||
* various operations such as programming necessary flash encryption
|
||||
* eFuses, detect whether flash encryption is enabled (by reading eFuse)
|
||||
* and if required encrypt the partitions in flash memory
|
||||
*/
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "flash_encrypt");
|
||||
|
||||
/* Static functions for stages of flash encryption */
|
||||
static esp_err_t encrypt_bootloader(void);
|
||||
static esp_err_t encrypt_and_load_partition_table(uint32_t offset, esp_partition_info_t *partition_table, int *num_partitions);
|
||||
static esp_err_t encrypt_partition(int index, const esp_partition_info_t *partition);
|
||||
static size_t get_flash_encrypt_cnt_value(void);
|
||||
|
||||
static size_t get_flash_encrypt_cnt_value(void)
|
||||
{
|
||||
size_t flash_crypt_cnt = 0;
|
||||
esp_efuse_read_field_cnt(CRYPT_CNT, &flash_crypt_cnt);
|
||||
return flash_crypt_cnt;
|
||||
}
|
||||
|
||||
bool esp_flash_encrypt_initialized_once(void)
|
||||
{
|
||||
return get_flash_encrypt_cnt_value() != 0;
|
||||
}
|
||||
|
||||
bool esp_flash_encrypt_is_write_protected(bool print_error)
|
||||
{
|
||||
if (esp_efuse_read_field_bit(WR_DIS_CRYPT_CNT)) {
|
||||
if (print_error) {
|
||||
ESP_LOGE(TAG, "Flash Encryption cannot be enabled (CRYPT_CNT (%d) is write protected)", get_flash_encrypt_cnt_value());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool esp_flash_encrypt_state(void)
|
||||
{
|
||||
size_t flash_crypt_cnt = get_flash_encrypt_cnt_value();
|
||||
bool flash_crypt_wr_dis = esp_flash_encrypt_is_write_protected(false);
|
||||
|
||||
ESP_LOGV(TAG, "CRYPT_CNT %d, write protection %d", flash_crypt_cnt, flash_crypt_wr_dis);
|
||||
|
||||
if (flash_crypt_cnt % 2 == 1) {
|
||||
/* Flash is already encrypted */
|
||||
int left = (FLASH_ENC_CNT_MAX - flash_crypt_cnt) / 2;
|
||||
if (flash_crypt_wr_dis) {
|
||||
left = 0; /* can't update FLASH_CRYPT_CNT, no more flashes */
|
||||
}
|
||||
ESP_LOGI(TAG, "flash encryption is enabled (%d plaintext flashes left)", left);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
esp_err_t esp_flash_encrypt_check_and_update(void)
|
||||
{
|
||||
bool flash_encryption_enabled = esp_flash_encrypt_state();
|
||||
if (!flash_encryption_enabled) {
|
||||
#ifndef CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED
|
||||
if (esp_flash_encrypt_is_write_protected(true)) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t err = esp_flash_encrypt_init();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Initialization of Flash encryption key failed (%d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = esp_flash_encrypt_contents();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Encryption flash contents failed (%d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = esp_flash_encrypt_enable();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Enabling of Flash encryption failed (%d)", err);
|
||||
return err;
|
||||
}
|
||||
#else
|
||||
ESP_LOGE(TAG, "flash encryption is not enabled, and SECURE_FLASH_REQUIRE_ALREADY_ENABLED "
|
||||
"is set, refusing to boot.");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
#endif // CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#if CONFIG_SECURE_FLASH_ENCRYPTION_KEY_SOURCE_KEY_MGR
|
||||
static esp_err_t key_manager_read_key_recovery_info(esp_key_mgr_key_recovery_info_t *key_recovery_info)
|
||||
{
|
||||
esp_err_t err = ESP_FAIL;
|
||||
uint32_t crc = 0;
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
err = bootloader_flash_read(KEY_HUK_SECTOR_OFFSET(i), (uint32_t *)key_recovery_info, sizeof(esp_key_mgr_key_recovery_info_t), false);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGD(TAG, "Failed to read key recovery info from Key Manager sector %d: %x", i, err);
|
||||
continue;
|
||||
}
|
||||
|
||||
// check Key Recovery Info magic
|
||||
if (key_recovery_info->magic != KEY_HUK_SECTOR_MAGIC) {
|
||||
ESP_LOGD(TAG, "Key Manager sector %d Magic %08x failed", i, key_recovery_info->magic);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (key_recovery_info->key_type != ESP_KEY_MGR_FLASH_XTS_AES_KEY) {
|
||||
ESP_LOGD(TAG, "Key Manager sector %d has incorrect key type %d", i, key_recovery_info->key_type);
|
||||
continue;
|
||||
}
|
||||
|
||||
#if CONFIG_SECURE_FLASH_ENCRYPTION_AES256
|
||||
if (key_recovery_info->key_len != ESP_KEY_MGR_XTS_AES_LEN_256) {
|
||||
ESP_LOGD(TAG, "Key Manager sector %d has incorrect key length %d", i, key_recovery_info->key_len);
|
||||
continue;
|
||||
}
|
||||
#else
|
||||
if (key_recovery_info->key_len != ESP_KEY_MGR_XTS_AES_LEN_128) {
|
||||
ESP_LOGD(TAG, "Key Manager sector %d has incorrect key length %d", i, key_recovery_info->key_len);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
// check HUK Info CRC
|
||||
crc = esp_rom_crc32_le(0, key_recovery_info->huk_info.info, HUK_INFO_LEN);
|
||||
if (crc != key_recovery_info->huk_info.crc) {
|
||||
ESP_LOGD(TAG, "Key Manager sector %d HUK Info CRC error", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
// check Key Info 0 CRC
|
||||
crc = esp_rom_crc32_le(0, key_recovery_info->key_info[0].info, KEY_INFO_LEN);
|
||||
if (crc != key_recovery_info->key_info[0].crc) {
|
||||
ESP_LOGD(TAG, "Key Manager sector %d Key Info 0 CRC error", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
#if CONFIG_SECURE_FLASH_ENCRYPTION_AES256
|
||||
// check Key Info 1 CRC
|
||||
crc = esp_rom_crc32_le(0, key_recovery_info->key_info[1].info, KEY_INFO_LEN);
|
||||
if (crc != key_recovery_info->key_info[1].crc) {
|
||||
ESP_LOGD(TAG, "Key Manager sector %d Key Info 1 CRC error", i);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
ESP_LOGI(TAG, "Valid Key Manager key recovery info found in sector %d", i);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "No valid key recovery info found");
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
static esp_err_t key_manager_generate_key(esp_key_mgr_key_recovery_info_t *key_recovery_info)
|
||||
{
|
||||
ESP_LOGI(TAG, "Deploying new flash encryption key using Key Manager");
|
||||
|
||||
esp_key_mgr_random_key_config_t key_config;
|
||||
memset(&key_config, 0, sizeof(esp_key_mgr_random_key_config_t));
|
||||
|
||||
key_config.key_type = ESP_KEY_MGR_FLASH_XTS_AES_KEY;
|
||||
|
||||
#if CONFIG_SECURE_FLASH_ENCRYPTION_AES256
|
||||
key_config.key_len = ESP_KEY_MGR_XTS_AES_LEN_256;
|
||||
#else
|
||||
key_config.key_len = ESP_KEY_MGR_XTS_AES_LEN_128;
|
||||
#endif
|
||||
|
||||
// Generate a new key and load it into Key Manager
|
||||
esp_err_t err = esp_key_mgr_deploy_key_in_random_mode(&key_config, key_recovery_info);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to generate key for Key Manager: %x", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
ESP_LOGV(TAG, "Successfully deployed new flash encryption key using Key Manager");
|
||||
|
||||
// Write the key recovery info of the newly generated key into the flash
|
||||
for (int i = 0; i < 2; i++) {
|
||||
err = bootloader_flash_erase_sector(i);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to erase sector %d: %x", i, err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
// Write the key recovery info of the newly generated key into the flash
|
||||
err = bootloader_flash_write(KEY_HUK_SECTOR_OFFSET(0), (uint32_t *)key_recovery_info, sizeof(esp_key_mgr_key_recovery_info_t), false);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to write key recovery info to flash: %x", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
ESP_LOGV(TAG, "Successfully wrote the newly generated Flash Encryption key recovery info into the flash");
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t key_manager_check_and_generate_key(void)
|
||||
{
|
||||
/*
|
||||
1. Check if we have a valid key info in the first two sectors of the flash
|
||||
2. If we have a valid key info, check if it is valid
|
||||
1. If the key is valid, use it
|
||||
2. If the key is not valid, generate a new key and load it into key manager
|
||||
3. If not, generate a new key and load it into key manager
|
||||
*/
|
||||
esp_key_mgr_key_recovery_info_t key_recovery_info;
|
||||
|
||||
memset(&key_recovery_info, 0, sizeof(esp_key_mgr_key_recovery_info_t));
|
||||
|
||||
esp_err_t err = key_manager_read_key_recovery_info(&key_recovery_info);
|
||||
if (err == ESP_ERR_NOT_FOUND) {
|
||||
// No valid key recovery info found, generate a new key
|
||||
err = key_manager_generate_key(&key_recovery_info);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to generate key for Key Manager: %x", err);
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
// Valid key recovery info found, use it
|
||||
ESP_LOGI(TAG, "Using pre-deployed Key Manager key for flash encryption");
|
||||
}
|
||||
|
||||
// Recover key using the key recovery info
|
||||
err = esp_key_mgr_activate_key(&key_recovery_info);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to activate Key Manager key: %x", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
static esp_err_t check_and_generate_encryption_keys(void)
|
||||
{
|
||||
#if CONFIG_SECURE_FLASH_ENCRYPTION_KEY_SOURCE_EFUSES
|
||||
size_t key_size = 32;
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
enum { BLOCKS_NEEDED = 1 };
|
||||
esp_efuse_purpose_t purposes[BLOCKS_NEEDED] = {
|
||||
ESP_EFUSE_KEY_PURPOSE_FLASH_ENCRYPTION,
|
||||
};
|
||||
esp_efuse_coding_scheme_t coding_scheme = esp_efuse_get_coding_scheme(EFUSE_BLK_ENCRYPT_FLASH);
|
||||
if (coding_scheme != EFUSE_CODING_SCHEME_NONE && coding_scheme != EFUSE_CODING_SCHEME_3_4) {
|
||||
ESP_LOGE(TAG, "Unknown/unsupported CODING_SCHEME value 0x%x", coding_scheme);
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
if (coding_scheme == EFUSE_CODING_SCHEME_3_4) {
|
||||
key_size = 24;
|
||||
}
|
||||
#else
|
||||
#ifdef CONFIG_SECURE_FLASH_ENCRYPTION_AES256
|
||||
enum { BLOCKS_NEEDED = 2 };
|
||||
esp_efuse_purpose_t purposes[BLOCKS_NEEDED] = {
|
||||
ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_1,
|
||||
ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_2,
|
||||
};
|
||||
if (esp_efuse_find_purpose(ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY, NULL)) {
|
||||
ESP_LOGE(TAG, "XTS_AES_128_KEY is already in use, XTS_AES_256_KEY_1/2 can not be used");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
#else
|
||||
#ifdef CONFIG_SECURE_FLASH_ENCRYPTION_AES128_DERIVED
|
||||
enum { BLOCKS_NEEDED = 1 };
|
||||
esp_efuse_purpose_t purposes[BLOCKS_NEEDED] = {
|
||||
ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS,
|
||||
};
|
||||
key_size = 16;
|
||||
#else
|
||||
enum { BLOCKS_NEEDED = 1 };
|
||||
esp_efuse_purpose_t purposes[BLOCKS_NEEDED] = {
|
||||
ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY,
|
||||
};
|
||||
#endif // CONFIG_SECURE_FLASH_ENCRYPTION_AES128_DERIVED
|
||||
#endif // CONFIG_SECURE_FLASH_ENCRYPTION_AES256
|
||||
#endif // CONFIG_IDF_TARGET_ESP32
|
||||
|
||||
/* Initialize all efuse block entries to invalid (max) value */
|
||||
esp_efuse_block_t blocks[BLOCKS_NEEDED] = {[0 ... BLOCKS_NEEDED-1] = EFUSE_BLK_KEY_MAX};
|
||||
bool has_key = true;
|
||||
for (unsigned i = 0; i < BLOCKS_NEEDED; i++) {
|
||||
bool tmp_has_key = esp_efuse_find_purpose(purposes[i], &blocks[i]);
|
||||
if (tmp_has_key) { // For ESP32: esp_efuse_find_purpose() always returns True, need to check whether the key block is used or not.
|
||||
tmp_has_key &= !esp_efuse_key_block_unused(blocks[i]);
|
||||
}
|
||||
#if CONFIG_SECURE_FLASH_ENCRYPTION_AES256
|
||||
if (i == 1 && tmp_has_key != has_key) {
|
||||
ESP_LOGE(TAG, "Invalid efuse key blocks: Both AES-256 key blocks must be set.");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
#endif
|
||||
has_key &= tmp_has_key;
|
||||
}
|
||||
|
||||
if (!has_key) {
|
||||
/* Generate key */
|
||||
uint8_t keys[BLOCKS_NEEDED][32] = { 0 };
|
||||
ESP_LOGI(TAG, "Generating new flash encryption key...");
|
||||
for (unsigned i = 0; i < BLOCKS_NEEDED; ++i) {
|
||||
bootloader_fill_random(keys[i], key_size);
|
||||
}
|
||||
ESP_LOGD(TAG, "Key generation complete");
|
||||
|
||||
esp_err_t err = esp_efuse_write_keys(purposes, keys, BLOCKS_NEEDED);
|
||||
if (err != ESP_OK) {
|
||||
if (err == ESP_ERR_NOT_ENOUGH_UNUSED_KEY_BLOCKS) {
|
||||
ESP_LOGE(TAG, "Not enough free efuse key blocks (need %d) to continue", BLOCKS_NEEDED);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Failed to write efuse block with purpose (err=0x%x). Can't continue.", err);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
for (unsigned i = 0; i < BLOCKS_NEEDED; i++) {
|
||||
if (!esp_efuse_get_key_dis_write(blocks[i])
|
||||
|| !esp_efuse_get_key_dis_read(blocks[i])
|
||||
|| !esp_efuse_get_keypurpose_dis_write(blocks[i])) { // For ESP32: no keypurpose, it returns always True.
|
||||
ESP_LOGE(TAG, "Invalid key state, check read&write protection for key and keypurpose(if exists)");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
}
|
||||
ESP_LOGI(TAG, "Using pre-loaded flash encryption key in efuse");
|
||||
}
|
||||
|
||||
#if SOC_KEY_MANAGER_FE_KEY_DEPLOY
|
||||
// In the case of Key Manager supported targets, the default XTS-AES key source is set to Key Manager.
|
||||
esp_flash_encryption_use_efuse_key();
|
||||
#endif
|
||||
#elif CONFIG_SECURE_FLASH_ENCRYPTION_KEY_SOURCE_KEY_MGR
|
||||
esp_err_t err = key_manager_check_and_generate_key();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to check and generate key using Key Manager: %x", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
#if CONFIG_SECURE_FLASH_ENCRYPTION_AES128
|
||||
err = esp_efuse_write_field_bit(ESP_EFUSE_KM_XTS_KEY_LENGTH_256);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set the efuse bit KM_XTS_KEY_LENGTH_256: %x", err);
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
const uint32_t force_key_mgr_key_for_fe = 1 << ESP_KEY_MGR_FORCE_USE_KM_XTS_AES_KEY;
|
||||
err = esp_efuse_write_field_blob(ESP_EFUSE_FORCE_USE_KEY_MANAGER_KEY, &force_key_mgr_key_for_fe, ESP_EFUSE_FORCE_USE_KEY_MANAGER_KEY[0]->bit_count);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set the efuse bit %d (XTS-AES key) of FORCE_USE_KEY_MANAGER_KEY: %x", ESP_KEY_MGR_FORCE_USE_KM_XTS_AES_KEY, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
ESP_LOGV(TAG, "Successfully activated the flash encryption key using Key Manager");
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_flash_encrypt_init(void)
|
||||
{
|
||||
if (esp_efuse_is_flash_encryption_enabled()) {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#if CONFIG_SECURE_FLASH_ENCRYPTION_KEY_SOURCE_KEY_MGR
|
||||
if (!(key_mgr_ll_is_supported() && key_mgr_ll_flash_encryption_supported())) {
|
||||
ESP_LOGE(TAG, "Flash Encryption using Key Manager is not supported, please use efuses instead");
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (esp_flash_encrypt_initialized_once()) {
|
||||
#if CONFIG_SECURE_FLASH_ENCRYPTION_KEY_SOURCE_KEY_MGR
|
||||
// Allow generating a new key if the key recovery info is not present in the flash
|
||||
esp_err_t err = key_manager_check_and_generate_key();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to recover key using Key Manager: %x", err);
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/* Very first flash encryption pass: generate keys, etc. */
|
||||
|
||||
esp_efuse_batch_write_begin(); /* Batch all efuse writes at the end of this function */
|
||||
|
||||
/* Before first flash encryption pass, need to initialise key & crypto config */
|
||||
esp_err_t err = check_and_generate_encryption_keys();
|
||||
if (err != ESP_OK) {
|
||||
esp_efuse_batch_write_cancel();
|
||||
return err;
|
||||
}
|
||||
|
||||
err = esp_flash_encryption_enable_secure_features();
|
||||
if (err != ESP_OK) {
|
||||
esp_efuse_batch_write_cancel();
|
||||
return err;
|
||||
}
|
||||
|
||||
err = esp_efuse_batch_write_commit();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Error programming security eFuses (err=0x%x).", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/* Encrypt all flash data that should be encrypted */
|
||||
esp_err_t esp_flash_encrypt_contents(void)
|
||||
{
|
||||
esp_err_t err;
|
||||
esp_partition_info_t partition_table[ESP_PARTITION_TABLE_MAX_ENTRIES];
|
||||
int num_partitions;
|
||||
|
||||
#ifdef CONFIG_SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK
|
||||
REG_WRITE(SENSITIVE_XTS_AES_KEY_UPDATE_REG, 1);
|
||||
#endif
|
||||
|
||||
err = encrypt_bootloader(); // PART_SUBTYPE_BOOTLOADER_PRIMARY
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = encrypt_and_load_partition_table(ESP_PRIMARY_PARTITION_TABLE_OFFSET, partition_table, &num_partitions); // PART_SUBTYPE_PARTITION_TABLE_PRIMARY
|
||||
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++) {
|
||||
if ((partition_table[i].type == PART_TYPE_BOOTLOADER && partition_table[i].subtype == PART_SUBTYPE_BOOTLOADER_PRIMARY)
|
||||
|| (partition_table[i].type == PART_TYPE_PARTITION_TABLE && partition_table[i].subtype == PART_SUBTYPE_PARTITION_TABLE_PRIMARY)) {
|
||||
/* Skip encryption of PRIMARY partitions for bootloader and partition table.
|
||||
* PRIMARY partitions have already been encrypted above.
|
||||
* We allow to encrypt partitions that are not PRIMARY.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
err = encrypt_partition(i, &partition_table[i]);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "All flash regions checked for encryption pass");
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_flash_encrypt_enable(void)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
if (!esp_efuse_is_flash_encryption_enabled()) {
|
||||
|
||||
if (esp_flash_encrypt_is_write_protected(true)) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
size_t flash_crypt_cnt = get_flash_encrypt_cnt_value();
|
||||
|
||||
#ifdef CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE
|
||||
// Go straight to max, permanently enabled
|
||||
ESP_LOGI(TAG, "Setting CRYPT_CNT for permanent encryption");
|
||||
size_t new_flash_crypt_cnt = FLASH_ENC_CNT_MAX - flash_crypt_cnt;
|
||||
#else
|
||||
/* Set least significant 0-bit in flash_crypt_cnt */
|
||||
size_t new_flash_crypt_cnt = 1;
|
||||
#endif
|
||||
ESP_LOGD(TAG, "CRYPT_CNT %d -> %d", flash_crypt_cnt, new_flash_crypt_cnt);
|
||||
err = esp_efuse_write_field_cnt(CRYPT_CNT, new_flash_crypt_cnt);
|
||||
|
||||
#if defined(CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE) && defined(CONFIG_SOC_FLASH_ENCRYPTION_XTS_AES_128_DERIVED)
|
||||
// For AES128_DERIVED, FE key is 16 bytes and XTS_KEY_LENGTH_256 is 0.
|
||||
// It is important to protect XTS_KEY_LENGTH_256 from further changing it to 1. Set write protection for this bit.
|
||||
// Burning WR_DIS_CRYPT_CNT, blocks further changing of eFuses: DOWNLOAD_DIS_MANUAL_ENCRYPT, SPI_BOOT_CRYPT_CNT, [XTS_KEY_LENGTH_256], SECURE_BOOT_EN.
|
||||
esp_efuse_write_field_bit(WR_DIS_CRYPT_CNT);
|
||||
#endif
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Flash encryption completed");
|
||||
|
||||
#ifdef CONFIG_EFUSE_VIRTUAL
|
||||
ESP_LOGW(TAG, "Flash encryption not really completed. Must disable virtual efuses");
|
||||
#endif
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
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...");
|
||||
|
||||
#if CONFIG_SECURE_BOOT_V2_ENABLED
|
||||
/* The image length obtained from esp_image_verify_bootloader includes the sector boundary padding and the signature block lengths */
|
||||
if (image_length > ESP_BOOTLOADER_SIZE) {
|
||||
ESP_LOGE(TAG, "Bootloader is too large to fit Secure Boot V2 signature sector and partition table (configured offset 0x%x)", ESP_PRIMARY_PARTITION_TABLE_OFFSET);
|
||||
return ESP_ERR_INVALID_SIZE;
|
||||
}
|
||||
#endif // CONFIG_SECURE_BOOT_V2_ENABLED
|
||||
|
||||
err = esp_flash_encrypt_region(ESP_PRIMARY_BOOTLOADER_OFFSET, image_length);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to encrypt bootloader in place: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SECURE_BOOT_V1_ENABLED
|
||||
/* If secure boot is enabled and bootloader was plaintext, also
|
||||
* need to encrypt secure boot IV+digest.
|
||||
*/
|
||||
ESP_LOGD(TAG, "Encrypting secure bootloader IV & digest...");
|
||||
err = esp_flash_encrypt_region(FLASH_OFFS_SECURE_BOOT_IV_DIGEST, FLASH_SECTOR_SIZE);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to encrypt bootloader IV & digest in place: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
ESP_LOGI(TAG, "bootloader encrypted successfully");
|
||||
} else {
|
||||
ESP_LOGW(TAG, "no valid bootloader was found");
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t read_and_verify_partition_table(uint32_t offset, esp_partition_info_t *partition_table, int *num_partitions)
|
||||
{
|
||||
esp_err_t err;
|
||||
/* Check for plaintext partition table */
|
||||
err = bootloader_flash_read(offset, partition_table, ESP_PARTITION_TABLE_MAX_LEN, false);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to read partition table data at 0x%" PRIx32, offset);
|
||||
return err;
|
||||
}
|
||||
err = esp_partition_table_verify(partition_table, false, num_partitions);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to read partition table data - not plaintext or empty?");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static esp_err_t encrypt_and_load_partition_table(uint32_t offset, esp_partition_info_t *partition_table, int *num_partitions)
|
||||
{
|
||||
esp_err_t err = read_and_verify_partition_table(offset, partition_table, num_partitions);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
ESP_LOGD(TAG, "partition table is plaintext. Encrypting...");
|
||||
err = esp_flash_encrypt_region(offset, FLASH_SECTOR_SIZE);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to encrypt partition table in place. %x", err);
|
||||
return err;
|
||||
}
|
||||
ESP_LOGI(TAG, "partition table encrypted and loaded successfully");
|
||||
return err;
|
||||
}
|
||||
|
||||
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);
|
||||
uint32_t size = partition->pos.size;
|
||||
|
||||
if (partition->type == PART_TYPE_APP || partition->type == PART_TYPE_BOOTLOADER) {
|
||||
/* check if the partition holds a valid unencrypted app/bootloader */
|
||||
esp_image_metadata_t image_data = {};
|
||||
if (partition->type == PART_TYPE_BOOTLOADER) {
|
||||
esp_image_bootloader_offset_set(partition->pos.offset);
|
||||
}
|
||||
err = esp_image_verify(ESP_IMAGE_VERIFY, &partition->pos, &image_data);
|
||||
should_encrypt = (err == ESP_OK);
|
||||
#ifdef CONFIG_SECURE_FLASH_ENCRYPT_ONLY_IMAGE_LEN_IN_APP_PART
|
||||
if (partition->type == PART_TYPE_APP && should_encrypt) {
|
||||
// Encrypt only the app image instead of encrypting the whole partition
|
||||
size = image_data.image_len;
|
||||
#if CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT
|
||||
// If secure update without secure boot, also encrypt the signature block
|
||||
size += esp_secure_boot_sig_block_size();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
} else if (partition->type == PART_TYPE_PARTITION_TABLE) {
|
||||
/* check if the partition holds a valid unencrypted partition table */
|
||||
esp_partition_info_t partition_table[ESP_PARTITION_TABLE_MAX_ENTRIES];
|
||||
int num_partitions;
|
||||
err = read_and_verify_partition_table(partition->pos.offset, partition_table, &num_partitions);
|
||||
should_encrypt = (err == ESP_OK && num_partitions != 0);
|
||||
} else if ((partition->type == PART_TYPE_DATA && partition->subtype == PART_SUBTYPE_DATA_OTA)
|
||||
|| (partition->type == PART_TYPE_DATA && partition->subtype == PART_SUBTYPE_DATA_TEE_OTA)
|
||||
|| (partition->type == PART_TYPE_DATA && partition->subtype == PART_SUBTYPE_DATA_NVS_KEYS)) {
|
||||
/* 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%" PRIx32 " (length 0x%" PRIx32 ")...", index, partition->pos.offset, size);
|
||||
|
||||
err = esp_flash_encrypt_region(partition->pos.offset, 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%" PRIx32, src_addr);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
#if SOC_RTC_WDT_SUPPORTED
|
||||
wdt_hal_context_t rtc_wdt_ctx = RWDT_HAL_CONTEXT_DEFAULT();
|
||||
#endif
|
||||
|
||||
for (size_t i = 0; i < data_length; i += FLASH_SECTOR_SIZE) {
|
||||
#if SOC_RTC_WDT_SUPPORTED
|
||||
wdt_hal_write_protect_disable(&rtc_wdt_ctx);
|
||||
wdt_hal_feed(&rtc_wdt_ctx);
|
||||
wdt_hal_write_protect_enable(&rtc_wdt_ctx);
|
||||
#endif
|
||||
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;
|
||||
}
|
||||
|
||||
#endif // CONFIG_SECURE_FLASH_ENC_ENABLED
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <string.h>
|
||||
#include "esp_flash_partitions.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_rom_md5.h"
|
||||
#include "esp_rom_spiflash.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "flash_parts");
|
||||
|
||||
esp_err_t esp_partition_table_verify(const esp_partition_info_t *partition_table, bool log_errors, int *num_partitions)
|
||||
{
|
||||
int md5_found = 0;
|
||||
size_t num_parts;
|
||||
uint32_t chip_size = g_rom_flashchip.chip_size;
|
||||
*num_partitions = 0;
|
||||
|
||||
for (num_parts = 0; num_parts < ESP_PARTITION_TABLE_MAX_ENTRIES; num_parts++) {
|
||||
const esp_partition_info_t *part = &partition_table[num_parts];
|
||||
|
||||
if (part->magic == ESP_PARTITION_MAGIC) {
|
||||
const esp_partition_pos_t *pos = &part->pos;
|
||||
if (pos->offset > chip_size || pos->size > chip_size - pos->offset) {
|
||||
if (log_errors) {
|
||||
ESP_LOGE(TAG, "partition %d invalid - offset 0x%"PRIx32" size 0x%"PRIx32" exceeds flash chip size 0x%"PRIx32,
|
||||
num_parts, pos->offset, pos->size, chip_size);
|
||||
}
|
||||
return ESP_ERR_INVALID_SIZE;
|
||||
}
|
||||
} else if (part->magic == ESP_PARTITION_MAGIC_MD5) {
|
||||
if (md5_found) {
|
||||
if (log_errors) {
|
||||
ESP_LOGE(TAG, "Only one MD5 checksum is allowed");
|
||||
}
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
md5_context_t context;
|
||||
unsigned char digest[16];
|
||||
esp_rom_md5_init(&context);
|
||||
esp_rom_md5_update(&context, (unsigned char *) partition_table, num_parts * sizeof(esp_partition_info_t));
|
||||
esp_rom_md5_final(digest, &context);
|
||||
|
||||
unsigned char *md5sum = ((unsigned char *) part) + ESP_PARTITION_MD5_OFFSET;
|
||||
|
||||
if (memcmp(md5sum, digest, sizeof(digest)) != 0) {
|
||||
if (log_errors) {
|
||||
ESP_LOGE(TAG, "Incorrect MD5 checksum");
|
||||
}
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
//MD5 checksum matches and we continue with the next iteration in
|
||||
//order to detect the end of the partition table
|
||||
md5_found = 1;
|
||||
} else if (num_parts != 0 // the first record cannot be empty, otherwise the whole table is empty
|
||||
&& part->magic == 0xFFFF
|
||||
&& part->type == PART_TYPE_END
|
||||
&& part->subtype == PART_SUBTYPE_END) {
|
||||
ESP_LOGD(TAG, "partition table verified, %d entries", num_parts);
|
||||
*num_partitions = num_parts - md5_found; //do not count the partition where the MD5 checksum is held
|
||||
return ESP_OK;
|
||||
} else {
|
||||
if (log_errors) {
|
||||
ESP_LOGE(TAG, "partition %d invalid magic number 0x%x", num_parts, part->magic);
|
||||
}
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
}
|
||||
|
||||
if (log_errors) {
|
||||
ESP_LOGE(TAG, "partition table has no terminating entry, not valid");
|
||||
}
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
@@ -0,0 +1,464 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <strings.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "hal/efuse_hal.h"
|
||||
|
||||
#ifdef SOC_ECDSA_SUPPORTED
|
||||
#include "hal/ecdsa_ll.h"
|
||||
#endif
|
||||
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
ESP_LOG_ATTR_TAG(TAG, "secure_boot");
|
||||
|
||||
#ifdef CONFIG_SECURE_BOOT
|
||||
static void efuse_batch_write_begin(bool *need_fix)
|
||||
{
|
||||
if (*need_fix == false) {
|
||||
esp_efuse_batch_write_begin();
|
||||
}
|
||||
*need_fix = true;
|
||||
}
|
||||
|
||||
static void update_efuses(bool need_fix, esp_err_t err)
|
||||
{
|
||||
if (need_fix) {
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Can not be fixed (err=0x%x).", err);
|
||||
esp_efuse_batch_write_cancel();
|
||||
} else {
|
||||
err = esp_efuse_batch_write_commit();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Error programming eFuses (err=0x%x)", err);
|
||||
return;
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Fixed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef CONFIG_SECURE_BOOT_V1_ENABLED
|
||||
static esp_err_t secure_boot_v1_check(bool *need_fix)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
esp_efuse_block_t block = EFUSE_BLK_SECURE_BOOT;
|
||||
if (!esp_efuse_get_key_dis_read(block)) {
|
||||
efuse_batch_write_begin(need_fix);
|
||||
ESP_LOGW(TAG, "eFuse BLOCK%d should not be readable. Fixing..", block);
|
||||
err = esp_efuse_set_key_dis_read(block);
|
||||
}
|
||||
if (!esp_efuse_get_key_dis_write(block)) {
|
||||
efuse_batch_write_begin(need_fix);
|
||||
ESP_LOGW(TAG, "eFuse BLOCK%d should not be writeable. Fixing..", block);
|
||||
if (err == ESP_OK) {
|
||||
err = esp_efuse_set_key_dis_write(block);
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
#elif SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS == 1 && CONFIG_SECURE_BOOT_V2_ENABLED
|
||||
static esp_err_t secure_boot_v2_check(bool *need_fix)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
esp_efuse_block_t block = EFUSE_BLK_SECURE_BOOT;
|
||||
#ifndef CONFIG_SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK
|
||||
if (esp_efuse_get_key_dis_read(block)) {
|
||||
ESP_LOGE(TAG, "eFuse BLOCK%d should be readable", block);
|
||||
abort();
|
||||
// This code is not achievable because the bootloader will not boot an app in this state.
|
||||
// But we keep it here just in case (any unexpected behavior).
|
||||
}
|
||||
#endif
|
||||
if (esp_efuse_block_is_empty(block)) {
|
||||
ESP_LOGE(TAG, "eFuse BLOCK%d should not be empty", block);
|
||||
abort();
|
||||
// This code is not achievable because the bootloader will not boot an app in this state.
|
||||
// But we keep it here just in case (any unexpected behavior).
|
||||
}
|
||||
if (!esp_efuse_get_key_dis_write(block)) {
|
||||
efuse_batch_write_begin(need_fix);
|
||||
ESP_LOGW(TAG, "eFuse BLOCK%d should not be writeable. Fixing..", block);
|
||||
err = esp_efuse_set_key_dis_write(block);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
#elif SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS > 1 && CONFIG_SECURE_BOOT_V2_ENABLED
|
||||
static esp_err_t secure_boot_v2_check(bool *need_fix)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
esp_efuse_purpose_t purpose[SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS] = {
|
||||
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST0,
|
||||
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST1,
|
||||
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST2,
|
||||
};
|
||||
|
||||
for (unsigned i = 0; i < SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS; ++i) {
|
||||
esp_efuse_block_t block;
|
||||
if (esp_efuse_find_purpose(purpose[i], &block)) {
|
||||
if (!esp_efuse_get_digest_revoke(i)) {
|
||||
if (esp_efuse_get_key_dis_read(block)) {
|
||||
ESP_LOGE(TAG, "eFuse BLOCK%d should be readable", block);
|
||||
abort();
|
||||
// This state is not expected unless the eFuses have been manually misconfigured.
|
||||
}
|
||||
if (esp_efuse_block_is_empty(block)) {
|
||||
ESP_LOGE(TAG, "eFuse BLOCK%d should not be empty", block);
|
||||
abort();
|
||||
// This state is not expected unless the eFuses have been manually misconfigured.
|
||||
}
|
||||
if (!esp_efuse_get_key_dis_write(block)) {
|
||||
efuse_batch_write_begin(need_fix);
|
||||
ESP_LOGW(TAG, "eFuse BLOCK%d should not be writeable. Fixing..", block);
|
||||
if (err == ESP_OK) {
|
||||
err = esp_efuse_set_key_dis_write(block);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!esp_efuse_get_keypurpose_dis_write(block)) {
|
||||
efuse_batch_write_begin(need_fix);
|
||||
ESP_LOGW(TAG, "The KEY_PURPOSE_SECURE_BOOT_DIGEST%d should be write-protected. Fixing..", block);
|
||||
if (err == ESP_OK) {
|
||||
err = esp_efuse_set_keypurpose_dis_write(block);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!esp_efuse_get_digest_revoke(i)) {
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_UNUSED_DIGEST_SLOTS
|
||||
efuse_batch_write_begin(need_fix);
|
||||
ESP_LOGW(TAG, "Unused SECURE_BOOT_DIGEST%d should be revoked. Fixing..", i);
|
||||
if (err == ESP_OK) {
|
||||
err = esp_efuse_set_digest_revoke(i);
|
||||
}
|
||||
#else
|
||||
ESP_LOGW(TAG, "Unused SECURE_BOOT_DIGEST%d should be revoked. It will not be fixed due to the config", i);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
#endif // CONFIG_SECURE_BOOT
|
||||
|
||||
#if (CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME || CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME) && CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT
|
||||
|
||||
static void check_signature_on_update_check(void)
|
||||
{
|
||||
// We rely on the keys used to sign this app to verify the next app on OTA, so make sure there is at
|
||||
// least one to avoid a stuck firmware
|
||||
esp_image_sig_public_key_digests_t digests = { 0 };
|
||||
|
||||
esp_err_t err = esp_secure_boot_get_signature_blocks_for_running_app(false, &digests);
|
||||
|
||||
if (err != ESP_OK || digests.num_digests == 0) {
|
||||
ESP_LOGE(TAG, "This app is not signed, but check signature on update is enabled in config. It won't be possible to verify any update.");
|
||||
abort();
|
||||
}
|
||||
#if CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT && SECURE_BOOT_NUM_BLOCKS > 1
|
||||
if (digests.num_digests > 1) {
|
||||
ESP_LOGW(TAG, "App has %d signatures. Only the first position of signature blocks is used to verify any update", digests.num_digests);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif // (CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME || CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME) && CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT
|
||||
|
||||
void esp_secure_boot_init_checks(void)
|
||||
{
|
||||
#ifdef CONFIG_SECURE_BOOT
|
||||
|
||||
if (esp_secure_boot_enabled()) {
|
||||
bool need_fix = false;
|
||||
#ifdef CONFIG_SECURE_BOOT_V1_ENABLED
|
||||
esp_err_t err = secure_boot_v1_check(&need_fix);
|
||||
#else
|
||||
esp_err_t err = secure_boot_v2_check(&need_fix);
|
||||
#endif
|
||||
update_efuses(need_fix, err);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Mismatch in secure boot settings: the app config is enabled but eFuse not");
|
||||
}
|
||||
#endif // CONFIG_SECURE_BOOT
|
||||
|
||||
|
||||
#if (CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME || CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME) && CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT
|
||||
check_signature_on_update_check();
|
||||
#endif // (CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME || CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME) && CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT
|
||||
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
bool esp_secure_boot_cfg_verify_release_mode(void)
|
||||
{
|
||||
bool result = false;
|
||||
bool secure;
|
||||
|
||||
bool secure_boot_v1 = esp_efuse_read_field_bit(ESP_EFUSE_ABS_DONE_0);
|
||||
bool chip_supports_sbv2 = efuse_hal_chip_revision() >= 300;
|
||||
bool secure_boot_v2 = (chip_supports_sbv2) ? esp_efuse_read_field_bit(ESP_EFUSE_ABS_DONE_1) : false;
|
||||
result = secure_boot_v1 || secure_boot_v2;
|
||||
if (secure_boot_v1 && secure_boot_v2) {
|
||||
ESP_LOGI(TAG, "ABS_DONE_0=1 (V1) and ABS_DONE_1=1 (V2)");
|
||||
ESP_LOGI(TAG, "Secure boot V2 shall take the precedence");
|
||||
} else if (!secure_boot_v1 && !secure_boot_v2) {
|
||||
result = false;
|
||||
ESP_LOGE(TAG, "Not enabled Secure Boot V1 (set ABS_DONE_0->1)");
|
||||
if (chip_supports_sbv2) {
|
||||
ESP_LOGE(TAG, "Not enabled Secure Boot V2 (set ABS_DONE_1->1)");
|
||||
}
|
||||
}
|
||||
|
||||
if (secure_boot_v1 && !secure_boot_v2) {
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_RD_DIS_BLK2);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not read-protected secure boot key (set RD_DIS_BLK2->1)");
|
||||
}
|
||||
}
|
||||
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_WR_DIS_BLK2);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not write-protected secure boot key (set WR_DIS_BLK2->1)");
|
||||
}
|
||||
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_DISABLE_JTAG);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not disabled JTAG (set DISABLE_JTAG->1)");
|
||||
}
|
||||
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_CONSOLE_DEBUG_DISABLE);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not disabled ROM BASIC interpreter fallback (set CONSOLE_DEBUG_DISABLE->1)");
|
||||
}
|
||||
|
||||
if (secure_boot_v2) {
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_UART_DOWNLOAD_DIS);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not disabled UART ROM Download mode (set UART_DOWNLOAD_DIS->1)");
|
||||
}
|
||||
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_WR_DIS_EFUSE_RD_DISABLE);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not disabled write-protection for read-protection (set WR_DIS_EFUSE_RD_DISABLE->1)");
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#else // not CONFIG_IDF_TARGET_ESP32
|
||||
bool esp_secure_boot_cfg_verify_release_mode(void)
|
||||
{
|
||||
bool result = false;
|
||||
bool secure;
|
||||
|
||||
secure = esp_secure_boot_enabled();
|
||||
result = secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not enabled Secure Boot (SECURE_BOOT_EN->1)");
|
||||
}
|
||||
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_DIS_DOWNLOAD_MODE);
|
||||
bool en_secure_download = esp_efuse_read_field_bit(ESP_EFUSE_ENABLE_SECURITY_DOWNLOAD);
|
||||
if (!secure && !en_secure_download) {
|
||||
result &= false;
|
||||
ESP_LOGW(TAG, "Download mode has not been changed, disable it or set security mode:");
|
||||
ESP_LOGW(TAG, "Not disabled ROM Download mode (DIS_DOWNLOAD_MODE->1)");
|
||||
ESP_LOGW(TAG, "Not enabled Security download mode (ENABLE_SECURITY_DOWNLOAD->1)");
|
||||
}
|
||||
|
||||
#if SOC_EFUSE_DIS_BOOT_REMAP
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_DIS_BOOT_REMAP);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not disabled boot from RAM (set DIS_BOOT_REMAP->1)");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SOC_EFUSE_DIS_LEGACY_SPI_BOOT
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_DIS_LEGACY_SPI_BOOT);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not disabled Legcy SPI boot (set DIS_LEGACY_SPI_BOOT->1)");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SOC_EFUSE_DIS_DIRECT_BOOT
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_DIS_DIRECT_BOOT);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not disabled direct boot mode (set DIS_DIRECT_BOOT->1)");
|
||||
}
|
||||
#endif
|
||||
|
||||
bool soft_dis_jtag_complete = false;
|
||||
#if SOC_EFUSE_SOFT_DIS_JTAG
|
||||
size_t soft_dis_jtag_cnt_val = 0;
|
||||
esp_efuse_read_field_cnt(ESP_EFUSE_SOFT_DIS_JTAG, &soft_dis_jtag_cnt_val);
|
||||
soft_dis_jtag_complete = (soft_dis_jtag_cnt_val == ESP_EFUSE_SOFT_DIS_JTAG[0]->bit_count);
|
||||
if (soft_dis_jtag_complete) {
|
||||
bool hmac_key_found = false;
|
||||
hmac_key_found = esp_efuse_find_purpose(ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_JTAG, NULL);
|
||||
hmac_key_found |= esp_efuse_find_purpose(ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_ALL, NULL);
|
||||
if (!hmac_key_found) {
|
||||
ESP_LOGW(TAG, "SOFT_DIS_JTAG is set but HMAC key with respective purpose not found");
|
||||
soft_dis_jtag_complete = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!soft_dis_jtag_complete) {
|
||||
#if SOC_EFUSE_HARD_DIS_JTAG
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_HARD_DIS_JTAG);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not disabled JTAG (set HARD_DIS_JTAG->1)");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SOC_EFUSE_DIS_PAD_JTAG
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_DIS_PAD_JTAG);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not disabled JTAG PADs (set DIS_PAD_JTAG->1)");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SOC_EFUSE_DIS_USB_JTAG
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_DIS_USB_JTAG);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not disabled USB JTAG (set DIS_USB_JTAG->1)");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef SOC_ECDSA_P192_CURVE_DEFAULT_DISABLED
|
||||
if (ecdsa_ll_is_configurable_curve_supported()) {
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_WR_DIS_ECDSA_CURVE_MODE);
|
||||
if (!secure) {
|
||||
uint8_t current_curve;
|
||||
esp_err_t err = esp_efuse_read_field_blob(ESP_EFUSE_ECDSA_CURVE_MODE, ¤t_curve, ESP_EFUSE_ECDSA_CURVE_MODE[0]->bit_count);
|
||||
if (err == ESP_OK) {
|
||||
if (current_curve != ESP_EFUSE_ECDSA_CURVE_MODE_ALLOW_ONLY_P256_BIT_LOCKED) {
|
||||
// If not P256 mode
|
||||
result &= secure;
|
||||
ESP_LOGW(TAG, "Not write disabled ECDSA curve mode (set WR_DIS_ECDSA_CURVE_MODE->1)");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SECURE_BOOT_ENABLE_AGGRESSIVE_KEY_REVOKE
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_SECURE_BOOT_AGGRESSIVE_REVOKE);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not enabled AGGRESSIVE KEY REVOKE (set SECURE_BOOT_AGGRESSIVE_REVOKE->1)");
|
||||
}
|
||||
#endif
|
||||
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not disabled write-protection for read-protection (set WR_DIS_RD_DIS->1)");
|
||||
}
|
||||
|
||||
#if SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS == 1
|
||||
unsigned purpose = ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_V2;
|
||||
#else
|
||||
unsigned purpose = ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST0; // DIGEST0, DIGEST1 and DIGEST2
|
||||
#endif
|
||||
secure = false;
|
||||
unsigned num_keys = 0;
|
||||
for (unsigned i = 0; i < SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS; ++i) {
|
||||
esp_efuse_block_t block;
|
||||
if (esp_efuse_find_purpose(purpose + i, &block)) {
|
||||
// if chip has a few secure boot slots then we check all
|
||||
#if SOC_SUPPORT_SECURE_BOOT_REVOKE_KEY
|
||||
bool revoke = esp_efuse_get_digest_revoke(i);
|
||||
if (revoke) {
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
++num_keys;
|
||||
#if SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK
|
||||
secure = !esp_efuse_read_field_bit(ESP_EFUSE_RD_DIS_KEY0_HI);
|
||||
#else
|
||||
secure = !esp_efuse_get_key_dis_read(block);
|
||||
#endif // !SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGE(TAG, "Secure boot key in BLOCK%d must NOT be read-protected (can not be used)", block);
|
||||
#if SOC_SUPPORT_SECURE_BOOT_REVOKE_KEY
|
||||
ESP_LOGE(TAG, "Revoke this secure boot key (set SECURE_BOOT_KEY_REVOKE%d->1)", i);
|
||||
#endif
|
||||
}
|
||||
secure = !esp_efuse_block_is_empty(block);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGE(TAG, "Secure boot key in BLOCK%d must NOT be empty (can not be used)", block);
|
||||
#if SOC_SUPPORT_SECURE_BOOT_REVOKE_KEY
|
||||
ESP_LOGE(TAG, "Revoke this secure boot key (set SECURE_BOOT_KEY_REVOKE%d->1)", i);
|
||||
#endif
|
||||
}
|
||||
secure = esp_efuse_get_key_dis_write(block);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not write-protected secure boot key in BLOCK%d (set WR_DIS_KEY%d->1)", block, block - EFUSE_BLK_KEY0);
|
||||
}
|
||||
#if SOC_EFUSE_KEY_PURPOSE_FIELD
|
||||
secure = esp_efuse_get_keypurpose_dis_write(block);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not write-protected KEY_PURPOSE for BLOCK%d (set WR_DIS_KEY_PURPOSE%d->1)", block, block - EFUSE_BLK_KEY0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if SOC_ECDSA_SUPPORT_CURVE_P384
|
||||
#if CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_SECURE_BOOT_SHA384_EN);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not enabled Secure Boot using SHA-384 mode (set SECURE_BOOT_SHA384_EN->1)");
|
||||
}
|
||||
#else
|
||||
#if SOC_EFUSE_SECURE_BOOT_P384_WR_DIS
|
||||
/* When using Secure Boot with SHA-384, the efuse bit representing Secure Boot with SHA-384 would already be programmed.
|
||||
* But in the case of the existing Secure Boot V2 schemes using SHA-256, the efuse bit representing
|
||||
* Secure Boot with SHA-384 needs to be write-protected, so that an attacker cannot perform a denial-of-service
|
||||
* attack by changing the existing secure boot mode using SHA-256 to SHA-384.
|
||||
*/
|
||||
secure = esp_efuse_read_field_bit(ESP_EFUSE_WR_DIS_SECURE_BOOT_SHA384_EN);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGW(TAG, "Not write-protected secure boot using SHA-384 mode (set WR_DIS_SECURE_BOOT_SHA384_EN->1)");
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
secure = (num_keys != 0);
|
||||
result &= secure;
|
||||
if (!secure) {
|
||||
ESP_LOGE(TAG, "No secure boot key found");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif // not CONFIG_IDF_TARGET_ESP32
|
||||
|
||||
#endif // not BOOTLOADER_BUILD
|
||||
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "esp_attr.h"
|
||||
#include "esp_types.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "esp32/rom/cache.h"
|
||||
#include "esp32/rom/secure_boot.h"
|
||||
|
||||
#include "soc/rtc_periph.h"
|
||||
#include "bootloader_utility.h"
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "bootloader_random.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
|
||||
/* The following API implementations are used only when called
|
||||
* from the bootloader code.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_SECURE_BOOT_V1_ENABLED
|
||||
ESP_LOG_ATTR_TAG(TAG, "secure_boot_v1");
|
||||
/**
|
||||
* @function : secure_boot_generate
|
||||
* @description: generate boot digest (aka "abstract") & iv
|
||||
*
|
||||
* @inputs: image_len - length of image to calculate digest for
|
||||
*/
|
||||
static bool secure_boot_generate(uint32_t image_len){
|
||||
esp_err_t err;
|
||||
esp_secure_boot_iv_digest_t digest;
|
||||
const uint32_t *image;
|
||||
|
||||
/* hardware secure boot engine only takes full blocks, so round up the
|
||||
image length. The additional data should all be 0xFF (or the appended SHA, if it falls in the same block).
|
||||
*/
|
||||
if (image_len % sizeof(digest.iv) != 0) {
|
||||
image_len = (image_len / sizeof(digest.iv) + 1) * sizeof(digest.iv);
|
||||
}
|
||||
ets_secure_boot_start();
|
||||
ets_secure_boot_rd_iv((uint32_t *)digest.iv);
|
||||
ets_secure_boot_hash(NULL);
|
||||
/* iv stored in sec 0 */
|
||||
err = bootloader_flash_erase_sector(0);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "SPI erase failed: 0x%x", err);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* generate digest from image contents */
|
||||
image = bootloader_mmap(ESP_BOOTLOADER_OFFSET, image_len);
|
||||
if (!image) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x1000, 0x%" PRIx32 ") failed", image_len);
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 0; i < image_len; i+= sizeof(digest.iv)) {
|
||||
ets_secure_boot_hash(&image[i/sizeof(uint32_t)]);
|
||||
}
|
||||
bootloader_munmap(image);
|
||||
|
||||
ets_secure_boot_obtain();
|
||||
ets_secure_boot_rd_abstract((uint32_t *)digest.digest);
|
||||
ets_secure_boot_finish();
|
||||
|
||||
ESP_LOGD(TAG, "write iv+digest to flash");
|
||||
err = bootloader_flash_write(FLASH_OFFS_SECURE_BOOT_IV_DIGEST, &digest,
|
||||
sizeof(digest), esp_efuse_is_flash_encryption_enabled());
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "SPI write failed: 0x%x", err);
|
||||
return false;
|
||||
}
|
||||
Cache_Read_Enable(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
esp_err_t esp_secure_boot_generate_digest(void)
|
||||
{
|
||||
esp_err_t err;
|
||||
if (esp_secure_boot_enabled()) {
|
||||
ESP_LOGI(TAG, "bootloader secure boot is already enabled."
|
||||
" No need to generate digest. continuing..");
|
||||
return ESP_OK;
|
||||
}
|
||||
#if CONFIG_SECURE_BOOT_REQUIRE_ALREADY_ENABLED
|
||||
else {
|
||||
ESP_LOGE(TAG, "secure boot is not enabled, and SECURE_BOOT_REQUIRE_ALREADY_ENABLED is set, refusing to boot.");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
#endif // CONFIG_SECURE_BOOT_REQUIRE_ALREADY_ENABLED
|
||||
|
||||
esp_efuse_coding_scheme_t coding_scheme = esp_efuse_get_coding_scheme(EFUSE_BLK_SECURE_BOOT);
|
||||
if (coding_scheme != EFUSE_CODING_SCHEME_NONE && coding_scheme != EFUSE_CODING_SCHEME_3_4) {
|
||||
ESP_LOGE(TAG, "Unknown/unsupported CODING_SCHEME value 0x%x", coding_scheme);
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
/* Verify the bootloader */
|
||||
esp_image_metadata_t bootloader_data = { 0 };
|
||||
err = esp_image_verify_bootloader_data(&bootloader_data);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "bootloader image appears invalid! error %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
bool dis_write = esp_efuse_read_field_bit(ESP_EFUSE_WR_DIS_BLK2);
|
||||
bool dis_read = esp_efuse_read_field_bit(ESP_EFUSE_RD_DIS_BLK2);
|
||||
bool key_is_empty = esp_efuse_block_is_empty(EFUSE_BLK_SECURE_BOOT);
|
||||
|
||||
/* Generate secure boot key and keep in EFUSE */
|
||||
if (!dis_read && !dis_write && key_is_empty) {
|
||||
ESP_LOGI(TAG, "Generating new secure boot key...");
|
||||
uint32_t key[8];
|
||||
size_t key_size = 256;
|
||||
if (coding_scheme == EFUSE_CODING_SCHEME_3_4) {
|
||||
key_size = 192;
|
||||
}
|
||||
bootloader_fill_random(key, key_size / 8);
|
||||
esp_efuse_write_block(EFUSE_BLK_SECURE_BOOT, key, 0, key_size);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "Using pre-loaded secure boot key in EFUSE block 2");
|
||||
}
|
||||
|
||||
/* Generate secure boot digest using programmed key in EFUSE */
|
||||
ESP_LOGI(TAG, "Generating secure boot digest...");
|
||||
uint32_t image_len = bootloader_data.image_len;
|
||||
if(bootloader_data.image.hash_appended) {
|
||||
/* Secure boot digest doesn't cover the hash */
|
||||
image_len -= ESP_IMAGE_HASH_LEN;
|
||||
}
|
||||
if (false == secure_boot_generate(image_len)){
|
||||
ESP_LOGE(TAG, "secure boot generation failed");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
ESP_LOGI(TAG, "Digest generation complete.");
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_secure_boot_permanently_enable(void)
|
||||
{
|
||||
if (esp_secure_boot_enabled()) {
|
||||
ESP_LOGI(TAG, "bootloader secure boot is already enabled, continuing..");
|
||||
return ESP_OK;
|
||||
}
|
||||
#if CONFIG_SECURE_BOOT_REQUIRE_ALREADY_ENABLED
|
||||
else {
|
||||
ESP_LOGE(TAG, "secure boot is not enabled, and SECURE_BOOT_REQUIRE_ALREADY_ENABLED is set, refusing to boot.");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
#endif // CONFIG_SECURE_BOOT_REQUIRE_ALREADY_ENABLED
|
||||
|
||||
bool dis_read = esp_efuse_read_field_bit(ESP_EFUSE_RD_DIS_BLK2);
|
||||
bool dis_write = esp_efuse_read_field_bit(ESP_EFUSE_WR_DIS_BLK2);
|
||||
if (dis_read != dis_write) {
|
||||
ESP_LOGE(TAG, "Pre-loaded key is not %s %s protected. Refusing to blow secure boot efuse.",
|
||||
(!dis_read) ? "read,":" ",
|
||||
(!dis_read) ? "write":" ");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
esp_efuse_batch_write_begin(); /* Batch all efuse writes at the end of this function */
|
||||
|
||||
ESP_LOGI(TAG, "blowing secure boot efuse...");
|
||||
esp_err_t err = esp_secure_boot_enable_secure_features();
|
||||
if (err != ESP_OK) {
|
||||
esp_efuse_batch_write_cancel();
|
||||
return err;
|
||||
}
|
||||
|
||||
err = esp_efuse_batch_write_commit();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Error programming security eFuses (err=0x%x).", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
assert(esp_secure_boot_enabled());
|
||||
|
||||
ESP_LOGI(TAG, "secure boot is now enabled for bootloader image");
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif // CONFIG_SECURE_BOOT_V1_ENABLED
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "bootloader_sha.h"
|
||||
#include "bootloader_utility.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "psa/crypto.h"
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
#include "mbedtls/pk.h"
|
||||
|
||||
|
||||
#ifdef CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME
|
||||
ESP_LOG_ATTR_TAG(TAG, "secure_boot_v1");
|
||||
|
||||
extern const uint8_t signature_verification_key_start[] asm("_binary_signature_verification_key_bin_start");
|
||||
extern const uint8_t signature_verification_key_end[] asm("_binary_signature_verification_key_bin_end");
|
||||
|
||||
#define SIGNATURE_VERIFICATION_KEYLEN 64
|
||||
#define PSA_ECDSA_PUB_KEY_SIZE_BITS 256
|
||||
#define UNCOMPRESSED_SECP256R1_KEY_SIZE 65 // Size for uncompressed SECP256R1 (1 + 32 + 32)
|
||||
#define ECC_UNCOMPRESSED_POINT_FORMAT_INDICATOR 0x04
|
||||
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||
{
|
||||
uint8_t digest[ESP_SECURE_BOOT_DIGEST_LEN];
|
||||
uint8_t verified_digest[ESP_SECURE_BOOT_DIGEST_LEN];
|
||||
const esp_secure_boot_sig_block_t *sigblock;
|
||||
|
||||
ESP_LOGD(TAG, "verifying signature src_addr 0x%"PRIx32" length 0x%"PRIx32, src_addr, length);
|
||||
|
||||
esp_err_t err = bootloader_sha256_flash_contents(src_addr, length, digest);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Digest calculation failed 0x%"PRIx32", 0x%"PRIx32, src_addr, length);
|
||||
return err;
|
||||
}
|
||||
|
||||
// Map the signature block and verify the signature
|
||||
sigblock = (const esp_secure_boot_sig_block_t *)bootloader_mmap(src_addr + length, sizeof(esp_secure_boot_sig_block_t));
|
||||
if (sigblock == NULL) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%"PRIx32", 0x%x) failed", src_addr + length, sizeof(esp_secure_boot_sig_block_t));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
err = esp_secure_boot_verify_ecdsa_signature_block(sigblock, digest, verified_digest);
|
||||
bootloader_munmap(sigblock);
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t esp_secure_boot_verify_ecdsa_signature_block(const esp_secure_boot_sig_block_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest)
|
||||
{
|
||||
#if !(defined(CONFIG_MBEDTLS_ECDSA_C) && defined(CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED))
|
||||
ESP_LOGE(TAG, "Signature verification requires ECDSA & SECP256R1 curve enabled");
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
#else
|
||||
ptrdiff_t keylen;
|
||||
|
||||
/* Note: in IDF app image verification we don't add any fault injection resistance, boot-time checks only */
|
||||
memset(verified_digest, 0, ESP_SECURE_BOOT_DIGEST_LEN);
|
||||
|
||||
keylen = signature_verification_key_end - signature_verification_key_start;
|
||||
if (keylen != SIGNATURE_VERIFICATION_KEYLEN) {
|
||||
ESP_LOGE(TAG, "Embedded public verification key has wrong length %d", keylen);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (sig_block->version != ESP_SECURE_BOOT_SCHEME) {
|
||||
ESP_LOGE(TAG, "image has invalid signature version field 0x%08"PRIx32" (image without a signature?)", sig_block->version);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Verifying secure boot signature");
|
||||
psa_status_t status;
|
||||
psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;
|
||||
psa_key_id_t key_handle;
|
||||
|
||||
// Format the public key for PSA import
|
||||
uint8_t formatted_key[UNCOMPRESSED_SECP256R1_KEY_SIZE];
|
||||
formatted_key[0] = ECC_UNCOMPRESSED_POINT_FORMAT_INDICATOR;
|
||||
|
||||
// Copy X and Y coordinates
|
||||
if (keylen == 64) { // Raw coordinates without format byte
|
||||
memcpy(&formatted_key[1], signature_verification_key_start, 64);
|
||||
} else if (keylen == UNCOMPRESSED_SECP256R1_KEY_SIZE && signature_verification_key_start[0] == ECC_UNCOMPRESSED_POINT_FORMAT_INDICATOR) {
|
||||
// Key is already in correct format
|
||||
memcpy(formatted_key, signature_verification_key_start, UNCOMPRESSED_SECP256R1_KEY_SIZE);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Invalid key format or length");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
// Set key attributes
|
||||
psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_VERIFY_HASH);
|
||||
psa_set_key_algorithm(&key_attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256));
|
||||
psa_set_key_type(&key_attributes, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1));
|
||||
psa_set_key_bits(&key_attributes, PSA_ECDSA_PUB_KEY_SIZE_BITS);
|
||||
|
||||
// Import the properly formatted public key
|
||||
status = psa_import_key(&key_attributes, formatted_key, sizeof(formatted_key), &key_handle);
|
||||
if (status != PSA_SUCCESS) {
|
||||
ESP_LOGE(TAG, "Failed to import key, status:%d", status);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
// Verify the signature
|
||||
status = psa_verify_hash(key_handle, PSA_ALG_ECDSA(PSA_ALG_SHA_256), image_digest, ESP_SECURE_BOOT_DIGEST_LEN, sig_block->signature, SIGNATURE_VERIFICATION_KEYLEN);
|
||||
ESP_LOGI(TAG, "Verification result %d", status);
|
||||
|
||||
// Destroy the key handle
|
||||
psa_destroy_key(key_handle);
|
||||
psa_reset_key_attributes(&key_attributes);
|
||||
|
||||
return status == PSA_SUCCESS ? ESP_OK : ESP_ERR_IMAGE_INVALID;
|
||||
#endif // CONFIG_MBEDTLS_ECDSA_C && CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED
|
||||
}
|
||||
#endif // CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "bootloader_sha.h"
|
||||
#include "bootloader_utility.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_fault.h"
|
||||
#include "esp32/rom/sha.h"
|
||||
#include "uECC_verify_antifault.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <string.h>
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "secure_boot");
|
||||
|
||||
#ifdef CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME
|
||||
extern const uint8_t signature_verification_key_start[] asm("_binary_signature_verification_key_bin_start");
|
||||
extern const uint8_t signature_verification_key_end[] asm("_binary_signature_verification_key_bin_end");
|
||||
|
||||
#define SIGNATURE_VERIFICATION_KEYLEN 64
|
||||
|
||||
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||
{
|
||||
uint8_t digest[ESP_SECURE_BOOT_DIGEST_LEN];
|
||||
uint8_t verified_digest[ESP_SECURE_BOOT_DIGEST_LEN] = { 0 }; /* ignored in this function */
|
||||
const esp_secure_boot_sig_block_t *sigblock;
|
||||
|
||||
ESP_LOGD(TAG, "verifying signature src_addr 0x%" PRIx32 " length 0x%" PRIx32, src_addr, length);
|
||||
|
||||
esp_err_t err = bootloader_sha256_flash_contents(src_addr, length, digest);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// Map the signature block
|
||||
sigblock = (const esp_secure_boot_sig_block_t *) bootloader_mmap(src_addr + length, sizeof(esp_secure_boot_sig_block_t));
|
||||
if(!sigblock) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%" PRIx32 ", 0x%x) failed", src_addr + length, sizeof(esp_secure_boot_sig_block_t));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
// Verify the signature
|
||||
err = esp_secure_boot_verify_ecdsa_signature_block(sigblock, digest, verified_digest);
|
||||
// Unmap
|
||||
bootloader_munmap(sigblock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
esp_err_t esp_secure_boot_verify_ecdsa_signature_block(const esp_secure_boot_sig_block_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest)
|
||||
{
|
||||
ptrdiff_t keylen;
|
||||
|
||||
keylen = signature_verification_key_end - signature_verification_key_start;
|
||||
if (keylen != SIGNATURE_VERIFICATION_KEYLEN) {
|
||||
ESP_LOGE(TAG, "Embedded public verification key has wrong length %d", keylen);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (sig_block->version != ESP_SECURE_BOOT_SCHEME) {
|
||||
ESP_LOGE(TAG, "image has invalid signature version field 0x%08" PRIx32 " (image without a signature?)", sig_block->version);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Verifying secure boot signature");
|
||||
|
||||
bool is_valid;
|
||||
is_valid = uECC_verify_antifault(signature_verification_key_start,
|
||||
image_digest,
|
||||
ESP_SECURE_BOOT_DIGEST_LEN,
|
||||
sig_block->signature,
|
||||
uECC_secp256r1(),
|
||||
verified_digest);
|
||||
ESP_LOGD(TAG, "Verification result %d", is_valid);
|
||||
|
||||
return is_valid ? ESP_OK : ESP_ERR_IMAGE_INVALID;
|
||||
}
|
||||
|
||||
#endif // CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME
|
||||
@@ -0,0 +1,411 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "bootloader_sha.h"
|
||||
#include "bootloader_utility.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "secure_boot_signature_priv.h"
|
||||
#include "esp_macros.h"
|
||||
|
||||
|
||||
/* The following API implementations are used only when called
|
||||
* from the bootloader code.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_SECURE_BOOT_V2_ENABLED
|
||||
|
||||
#if CONFIG_SECURE_ENABLE_TEE
|
||||
extern esp_image_metadata_t tee_data;
|
||||
#endif
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "secure_boot_v2");
|
||||
|
||||
/* A signature block is valid when it has correct magic byte, crc and image digest. */
|
||||
static esp_err_t validate_signature_block(const ets_secure_boot_sig_block_t *block, int block_num, const uint8_t *image_digest)
|
||||
{
|
||||
if (block->magic_byte != ETS_SECURE_BOOT_V2_SIGNATURE_MAGIC) {
|
||||
// All signature blocks have been parsed, no new signature block present.
|
||||
ESP_LOGD(TAG, "Signature block(%d) invalid/absent.", block_num);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (block->block_crc != esp_rom_crc32_le(0, (uint8_t *)block, CRC_SIGN_BLOCK_LEN)) {
|
||||
ESP_LOGE(TAG, "Magic byte correct but incorrect crc.");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (memcmp(image_digest, block->image_digest, ESP_SECURE_BOOT_DIGEST_LEN)) {
|
||||
ESP_LOGE(TAG, "Magic byte & CRC correct but incorrect image digest.");
|
||||
return ESP_FAIL;
|
||||
} else {
|
||||
ESP_LOGD(TAG, "valid signature block(%d) found", block_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Generates the public key digests of the valid public keys in an image's
|
||||
signature block, verifies each signature, and stores the key digests in the
|
||||
public_key_digests structure.
|
||||
|
||||
@param flash_offset Image offset in flash
|
||||
@param flash_size Image size in flash (not including signature block)
|
||||
@param[out] public_key_digests Pointer to structure to hold the key digests for valid sig blocks
|
||||
|
||||
|
||||
Note that this function doesn't read any eFuses, so it doesn't know if the
|
||||
keys are ultimately trusted by the hardware or not
|
||||
|
||||
@return - ESP_OK if no signatures failed to verify, or if no valid signature blocks are found at all.
|
||||
- ESP_FAIL if there's a valid signature block that doesn't verify using the included public key (unexpected!)
|
||||
*/
|
||||
static esp_err_t s_calculate_image_public_key_digests(uint32_t flash_offset, uint32_t flash_size, esp_image_sig_public_key_digests_t *public_key_digests)
|
||||
{
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
uint8_t image_digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
|
||||
uint8_t __attribute__((aligned(4))) key_digest[ESP_SECURE_BOOT_KEY_DIGEST_SHA_256_LEN] = {0};
|
||||
size_t sig_block_addr = flash_offset + ESP_ALIGN_UP(flash_size, FLASH_SECTOR_SIZE);
|
||||
|
||||
ESP_LOGD(TAG, "calculating public key digests for sig blocks of image offset 0x%" PRIx32 " (sig block offset 0x%x)", flash_offset, sig_block_addr);
|
||||
|
||||
bzero(public_key_digests, sizeof(esp_image_sig_public_key_digests_t));
|
||||
|
||||
#if CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS
|
||||
ret = bootloader_sha384_flash_contents(flash_offset, sig_block_addr - flash_offset, image_digest);
|
||||
#else
|
||||
ret = bootloader_sha256_flash_contents(flash_offset, sig_block_addr - flash_offset, image_digest);
|
||||
#endif
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "error generating image digest, %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "reading signature(s)");
|
||||
const ets_secure_boot_signature_t *signatures = bootloader_mmap(sig_block_addr, sizeof(ets_secure_boot_signature_t));
|
||||
if (signatures == NULL) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", sig_block_addr, sizeof(ets_secure_boot_signature_t));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Validating Signature block */
|
||||
for (unsigned i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
|
||||
const ets_secure_boot_sig_block_t *block = &signatures->block[i];
|
||||
|
||||
ret = validate_signature_block(block, i, image_digest);
|
||||
if (ret != ESP_OK) {
|
||||
ret = ESP_OK; // past the last valid signature block
|
||||
break;
|
||||
}
|
||||
|
||||
/* Generating the SHA of the public key components in the signature block */
|
||||
bootloader_sha256_handle_t sig_block_sha;
|
||||
sig_block_sha = bootloader_sha256_start();
|
||||
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
bootloader_sha256_data(sig_block_sha, &block->key, sizeof(block->key));
|
||||
#elif CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME
|
||||
bootloader_sha256_data(sig_block_sha, &block->ecdsa.key, sizeof(block->ecdsa.key));
|
||||
#endif
|
||||
bootloader_sha256_finish(sig_block_sha, key_digest);
|
||||
|
||||
// Check we can verify the image using this signature and this key
|
||||
uint8_t temp_verified_digest[ESP_SECURE_BOOT_DIGEST_LEN];
|
||||
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
bool verified = ets_rsa_pss_verify(&block->key, block->signature, image_digest, temp_verified_digest);
|
||||
#elif CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME
|
||||
bool verified = ets_ecdsa_verify(&block->ecdsa.key.point[0], block->ecdsa.signature, block->ecdsa.key.curve_id, image_digest, temp_verified_digest);
|
||||
#endif
|
||||
|
||||
if (!verified) {
|
||||
/* We don't expect this: the signature blocks before we enable secure boot should all be verifiable or invalid,
|
||||
so this is a fatal error
|
||||
*/
|
||||
ret = ESP_FAIL;
|
||||
ESP_LOGE(TAG, "Secure boot key (%d) verification failed.", i);
|
||||
break;
|
||||
}
|
||||
ESP_LOGD(TAG, "Signature block (%d) is verified", i);
|
||||
/* Copy the key digest to the buffer provided by the caller */
|
||||
memcpy((void *)public_key_digests->key_digests[i], key_digest, ESP_SECURE_BOOT_KEY_DIGEST_SHA_256_LEN);
|
||||
public_key_digests->num_digests++;
|
||||
}
|
||||
|
||||
if (ret == ESP_OK && public_key_digests->num_digests > 0) {
|
||||
ESP_LOGI(TAG, "Digests successfully calculated, %d valid signatures (image offset 0x%" PRIx32 ")",
|
||||
public_key_digests->num_digests, flash_offset);
|
||||
}
|
||||
|
||||
bootloader_munmap(signatures);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t check_and_generate_secure_boot_keys(const esp_image_metadata_t *image_data)
|
||||
{
|
||||
esp_err_t ret;
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
esp_efuse_coding_scheme_t coding_scheme = esp_efuse_get_coding_scheme(EFUSE_BLK_SECURE_BOOT);
|
||||
if (coding_scheme != EFUSE_CODING_SCHEME_NONE) {
|
||||
ESP_LOGE(TAG, "No coding schemes are supported in secure boot v2.(Detected scheme: 0x%x)", coding_scheme);
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
#endif // CONFIG_IDF_TARGET_ESP32
|
||||
|
||||
esp_efuse_purpose_t secure_boot_key_purpose[SECURE_BOOT_NUM_BLOCKS] = {
|
||||
#if SECURE_BOOT_NUM_BLOCKS == 1
|
||||
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_V2,
|
||||
#else
|
||||
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST0,
|
||||
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST1,
|
||||
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST2,
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Verify the bootloader */
|
||||
esp_image_metadata_t bootloader_data = { 0 };
|
||||
ret = esp_image_verify_bootloader_data(&bootloader_data);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "bootloader image appears invalid! error %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Initialize all efuse block entries to invalid (max) value */
|
||||
esp_efuse_block_t blocks[SECURE_BOOT_NUM_BLOCKS] = {[0 ... SECURE_BOOT_NUM_BLOCKS-1] = EFUSE_BLK_KEY_MAX};
|
||||
/* Check if secure boot digests are present */
|
||||
bool has_secure_boot_digest = false;
|
||||
for (unsigned i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
|
||||
bool tmp_has_key = esp_efuse_find_purpose(secure_boot_key_purpose[i], &blocks[i]);
|
||||
if (tmp_has_key) { // For ESP32: esp_efuse_find_purpose() always returns True, need to check whether the key block is used or not.
|
||||
tmp_has_key &= !esp_efuse_key_block_unused(blocks[i]);
|
||||
}
|
||||
has_secure_boot_digest |= tmp_has_key;
|
||||
}
|
||||
|
||||
esp_image_sig_public_key_digests_t boot_key_digests = {0};
|
||||
esp_image_sig_public_key_digests_t app_key_digests = {0};
|
||||
ESP_LOGI(TAG, "Secure boot digests %s", has_secure_boot_digest ? "already present":"absent, generating..");
|
||||
|
||||
if (!has_secure_boot_digest) {
|
||||
/* Generate the bootloader public key digests */
|
||||
ret = s_calculate_image_public_key_digests(bootloader_data.start_addr, bootloader_data.image_len - SIG_BLOCK_PADDING, &boot_key_digests);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Bootloader signature block is invalid");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (boot_key_digests.num_digests == 0) {
|
||||
ESP_LOGE(TAG, "No valid bootloader signature blocks found.");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
ESP_LOGI(TAG, "%d signature block(s) found appended to the bootloader.", boot_key_digests.num_digests);
|
||||
|
||||
ESP_LOGI(TAG, "Burning public key hash to eFuse");
|
||||
ret = esp_efuse_write_keys(secure_boot_key_purpose, boot_key_digests.key_digests, boot_key_digests.num_digests);
|
||||
if (ret != ESP_OK) {
|
||||
if (ret == ESP_ERR_NOT_ENOUGH_UNUSED_KEY_BLOCKS) {
|
||||
ESP_LOGE(TAG, "Bootloader signatures(%d) more than available key slots.", boot_key_digests.num_digests);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Failed to write efuse block with purpose (err=0x%x). Can't continue.", ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
for (unsigned i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
|
||||
/* Check if corresponding digest slot is used or not */
|
||||
if (blocks[i] == EFUSE_BLK_KEY_MAX) {
|
||||
ESP_LOGD(TAG, "SECURE_BOOT_DIGEST%d slot is not used", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
#if SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS
|
||||
if (esp_efuse_get_digest_revoke(i)) {
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
#ifndef CONFIG_SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK
|
||||
if (esp_efuse_get_key_dis_read(blocks[i])) {
|
||||
ESP_LOGE(TAG, "Key digest (BLK%d) read protected, aborting...", blocks[i]);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
#endif
|
||||
if (esp_efuse_block_is_empty(blocks[i])) {
|
||||
ESP_LOGE(TAG, "%d eFuse block is empty, aborting...", blocks[i]);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
esp_efuse_set_key_dis_write(blocks[i]);
|
||||
#ifdef CONFIG_SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK
|
||||
size_t offset = 128;
|
||||
#else
|
||||
size_t offset = 0;
|
||||
#endif
|
||||
ret = esp_efuse_read_block(blocks[i], boot_key_digests.key_digests[boot_key_digests.num_digests], offset,
|
||||
ESP_SECURE_BOOT_KEY_DIGEST_LEN * 8);
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "Error during reading %d eFuse block (err=0x%x)", blocks[i], ret);
|
||||
return ret;
|
||||
}
|
||||
boot_key_digests.num_digests++;
|
||||
}
|
||||
if (boot_key_digests.num_digests == 0) {
|
||||
ESP_LOGE(TAG, "No valid pre-loaded public key digest in eFuse");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
ESP_LOGW(TAG, "Using pre-loaded public key digest in eFuse");
|
||||
}
|
||||
|
||||
/* Generate the application public key digests */
|
||||
ret = s_calculate_image_public_key_digests(image_data->start_addr, image_data->image_len - SIG_BLOCK_PADDING, &app_key_digests);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Application signature block is invalid.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (app_key_digests.num_digests == 0) {
|
||||
ESP_LOGE(TAG, "No valid applications signature blocks found.");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "%d signature block(s) found appended to the app.", app_key_digests.num_digests);
|
||||
if (app_key_digests.num_digests > boot_key_digests.num_digests) {
|
||||
ESP_LOGW(TAG, "App has %d signature blocks but bootloader only has %d. Some keys missing from bootloader?", app_key_digests.num_digests, boot_key_digests.num_digests);
|
||||
}
|
||||
|
||||
#if CONFIG_SECURE_ENABLE_TEE
|
||||
/* Generate the TEE public key digests */
|
||||
bool tee_match = false;
|
||||
esp_image_sig_public_key_digests_t tee_key_digests = {0};
|
||||
|
||||
ret = s_calculate_image_public_key_digests(tee_data.start_addr, tee_data.image_len - SIG_BLOCK_PADDING, &tee_key_digests);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "TEE signature block is invalid.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (tee_key_digests.num_digests == 0) {
|
||||
ESP_LOGE(TAG, "No valid TEE signature blocks found.");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "%d signature block(s) found appended to the tee.", tee_key_digests.num_digests);
|
||||
if (tee_key_digests.num_digests > boot_key_digests.num_digests) {
|
||||
ESP_LOGW(TAG, "TEE has %d signature blocks but bootloader only has %d. Some keys missing from bootloader?", tee_key_digests.num_digests, boot_key_digests.num_digests);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Confirm if at least one public key from the application matches a public key in the bootloader
|
||||
(Also, ensure if that public revoke bit is not set for the matched key) */
|
||||
bool match = false;
|
||||
|
||||
for (unsigned i = 0; i < boot_key_digests.num_digests; i++) {
|
||||
#if SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS
|
||||
if (esp_efuse_get_digest_revoke(i)) {
|
||||
ESP_LOGI(TAG, "Key block(%d) has been revoked.", i);
|
||||
continue; // skip if the key block is revoked
|
||||
}
|
||||
#endif // SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS
|
||||
for (unsigned j = 0; j < app_key_digests.num_digests; j++) {
|
||||
if (!memcmp(boot_key_digests.key_digests[i], app_key_digests.key_digests[j], ESP_SECURE_BOOT_KEY_DIGEST_LEN)) {
|
||||
ESP_LOGI(TAG, "Application key(%d) matches with bootloader key(%d).", j, i);
|
||||
match = true;
|
||||
}
|
||||
}
|
||||
#if CONFIG_SECURE_ENABLE_TEE
|
||||
if (!match) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (unsigned j = 0; j < tee_key_digests.num_digests; j++) {
|
||||
if (!memcmp(boot_key_digests.key_digests[i], tee_key_digests.key_digests[j], ESP_SECURE_BOOT_KEY_DIGEST_LEN)) {
|
||||
ESP_LOGI(TAG, "TEE key(%d) matches with bootloader key(%d).", j, i);
|
||||
tee_match = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (match == false) {
|
||||
ESP_LOGE(TAG, "No application key digest matches the bootloader key digest.");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
#if CONFIG_SECURE_ENABLE_TEE
|
||||
if (tee_match == false) {
|
||||
ESP_LOGE(TAG, "No TEE key digest matches the bootloader key digest.");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS
|
||||
/* Revoke the empty signature blocks */
|
||||
if (boot_key_digests.num_digests < SECURE_BOOT_NUM_BLOCKS) {
|
||||
/* The revocation index can be 0, 1, 2. Bootloader count can be 1,2,3. */
|
||||
for (unsigned i = boot_key_digests.num_digests; i < SECURE_BOOT_NUM_BLOCKS; i++) {
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_UNUSED_DIGEST_SLOTS
|
||||
ESP_LOGI(TAG, "Revoking empty key digest slot (%d)...", i);
|
||||
esp_efuse_set_digest_revoke(i);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Unused key digest slot (%d) left un-revoked due to the config SECURE_BOOT_ALLOW_UNUSED_DIGEST_SLOTS", i);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif // SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_secure_boot_v2_permanently_enable(const esp_image_metadata_t *image_data)
|
||||
{
|
||||
ESP_LOGI(TAG, "enabling secure boot v2...");
|
||||
|
||||
if (esp_secure_boot_enabled()) {
|
||||
ESP_LOGI(TAG, "secure boot v2 is already enabled, continuing..");
|
||||
return ESP_OK;
|
||||
}
|
||||
#if CONFIG_SECURE_BOOT_REQUIRE_ALREADY_ENABLED
|
||||
else {
|
||||
ESP_LOGE(TAG, "secure boot is not enabled, and SECURE_BOOT_REQUIRE_ALREADY_ENABLED is set, refusing to boot.");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
#endif // CONFIG_SECURE_BOOT_REQUIRE_ALREADY_ENABLED
|
||||
|
||||
esp_efuse_batch_write_begin(); /* Batch all efuse writes at the end of this function */
|
||||
|
||||
esp_err_t err;
|
||||
err = check_and_generate_secure_boot_keys(image_data);
|
||||
if (err != ESP_OK) {
|
||||
esp_efuse_batch_write_cancel();
|
||||
return err;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "blowing secure boot efuse...");
|
||||
err = esp_secure_boot_enable_secure_features();
|
||||
if (err != ESP_OK) {
|
||||
esp_efuse_batch_write_cancel();
|
||||
return err;
|
||||
}
|
||||
|
||||
err = esp_efuse_batch_write_commit();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Error programming security eFuses (err=0x%x).", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SECURE_BOOT_ENABLE_AGGRESSIVE_KEY_REVOKE
|
||||
assert(esp_efuse_read_field_bit(ESP_EFUSE_SECURE_BOOT_AGGRESSIVE_REVOKE));
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_FLASH_ENC_KEYS_BURN_TOGETHER
|
||||
assert(esp_secure_boot_enabled());
|
||||
ESP_LOGI(TAG, "Secure boot permanently enabled");
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#endif // CONFIG_SECURE_BOOT_V2_ENABLED
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "esp_log.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "rom/ecdsa.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "psa/crypto.h"
|
||||
|
||||
#include "secure_boot_signature_priv.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "secure_boot_v2_ecdsa");
|
||||
|
||||
#if CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS
|
||||
#define ECDSA_INTEGER_LEN 48
|
||||
#else
|
||||
#define ECDSA_INTEGER_LEN 32
|
||||
#endif
|
||||
|
||||
esp_err_t verify_ecdsa_signature_block(const ets_secure_boot_signature_t *sig_block, const uint8_t *image_digest, const ets_secure_boot_sig_block_t *trusted_block)
|
||||
{
|
||||
if (!sig_block || !image_digest || !trusted_block) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
psa_status_t status;
|
||||
|
||||
/* Prepare public key for verification */
|
||||
psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;
|
||||
psa_key_id_t key_handle = 0;
|
||||
|
||||
/* Set key attributes according to the curve */
|
||||
psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_VERIFY_HASH);
|
||||
|
||||
uint8_t key_size = 0;
|
||||
psa_ecc_family_t curve_family;
|
||||
|
||||
switch(trusted_block->ecdsa.key.curve_id) {
|
||||
#if CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_256_BITS
|
||||
case ECDSA_CURVE_P256:
|
||||
key_size = 32;
|
||||
curve_family = PSA_ECC_FAMILY_SECP_R1;
|
||||
psa_set_key_bits(&key_attributes, PSA_BYTES_TO_BITS(key_size));
|
||||
break;
|
||||
#endif /* CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_256_BITS */
|
||||
#if CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS
|
||||
case ECDSA_CURVE_P384:
|
||||
key_size = 48;
|
||||
curve_family = PSA_ECC_FAMILY_SECP_R1;
|
||||
psa_set_key_bits(&key_attributes, PSA_BYTES_TO_BITS(key_size));
|
||||
break;
|
||||
#endif /* CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS */
|
||||
default:
|
||||
ESP_LOGE(TAG, "Invalid curve ID");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
#if CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS
|
||||
const psa_algorithm_t alg = PSA_ALG_ECDSA(PSA_ALG_SHA_384);
|
||||
#else
|
||||
const psa_algorithm_t alg = PSA_ALG_ECDSA(PSA_ALG_SHA_256);
|
||||
#endif
|
||||
psa_set_key_algorithm(&key_attributes, alg);
|
||||
psa_set_key_type(&key_attributes, PSA_KEY_TYPE_ECC_PUBLIC_KEY(curve_family));
|
||||
|
||||
/* Prepare the public key data from X and Y coordinates */
|
||||
uint8_t public_key[(2 * ECDSA_INTEGER_LEN) + 1];
|
||||
uint8_t x_point[ECDSA_INTEGER_LEN] = {0};
|
||||
uint8_t y_point[ECDSA_INTEGER_LEN] = {0};
|
||||
|
||||
/* Convert key points from little-endian to big-endian format */
|
||||
for (int i = 0; i < key_size; i++) {
|
||||
x_point[i] = trusted_block->ecdsa.key.point[key_size - i - 1];
|
||||
|
||||
y_point[i] = trusted_block->ecdsa.key.point[2 * key_size - i - 1];
|
||||
}
|
||||
|
||||
public_key[0] = 0x04; /* Uncompressed point format */
|
||||
|
||||
/* Combine X and Y into a single public key buffer */
|
||||
memcpy(public_key + 1, x_point, key_size);
|
||||
memcpy(public_key + 1 + key_size, y_point, key_size);
|
||||
|
||||
/* Import the public key */
|
||||
status = psa_import_key(&key_attributes, public_key, (2 * key_size) + 1, &key_handle);
|
||||
if (status != PSA_SUCCESS) {
|
||||
ESP_LOGE(TAG, "Failed to import key, err:%d", status);
|
||||
ret = ESP_FAIL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Convert signature from little-endian to big-endian format */
|
||||
uint8_t signature[2 * ECDSA_INTEGER_LEN] = {0};
|
||||
for (int i = 0; i < key_size; i++) {
|
||||
signature[i] = trusted_block->ecdsa.signature[key_size - i - 1];
|
||||
signature[key_size + i] = trusted_block->ecdsa.signature[2 * key_size - i - 1];
|
||||
}
|
||||
|
||||
/* Verify the signature */
|
||||
status = psa_verify_hash(key_handle, alg,
|
||||
image_digest, ESP_SECURE_BOOT_DIGEST_LEN,
|
||||
signature, 2 * key_size);
|
||||
|
||||
if (status != PSA_SUCCESS) {
|
||||
ESP_LOGE(TAG, "Signature verification failed, err:%d", status);
|
||||
ret = ESP_FAIL;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
/* Clean up resources */
|
||||
if (key_handle) {
|
||||
psa_destroy_key(key_handle);
|
||||
}
|
||||
psa_reset_key_attributes(&key_attributes);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "esp_log.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "psa/crypto.h"
|
||||
#include "mbedtls/asn1.h"
|
||||
#include "mbedtls/asn1write.h"
|
||||
#include "mbedtls/x509.h"
|
||||
|
||||
#include "secure_boot_signature_priv.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "secure_boot_v2_rsa");
|
||||
|
||||
/*
|
||||
* Helper function to encode RSA public key (N, e) into DER format manually
|
||||
* This creates a PKCS#1 RSAPublicKey structure:
|
||||
*
|
||||
* RSAPublicKey ::= SEQUENCE {
|
||||
* modulus INTEGER, -- n
|
||||
* publicExponent INTEGER -- e
|
||||
* }
|
||||
*/
|
||||
static int encode_rsa_pubkey_der(const uint8_t *modulus, size_t modulus_len,
|
||||
const uint8_t *exponent, size_t exponent_len,
|
||||
uint8_t *der_buf, size_t der_buf_size,
|
||||
uint8_t **der_start, size_t *der_len)
|
||||
{
|
||||
if (!der_buf || !der_start || !der_len || der_buf_size == 0) {
|
||||
return MBEDTLS_ERR_X509_BAD_INPUT_DATA;
|
||||
}
|
||||
|
||||
int ret;
|
||||
unsigned char *c = der_buf + der_buf_size;
|
||||
size_t len = 0;
|
||||
|
||||
/* Write the exponent (e) as an INTEGER */
|
||||
/* Skip leading zeros in exponent */
|
||||
while (exponent_len > 0 && *exponent == 0) {
|
||||
exponent++;
|
||||
exponent_len--;
|
||||
}
|
||||
|
||||
/* Write exponent */
|
||||
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_raw_buffer(&c, der_buf, exponent, exponent_len));
|
||||
|
||||
/* Add padding byte if MSB is set (to keep it positive) */
|
||||
if (exponent_len > 0 && (exponent[0] & 0x80)) {
|
||||
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_raw_buffer(&c, der_buf, (const unsigned char *)"\x00", 1));
|
||||
}
|
||||
|
||||
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, der_buf, exponent_len + ((exponent[0] & 0x80) ? 1 : 0)));
|
||||
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(&c, der_buf, MBEDTLS_ASN1_INTEGER));
|
||||
|
||||
/* Write the modulus (N) as an INTEGER */
|
||||
/* Skip leading zeros in modulus */
|
||||
const uint8_t *mod_ptr = modulus;
|
||||
size_t mod_len = modulus_len;
|
||||
while (mod_len > 0 && *mod_ptr == 0) {
|
||||
mod_ptr++;
|
||||
mod_len--;
|
||||
}
|
||||
|
||||
/* Write modulus */
|
||||
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_raw_buffer(&c, der_buf, mod_ptr, mod_len));
|
||||
|
||||
/* Add padding byte if MSB is set */
|
||||
if (mod_len > 0 && (mod_ptr[0] & 0x80)) {
|
||||
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_raw_buffer(&c, der_buf, (const unsigned char *)"\x00", 1));
|
||||
}
|
||||
|
||||
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, der_buf, mod_len + ((mod_ptr[0] & 0x80) ? 1 : 0)));
|
||||
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(&c, der_buf, MBEDTLS_ASN1_INTEGER));
|
||||
|
||||
/* Write SEQUENCE header */
|
||||
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, der_buf, len));
|
||||
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(&c, der_buf,
|
||||
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));
|
||||
|
||||
*der_start = c;
|
||||
*der_len = len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
esp_err_t verify_rsa_signature_block(const ets_secure_boot_signature_t *sig_block, const uint8_t *image_digest, const ets_secure_boot_sig_block_t *trusted_block)
|
||||
{
|
||||
if (!sig_block || !image_digest || !trusted_block) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
psa_status_t status;
|
||||
const unsigned rsa_key_size = sizeof(sig_block->block[0].signature);
|
||||
unsigned char *sig_be = NULL;
|
||||
unsigned char *pubkey_der_buf = NULL;
|
||||
|
||||
sig_be = calloc(1, rsa_key_size);
|
||||
if (sig_be == NULL) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
/* Create key attributes for RSA public key */
|
||||
psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;
|
||||
psa_key_id_t key_id = 0;
|
||||
|
||||
/* Allocate buffer for DER-encoded public key */
|
||||
size_t pubkey_der_buf_size = PSA_KEY_EXPORT_RSA_PUBLIC_KEY_MAX_SIZE(3072);
|
||||
pubkey_der_buf = calloc(1, pubkey_der_buf_size);
|
||||
if (pubkey_der_buf == NULL) {
|
||||
free(sig_be);
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
/* Convert raw N and e to DER format manually */
|
||||
uint8_t *der_start = NULL;
|
||||
size_t der_len = 0;
|
||||
|
||||
/* Convert modulus from little-endian to big-endian */
|
||||
uint8_t *n_be = calloc(1, rsa_key_size);
|
||||
if (n_be == NULL) {
|
||||
free(sig_be);
|
||||
free(pubkey_der_buf);
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
for (size_t i = 0; i < rsa_key_size; i++) {
|
||||
n_be[i] = trusted_block->key.n[rsa_key_size - 1 - i];
|
||||
}
|
||||
|
||||
/* Convert e from uint32_t to byte array (big-endian) */
|
||||
uint8_t e_bytes[4];
|
||||
e_bytes[0] = (trusted_block->key.e >> 24) & 0xFF;
|
||||
e_bytes[1] = (trusted_block->key.e >> 16) & 0xFF;
|
||||
e_bytes[2] = (trusted_block->key.e >> 8) & 0xFF;
|
||||
e_bytes[3] = trusted_block->key.e & 0xFF;
|
||||
|
||||
ret = encode_rsa_pubkey_der(
|
||||
n_be, rsa_key_size,
|
||||
e_bytes, sizeof(e_bytes),
|
||||
pubkey_der_buf, pubkey_der_buf_size,
|
||||
&der_start, &der_len
|
||||
);
|
||||
|
||||
free(n_be);
|
||||
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "Failed to encode RSA public key to DER, err: %d", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Set key attributes */
|
||||
psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_VERIFY_HASH);
|
||||
psa_set_key_algorithm(&key_attributes, PSA_ALG_RSA_PSS(PSA_ALG_SHA_256));
|
||||
psa_set_key_type(&key_attributes, PSA_KEY_TYPE_RSA_PUBLIC_KEY);
|
||||
|
||||
/* Import DER-encoded public key into PSA */
|
||||
status = psa_import_key(&key_attributes, der_start, der_len, &key_id);
|
||||
if (status != PSA_SUCCESS) {
|
||||
ESP_LOGE(TAG, "Failed to import key into PSA, err: %d", status);
|
||||
ret = ESP_FAIL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Signature needs to be byte swapped into BE representation */
|
||||
for (int j = 0; j < rsa_key_size; j++) {
|
||||
sig_be[rsa_key_size - j - 1] = trusted_block->signature[j];
|
||||
}
|
||||
|
||||
/* Verify the signature using PSA APIs */
|
||||
status = psa_verify_hash(key_id, PSA_ALG_RSA_PSS(PSA_ALG_SHA_256),
|
||||
image_digest, ESP_SECURE_BOOT_DIGEST_LEN,
|
||||
sig_be, rsa_key_size);
|
||||
|
||||
if (status != PSA_SUCCESS) {
|
||||
ESP_LOGE(TAG, "Signature verification failed, err: %d", status);
|
||||
ret = ESP_FAIL;
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Signature verified successfully!");
|
||||
ret = ESP_OK;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
/* Clean up resources */
|
||||
if (key_id != 0) {
|
||||
psa_destroy_key(key_id);
|
||||
}
|
||||
psa_reset_key_attributes(&key_attributes);
|
||||
free(sig_be);
|
||||
free(pubkey_der_buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "esp_secure_boot.h"
|
||||
#include "rom/secure_boot.h"
|
||||
|
||||
esp_err_t verify_ecdsa_signature_block(const ets_secure_boot_signature_t *sig_block, const uint8_t *image_digest, const ets_secure_boot_sig_block_t *trusted_block);
|
||||
|
||||
esp_err_t verify_rsa_signature_block(const ets_secure_boot_signature_t *sig_block, const uint8_t *image_digest, const ets_secure_boot_sig_block_t *trusted_block);
|
||||
@@ -0,0 +1,332 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "bootloader_sha.h"
|
||||
#include "bootloader_utility.h"
|
||||
#include "bootloader_signature.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_image_format.h"
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_ota_ops.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_chip.h"
|
||||
|
||||
#include "secure_boot_signature_priv.h"
|
||||
#include "esp_macros.h"
|
||||
|
||||
// Secure boot V2 for app
|
||||
|
||||
_Static_assert(SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS == SECURE_BOOT_NUM_BLOCKS,
|
||||
"Parts of this code rely on the max number of signatures appended to an image"
|
||||
"being the same as the max number of trusted keys.");
|
||||
|
||||
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME || CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME || CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "secure_boot_v2");
|
||||
|
||||
/* A signature block is valid when it has correct magic byte, crc. */
|
||||
static esp_err_t validate_signature_block(const ets_secure_boot_sig_block_t *block)
|
||||
{
|
||||
if (block->magic_byte != ETS_SECURE_BOOT_V2_SIGNATURE_MAGIC
|
||||
|| block->block_crc != esp_rom_crc32_le(0, (uint8_t *)block, CRC_SIGN_BLOCK_LEN)) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (block->version != ESP_SECURE_BOOT_SCHEME) {
|
||||
ESP_LOGE(TAG, "%s signing scheme selected but signature block generated for %s scheme", esp_secure_boot_get_scheme_name(ESP_SECURE_BOOT_SCHEME), esp_secure_boot_get_scheme_name(block->version));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
#if CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME
|
||||
if (block->ecdsa.key.curve_id != ESP_SECURE_BOOT_ECDSA_CURVE_ID) {
|
||||
ESP_LOGE(TAG, "ECDSA curve mismatch: actual (curve_id %u), expected (curve_id %u)", (unsigned) block->ecdsa.key.curve_id, (unsigned) ESP_SECURE_BOOT_ECDSA_CURVE_ID);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t calculate_image_public_key_digests(bool verify_image_digest, bool digest_public_keys, esp_image_sig_public_key_digests_t *public_key_digests, esp_partition_pos_t *part_pos)
|
||||
{
|
||||
esp_image_metadata_t img_metadata = {0};
|
||||
esp_err_t ret = esp_image_get_metadata(part_pos, &img_metadata);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Error reading metadata from running app (err=0x%x)", ret);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
uint8_t image_digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
|
||||
uint8_t __attribute__((aligned(4))) key_digest[ESP_SECURE_BOOT_KEY_DIGEST_SHA_256_LEN] = {0};
|
||||
size_t sig_block_addr = img_metadata.start_addr + ESP_ALIGN_UP(img_metadata.image_len, FLASH_SECTOR_SIZE);
|
||||
|
||||
ESP_LOGD(TAG, "calculating public key digests for sig blocks of image offset 0x%"PRIu32" (sig block offset 0x%u)", img_metadata.start_addr, sig_block_addr);
|
||||
|
||||
bzero(public_key_digests, sizeof(esp_image_sig_public_key_digests_t));
|
||||
|
||||
if (verify_image_digest) {
|
||||
#if CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS
|
||||
ret = bootloader_sha384_flash_contents(img_metadata.start_addr, sig_block_addr - img_metadata.start_addr, image_digest);
|
||||
#else
|
||||
ret = bootloader_sha256_flash_contents(img_metadata.start_addr, sig_block_addr - img_metadata.start_addr, image_digest);
|
||||
#endif
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "error generating image digest, %d", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "reading signature(s)");
|
||||
for (unsigned i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
|
||||
ets_secure_boot_sig_block_t block;
|
||||
size_t addr = sig_block_addr + sizeof(ets_secure_boot_sig_block_t) * i;
|
||||
esp_err_t err = bootloader_flash_read(addr, &block, sizeof(ets_secure_boot_sig_block_t), true);
|
||||
if (err == ESP_OK) {
|
||||
if (validate_signature_block(&block) == ESP_OK) {
|
||||
if (digest_public_keys) {
|
||||
bootloader_sha256_handle_t sig_block_sha = bootloader_sha256_start();
|
||||
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
bootloader_sha256_data(sig_block_sha, &block.key, sizeof(block.key));
|
||||
#elif CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME
|
||||
bootloader_sha256_data(sig_block_sha, &block.ecdsa.key, sizeof(block.ecdsa.key));
|
||||
#endif
|
||||
bootloader_sha256_finish(sig_block_sha, key_digest);
|
||||
if (verify_image_digest) {
|
||||
// Check we can verify the image using this signature and this key
|
||||
uint8_t temp_verified_digest[ESP_SECURE_BOOT_DIGEST_LEN];
|
||||
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
bool verified = ets_rsa_pss_verify(&block.key, block.signature, image_digest, temp_verified_digest);
|
||||
#elif CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME
|
||||
bool verified = ets_ecdsa_verify(&block.ecdsa.key.point[0], block.ecdsa.signature, block.ecdsa.key.curve_id, image_digest, temp_verified_digest);
|
||||
#endif
|
||||
if (!verified) {
|
||||
ESP_LOGE(TAG, "Secure boot key (%d) verification failed.", i);
|
||||
continue;
|
||||
}
|
||||
ESP_LOGD(TAG, "Signature block (%d) is verified", i);
|
||||
}
|
||||
/* Copy the key digest to the buffer provided by the caller */
|
||||
memcpy((void *)public_key_digests->key_digests[public_key_digests->num_digests], key_digest, ESP_SECURE_BOOT_KEY_DIGEST_SHA_256_LEN);
|
||||
}
|
||||
public_key_digests->num_digests++;
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Secure boot sign blocks cannot be read from image at %lx (err=0x%x)", part_pos->offset, err);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == ESP_OK && public_key_digests->num_digests > 0) {
|
||||
ESP_LOGD(TAG, "Digests successfully calculated, %d valid signatures (image offset 0x%"PRIu32")",
|
||||
public_key_digests->num_digests, img_metadata.start_addr);
|
||||
}
|
||||
|
||||
if (public_key_digests->num_digests == 0) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t esp_secure_boot_get_signature_blocks_for_running_app(bool digest_public_keys, esp_image_sig_public_key_digests_t *public_key_digests)
|
||||
{
|
||||
esp_partition_pos_t part_pos;
|
||||
const esp_partition_t* running_app_part = esp_ota_get_running_partition();
|
||||
if (running_app_part == NULL) {
|
||||
ESP_LOGE(TAG, "Cannot get running partition");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
part_pos.offset = running_app_part->address;
|
||||
part_pos.size = running_app_part->size;
|
||||
|
||||
esp_err_t err = calculate_image_public_key_digests(false, digest_public_keys, public_key_digests, &part_pos);
|
||||
if (public_key_digests->num_digests == 0) {
|
||||
ESP_LOGE(TAG, "No signatures were found for the running app");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static esp_err_t get_secure_boot_key_digests(esp_image_sig_public_key_digests_t *public_key_digests)
|
||||
{
|
||||
if (!esp_secure_boot_enabled()) { // CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT
|
||||
// Gets key digests from running app
|
||||
ESP_LOGI(TAG, "Take trusted digest key(s) from running app");
|
||||
return esp_secure_boot_get_signature_blocks_for_running_app(true, public_key_digests);
|
||||
} else { // CONFIG_SECURE_BOOT_V2_ENABLED
|
||||
ESP_LOGI(TAG, "Take trusted digest key(s) from eFuse block(s)");
|
||||
// Read key digests from efuse
|
||||
esp_secure_boot_key_digests_t efuse_trusted;
|
||||
if (esp_secure_boot_read_key_digests(&efuse_trusted) == ESP_OK) {
|
||||
for (unsigned i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
|
||||
if (efuse_trusted.key_digests[i] != NULL) {
|
||||
memcpy(public_key_digests->key_digests[i], (uint8_t *)efuse_trusted.key_digests[i], ESP_SECURE_BOOT_KEY_DIGEST_LEN);
|
||||
public_key_digests->num_digests++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (public_key_digests->num_digests > 0) {
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||
{
|
||||
esp_err_t err = ESP_FAIL;
|
||||
uint8_t digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
|
||||
|
||||
/* Rounding off length to the upper 4k boundary */
|
||||
uint32_t padded_length = ESP_ALIGN_UP(length, FLASH_SECTOR_SIZE);
|
||||
ESP_LOGD(TAG, "verifying signature src_addr 0x%"PRIx32" length 0x%"PRIx32, src_addr, length);
|
||||
|
||||
#if CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS
|
||||
err = bootloader_sha384_flash_contents(src_addr, padded_length, digest);
|
||||
#else
|
||||
err = bootloader_sha256_flash_contents(src_addr, padded_length, digest);
|
||||
#endif
|
||||
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Digest calculation failed 0x%"PRIx32", 0x%"PRIx32, src_addr, padded_length);
|
||||
return err;
|
||||
}
|
||||
|
||||
const ets_secure_boot_signature_t *sig_block = bootloader_mmap(src_addr + padded_length, sizeof(ets_secure_boot_signature_t));
|
||||
if (sig_block == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to mmap data at offset 0x%"PRIx32, src_addr + padded_length);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
err = esp_secure_boot_verify_sbv2_signature_block(sig_block, digest, NULL);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Secure Boot V2 verification failed.");
|
||||
}
|
||||
bootloader_munmap(sig_block);
|
||||
return err;
|
||||
}
|
||||
|
||||
// This verify function is called only from app, during ota update.
|
||||
// This function is compiled in case when CONFIG_SECURE_BOOT_V2_ENABLED==y or CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT==y.
|
||||
// if CONFIG_SECURE_BOOT_V2_ENABLED==y and key digests from eFuse are missing, then FAIL (eFuse blocks should be set).
|
||||
esp_err_t esp_secure_boot_verify_sbv2_signature_block(const ets_secure_boot_signature_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest)
|
||||
{
|
||||
bool any_trusted_key = false;
|
||||
|
||||
if (verified_digest != NULL) {
|
||||
/* Note: in IDF verification we don't add any fault injection resistance, as we don't expect this to be called
|
||||
during boot-time verification. */
|
||||
memset(verified_digest, 0, ESP_SECURE_BOOT_DIGEST_LEN);
|
||||
}
|
||||
|
||||
esp_image_sig_public_key_digests_t trusted = {0};
|
||||
|
||||
if (get_secure_boot_key_digests(&trusted) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Could not read secure boot digests!");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
#ifdef CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT
|
||||
const unsigned secure_boot_num_blocks = 1;
|
||||
#else
|
||||
const unsigned secure_boot_num_blocks = SECURE_BOOT_NUM_BLOCKS;
|
||||
#endif
|
||||
|
||||
for (unsigned app_blk_idx = 0; app_blk_idx < secure_boot_num_blocks; app_blk_idx++) {
|
||||
uint8_t app_blk_digest[ESP_SECURE_BOOT_KEY_DIGEST_SHA_256_LEN] = { 0 };
|
||||
const ets_secure_boot_sig_block_t *app_blk = &sig_block->block[app_blk_idx];
|
||||
const ets_secure_boot_sig_block_t *trusted_block = NULL;
|
||||
|
||||
if (validate_signature_block(app_blk) != ESP_OK) {
|
||||
continue; // Skip invalid signature blocks
|
||||
}
|
||||
|
||||
/* Generate the SHA of the public key components in the signature block */
|
||||
bootloader_sha256_handle_t sig_block_sha = bootloader_sha256_start();
|
||||
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
bootloader_sha256_data(sig_block_sha, &app_blk->key, sizeof(app_blk->key));
|
||||
#elif CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME
|
||||
bootloader_sha256_data(sig_block_sha, &app_blk->ecdsa.key, sizeof(app_blk->ecdsa.key));
|
||||
#endif
|
||||
|
||||
bootloader_sha256_finish(sig_block_sha, app_blk_digest);
|
||||
|
||||
/* Check if the key is one we trust */
|
||||
for (unsigned trusted_key_idx = 0; trusted_key_idx < secure_boot_num_blocks; trusted_key_idx++) {
|
||||
if (memcmp(app_blk_digest, trusted.key_digests[trusted_key_idx], ESP_SECURE_BOOT_KEY_DIGEST_LEN) == 0) {
|
||||
ESP_LOGI(TAG, "#%d app key digest == #%d trusted key digest", app_blk_idx, trusted_key_idx);
|
||||
trusted_block = app_blk;
|
||||
any_trusted_key = true;
|
||||
break;
|
||||
}
|
||||
ESP_LOGV(TAG, "not trusting app sig %d trust idx %d", app_blk_idx, trusted_key_idx);
|
||||
}
|
||||
|
||||
if (trusted_block == NULL) {
|
||||
continue; // Skip the signature blocks with no trusted digest
|
||||
}
|
||||
|
||||
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
ESP_LOGI(TAG, "Verifying with RSA-PSS...");
|
||||
ret = verify_rsa_signature_block(sig_block, image_digest, trusted_block);
|
||||
#elif CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME
|
||||
ESP_LOGI(TAG, "Verifying with ECDSA...");
|
||||
ret = verify_ecdsa_signature_block(sig_block, image_digest, trusted_block);
|
||||
#endif
|
||||
if (ret == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (ret != 0 || any_trusted_key == false) ? ESP_ERR_IMAGE_INVALID: ESP_OK;
|
||||
}
|
||||
|
||||
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
// To maintain backward compatibility
|
||||
esp_err_t esp_secure_boot_verify_rsa_signature_block(const ets_secure_boot_signature_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest)
|
||||
{
|
||||
return esp_secure_boot_verify_sbv2_signature_block(sig_block, image_digest, verified_digest);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME || CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME || CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT
|
||||
|
||||
#if SOC_SUPPORT_SECURE_BOOT_REVOKE_KEY && CONFIG_SECURE_BOOT_V2_ENABLED
|
||||
|
||||
esp_err_t esp_secure_boot_verify_with_efuse_digest_index(int efuse_digest_index, esp_partition_pos_t *part_pos)
|
||||
{
|
||||
if (!part_pos || (efuse_digest_index < 0 || efuse_digest_index >= SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
esp_image_sig_public_key_digests_t img_key_digests = {0};
|
||||
esp_err_t ret = calculate_image_public_key_digests(true, true, &img_key_digests, part_pos);
|
||||
if (ret != ESP_OK) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (esp_efuse_get_digest_revoke(efuse_digest_index)) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
// Read key digests from efuse
|
||||
esp_secure_boot_key_digests_t efuse_key_digests;
|
||||
memset(&efuse_key_digests, 0, sizeof(esp_secure_boot_key_digests_t));
|
||||
/* A non-revoked slot can still be unprovisioned, leaving its digest pointer NULL even
|
||||
* when the read returns ESP_OK; comparing it would dereference NULL in memcmp(). Check
|
||||
* both the read result and the specific slot (matches get_secure_boot_key_digests()). */
|
||||
if (esp_secure_boot_read_key_digests(&efuse_key_digests) != ESP_OK ||
|
||||
efuse_key_digests.key_digests[efuse_digest_index] == NULL) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
for (int i = 0; i < img_key_digests.num_digests; i++) {
|
||||
if (!memcmp(img_key_digests.key_digests[i], efuse_key_digests.key_digests[efuse_digest_index], ESP_SECURE_BOOT_KEY_DIGEST_LEN)) {
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
return ESP_FAIL;
|
||||
}
|
||||
#endif // SOC_SUPPORT_SECURE_BOOT_REVOKE_KEY && CONFIG_SECURE_BOOT_V2_ENABLED
|
||||
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include <string.h>
|
||||
#include "esp_fault.h"
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "bootloader_sha.h"
|
||||
#include "bootloader_utility.h"
|
||||
#include "bootloader_signature.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_macros.h"
|
||||
|
||||
// Secure boot V2 for bootloader.
|
||||
|
||||
#if CONFIG_SECURE_BOOT_V2_ENABLED
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "secure_boot_v2");
|
||||
|
||||
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||
{
|
||||
esp_err_t err = ESP_FAIL;
|
||||
uint8_t digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
|
||||
uint8_t verified_digest[ESP_SECURE_BOOT_DIGEST_LEN] = { 0 }; /* Note: this function doesn't do any anti-FI checks on this buffer */
|
||||
|
||||
/* Rounding off length to the upper 4k boundary */
|
||||
uint32_t padded_length = ESP_ALIGN_UP(length, FLASH_SECTOR_SIZE);
|
||||
ESP_LOGD(TAG, "verifying signature src_addr 0x%" PRIx32 " length 0x%" PRIx32, src_addr, length);
|
||||
|
||||
/* Calculate digest of main image */
|
||||
#if CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS
|
||||
err = bootloader_sha384_flash_contents(src_addr, padded_length, digest);
|
||||
#else
|
||||
err = bootloader_sha256_flash_contents(src_addr, padded_length, digest);
|
||||
#endif
|
||||
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Digest calculation failed 0x%" PRIx32 ", 0x%" PRIx32, src_addr, padded_length);
|
||||
return err;
|
||||
}
|
||||
|
||||
const ets_secure_boot_signature_t *sig_block = bootloader_mmap(src_addr + padded_length, sizeof(ets_secure_boot_signature_t));
|
||||
if (sig_block == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to mmap data at offset 0x%" PRIx32, src_addr + padded_length);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
err = esp_secure_boot_verify_sbv2_signature_block(sig_block, digest, verified_digest);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Secure Boot V2 verification failed.");
|
||||
}
|
||||
bootloader_munmap(sig_block);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* A signature block is valid when it has correct magic byte, crc. */
|
||||
static esp_err_t validate_signature_block(const ets_secure_boot_sig_block_t *block)
|
||||
{
|
||||
if (block->magic_byte != ETS_SECURE_BOOT_V2_SIGNATURE_MAGIC
|
||||
|| block->block_crc != esp_rom_crc32_le(0, (uint8_t *)block, CRC_SIGN_BLOCK_LEN)) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (block->version != ESP_SECURE_BOOT_SCHEME) {
|
||||
ESP_LOGE(TAG, "%s signing scheme selected but signature block generated for %s scheme", esp_secure_boot_get_scheme_name(ESP_SECURE_BOOT_SCHEME), esp_secure_boot_get_scheme_name(block->version));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
#if CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME
|
||||
if (block->ecdsa.key.curve_id != ESP_SECURE_BOOT_ECDSA_CURVE_ID) {
|
||||
ESP_LOGE(TAG, "ECDSA curve mismatch: actual (curve_id %u), expected (curve_id %u)", (unsigned) block->ecdsa.key.curve_id, (unsigned) ESP_SECURE_BOOT_ECDSA_CURVE_ID);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t get_secure_boot_key_digests(esp_image_sig_public_key_digests_t *public_key_digests)
|
||||
{
|
||||
// Read key digests from efuse
|
||||
esp_secure_boot_key_digests_t trusted_keys;
|
||||
esp_secure_boot_key_digests_t trusted_key_copies[2];
|
||||
|
||||
memset(&trusted_keys, 0, sizeof(esp_secure_boot_key_digests_t));
|
||||
memset(trusted_key_copies, 0, 2 * sizeof(esp_secure_boot_key_digests_t));
|
||||
|
||||
esp_err_t err = esp_secure_boot_read_key_digests(&trusted_keys);
|
||||
|
||||
// Create the copies for FI checks (assuming result is ETS_OK, if it's not then it'll fail the fault check anyhow)
|
||||
esp_secure_boot_read_key_digests(&trusted_key_copies[0]);
|
||||
esp_secure_boot_read_key_digests(&trusted_key_copies[1]);
|
||||
ESP_FAULT_ASSERT(memcmp(&trusted_keys, &trusted_key_copies[0], sizeof(esp_secure_boot_key_digests_t)) == 0);
|
||||
ESP_FAULT_ASSERT(memcmp(&trusted_keys, &trusted_key_copies[1], sizeof(esp_secure_boot_key_digests_t)) == 0);
|
||||
|
||||
if (err == ESP_OK) {
|
||||
for (unsigned i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
|
||||
if (trusted_keys.key_digests[i] != NULL) {
|
||||
memcpy(public_key_digests->key_digests[i], (uint8_t *)trusted_keys.key_digests[i], ESP_SECURE_BOOT_KEY_DIGEST_LEN);
|
||||
public_key_digests->num_digests++;
|
||||
}
|
||||
}
|
||||
#if SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS == 1
|
||||
if (esp_efuse_block_is_empty(EFUSE_BLK_SECURE_BOOT)) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
#endif // SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS
|
||||
if (public_key_digests->num_digests > 0) {
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
// if CONFIG_SECURE_BOOT_V2_ENABLED==y and key digests from eFuse are missing, then it is the first boot,
|
||||
// trusted.key_digests are filled from app sig_block.
|
||||
esp_err_t esp_secure_boot_verify_sbv2_signature_block(const ets_secure_boot_signature_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest)
|
||||
{
|
||||
esp_image_sig_public_key_digests_t trusted = {0};
|
||||
bool efuse_keys_are_not_set = false;
|
||||
if (get_secure_boot_key_digests(&trusted) != ESP_OK) {
|
||||
if (esp_secure_boot_enabled()) {
|
||||
ESP_LOGE(TAG, "Could not read eFuse secure boot digests!");
|
||||
return ESP_FAIL;
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Secure boot V2 is not enabled yet and eFuse digest keys are not set");
|
||||
efuse_keys_are_not_set = true;
|
||||
ESP_FAULT_ASSERT(!esp_secure_boot_enabled());
|
||||
}
|
||||
}
|
||||
|
||||
if (!esp_secure_boot_enabled()) {
|
||||
// It is the first boot. eFuse secure boot bit is not set yet. eFuse block(s) can be written or not.
|
||||
// Generating the SHA of the public key components in the signature block
|
||||
for (unsigned i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
|
||||
if (validate_signature_block(&sig_block->block[i]) == ESP_OK) {
|
||||
if (efuse_keys_are_not_set) {
|
||||
// if efuse key digests are not in eFuse yet due to it is the first boot
|
||||
// then use digests from app to skip error in ets_secure_boot_verify_signature().
|
||||
bootloader_sha256_handle_t sig_block_sha = bootloader_sha256_start();
|
||||
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
bootloader_sha256_data(sig_block_sha, &sig_block->block[i].key, sizeof(sig_block->block[i].key));
|
||||
#elif CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME
|
||||
bootloader_sha256_data(sig_block_sha, &sig_block->block[i].ecdsa.key, sizeof(sig_block->block[i].ecdsa.key));
|
||||
#endif
|
||||
bootloader_sha256_finish(sig_block_sha, trusted.key_digests[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
ESP_FAULT_ASSERT(!esp_secure_boot_enabled());
|
||||
}
|
||||
|
||||
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
ESP_LOGI(TAG, "Verifying with RSA-PSS...");
|
||||
#else
|
||||
ESP_LOGI(TAG, "Verifying with ECDSA...");
|
||||
#endif
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
int sb_result = ets_secure_boot_verify_signature(sig_block, image_digest, trusted.key_digests[0], verified_digest);
|
||||
#else
|
||||
ets_secure_boot_key_digests_t trusted_key_digests = {0};
|
||||
bool valid_sig_blk = false;
|
||||
for (unsigned i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
|
||||
trusted_key_digests.key_digests[i] = &trusted.key_digests[i];
|
||||
if (sig_block->block[i].version != ESP_SECURE_BOOT_SCHEME) {
|
||||
ESP_LOGD(TAG, "%s signing scheme selected but signature block %d generated for %s scheme", esp_secure_boot_get_scheme_name(ESP_SECURE_BOOT_SCHEME), i, esp_secure_boot_get_scheme_name(sig_block->block[i].version));
|
||||
} else {
|
||||
valid_sig_blk = true;
|
||||
}
|
||||
}
|
||||
if (valid_sig_blk != true) {
|
||||
ESP_LOGE(TAG, "No signature block generated for valid scheme");
|
||||
ESP_LOGE(TAG, "%s signing scheme selected but no signature block for the selected scheme", esp_secure_boot_get_scheme_name(ESP_SECURE_BOOT_SCHEME));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
// Key revocation happens in ROM bootloader.
|
||||
// Do NOT allow key revocation while verifying application
|
||||
trusted_key_digests.allow_key_revoke = false;
|
||||
|
||||
int sb_result = ets_secure_boot_verify_signature(sig_block, image_digest, &trusted_key_digests, verified_digest);
|
||||
#endif // CONFIG_IDF_TARGET_ESP32
|
||||
|
||||
if (sb_result != SB_SUCCESS) {
|
||||
ESP_LOGE(TAG, "Secure Boot V2 verification failed.");
|
||||
return ESP_ERR_IMAGE_INVALID;
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Signature verified successfully!");
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
|
||||
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
// To maintain backward compatibility
|
||||
esp_err_t esp_secure_boot_verify_rsa_signature_block(const ets_secure_boot_signature_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest)
|
||||
{
|
||||
return esp_secure_boot_verify_sbv2_signature_block(sig_block, image_digest, verified_digest);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // CONFIG_SECURE_BOOT_V2_ENABLED
|
||||
Reference in New Issue
Block a user