mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'backport/anti-fi-check-sbv1-v3.3.3' into 'release/v3.3'
bootloader: Add fault injection resistance to Secure Boot bootloader verification See merge request espressif/esp-idf!12738
This commit is contained in:
commit
63d482e162
@ -75,6 +75,7 @@ SECTIONS
|
||||
.dram0.bss (NOLOAD) :
|
||||
{
|
||||
. = ALIGN (8);
|
||||
_dram_start = ABSOLUTE(.);
|
||||
_bss_start = ABSOLUTE(.);
|
||||
*(.dynsbss)
|
||||
*(.sbss)
|
||||
@ -151,7 +152,7 @@ SECTIONS
|
||||
*(.gnu.linkonce.lit4.*)
|
||||
_lit4_end = ABSOLUTE(.);
|
||||
. = ALIGN(4);
|
||||
_heap_start = ABSOLUTE(.);
|
||||
_dram_end = ABSOLUTE(.);
|
||||
} >dram_seg
|
||||
|
||||
.iram.text :
|
||||
|
@ -123,6 +123,19 @@ typedef struct {
|
||||
|
||||
esp_err_t esp_secure_boot_verify_signature_block(const esp_secure_boot_sig_block_t *sig_block, const uint8_t *image_digest);
|
||||
|
||||
/** @brief Verify the ECDSA secure boot signature block for Secure Boot.
|
||||
*
|
||||
* Calculates Deterministic ECDSA w/ SHA256 based on the SHA256 hash of the image. ECDSA signature
|
||||
* verification must be enabled in project configuration to use this function.
|
||||
*
|
||||
* Similar to esp_secure_boot_verify_signature(), but can be used when the digest is precalculated.
|
||||
* @param sig_block Pointer to ECDSA signature block data
|
||||
* @param image_digest Pointer to 32 byte buffer holding SHA-256 hash.
|
||||
* @param verified_digest Pointer to 32 byte buffer that will receive verified digest if verification completes. (Used during bootloader implementation only, result is invalid otherwise.)
|
||||
*
|
||||
*/
|
||||
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);
|
||||
|
||||
#define FLASH_OFFS_SECURE_BOOT_IV_DIGEST 0
|
||||
|
||||
/** @brief Secure boot IV+digest header */
|
||||
|
@ -14,6 +14,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "esp_image_format.h"
|
||||
#include "bootloader_config.h"
|
||||
|
||||
/**
|
||||
* @brief Load partition table.
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <soc/cpu.h>
|
||||
#include <esp_image_format.h>
|
||||
#include <esp_secure_boot.h>
|
||||
#include <esp_fault.h>
|
||||
#include <esp_log.h>
|
||||
#include <esp_spi_flash.h>
|
||||
#include <bootloader_flash.h>
|
||||
@ -25,6 +26,7 @@
|
||||
#include <bootloader_sha.h>
|
||||
#include "bootloader_util.h"
|
||||
#include "bootloader_common.h"
|
||||
#include "soc/soc_memory_layout.h"
|
||||
|
||||
/* Checking signatures as part of verifying images is necessary:
|
||||
- Always if secure boot is enabled
|
||||
@ -92,7 +94,7 @@ static esp_err_t verify_segment_header(int index, const esp_image_segment_header
|
||||
|
||||
static esp_err_t verify_checksum(bootloader_sha256_handle_t sha_handle, uint32_t checksum_word, esp_image_metadata_t *data);
|
||||
|
||||
static esp_err_t __attribute__((unused)) verify_secure_boot_signature(bootloader_sha256_handle_t sha_handle, esp_image_metadata_t *data);
|
||||
static esp_err_t __attribute__((unused)) verify_secure_boot_signature(bootloader_sha256_handle_t sha_handle, esp_image_metadata_t *data,uint8_t *image_digest, uint8_t *verified_digest);
|
||||
static esp_err_t __attribute__((unused)) verify_simple_hash(bootloader_sha256_handle_t sha_handle, esp_image_metadata_t *data);
|
||||
|
||||
static esp_err_t image_load(esp_image_load_mode_t mode, const esp_partition_pos_t *part, esp_image_metadata_t *data)
|
||||
@ -108,6 +110,12 @@ static esp_err_t image_load(esp_image_load_mode_t mode, const esp_partition_pos_
|
||||
uint32_t checksum_word = ESP_ROM_CHECKSUM_INITIAL;
|
||||
bootloader_sha256_handle_t sha_handle = NULL;
|
||||
|
||||
#ifdef SECURE_BOOT_CHECK_SIGNATURE
|
||||
/* used for anti-FI checks */
|
||||
uint8_t image_digest[HASH_LEN] = { [ 0 ... 31] = 0xEE };
|
||||
uint8_t verified_digest[HASH_LEN] = { [ 0 ... 31 ] = 0x01 };
|
||||
#endif
|
||||
|
||||
if (data == NULL || part == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
@ -196,7 +204,7 @@ static esp_err_t image_load(esp_image_load_mode_t mode, const esp_partition_pos_
|
||||
if (!is_bootloader) {
|
||||
#ifdef SECURE_BOOT_CHECK_SIGNATURE
|
||||
// secure boot images have a signature appended
|
||||
err = verify_secure_boot_signature(sha_handle, data);
|
||||
err = verify_secure_boot_signature(sha_handle, data, image_digest, verified_digest);
|
||||
#else
|
||||
// No secure boot, but SHA-256 can be appended for basic corruption detection
|
||||
if (sha_handle != NULL && !esp_cpu_in_ocd_debug_mode()) {
|
||||
@ -226,7 +234,22 @@ static esp_err_t image_load(esp_image_load_mode_t mode, const esp_partition_pos_
|
||||
}
|
||||
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
if (do_load) { // Need to deobfuscate RAM
|
||||
|
||||
#ifdef SECURE_BOOT_CHECK_SIGNATURE
|
||||
/* If signature was checked in bootloader build, verified_digest should equal image_digest
|
||||
|
||||
This is to detect any fault injection that caused signature verification to not complete normally.
|
||||
|
||||
Any attack which bypasses this check should be of limited use as the RAM contents are still obfuscated, therefore we do the check
|
||||
immediately before we deobfuscate.
|
||||
|
||||
Note: the conditions for making this check are the same as for setting verify_sha above, but on ESP32 SB V1 we move the test for
|
||||
"only verify signature in bootloader" into the macro so it's tested multiple times.
|
||||
*/
|
||||
ESP_FAULT_ASSERT(data->start_addr == ESP_BOOTLOADER_OFFSET || memcmp(image_digest, verified_digest, HASH_LEN) == 0);
|
||||
#endif // SECURE_BOOT_CHECK_SIGNATURE
|
||||
|
||||
if (do_load && ram_obfs_value[0] != 0 && ram_obfs_value[1] != 0) { // Need to deobfuscate RAM
|
||||
for (int i = 0; i < data->image.segment_count; i++) {
|
||||
uint32_t load_addr = data->segments[i].load_addr;
|
||||
if (should_load(load_addr)) {
|
||||
@ -298,6 +321,127 @@ static esp_err_t verify_image_header(uint32_t src_addr, const esp_image_header_t
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
/* Check the region load_addr - load_end doesn't overlap any memory used by the bootloader, registers, or other invalid memory
|
||||
*/
|
||||
static bool verify_load_addresses(int segment_index, intptr_t load_addr, intptr_t load_end, bool print_error, bool no_recurse)
|
||||
{
|
||||
/* Addresses of static data and the "loader" section of bootloader IRAM, all defined in ld script */
|
||||
const char *reason = NULL;
|
||||
extern int _dram_start, _dram_end, _loader_text_start, _loader_text_end;
|
||||
void *load_addr_p = (void *)load_addr;
|
||||
void *load_end_p = (void *)load_end;
|
||||
|
||||
if (load_end == load_addr) {
|
||||
return true; // zero-length segments are fine
|
||||
}
|
||||
assert(load_end > load_addr); // data_len<16MB is checked in verify_segment_header() which is called before this, so this should always be true
|
||||
|
||||
if (esp_ptr_in_dram(load_addr_p) && esp_ptr_in_dram(load_end_p)) { /* Writing to DRAM */
|
||||
/* Check if we're clobbering the stack */
|
||||
intptr_t sp = (intptr_t)get_sp();
|
||||
if (bootloader_util_regions_overlap(sp - STACK_LOAD_HEADROOM, SOC_ROM_STACK_START,
|
||||
load_addr, load_end)) {
|
||||
reason = "overlaps bootloader stack";
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
/* Check if we're clobbering static data
|
||||
|
||||
(_dram_start.._dram_end includes bss, data, rodata sections in DRAM)
|
||||
*/
|
||||
if (bootloader_util_regions_overlap((intptr_t)&_dram_start, (intptr_t)&_dram_end, load_addr, load_end)) {
|
||||
reason = "overlaps bootloader data";
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
/* LAST DRAM CHECK (recursive): for D/IRAM, check the equivalent IRAM addresses if needed
|
||||
|
||||
Allow for the possibility that even though both pointers are IRAM, only part of the region is in a D/IRAM
|
||||
section. In which case we recurse to check the part which falls in D/IRAM.
|
||||
|
||||
Note: We start with SOC_DIRAM_DRAM_LOW/HIGH and convert that address to IRAM to account for any reversing of word order
|
||||
(chip-specific).
|
||||
*/
|
||||
if (!no_recurse && bootloader_util_regions_overlap(SOC_DIRAM_DRAM_LOW, SOC_DIRAM_DRAM_HIGH, load_addr, load_end)) {
|
||||
intptr_t iram_load_addr, iram_load_end;
|
||||
|
||||
if (esp_ptr_in_diram_dram(load_addr_p)) {
|
||||
iram_load_addr = (intptr_t)esp_ptr_diram_dram_to_iram(load_addr_p);
|
||||
} else {
|
||||
iram_load_addr = (intptr_t)esp_ptr_diram_dram_to_iram((void *)SOC_DIRAM_DRAM_LOW);
|
||||
}
|
||||
|
||||
if (esp_ptr_in_diram_dram(load_end_p)) {
|
||||
iram_load_end = (intptr_t)esp_ptr_diram_dram_to_iram(load_end_p);
|
||||
} else {
|
||||
iram_load_end = (intptr_t)esp_ptr_diram_dram_to_iram((void *)SOC_DIRAM_DRAM_HIGH);
|
||||
}
|
||||
|
||||
if (iram_load_end < iram_load_addr) {
|
||||
return verify_load_addresses(segment_index, iram_load_end, iram_load_addr, print_error, true);
|
||||
} else {
|
||||
return verify_load_addresses(segment_index, iram_load_addr, iram_load_end, print_error, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (esp_ptr_in_iram(load_addr_p) && esp_ptr_in_iram(load_end_p)) { /* Writing to IRAM */
|
||||
/* Check for overlap of 'loader' section of IRAM */
|
||||
if (bootloader_util_regions_overlap((intptr_t)&_loader_text_start, (intptr_t)&_loader_text_end,
|
||||
load_addr, load_end)) {
|
||||
reason = "overlaps loader IRAM";
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
/* LAST IRAM CHECK (recursive): for D/IRAM, check the equivalent DRAM address if needed
|
||||
|
||||
Allow for the possibility that even though both pointers are IRAM, only part of the region is in a D/IRAM
|
||||
section. In which case we recurse to check the part which falls in D/IRAM.
|
||||
Note: We start with SOC_DIRAM_IRAM_LOW/HIGH and convert that address to DRAM to account for any reversing of word order
|
||||
(chip-specific).
|
||||
*/
|
||||
if (!no_recurse && bootloader_util_regions_overlap(SOC_DIRAM_IRAM_LOW, SOC_DIRAM_IRAM_HIGH, load_addr, load_end)) {
|
||||
intptr_t dram_load_addr, dram_load_end;
|
||||
|
||||
if (esp_ptr_in_diram_iram(load_addr_p)) {
|
||||
dram_load_addr = (intptr_t)esp_ptr_diram_iram_to_dram(load_addr_p);
|
||||
} else {
|
||||
dram_load_addr = (intptr_t)esp_ptr_diram_iram_to_dram((void *)SOC_DIRAM_IRAM_LOW);
|
||||
}
|
||||
|
||||
if (esp_ptr_in_diram_iram(load_end_p)) {
|
||||
dram_load_end = (intptr_t)esp_ptr_diram_iram_to_dram(load_end_p);
|
||||
} else {
|
||||
dram_load_end = (intptr_t)esp_ptr_diram_iram_to_dram((void *)SOC_DIRAM_IRAM_HIGH);
|
||||
}
|
||||
|
||||
if (dram_load_end < dram_load_addr) {
|
||||
return verify_load_addresses(segment_index, dram_load_end, dram_load_addr, print_error, true);
|
||||
} else {
|
||||
return verify_load_addresses(segment_index, dram_load_addr, dram_load_end, print_error, true);
|
||||
}
|
||||
}
|
||||
/* Sections entirely in RTC memory won't overlap with a vanilla bootloader but are valid load addresses, thus skipping them from the check */
|
||||
} else if (esp_ptr_in_rtc_iram_fast(load_addr_p) && esp_ptr_in_rtc_iram_fast(load_end_p)){
|
||||
return true;
|
||||
} else if (esp_ptr_in_rtc_dram_fast(load_addr_p) && esp_ptr_in_rtc_dram_fast(load_end_p)){
|
||||
return true;
|
||||
} else if (esp_ptr_in_rtc_slow(load_addr_p) && esp_ptr_in_rtc_slow(load_end_p)) {
|
||||
return true;
|
||||
} else { /* Not a DRAM or an IRAM or RTC Fast IRAM, RTC Fast DRAM or RTC Slow address */
|
||||
reason = "bad load address range";
|
||||
goto invalid;
|
||||
}
|
||||
return true;
|
||||
|
||||
invalid:
|
||||
if (print_error) {
|
||||
ESP_LOGE(TAG, "Segment %d 0x%08x-0x%08x invalid: %s", segment_index, load_addr, load_end, reason);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif // BOOTLOADER_BUILD
|
||||
|
||||
static esp_err_t process_segment(int index, uint32_t flash_addr, esp_image_segment_header_t *header, bool silent, bool do_load, bootloader_sha256_handle_t sha_handle, uint32_t *checksum)
|
||||
{
|
||||
esp_err_t err;
|
||||
@ -337,37 +481,11 @@ static esp_err_t process_segment(int index, uint32_t flash_addr, esp_image_segme
|
||||
(do_load)?"load":(is_mapping)?"map":"");
|
||||
}
|
||||
|
||||
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
/* Before loading segment, check it doesn't clobber bootloader RAM. */
|
||||
if (do_load) {
|
||||
const intptr_t load_end = load_addr + data_len;
|
||||
if (load_end <= (intptr_t) SOC_DIRAM_DRAM_HIGH) {
|
||||
/* Writing to DRAM */
|
||||
intptr_t sp = (intptr_t)get_sp();
|
||||
if (load_end > sp - STACK_LOAD_HEADROOM) {
|
||||
/* Bootloader .data/.rodata/.bss is above the stack, so this
|
||||
* also checks that we aren't overwriting these segments.
|
||||
*
|
||||
* TODO: This assumes specific arrangement of sections we have
|
||||
* in the ESP32. Rewrite this in a generic way to support other
|
||||
* layouts.
|
||||
*/
|
||||
ESP_LOGE(TAG, "Segment %d end address 0x%08x too high (bootloader stack 0x%08x limit 0x%08x)",
|
||||
index, load_end, sp, sp - STACK_LOAD_HEADROOM);
|
||||
return ESP_ERR_IMAGE_INVALID;
|
||||
}
|
||||
} else {
|
||||
/* Writing to IRAM */
|
||||
const intptr_t loader_iram_start = (intptr_t) &_loader_text_start;
|
||||
const intptr_t loader_iram_end = (intptr_t) &_loader_text_end;
|
||||
|
||||
if (bootloader_util_regions_overlap(loader_iram_start, loader_iram_end,
|
||||
load_addr, load_end)) {
|
||||
ESP_LOGE(TAG, "Segment %d (0x%08x-0x%08x) overlaps bootloader IRAM (0x%08x-0x%08x)",
|
||||
index, load_addr, load_end, loader_iram_start, loader_iram_end);
|
||||
return ESP_ERR_IMAGE_INVALID;
|
||||
}
|
||||
if (do_load && data_len > 0) {
|
||||
if (!verify_load_addresses(index, load_addr, load_addr + data_len, true, false)) {
|
||||
return ESP_ERR_IMAGE_INVALID;
|
||||
}
|
||||
}
|
||||
#endif // BOOTLOADER_BUILD
|
||||
@ -377,6 +495,10 @@ static esp_err_t process_segment(int index, uint32_t flash_addr, esp_image_segme
|
||||
|
||||
int32_t data_len_remain = data_len;
|
||||
while (data_len_remain > 0) {
|
||||
#if defined(SECURE_BOOT_CHECK_SIGNATURE) && defined(BOOTLOADER_BUILD)
|
||||
/* Double check the address verification done above */
|
||||
ESP_FAULT_ASSERT(!do_load || verify_load_addresses(0, load_addr, load_addr + data_len_remain, false, false));
|
||||
#endif
|
||||
uint32_t offset_page = ((data_addr & MMAP_ALIGNED_MASK) != 0) ? 1 : 0;
|
||||
/* Data we could map in case we are not aligned to PAGE boundary is one page size lesser. */
|
||||
data_len = MIN(data_len_remain, ((free_page_count - offset_page) * SPI_FLASH_MMU_PAGE_SIZE));
|
||||
@ -572,28 +694,33 @@ static esp_err_t verify_checksum(bootloader_sha256_handle_t sha_handle, uint32_t
|
||||
|
||||
static void debug_log_hash(const uint8_t *image_hash, const char *caption);
|
||||
|
||||
static esp_err_t verify_secure_boot_signature(bootloader_sha256_handle_t sha_handle, esp_image_metadata_t *data)
|
||||
static esp_err_t verify_secure_boot_signature(bootloader_sha256_handle_t sha_handle, esp_image_metadata_t *data, uint8_t *image_digest, uint8_t *verified_digest)
|
||||
{
|
||||
uint8_t image_hash[HASH_LEN] = { 0 };
|
||||
#ifdef SECURE_BOOT_CHECK_SIGNATURE
|
||||
uint32_t end = data->start_addr + data->image_len;
|
||||
|
||||
ESP_LOGI(TAG, "Verifying image signature...");
|
||||
|
||||
// For secure boot, we calculate the signature hash over the whole file, which includes any "simple" hash
|
||||
// appended to the image for corruption detection
|
||||
if (data->image.hash_appended) {
|
||||
const void *simple_hash = bootloader_mmap(data->start_addr + data->image_len - HASH_LEN, HASH_LEN);
|
||||
const void *simple_hash = bootloader_mmap(end - HASH_LEN, HASH_LEN);
|
||||
bootloader_sha256_data(sha_handle, simple_hash, HASH_LEN);
|
||||
bootloader_munmap(simple_hash);
|
||||
}
|
||||
|
||||
bootloader_sha256_finish(sha_handle, image_hash);
|
||||
bootloader_sha256_finish(sha_handle, image_digest);
|
||||
|
||||
// Log the hash for debugging
|
||||
debug_log_hash(image_hash, "Calculated secure boot hash");
|
||||
debug_log_hash(image_digest, "Calculated secure boot hash");
|
||||
|
||||
// Use hash to verify signature block
|
||||
const esp_secure_boot_sig_block_t *sig_block = bootloader_mmap(data->start_addr + data->image_len, sizeof(esp_secure_boot_sig_block_t));
|
||||
esp_err_t err = esp_secure_boot_verify_signature_block(sig_block, image_hash);
|
||||
esp_err_t err = ESP_ERR_IMAGE_INVALID;
|
||||
const void *sig_block;
|
||||
ESP_FAULT_ASSERT(memcmp(image_digest, verified_digest, HASH_LEN) != 0); /* sanity check that these values start differently */
|
||||
sig_block = bootloader_mmap(data->start_addr + data->image_len, sizeof(esp_secure_boot_sig_block_t));
|
||||
err = esp_secure_boot_verify_ecdsa_signature_block(sig_block, image_digest, verified_digest);
|
||||
|
||||
bootloader_munmap(sig_block);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Secure boot signature verification failed");
|
||||
@ -614,6 +741,7 @@ static esp_err_t verify_secure_boot_signature(bootloader_sha256_handle_t sha_han
|
||||
return ESP_ERR_IMAGE_INVALID;
|
||||
}
|
||||
|
||||
#endif // SECURE_BOOT_CHECK_SIGNATURE
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
@ -15,11 +15,22 @@
|
||||
|
||||
#include "bootloader_flash.h"
|
||||
#include "bootloader_sha.h"
|
||||
#include "bootloader_utility.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_secure_boot.h"
|
||||
|
||||
#include "uECC.h"
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
#include "uECC_verify_antifault.h"
|
||||
#else
|
||||
#include "mbedtls/sha256.h"
|
||||
#include "mbedtls/x509.h"
|
||||
#include "mbedtls/md.h"
|
||||
#include "mbedtls/platform.h"
|
||||
#include "mbedtls/entropy.h"
|
||||
#include "mbedtls/ctr_drbg.h"
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
@ -38,38 +49,17 @@ extern const uint8_t signature_verification_key_end[] asm("_binary_signature_ver
|
||||
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||
{
|
||||
uint8_t digest[DIGEST_LEN];
|
||||
const uint8_t *data;
|
||||
uint8_t verified_digest[DIGEST_LEN] = { 0 }; /* ignored in this function */
|
||||
const esp_secure_boot_sig_block_t *sigblock;
|
||||
|
||||
ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length);
|
||||
|
||||
bootloader_sha256_handle_t handle = bootloader_sha256_start();
|
||||
esp_err_t err = bootloader_sha256_flash_contents(src_addr, length, digest);
|
||||
|
||||
uint32_t free_page_count = bootloader_mmap_get_free_pages();
|
||||
ESP_LOGD(TAG, "free data page_count 0x%08x", free_page_count);
|
||||
|
||||
int32_t data_len_remain = length;
|
||||
uint32_t data_addr = src_addr;
|
||||
while (data_len_remain > 0) {
|
||||
uint32_t offset_page = ((data_addr & MMAP_ALIGNED_MASK) != 0) ? 1 : 0;
|
||||
/* Data we could map in case we are not aligned to PAGE boundary is one page size lesser. */
|
||||
uint32_t data_len = MIN(data_len_remain, ((free_page_count - offset_page) * SPI_FLASH_MMU_PAGE_SIZE));
|
||||
data = (const uint8_t *) bootloader_mmap(data_addr, data_len);
|
||||
if(!data) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", data_addr, data_len);
|
||||
bootloader_sha256_finish(handle, NULL);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
bootloader_sha256_data(handle, data, data_len);
|
||||
bootloader_munmap(data);
|
||||
|
||||
data_addr += data_len;
|
||||
data_len_remain -= data_len;
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Done! Get the digest */
|
||||
bootloader_sha256_finish(handle, digest);
|
||||
|
||||
// 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) {
|
||||
@ -77,20 +67,27 @@ esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||
return ESP_FAIL;
|
||||
}
|
||||
// Verify the signature
|
||||
esp_err_t err = esp_secure_boot_verify_signature_block(sigblock, digest);
|
||||
err = esp_secure_boot_verify_ecdsa_signature_block(sigblock, digest, verified_digest);
|
||||
// Unmap
|
||||
bootloader_munmap(sigblock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
esp_err_t esp_secure_boot_verify_signature_block(const esp_secure_boot_sig_block_t *sig_block, const uint8_t *image_digest)
|
||||
{
|
||||
uint8_t verified_digest[DIGEST_LEN] = { 0 };
|
||||
return esp_secure_boot_verify_ecdsa_signature_block(sig_block, image_digest, verified_digest);
|
||||
}
|
||||
|
||||
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;
|
||||
bool is_valid;
|
||||
|
||||
keylen = signature_verification_key_end - signature_verification_key_start;
|
||||
if(keylen != SIGNATURE_VERIFICATION_KEYLEN) {
|
||||
if (keylen != SIGNATURE_VERIFICATION_KEYLEN) {
|
||||
ESP_LOGE(TAG, "Embedded public verification key has wrong length %d", keylen);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
@ -102,11 +99,88 @@ esp_err_t esp_secure_boot_verify_signature_block(const esp_secure_boot_sig_block
|
||||
|
||||
ESP_LOGD(TAG, "Verifying secure boot signature");
|
||||
|
||||
is_valid = uECC_verify(signature_verification_key_start,
|
||||
is_valid = uECC_verify_antifault(signature_verification_key_start,
|
||||
image_digest,
|
||||
DIGEST_LEN,
|
||||
sig_block->signature,
|
||||
uECC_secp256r1());
|
||||
uECC_secp256r1(),
|
||||
verified_digest);
|
||||
ESP_LOGD(TAG, "Verification result %d", is_valid);
|
||||
return is_valid ? ESP_OK : ESP_ERR_IMAGE_INVALID;
|
||||
}
|
||||
|
||||
#else // BOOTLOADER_BUILD
|
||||
|
||||
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, 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 != 0) {
|
||||
ESP_LOGE(TAG, "image has invalid signature version field 0x%08x", sig_block->version);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Verifying secure boot signature");
|
||||
|
||||
int ret;
|
||||
mbedtls_mpi r, s;
|
||||
|
||||
mbedtls_mpi_init(&r);
|
||||
mbedtls_mpi_init(&s);
|
||||
|
||||
/* Extract r and s components from RAW ECDSA signature of 64 bytes */
|
||||
#define ECDSA_INTEGER_LEN 32
|
||||
ret = mbedtls_mpi_read_binary(&r, &sig_block->signature[0], ECDSA_INTEGER_LEN);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "Failed mbedtls_mpi_read_binary(1), err:%d", ret);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ret = mbedtls_mpi_read_binary(&s, &sig_block->signature[ECDSA_INTEGER_LEN], ECDSA_INTEGER_LEN);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "Failed mbedtls_mpi_read_binary(2), err:%d", ret);
|
||||
mbedtls_mpi_free(&r);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Initialise ECDSA context */
|
||||
mbedtls_ecdsa_context ecdsa_context;
|
||||
mbedtls_ecdsa_init(&ecdsa_context);
|
||||
|
||||
mbedtls_ecp_group_load(&ecdsa_context.grp, MBEDTLS_ECP_DP_SECP256R1);
|
||||
size_t plen = mbedtls_mpi_size(&ecdsa_context.grp.P);
|
||||
if (keylen != 2 * plen) {
|
||||
ESP_LOGE(TAG, "Incorrect ECDSA key length %d", keylen);
|
||||
ret = ESP_FAIL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Extract X and Y components from ECDSA public key */
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&ecdsa_context.Q.X, signature_verification_key_start, plen));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&ecdsa_context.Q.Y, signature_verification_key_start + plen, plen));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&ecdsa_context.Q.Z, 1));
|
||||
|
||||
ret = mbedtls_ecdsa_verify(&ecdsa_context.grp, image_digest, DIGEST_LEN, &ecdsa_context.Q, &r, &s);
|
||||
ESP_LOGD(TAG, "Verification result %d", ret);
|
||||
|
||||
cleanup:
|
||||
mbedtls_mpi_free(&r);
|
||||
mbedtls_mpi_free(&s);
|
||||
mbedtls_ecdsa_free(&ecdsa_context);
|
||||
return ret == 0 ? ESP_OK : ESP_ERR_IMAGE_INVALID;
|
||||
#endif // CONFIG_MBEDTLS_ECDSA_C && CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED
|
||||
}
|
||||
#endif // BOOTLOADER_BUILD
|
||||
|
94
components/esp32/include/esp_fault.h
Normal file
94
components/esp32/include/esp_fault.h
Normal file
@ -0,0 +1,94 @@
|
||||
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "sdkconfig.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Assert a condition is true, in a way that should be resistant to fault injection for
|
||||
* single fault attacks.
|
||||
*
|
||||
* - Expands CONDITION multiple times (condition must have no side effects)
|
||||
* - Compiler is told all registers are invalid before evaluating CONDITION each time, to avoid a fault
|
||||
* causing a misread of a register used in all three evaluations of CONDITION.
|
||||
* - If CONDITION is ever false, a system reset is triggered.
|
||||
*
|
||||
* @note Place this macro after a "normal" check of CONDITION that will fail with a normal error
|
||||
* message. This is the fallback in case a fault injection attack skips or corrupts the result of
|
||||
* that check. (Although ensure that an attacker can't use fault injection to skip past the "normal"
|
||||
* error message, to avoid this check entirely.)
|
||||
*
|
||||
* @note This macro increases binary size and is slow and should be used sparingly.
|
||||
*
|
||||
* @note This macro does not guarantee fault injection resistance. In particular CONDITION must be
|
||||
* chosen carefully - a fault injection attack which sets CONDITION to true will not be detected by
|
||||
* this macro. Care must also be taken that an attacker can't use a fault to completely bypass calling
|
||||
* whatever function tests ESP_FAULT_ASSERT.
|
||||
*
|
||||
* @note This is difficult to debug as a failure triggers an instant software reset, and UART output
|
||||
* is often truncated (as FIFO is not flushed). Define the ESP_FAULT_ASSERT_DEBUG macro to debug any
|
||||
* failures of this macro due to software bugs.
|
||||
*
|
||||
* @param CONDITION A condition which will evaluate true unless an attacker used fault injection to skip or corrupt some other critical system
|
||||
calculation.
|
||||
*
|
||||
*/
|
||||
#define ESP_FAULT_ASSERT(CONDITION) do { \
|
||||
asm volatile ("" ::: "memory"); \
|
||||
if(!(CONDITION)) _ESP_FAULT_RESET(); \
|
||||
asm volatile ("" ::: "memory"); \
|
||||
if(!(CONDITION)) _ESP_FAULT_RESET(); \
|
||||
asm volatile ("" ::: "memory"); \
|
||||
if(!(CONDITION)) _ESP_FAULT_RESET(); \
|
||||
} while(0)
|
||||
|
||||
|
||||
// Uncomment this macro to get debug output if ESP_FAULT_ASSERT() fails
|
||||
//
|
||||
// Note that uncommenting this macro reduces the anti-FI effectiveness
|
||||
//
|
||||
//#define ESP_FAULT_ASSERT_DEBUG
|
||||
|
||||
/* Internal macro, purpose is to trigger a system reset if an inconsistency due to fault injection
|
||||
is detected.
|
||||
|
||||
Illegal instruction opcodes are there as a fallback to crash the CPU in case it doesn't
|
||||
reset as expected.
|
||||
*/
|
||||
#ifndef ESP_FAULT_ASSERT_DEBUG
|
||||
|
||||
#define _ESP_FAULT_RESET() do { \
|
||||
REG_WRITE(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_SYS_RST); \
|
||||
asm volatile("ill; ill; ill;"); \
|
||||
} while(0)
|
||||
|
||||
#else // ESP_FAULT_ASSERT_DEBUG
|
||||
|
||||
#warning "Enabling ESP_FAULT_ASSERT_DEBUG makes ESP_FAULT_ASSERT() less effective"
|
||||
|
||||
#define _ESP_FAULT_RESET() do { \
|
||||
ets_printf("ESP_FAULT_ASSERT %s:%d\n", __FILE__, __LINE__); \
|
||||
asm volatile("ill;"); \
|
||||
} while(0)
|
||||
|
||||
#endif // ESP_FAULT_ASSERT_DEBUG
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -57,7 +57,7 @@ ifndef IS_BOOTLOADER_BUILD
|
||||
APP_BIN_UNSIGNED := $(APP_BIN:.bin=-unsigned.bin)
|
||||
|
||||
$(APP_BIN): $(APP_BIN_UNSIGNED) $(SECURE_BOOT_SIGNING_KEY) $(SDKCONFIG_MAKEFILE)
|
||||
$(ESPSECUREPY) sign_data --keyfile $(SECURE_BOOT_SIGNING_KEY) -o $@ $<
|
||||
$(ESPSECUREPY) sign_data --version 1 --keyfile $(SECURE_BOOT_SIGNING_KEY) -o $@ $<
|
||||
endif
|
||||
endif
|
||||
# non-secure boot (or bootloader), both these files are the same
|
||||
|
@ -1,7 +1,7 @@
|
||||
# only compile the "micro-ecc/uECC.c" source file
|
||||
set(COMPONENT_SRCS "micro-ecc/uECC.c")
|
||||
# only compile the "uECC_verify_antifault.c" file which includes the "micro-ecc/uECC.c" source file
|
||||
set(COMPONENT_SRCS "uECC_verify_antifault.c")
|
||||
|
||||
set(COMPONENT_ADD_INCLUDEDIRS micro-ecc)
|
||||
set(COMPONENT_ADD_INCLUDEDIRS . micro-ecc)
|
||||
|
||||
set(COMPONENT_REQUIRES)
|
||||
|
||||
|
@ -1,8 +1,7 @@
|
||||
# only compile the micro-ecc/uECC.c source file
|
||||
# (SRCDIRS is needed so build system can find the source file)
|
||||
COMPONENT_SRCDIRS := micro-ecc
|
||||
COMPONENT_OBJS := micro-ecc/uECC.o
|
||||
COMPONENT_SRCDIRS := .
|
||||
|
||||
COMPONENT_ADD_INCLUDEDIRS := micro-ecc
|
||||
COMPONENT_ADD_INCLUDEDIRS := . micro-ecc
|
||||
|
||||
COMPONENT_SUBMODULES := micro-ecc
|
||||
|
141
components/micro-ecc/uECC_verify_antifault.c
Normal file
141
components/micro-ecc/uECC_verify_antifault.c
Normal file
@ -0,0 +1,141 @@
|
||||
/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license.
|
||||
|
||||
Modifications Copyright 2020, Espressif Systems (Shanghai) PTE LTD. Licensed under the BSD
|
||||
2-clause license.
|
||||
*/
|
||||
|
||||
/* uECC_verify() calls a number of static functions form here and
|
||||
uses other definitions, so we just build that whole source file here and then append
|
||||
our modified version uECC_verify_antifault(). */
|
||||
#include "micro-ecc/uECC.c"
|
||||
|
||||
/* Version of uECC_verify() which also copies message_hash into verified_hash,
|
||||
but only if the signature is valid. Does this in an FI resistant way.
|
||||
*/
|
||||
int uECC_verify_antifault(const uint8_t *public_key,
|
||||
const uint8_t *message_hash,
|
||||
unsigned hash_size,
|
||||
const uint8_t *signature,
|
||||
uECC_Curve curve,
|
||||
uint8_t *verified_hash) {
|
||||
uECC_word_t u1[uECC_MAX_WORDS], u2[uECC_MAX_WORDS];
|
||||
uECC_word_t z[uECC_MAX_WORDS];
|
||||
uECC_word_t sum[uECC_MAX_WORDS * 2];
|
||||
uECC_word_t rx[uECC_MAX_WORDS];
|
||||
uECC_word_t ry[uECC_MAX_WORDS];
|
||||
uECC_word_t tx[uECC_MAX_WORDS];
|
||||
uECC_word_t ty[uECC_MAX_WORDS];
|
||||
uECC_word_t tz[uECC_MAX_WORDS];
|
||||
const uECC_word_t *points[4];
|
||||
const uECC_word_t *point;
|
||||
bitcount_t num_bits;
|
||||
bitcount_t i;
|
||||
#if uECC_VLI_NATIVE_LITTLE_ENDIAN
|
||||
uECC_word_t *_public = (uECC_word_t *)public_key;
|
||||
#else
|
||||
uECC_word_t _public[uECC_MAX_WORDS * 2];
|
||||
#endif
|
||||
uECC_word_t r[uECC_MAX_WORDS], s[uECC_MAX_WORDS];
|
||||
wordcount_t num_words = curve->num_words;
|
||||
wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits);
|
||||
|
||||
rx[num_n_words - 1] = 0;
|
||||
r[num_n_words - 1] = 0;
|
||||
s[num_n_words - 1] = 0;
|
||||
|
||||
#if uECC_VLI_NATIVE_LITTLE_ENDIAN
|
||||
bcopy((uint8_t *) r, signature, curve->num_bytes);
|
||||
bcopy((uint8_t *) s, signature + curve->num_bytes, curve->num_bytes);
|
||||
#else
|
||||
uECC_vli_bytesToNative(_public, public_key, curve->num_bytes);
|
||||
uECC_vli_bytesToNative(
|
||||
_public + num_words, public_key + curve->num_bytes, curve->num_bytes);
|
||||
uECC_vli_bytesToNative(r, signature, curve->num_bytes);
|
||||
uECC_vli_bytesToNative(s, signature + curve->num_bytes, curve->num_bytes);
|
||||
#endif
|
||||
|
||||
/* r, s must not be 0. */
|
||||
if (uECC_vli_isZero(r, num_words) || uECC_vli_isZero(s, num_words)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* r, s must be < n. */
|
||||
if (uECC_vli_cmp(curve->n, r, num_n_words) != 1 ||
|
||||
uECC_vli_cmp(curve->n, s, num_n_words) != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Calculate u1 and u2. */
|
||||
uECC_vli_modInv(z, s, curve->n, num_n_words); /* z = 1/s */
|
||||
u1[num_n_words - 1] = 0;
|
||||
bits2int(u1, message_hash, hash_size, curve);
|
||||
uECC_vli_modMult(u1, u1, z, curve->n, num_n_words); /* u1 = e/s */
|
||||
uECC_vli_modMult(u2, r, z, curve->n, num_n_words); /* u2 = r/s */
|
||||
|
||||
/* Calculate sum = G + Q. */
|
||||
uECC_vli_set(sum, _public, num_words);
|
||||
uECC_vli_set(sum + num_words, _public + num_words, num_words);
|
||||
uECC_vli_set(tx, curve->G, num_words);
|
||||
uECC_vli_set(ty, curve->G + num_words, num_words);
|
||||
uECC_vli_modSub(z, sum, tx, curve->p, num_words); /* z = x2 - x1 */
|
||||
XYcZ_add(tx, ty, sum, sum + num_words, curve);
|
||||
uECC_vli_modInv(z, z, curve->p, num_words); /* z = 1/z */
|
||||
apply_z(sum, sum + num_words, z, curve);
|
||||
|
||||
/* Use Shamir's trick to calculate u1*G + u2*Q */
|
||||
points[0] = 0;
|
||||
points[1] = curve->G;
|
||||
points[2] = _public;
|
||||
points[3] = sum;
|
||||
num_bits = smax(uECC_vli_numBits(u1, num_n_words),
|
||||
uECC_vli_numBits(u2, num_n_words));
|
||||
|
||||
point = points[(!!uECC_vli_testBit(u1, num_bits - 1)) |
|
||||
((!!uECC_vli_testBit(u2, num_bits - 1)) << 1)];
|
||||
uECC_vli_set(rx, point, num_words);
|
||||
uECC_vli_set(ry, point + num_words, num_words);
|
||||
uECC_vli_clear(z, num_words);
|
||||
z[0] = 1;
|
||||
|
||||
for (i = num_bits - 2; i >= 0; --i) {
|
||||
uECC_word_t index;
|
||||
curve->double_jacobian(rx, ry, z, curve);
|
||||
|
||||
index = (!!uECC_vli_testBit(u1, i)) | ((!!uECC_vli_testBit(u2, i)) << 1);
|
||||
point = points[index];
|
||||
if (point) {
|
||||
uECC_vli_set(tx, point, num_words);
|
||||
uECC_vli_set(ty, point + num_words, num_words);
|
||||
apply_z(tx, ty, z, curve);
|
||||
uECC_vli_modSub(tz, rx, tx, curve->p, num_words); /* Z = x2 - x1 */
|
||||
XYcZ_add(tx, ty, rx, ry, curve);
|
||||
uECC_vli_modMult_fast(z, z, tz, curve);
|
||||
}
|
||||
}
|
||||
|
||||
uECC_vli_modInv(z, z, curve->p, num_words); /* Z = 1/Z */
|
||||
apply_z(rx, ry, z, curve);
|
||||
|
||||
/* v = x1 (mod n) */
|
||||
if (uECC_vli_cmp(curve->n, rx, num_n_words) != 1) {
|
||||
uECC_vli_sub(rx, rx, curve->n, num_n_words);
|
||||
}
|
||||
|
||||
/* Anti-FI addition. Copy message_hash into verified_hash, but do it in a
|
||||
way that it will only happen if v == r (ie, rx == r)
|
||||
*/
|
||||
const uECC_word_t *mhash_words = (const uECC_word_t *)message_hash;
|
||||
uECC_word_t *vhash_words = (uECC_word_t *)verified_hash;
|
||||
unsigned hash_words = hash_size / sizeof(uECC_word_t);
|
||||
for (unsigned int w = 0; w < hash_words; w++) {
|
||||
/* note: using curve->num_words here to encourage compiler to re-read this variable */
|
||||
vhash_words[w] = mhash_words[w] ^ rx[w % curve->num_words] ^ r[w % curve->num_words];
|
||||
}
|
||||
/* Curve may be longer than hash, in which case keep reading the rest of the bytes */
|
||||
for (int w = hash_words; w < curve->num_words; w++) {
|
||||
vhash_words[w % hash_words] |= rx[w] ^ r[w];
|
||||
}
|
||||
|
||||
/* Accept only if v == r. */
|
||||
return (int)(uECC_vli_equal(rx, r, num_words));
|
||||
}
|
18
components/micro-ecc/uECC_verify_antifault.h
Normal file
18
components/micro-ecc/uECC_verify_antifault.h
Normal file
@ -0,0 +1,18 @@
|
||||
/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license.
|
||||
|
||||
Modifications Copyright 2020, Espressif Systems (Shanghai) PTE LTD. Licensed under the BSD
|
||||
2-clause license.
|
||||
*/
|
||||
#pragma once
|
||||
#include "uECC.h"
|
||||
|
||||
/* Version uECC_verify() that also copies message_hash to verified_hash
|
||||
if the signature is valid, and does it in a way that is harder to attack
|
||||
with fault injection.
|
||||
*/
|
||||
int uECC_verify_antifault(const uint8_t *public_key,
|
||||
const uint8_t *message_hash,
|
||||
unsigned hash_size,
|
||||
const uint8_t *signature,
|
||||
uECC_Curve curve,
|
||||
uint8_t *verified_hash);
|
@ -50,7 +50,7 @@ ifdef CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES
|
||||
PARTITION_TABLE_BIN_UNSIGNED := $(PARTITION_TABLE_BIN:.bin=-unsigned.bin)
|
||||
# add an extra signing step for secure partition table
|
||||
$(PARTITION_TABLE_BIN): $(PARTITION_TABLE_BIN_UNSIGNED) $(SDKCONFIG_MAKEFILE) $(SECURE_BOOT_SIGNING_KEY)
|
||||
$(ESPSECUREPY) sign_data --keyfile $(SECURE_BOOT_SIGNING_KEY) -o $@ $<
|
||||
$(ESPSECUREPY) sign_data --version 1 --keyfile $(SECURE_BOOT_SIGNING_KEY) -o $@ $<
|
||||
else
|
||||
# secure bootloader disabled, both files are the same
|
||||
PARTITION_TABLE_BIN_UNSIGNED := $(PARTITION_TABLE_BIN)
|
||||
|
@ -322,6 +322,9 @@
|
||||
#define SOC_MEM_INTERNAL_LOW 0x3FF90000
|
||||
#define SOC_MEM_INTERNAL_HIGH 0x400C2000
|
||||
|
||||
// Start (highest address) of ROM boot stack, only relevant during early boot
|
||||
#define SOC_ROM_STACK_START 0x3ffe3f20
|
||||
|
||||
//Interrupt hardware source table
|
||||
//This table is decided by hardware, don't touch this.
|
||||
#define ETS_WIFI_MAC_INTR_SOURCE 0/**< interrupt of WiFi MAC, level*/
|
||||
|
@ -207,9 +207,38 @@ inline static bool IRAM_ATTR esp_ptr_in_diram_iram(const void *p) {
|
||||
return ((intptr_t)p >= SOC_DIRAM_IRAM_LOW && (intptr_t)p < SOC_DIRAM_IRAM_HIGH);
|
||||
}
|
||||
|
||||
|
||||
inline static bool IRAM_ATTR esp_stack_ptr_is_sane(uint32_t sp)
|
||||
{
|
||||
//Check if stack ptr is in between SOC_DRAM_LOW and SOC_DRAM_HIGH, and 16 byte aligned.
|
||||
return !(sp < SOC_DRAM_LOW + 0x10 || sp > SOC_DRAM_HIGH - 0x10 || ((sp & 0xF) != 0));
|
||||
}
|
||||
|
||||
inline static bool IRAM_ATTR esp_ptr_in_rtc_iram_fast(const void *p) {
|
||||
return ((intptr_t)p >= SOC_RTC_IRAM_LOW && (intptr_t)p < SOC_RTC_IRAM_HIGH);
|
||||
}
|
||||
|
||||
inline static bool IRAM_ATTR esp_ptr_in_rtc_dram_fast(const void *p) {
|
||||
return ((intptr_t)p >= SOC_RTC_DRAM_LOW && (intptr_t)p < SOC_RTC_DRAM_HIGH);
|
||||
}
|
||||
|
||||
inline static bool IRAM_ATTR esp_ptr_in_rtc_slow(const void *p) {
|
||||
return ((intptr_t)p >= SOC_RTC_DATA_LOW && (intptr_t)p < SOC_RTC_DATA_HIGH);
|
||||
}
|
||||
|
||||
/* Convert a D/IRAM DRAM pointer to equivalent word address in IRAM
|
||||
|
||||
- Address must be word aligned
|
||||
- Address must pass esp_ptr_in_diram_dram() test, or result will be invalid pointer
|
||||
*/
|
||||
inline static void * IRAM_ATTR esp_ptr_diram_dram_to_iram(const void *p) {
|
||||
return (void *) ( SOC_DIRAM_IRAM_LOW + ((intptr_t)p - SOC_DIRAM_DRAM_LOW) );
|
||||
}
|
||||
|
||||
/* Convert a D/IRAM IRAM pointer to equivalent word address in DRAM
|
||||
|
||||
- Address must be word aligned
|
||||
- Address must pass esp_ptr_in_diram_iram() test, or result will be invalid pointer
|
||||
*/
|
||||
inline static void * IRAM_ATTR esp_ptr_diram_iram_to_dram(const void *p) {
|
||||
return (void *) ( SOC_DIRAM_DRAM_LOW + ((intptr_t)p - SOC_DIRAM_IRAM_LOW) );
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user