chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 13:04:25 +08:00
commit 548b49ebc0
20937 changed files with 5455372 additions and 0 deletions
@@ -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 REE0REE2 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, &current_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