Merge branch 'feature/esp_tee_h2' into 'master'

feat(esp_tee): Support for ESP32-H2

See merge request espressif/esp-idf!37708
This commit is contained in:
Mahavir Jain
2025-05-21 09:59:26 +05:30
42 changed files with 1822 additions and 227 deletions

View File

@ -136,7 +136,7 @@ esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size)
#if ESP_TEE_BUILD
#include "esp_fault.h"
#include "esp_flash_partitions.h"
#include "esp32c6/rom/spi_flash.h"
#include "rom/spi_flash.h"
extern bool esp_tee_flash_check_paddr_in_active_tee_part(size_t paddr);
#endif

View File

@ -1,3 +1,5 @@
idf_build_get_property(non_os_build NON_OS_BUILD)
set(srcs "rtc_clk_init.c"
"rtc_clk.c"
"pmu_param.c"
@ -7,7 +9,7 @@ set(srcs "rtc_clk_init.c"
"chip_info.c"
)
if(NOT BOOTLOADER_BUILD)
if(NOT non_os_build)
list(APPEND srcs "sar_periph_ctrl.c")
endif()

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -112,6 +112,14 @@ void esp_cpu_configure_region_protection(void)
//
esp_cpu_configure_invalid_regions();
/* NOTE: When ESP-TEE is active, only configure invalid memory regions in bootloader
* to prevent errors before TEE initialization. TEE will handle all other
* memory protection.
*/
#if CONFIG_SECURE_ENABLE_TEE && BOOTLOADER_BUILD
return;
#endif
//
// Configure all the valid address regions using PMP
//

View File

@ -6,6 +6,7 @@
#include "esp_cpu.h"
#include "esp_riscv_intr.h"
#include "sdkconfig.h"
void esp_cpu_intr_get_desc(int core_id, int intr_num, esp_cpu_intr_desc_t *intr_desc_ret)
{
@ -15,7 +16,18 @@ void esp_cpu_intr_get_desc(int core_id, int intr_num, esp_cpu_intr_desc_t *intr_
* Interrupts 3, 4 and 7 are unavailable for PULP CPU as they are bound to Core-Local Interrupts (CLINT)
*/
// [TODO: IDF-2465]
const uint32_t rsvd_mask = BIT(3) | BIT(4) | BIT(6) | BIT(7);
const uint32_t base_rsvd_mask = BIT(3) | BIT(4) | BIT(6) | BIT(7);
/* On the ESP32-H2, interrupt 14 is reserved for ESP-TEE
* for operations related to secure peripherals under its control
* (e.g. AES, SHA, APM)
*/
#if CONFIG_SECURE_ENABLE_TEE
const uint32_t rsvd_mask = base_rsvd_mask | BIT(14);
#else
const uint32_t rsvd_mask = base_rsvd_mask;
#endif
intr_desc_ret->priority = 1;
intr_desc_ret->type = ESP_CPU_INTR_TYPE_NA;

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -10,15 +10,40 @@
#include "../ext_mem_layout.h"
#include "hal/mmu_types.h"
/* NOTE: With ESP-TEE enabled:
* - The start address is moved by the size of TEE IDROM segments since these
* segments are placed at the start of the linear address space
* - TEE IROM and DROM segments are both 64KB (CONFIG_SECURE_TEE_IROM_SIZE,
* CONFIG_SECURE_TEE_DROM_SIZE) for now. Thus, the number of reserved entries
* from the start would be (64KB + 64KB)/MMU_PAGE_SIZE
* - The last few MMU entries are reserved for TEE flash operations. The number
* of reserved entries matches the size of TEE IDROM segments (IROM + DROM)
* plus one additional entry, i.e. (64KB + 64KB)/MMU_PAGE_SIZE + 1
*/
#if CONFIG_SECURE_ENABLE_TEE
#define TEE_MMU_MEM_REG_START_OFFS (CONFIG_SECURE_TEE_IROM_SIZE + CONFIG_SECURE_TEE_DROM_SIZE)
#define TEE_MMU_RESV_PAGES ((CONFIG_SECURE_TEE_IROM_SIZE + CONFIG_SECURE_TEE_DROM_SIZE) / CONFIG_MMU_PAGE_SIZE)
#define TEE_MMU_MEM_REG_END_OFFS ((TEE_MMU_RESV_PAGES + 1) * CONFIG_MMU_PAGE_SIZE)
#define MMU_MEM_REG_START_ADDR_W_TEE (SOC_MMU_IRAM0_LINEAR_ADDRESS_LOW + TEE_MMU_MEM_REG_START_OFFS)
#define MMU_MEM_REG_END_ADDR_W_TEE (SOC_MMU_IRAM0_LINEAR_ADDRESS_HIGH - TEE_MMU_MEM_REG_END_OFFS)
#define MMU_IRAM0_LINEAR_ADDRESS_LOW MMU_MEM_REG_START_ADDR_W_TEE
#define MMU_IRAM0_LINEAR_ADDRESS_HIGH MMU_MEM_REG_END_ADDR_W_TEE
#else
#define MMU_IRAM0_LINEAR_ADDRESS_LOW SOC_MMU_IRAM0_LINEAR_ADDRESS_LOW
#define MMU_IRAM0_LINEAR_ADDRESS_HIGH SOC_MMU_IRAM0_LINEAR_ADDRESS_HIGH
#endif
/**
* The start addresses in this list should always be sorted from low to high, as MMU driver will need to
* coalesce adjacent regions
*/
const mmu_mem_region_t g_mmu_mem_regions[SOC_MMU_LINEAR_ADDRESS_REGION_NUM] = {
[0] = {
.start = SOC_MMU_IRAM0_LINEAR_ADDRESS_LOW,
.end = SOC_MMU_IRAM0_LINEAR_ADDRESS_HIGH,
.size = SOC_BUS_SIZE(SOC_MMU_IRAM0_LINEAR),
.start = MMU_IRAM0_LINEAR_ADDRESS_LOW,
.end = MMU_IRAM0_LINEAR_ADDRESS_HIGH,
.size = MMU_IRAM0_LINEAR_ADDRESS_HIGH - MMU_IRAM0_LINEAR_ADDRESS_LOW,
.bus_id = CACHE_BUS_IBUS0 | CACHE_BUS_DBUS0,
.targets = MMU_TARGET_FLASH0,
.caps = MMU_MEM_CAP_EXEC | MMU_MEM_CAP_READ | MMU_MEM_CAP_32BIT | MMU_MEM_CAP_8BIT,

View File

@ -131,10 +131,8 @@ if(CONFIG_ESP_ROM_HAS_VERSION)
endif()
if(ESP_TEE_BUILD)
if(target STREQUAL "esp32c6")
rom_linker_script("spiflash")
rom_linker_script("heap")
endif()
rom_linker_script("spiflash")
rom_linker_script("heap")
endif()
if(BOOTLOADER_BUILD)

View File

@ -15,7 +15,13 @@
#include "sdkconfig.h"
#include "ld.common"
#define SRAM_SEG_START 0x40800000
#if !CONFIG_SECURE_ENABLE_TEE
#define SRAM_SEG_START (0x40800000)
#else
#define SRAM_SEG_START (0x40800000 + CONFIG_SECURE_TEE_IRAM_SIZE + CONFIG_SECURE_TEE_DRAM_SIZE)
#define FLASH_SEG_OFFSET (CONFIG_SECURE_TEE_IROM_SIZE + CONFIG_SECURE_TEE_DROM_SIZE)
#endif // CONFIG_SECURE_ENABLE_TEE
#define SRAM_SEG_END 0x4083EFD0 /* 2nd stage bootloader iram_loader_seg start address */
#define SRAM_SEG_SIZE SRAM_SEG_END - SRAM_SEG_START
@ -35,8 +41,14 @@ MEMORY
*/
#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS
#if CONFIG_SECURE_ENABLE_TEE
/* Flash mapped instruction data */
irom_seg (RX) : org = 0x42000020 + FLASH_SEG_OFFSET,
len = IDRAM0_2_SEG_SIZE - FLASH_SEG_OFFSET - 0x20
#else
/* Flash mapped instruction data */
irom_seg (RX) : org = 0x42000020, len = IDRAM0_2_SEG_SIZE - 0x20
#endif
/**
* (0x20 offset above is a convenience for the app binary image generation.
@ -54,8 +66,14 @@ MEMORY
sram_seg (RWX) : org = SRAM_SEG_START, len = SRAM_SEG_SIZE
#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS
#if CONFIG_SECURE_ENABLE_TEE
/* Flash mapped constant data */
drom_seg (R) : org = 0x42000020 + FLASH_SEG_OFFSET,
len = IDRAM0_2_SEG_SIZE - FLASH_SEG_OFFSET - 0x20
#else
/* Flash mapped instruction data */
drom_seg (R) : org = 0x42000020, len = IDRAM0_2_SEG_SIZE - 0x20
#endif
/* (See irom_seg for meaning of 0x20 offset in the above.) */
#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS

View File

@ -173,9 +173,22 @@ SECTIONS
/* Vectors go to start of IRAM */
ASSERT(ABSOLUTE(.) % 0x100 == 0, "vector address must be 256 byte aligned");
_vector_table_start = ABSOLUTE(.);
KEEP(*(.exception_vectors_table.text));
KEEP(*(.exception_vectors.text));
ALIGNED_SYMBOL(4, _invalid_pc_placeholder)
/* esp_tee_config_t structure: used to share information between the TEE and REE
* (e.g. interrupt handler addresses, REE flash text-rodata boundaries, etc.)
* This symbol is expected by the TEE at an offset of 0x300 from the vector table start.
*/
#if CONFIG_SECURE_ENABLE_TEE
ALIGNED_SYMBOL(0x10, _esp_tee_app_cfg)
ASSERT(ABSOLUTE(.) == _vector_table_start + 0x2e0, "esp_tee_app_cfg must be at an offset 0x2e0 from the vector table start");
*libesp_tee.a:(.esp_tee_app_cfg);
#endif
/* Code marked as running out of IRAM */
_iram_text_start = ABSOLUTE(.);

View File

@ -277,11 +277,14 @@ __attribute__((weak)) void esp_perip_clk_init(void)
periph_ll_disable_clk_set_rst(PERIPH_ASSIST_DEBUG_MODULE);
#endif
periph_ll_disable_clk_set_rst(PERIPH_RSA_MODULE);
#if !CONFIG_SECURE_ENABLE_TEE
// NOTE: [ESP-TEE] The TEE is responsible for the AES and SHA peripherals
periph_ll_disable_clk_set_rst(PERIPH_AES_MODULE);
periph_ll_disable_clk_set_rst(PERIPH_SHA_MODULE);
periph_ll_disable_clk_set_rst(PERIPH_ECC_MODULE);
periph_ll_disable_clk_set_rst(PERIPH_HMAC_MODULE);
periph_ll_disable_clk_set_rst(PERIPH_DS_MODULE);
#endif
periph_ll_disable_clk_set_rst(PERIPH_ECDSA_MODULE);
// TODO: Replace with hal implementation

View File

@ -6,8 +6,8 @@ idf_build_get_property(target IDF_TARGET)
# headers & sources here are compiled into the app, not the esp_tee binary
# (see subproject/ for the esp_tee binary build files)
# ESP-TEE is currently supported only on the ESP32-C6 SoC
if(NOT ${target} STREQUAL "esp32c6")
# ESP-TEE is currently supported only on the ESP32-C6 and ESP32-H2 SoCs
if(NOT ${target} STREQUAL "esp32c6" AND NOT ${target} STREQUAL "esp32h2")
return()
endif()

View File

@ -1,9 +1,8 @@
menu "ESP-TEE (Trusted Execution Environment)"
depends on IDF_TARGET_ESP32C6
depends on IDF_TARGET_ESP32C6 || IDF_TARGET_ESP32H2
config SECURE_ENABLE_TEE
bool "Enable the ESP-TEE framework"
depends on IDF_TARGET_ESP32C6
select ESP_SYSTEM_MEMPROT_FEATURE_VIA_TEE
help
This configuration enables the Trusted Execution Environment (TEE) feature.
@ -75,7 +74,6 @@ menu "ESP-TEE (Trusted Execution Environment)"
Secure storage will be encrypted by a constant key embedded in the TEE firmware
config SECURE_TEE_SEC_STG_MODE_RELEASE
depends on IDF_TARGET_ESP32C6
bool "Release"
help
Secure storage will be encrypted by the data stored in eFuse block

View File

@ -0,0 +1,296 @@
secure_services:
- family: misc
entries:
- id: 0
type: custom
function: invalid_secure_service
args: 0
# ID: 1-4 (4) - External memory (Flash) protection [SPI0]
- family: flash_protection_spi0
entries:
- id: 1
type: IDF
function: mmu_hal_map_region
args: 6
- id: 2
type: IDF
function: mmu_hal_unmap_region
args: 3
- id: 3
type: IDF
function: mmu_hal_vaddr_to_paddr
args: 4
- id: 4
type: IDF
function: mmu_hal_paddr_to_vaddr
args: 5
# ID: 5-21 (17) - External memory (Flash) protection [SPI1]
- family: flash_protection_spi1
entries:
- id: 5
type: IDF
function: spi_flash_hal_check_status
args: 1
- id: 6
type: IDF
function: spi_flash_hal_common_command
args: 2
- id: 7
type: IDF
function: spi_flash_hal_device_config
args: 1
- id: 8
type: IDF
function: spi_flash_hal_erase_block
args: 2
- id: 9
type: IDF
function: spi_flash_hal_erase_chip
args: 1
- id: 10
type: IDF
function: spi_flash_hal_erase_sector
args: 2
- id: 11
type: IDF
function: spi_flash_hal_program_page
args: 4
- id: 12
type: IDF
function: spi_flash_hal_read
args: 4
- id: 13
type: IDF
function: spi_flash_hal_resume
args: 1
- id: 14
type: IDF
function: spi_flash_hal_set_write_protect
args: 2
- id: 15
type: IDF
function: spi_flash_hal_setup_read_suspend
args: 2
- id: 16
type: IDF
function: spi_flash_hal_supports_direct_read
args: 2
- id: 17
type: IDF
function: spi_flash_hal_supports_direct_write
args: 2
- id: 18
type: IDF
function: spi_flash_hal_suspend
args: 1
- id: 19
type: IDF
function: bootloader_flash_execute_command_common
args: 7
- id: 20
type: IDF
function: memspi_host_flush_cache
args: 3
- id: 21
type: IDF
function: spi_flash_chip_generic_config_host_io_mode
args: 2
# ID: 30-53 (24) - Interrupt Handling
- family: interrupt_handling
entries:
- id: 30
type: IDF
function: esp_rom_route_intr_matrix
args: 3
- id: 31
type: IDF
function: rv_utils_intr_enable
args: 1
- id: 32
type: IDF
function: rv_utils_intr_disable
args: 1
- id: 33
type: IDF
function: rv_utils_intr_set_priority
args: 2
- id: 34
type: IDF
function: rv_utils_intr_set_type
args: 2
- id: 35
type: IDF
function: rv_utils_intr_set_threshold
args: 1
- id: 36
type: IDF
function: rv_utils_intr_edge_ack
args: 1
- id: 37
type: IDF
function: rv_utils_intr_global_enable
args: 0
# ID: 54-85 (32) - HAL
- family: hal
entries:
- id: 54
type: IDF
function: wdt_hal_init
args: 4
- id: 55
type: IDF
function: wdt_hal_deinit
args: 1
# ID: 86-133 (48) - Crypto
- family: crypto
entries:
- id: 86
type: IDF
function: esp_aes_intr_alloc
args: 0
- id: 87
type: IDF
function: esp_aes_crypt_cbc
args: 6
- id: 88
type: IDF
function: esp_aes_crypt_cfb8
args: 6
- id: 89
type: IDF
function: esp_aes_crypt_cfb128
args: 7
- id: 90
type: IDF
function: esp_aes_crypt_ctr
args: 7
- id: 91
type: IDF
function: esp_aes_crypt_ecb
args: 4
- id: 92
type: IDF
function: esp_aes_crypt_ofb
args: 6
- id: 93
type: IDF
function: esp_sha
args: 4
- id: 94
type: IDF
function: esp_sha_block
args: 3
- id: 95
type: IDF
function: esp_sha_dma
args: 6
- id: 96
type: IDF
function: esp_sha_read_digest_state
args: 2
- id: 97
type: IDF
function: esp_sha_write_digest_state
args: 2
- id: 98
type: IDF
function: esp_crypto_sha_enable_periph_clk
args: 1
- id: 99
type: IDF
function: esp_hmac_calculate
args: 4
- id: 100
type: IDF
function: esp_hmac_jtag_enable
args: 2
- id: 101
type: IDF
function: esp_hmac_jtag_disable
args: 0
- id: 102
type: IDF
function: esp_ds_sign
args: 4
- id: 103
type: IDF
function: esp_ds_start_sign
args: 4
- id: 104
type: IDF
function: esp_ds_is_busy
args: 0
- id: 105
type: IDF
function: esp_ds_finish_sign
args: 2
- id: 106
type: IDF
function: esp_ds_encrypt_params
args: 4
- id: 107
type: IDF
function: esp_crypto_mpi_enable_periph_clk
args: 1
- id: 108
type: IDF
function: esp_ecc_point_multiply
args: 4
- id: 109
type: IDF
function: esp_ecc_point_verify
args: 1
- id: 110
type: IDF
function: esp_crypto_ecc_enable_periph_clk
args: 1
# ID: 134-169 (36) - Reserved for future use
- family: attestation
entries:
- id: 170
type: custom
function: esp_tee_att_generate_token
args: 6
# ID: 175-194 (20) - Secure Storage
- family: secure_storage
entries:
- id: 175
type: custom
function: esp_tee_sec_storage_clear_key
args: 1
- id: 176
type: custom
function: esp_tee_sec_storage_gen_key
args: 1
- id: 177
type: custom
function: esp_tee_sec_storage_ecdsa_sign
args: 4
- id: 178
type: custom
function: esp_tee_sec_storage_ecdsa_get_pubkey
args: 2
- id: 179
type: custom
function: esp_tee_sec_storage_aead_encrypt
args: 4
- id: 180
type: custom
function: esp_tee_sec_storage_aead_decrypt
args: 4
# ID: 195-199 (5) - OTA
- family: ota
entries:
- id: 195
type: custom
function: esp_tee_ota_begin
args: 0
- id: 196
type: custom
function: esp_tee_ota_write
args: 3
- id: 197
type: custom
function: esp_tee_ota_end
args: 0
# ID: 200+ - User-defined

View File

@ -331,6 +331,13 @@ int __wrap_esp_ecc_point_verify(const ecc_point_t *point)
return err;
}
#if SOC_ECDSA_SUPPORTED
void __wrap_esp_crypto_ecc_enable_periph_clk(bool enable)
{
esp_tee_service_call(2, SS_ESP_CRYPTO_ECC_ENABLE_PERIPH_CLK, enable);
}
#endif
/* ---------------------------------------------- MMU HAL ------------------------------------------------- */
void IRAM_ATTR __wrap_mmu_hal_map_region(uint32_t mmu_id, mmu_target_t mem_type, uint32_t vaddr, uint32_t paddr, uint32_t len, uint32_t *out_len)

View File

@ -20,9 +20,10 @@ list(APPEND srcs "arch/${arch}/esp_tee_vectors.S"
# SoC specific implementation for TEE
list(APPEND srcs "soc/${target}/esp_tee_secure_sys_cfg.c"
"soc/${target}/esp_tee_pmp_pma_prot_cfg.c"
"soc/${target}/esp_tee_apm_prot_cfg.c"
"soc/${target}/esp_tee_apm_intr.c"
"soc/${target}/esp_tee_aes_intr.c")
"soc/${target}/esp_tee_apm_prot_cfg.c")
list(APPEND srcs "soc/common/esp_tee_apm_intr.c"
"soc/common/esp_tee_aes_intr.c")
# Common module implementation for TEE
@ -35,6 +36,7 @@ list(APPEND srcs "common/brownout.c")
list(APPEND include "include"
"common"
"soc/common/include"
"soc/${target}/include")
# Heap
@ -52,6 +54,12 @@ list(APPEND srcs "common/syscall_stubs.c")
idf_component_register(SRCS ${srcs}
INCLUDE_DIRS ${include})
# NOTE: The ESP32-H2 ROM does not have sprintf/snprintf implementation,
# thus newlib-nano implementation from the toolchain has been used.
if(CONFIG_IDF_TARGET_ESP32H2)
target_link_libraries(${COMPONENT_LIB} INTERFACE "--specs=nano.specs")
endif()
# TODO: Currently only -Og optimization level works correctly at runtime
set_source_files_properties("core/esp_secure_dispatcher.c" PROPERTIES COMPILE_FLAGS "-Og")

View File

@ -7,14 +7,12 @@
#include "soc/soc.h"
#include "soc/soc_caps.h"
#include "soc/interrupt_reg.h"
#include "soc/interrupt_matrix_reg.h"
#include "riscv/encoding.h"
#include "riscv/rvruntime-frames.h"
#include "esp_private/vectors_const.h"
#include "esp_tee.h"
#include "esp_tee_intr_defs.h"
#include "sdkconfig.h"
.equ SAVE_REGS, 32
@ -25,13 +23,10 @@
.equ RTNVAL, 0xc0de
.equ ECALL_U_MODE, 0x8
.equ ECALL_M_MODE, 0xb
.equ TEE_APM_INTR_MASK_0, 0x00300000
.equ TEE_APM_INTR_MASK_1, 0x000000f8
.equ TEE_INTR_DELEG_MASK, 0xffffbfff
.global esp_tee_global_interrupt_handler
.global esp_tee_service_dispatcher
.global esp_tee_service_dispatcher
.section .data
.align 4
@ -441,22 +436,24 @@ _tee_s_intr_handler:
/* Check if the interrupt source is related to an APM exception */
/* Define the addresses of the registers */
li t0, INTMTX_CORE0_INT_STATUS_REG_0_REG
li t0, INTMTX_STATUS_REG_0
/* Load the values from the registers */
lw t1, 0(t0)
/* Define the masks */
li t2, TEE_APM_INTR_MASK_0
li t2, TEE_SECURE_INT_APM_MASK_0
/* Apply the masks */
and t1, t1, t2
/* Check if any of the masked bits are set */
bnez t1, _save_reg_ctx
#if CONFIG_IDF_TARGET_ESP32C6
/* Repeat for the other status register */
li t0, INTMTX_CORE0_INT_STATUS_REG_1_REG
li t0, INTMTX_STATUS_REG_1
lw t1, 0(t0)
li t2, TEE_APM_INTR_MASK_1
li t2, TEE_SECURE_INT_APM_MASK_1
and t1, t1, t2
bnez t1, _save_reg_ctx
#endif
/* Continue normal execution */
j _continue
@ -464,6 +461,11 @@ _tee_s_intr_handler:
_save_reg_ctx:
/* Save CSR context here */
save_mcsr
csrr t0, mcause
sw t0, RV_STK_MCAUSE(sp)
/* NOTE: With ESP-TEE, since APM violations trigger a panic, it's safe to use the mscratch
* register to pass on the stack pointer to the APM violation handler */
csrw mscratch, sp
j _intr_hdlr_exec
_continue:

View File

@ -6,6 +6,7 @@
#include <stdio.h>
#include <stdbool.h>
#include "esp_rom_tlsf.h"
#include "esp_rom_sys.h"
#include "tlsf_block_functions.h"
#include "multi_heap.h"
@ -153,15 +154,15 @@ size_t esp_tee_heap_get_min_free_size(void)
static void heap_dump_tlsf(void* ptr, size_t size, int used, void* user)
{
(void)user;
printf("Block %p data, size: %d bytes, Free: %s\n",
(void *)ptr,
size,
used ? "No" : "Yes");
esp_rom_printf("Block %p data, size: %d bytes, Free: %s\n",
(void *)ptr,
size,
used ? "No" : "Yes");
}
void esp_tee_heap_dump_info(void)
{
printf("Showing data for TEE heap: %p (%uB)\n", (void *)tee_heap, tee_heap->pool_size);
esp_rom_printf("Showing data for TEE heap: %p (%uB)\n", (void *)tee_heap, tee_heap->pool_size);
tlsf_walk_pool(tlsf_get_pool(tee_heap->heap_data), heap_dump_tlsf, NULL);
}

View File

@ -130,6 +130,13 @@ int __cxa_thread_atexit(void (*func)(void *), void *arg, void *dso)
return 0;
}
#if CONFIG_IDF_TARGET_ESP32H2
void *_sbrk(ptrdiff_t incr)
{
return (void *) -1;
}
#endif
void esp_tee_include_syscalls_impl(void)
{

View File

@ -345,6 +345,11 @@ int _ss_esp_ecc_point_verify(const ecc_point_t *point)
return esp_ecc_point_verify(point);
}
void _ss_esp_crypto_ecc_enable_periph_clk(bool enable)
{
esp_crypto_ecc_enable_periph_clk(enable);
}
/* ---------------------------------------------- OTA ------------------------------------------------- */
int _ss_esp_tee_ota_begin(void)

View File

@ -1,24 +1,25 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_log.h"
#include "esp_cpu.h"
#include "hal/cpu_ll.h"
#include "soc/periph_defs.h"
#include "soc/interrupts.h"
#include "soc/interrupt_reg.h"
#include "esp_tee.h"
#include "esp_tee_intr.h"
#include "esp_tee_intr_defs.h"
#include "esp_tee_rv_utils.h"
#include "soc/periph_defs.h"
#include "soc/interrupt_reg.h"
#include "hal/cpu_ll.h"
#include "esp_cpu.h"
#include "esp_log.h"
/* For ESP32-C6 */
#define INTR_MAX_SOURCE (77)
#define INTR_SET_SIZE (32)
#define INTR_SET_COUNT ((((INTR_MAX_SOURCE) + ((INTR_SET_SIZE) - 1)) & ~((INTR_SET_SIZE) - 1)) / INTR_SET_SIZE)
#define INTR_DISABLED_INUM (6)
#define INTR_SET_COUNT ((((ETS_MAX_INTR_SOURCE) + ((INTR_SET_SIZE) - 1)) & ~((INTR_SET_SIZE) - 1)) / INTR_SET_SIZE)
static const char *TAG = "esp_tee_intr";
@ -27,7 +28,7 @@ typedef struct tee_handler_table_entry {
void *arg;
} tee_handler_table_entry;
static tee_handler_table_entry tee_interrupt_table[INTR_MAX_SOURCE * portNUM_PROCESSORS];
static tee_handler_table_entry tee_interrupt_table[ETS_MAX_INTR_SOURCE * portNUM_PROCESSORS];
static uint32_t protected_sources[INTR_SET_COUNT];
@ -60,14 +61,6 @@ void esp_tee_route_intr_matrix(int cpu_no, uint32_t model_num, uint32_t intr_num
return;
}
if (intr_num != ETS_INVALID_INUM) {
if (intr_num == INTR_DISABLED_INUM) {
rv_utils_tee_intr_disable(BIT(intr_num));
} else {
rv_utils_tee_intr_enable(BIT(intr_num));
}
}
esp_rom_route_intr_matrix(cpu_no, model_num, intr_num);
}
@ -126,60 +119,45 @@ int esp_tee_intr_deregister(void *arg)
tee_set_interrupt_handler(vd);
// Setting back the default value for interrupt pin.
esp_rom_route_intr_matrix(cpu, vd->source, INTR_DISABLED_INUM);
esp_rom_route_intr_matrix(cpu, vd->source, 0);
return 0;
}
#define FIND_MSB_SET(n) (31 - __builtin_clz((uint32_t)(n)))
// LP_APM_M0_INTR, LP_APM_M1_INTR
#define TEE_SECURE_INT_APM_MASK_0 (0x00300000)
// EFUSE_INTR, LP_RTC_TIMER_INTR
#define TEE_SECURE_INT_MASK_0 (TEE_SECURE_INT_APM_MASK_0 | 0x0000C000)
// HP_APM_M0_INTR, HP_APM_M1_INTR, HP_APM_M2_INTR, HP_APM_M3_INTR, LP_APM0_INTR
#define TEE_SECURE_INT_APM_MASK_1 (0x000000F8)
#if !CONFIG_SECURE_TEE_TEST_MODE
#define TEE_SECURE_INT_MASK_1 (TEE_SECURE_INT_APM_MASK_1)
#else
// + TG0_T0_INTR (only for test mode)
#define TEE_SECURE_INT_MASK_1 (TEE_SECURE_INT_APM_MASK_1 | 0x00080000)
#endif
// AES_INTR, SHA_INTR, RSA_INTR, ECC_INTR
#define TEE_SECURE_INT_MASK_2 (0x00001E00)
/* called from esp_tee_vectors.S */
void esp_tee_global_interrupt_handler(intptr_t sp, int mcause)
{
uint32_t status, source;
while (1) {
if ((status = TEE_SECURE_INT_MASK_0 &
REG_READ(INTMTX_CORE0_INT_STATUS_REG_0_REG))) {
do {
status = REG_READ(INTMTX_STATUS_REG_0) & TEE_SECURE_INT_MASK_0;
if (status) {
source = FIND_MSB_SET(status);
/* NOTE: With ESP-TEE, since APM violations trigger a panic, it's safe to use the mscratch
* register to pass on the stack pointer to the APM violation handler */
if (status & TEE_SECURE_INT_APM_MASK_0) {
RV_WRITE_CSR(mscratch, sp);
}
} else if ((status = TEE_SECURE_INT_MASK_1 &
REG_READ(INTMTX_CORE0_INT_STATUS_REG_1_REG))) {
source = FIND_MSB_SET(status) + 32;
if (status & TEE_SECURE_INT_APM_MASK_1) {
RV_WRITE_CSR(mscratch, sp);
}
} else if ((status = TEE_SECURE_INT_MASK_2 &
REG_READ(INTMTX_CORE0_INT_STATUS_REG_2_REG))) {
source = FIND_MSB_SET(status) + 64;
}
if (!status) {
break;
}
ESP_LOGV(TAG, "Found intr src: %d", source);
tee_handler_table_entry ih = tee_interrupt_table[source];
if (ih.handler) {
(*ih.handler)(ih.arg);
status = REG_READ(INTMTX_STATUS_REG_1) & TEE_SECURE_INT_MASK_1;
if (status) {
source = FIND_MSB_SET(status) + 32;
break;
}
status = REG_READ(INTMTX_STATUS_REG_2) & TEE_SECURE_INT_MASK_2;
if (status) {
source = FIND_MSB_SET(status) + 64;
break;
}
/* No valid interrupt found */
ESP_LOGV(TAG, "No valid interrupt found");
return;
} while (0);
ESP_LOGV(TAG, "Found intr src: %d", source);
tee_handler_table_entry ih = tee_interrupt_table[source];
if (ih.handler) {
(*ih.handler)(ih.arg);
}
}

View File

@ -3,4 +3,4 @@ dependencies:
espressif/json_generator:
version: "^1.1.2"
rules:
- if: "target in [esp32c6]"
- if: "target in [esp32c6, esp32h2]"

View File

@ -0,0 +1,304 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "sdkconfig.h"
#define SRAM_IRAM_START (0x40800000)
#define SRAM_IRAM_TEE_ORG (SRAM_IRAM_START)
#define SRAM_DRAM_TEE_ORG (SRAM_IRAM_START)
#define SRAM_IRAM_ORG (SRAM_IRAM_TEE_ORG + CONFIG_SECURE_TEE_IRAM_SIZE + CONFIG_SECURE_TEE_DRAM_SIZE)
#define SRAM_DRAM_TEE_SIZE (CONFIG_SECURE_TEE_DRAM_SIZE - CONFIG_SECURE_TEE_STACK_SIZE - CONFIG_SECURE_TEE_INTR_STACK_SIZE)
#define SRAM_DRAM_TEE_END (SRAM_DRAM_TEE_ORG + CONFIG_SECURE_TEE_IRAM_SIZE + SRAM_DRAM_TEE_SIZE)
#define I_D_SRAM_TEE_SIZE (CONFIG_SECURE_TEE_IRAM_SIZE + SRAM_DRAM_TEE_SIZE)
/* TEE interrupt stack is placed at the end of the TEE DRAM segment.
* The top of the TEE stack is before the end of interrupt stack
* and the bottom of the stack is at _heap_end.
*/
#define SRAM_STACK_TEE_ORG (SRAM_DRAM_TEE_END)
#define SRAM_INTR_STACK_TEE_ORG (SRAM_DRAM_TEE_END + CONFIG_SECURE_TEE_STACK_SIZE)
#define FLASH_IROM_TEE_ORG (0x42000000)
#define FLASH_DROM_TEE_ORG (0x42000000)
#define I_D_FLASH_TEE_SIZE (CONFIG_SECURE_TEE_IROM_SIZE + CONFIG_SECURE_TEE_DROM_SIZE)
/**
* These values are the same in every app binary for the same chip target.
*
* Values that may change when the app is rebuilt, or in a new ESP-IDF version,
* should be stored via esp_app_tee_config structure
*/
#if CONFIG_ESP_DEBUG_INCLUDE_OCD_STUB_BINS
PROVIDE ( esp_tee_app_config = SRAM_IRAM_ORG + 0x22e0 );
#else
PROVIDE ( esp_tee_app_config = SRAM_IRAM_ORG + 0x2e0 );
#endif
PROVIDE ( GDMA = 0x60080000 );
/* Default entry point: */
ENTRY(esp_tee_init);
MEMORY
{
/* IRAM Configuration */
iram_tee_seg (RX) : org = SRAM_IRAM_TEE_ORG, len = I_D_SRAM_TEE_SIZE
/* DRAM Configuration */
dram_tee_seg (RW) : org = SRAM_DRAM_TEE_ORG, len = I_D_SRAM_TEE_SIZE
/* TEE Stack Configuration */
stack_tee_seg (RW) : org = SRAM_STACK_TEE_ORG, len = CONFIG_SECURE_TEE_STACK_SIZE
/* TEE Interrupt Stack Configuration */
intr_stack_tee_seg (RW) : org = SRAM_INTR_STACK_TEE_ORG, len = CONFIG_SECURE_TEE_INTR_STACK_SIZE
/* TEE flash data section */
flash_data_seg (R) : org = FLASH_DROM_TEE_ORG + 0x20, len = I_D_FLASH_TEE_SIZE - 0x20
/* TEE flash text section */
flash_text_seg (RX): org = FLASH_IROM_TEE_ORG + 0x20, len = I_D_FLASH_TEE_SIZE - 0x20
}
SECTIONS
{
/**
* This section is required to skip .iram.tee_text area because iram_tee_seg and
* dram_tee_seg reflect the same address space on different buses.
*/
.dram.tee_dummy (NOLOAD):
{
. = ORIGIN(dram_tee_seg) + CONFIG_SECURE_TEE_IRAM_SIZE;
} > dram_tee_seg
.dram.tee.bss (NOLOAD) :
{
. = ALIGN (8);
_tee_dram_start = ABSOLUTE(.);
_tee_bss_start = ABSOLUTE(.);
*(.bss .bss.*)
*(.sbss .sbss.*)
. = ALIGN (8);
_tee_bss_end = ABSOLUTE(.);
} > dram_tee_seg
.dram.tee.data :
{
_data_start = ABSOLUTE(.);
*(.data .data.*)
*(.sdata .sdata.*)
*(.dram1 .dram1.*)
. = ALIGN(4);
_data_end = ABSOLUTE(.);
} > dram_tee_seg
.dram.tee.rodata :
{
_rodata_start = ABSOLUTE(.);
/* TEE flash manager */
*libtee_flash_mgr.a:*(.rodata .srodata .rodata.* .srodata.*)
*libbootloader_support.a:bootloader_flash.*(.rodata .srodata .rodata.* .srodata.*)
/* Secure services */
*libmain.a:esp_secure_services_iram.c.*(.rodata .srodata .rodata.* .srodata.*)
*libmain.a:esp_secure_dispatcher.c.*(.rodata .srodata .rodata.* .srodata.*)
/* Panic handler */
*libmain.a:panic_helper_riscv.*(.rodata .srodata .rodata.* .srodata.*)
*libmain.a:esp_tee_apm_intr.c.*(.rodata .srodata .rodata.* .srodata.*)
/* HAL (noflash) */
*libhal.a:mmu_hal.c*(.rodata .srodata .rodata.* .srodata.*)
*libhal.a:cache_hal.c*(.rodata .srodata .rodata.* .srodata.*)
_rodata_end = ABSOLUTE(.);
_tee_dram_end = ABSOLUTE(.);
} > dram_tee_seg
.dram.tee.heap :
{
. = ALIGN (16);
_tee_heap_start = ABSOLUTE(.);
. = ORIGIN(dram_tee_seg) + LENGTH(dram_tee_seg);
_tee_heap_end = ABSOLUTE(.);
} > dram_tee_seg
.dram.tee.stack :
{
. = ALIGN (16);
_tee_stack_bottom = ABSOLUTE(.);
. = ORIGIN(stack_tee_seg) + LENGTH(stack_tee_seg);
_tee_stack = ABSOLUTE(.);
} > stack_tee_seg
.dram.tee.intr_stack :
{
. = ALIGN (16);
_tee_intr_stack_bottom = ABSOLUTE(.);
. = ORIGIN(intr_stack_tee_seg) + LENGTH(intr_stack_tee_seg);
_tee_intr_stack = ABSOLUTE(.);
} > intr_stack_tee_seg
.flash.rodata :
{
_tee_xip_data_start = ABSOLUTE(.);
*(.rodata_desc .rodata_desc.*) /* Should be the first. TEE App version info. DO NOT PUT ANYTHING BEFORE IT! */
*(.rodata .rodata.*)
*(.srodata .srodata.*)
*(.gcc_except_table .gcc_except_table.*)
_tee_xip_data_end = ABSOLUTE(.);
} > flash_data_seg
.flash.text_dummy (NOLOAD):
{
. = ALIGN(ALIGNOF(.flash.rodata));
/* Create an empty gap as big as .flash.rodata section */
. = . + SIZEOF(.flash.rodata);
/* Prepare the alignment of the section above. Few bytes (0x20) must be
* added for the mapping header. */
. = ALIGN(CONFIG_MMU_PAGE_SIZE) + 0x20;
} > flash_text_seg
/* HAL modules and their memory placement:
*
* +-----------+---------------+--------+
* | Module | Section | Memory |
* +-----------+---------------+--------+
* | MMU | text+rodata | SRAM |
* | CACHE | text+rodata | SRAM |
* | WDT | text | SRAM |
* | APM | text | Flash* |
* | AES | text | Flash |
* | SHA | text | Flash |
* | HMAC | text | Flash |
* | DS | text | Flash |
* | ECC | text | Flash |
* | BROWNOUT | text | Flash |
* | EFUSE | text | Flash |
* | LPTIMER | text | Flash |
* | SPI_FLASH | text | Flash |
* +-----------+---------------+--------+
*
* By default, for ESP-TEE, text sections are placed in SRAM while rodata sections go to the flash.
* Therefore, only HAL modules that require SRAM placement for proper functionality are located there,
* while the remaining modules are placed in flash memory.
*/
.flash.text :
{
_tee_xip_text_start = ABSOLUTE(.);
/* Secure Services */
*libmain.a:esp_secure_services.c*(.literal .text .literal.* .text.*)
/* HAL */
*libhal.a:aes_hal.c*(.literal .text .literal.* .text.*)
*libhal.a:sha_hal.c*(.literal .text .literal.* .text.*)
*libhal.a:hmac_hal.c*(.literal .text .literal.* .text.*)
*libhal.a:ds_hal.c*(.literal .text .literal.* .text.*)
*libhal.a:ecc_hal.c*(.literal .text .literal.* .text.*)
/* NOTE: There is a possibility of APM violations (SPI1 flash protection)
* being triggered with the flash cache disabled */
#if !CONFIG_SECURE_TEE_EXT_FLASH_MEMPROT_SPI1
*libhal.a:apm_hal.c*(.literal .text .literal.* .text.*)
#endif
*libhal.a:brownout_hal.c*(.literal .text .literal.* .text.*)
*libhal.a:spi_flash_hal.c*(.literal .text .literal.* .text.*)
/* These HAL modules have functions marked with the IRAM_ATTR attribute which get placed in the SRAM */
*libhal.a:efuse_hal.c*(.literal .text .literal.* .text.*)
*libhal.a:lp_timer_hal.c*(.literal .text .literal.* .text.*)
/* Mbedtls for TEE */
*libmbedtls.a:*(.literal .text .literal.* .text.*)
*libmbedcrypto.a:*(.literal .text .literal.* .text.*)
/* HMAC-DS layer */
*libesp_security.a:*(.literal .text .literal.* .text.*)
/* NVS flash and related modules */
*libnvs_flash.a:*(.literal .text .literal.* .text.*)
*libstdc++.a:*(.literal .text .literal.* .text.*)
*libgcc.a:*(.literal .text .literal.* .text.*)
/* esp_partition API */
*libesp_partition.a:*(.literal .text .literal.* .text.*)
/* TEE attestation module */
*libattestation.a:*(.literal .text .literal.* .text.*)
*json_generator.a:*(.literal .text .literal.* .text.*)
/* snprintf-related functions */
*libc_nano.a:(.literal .text .literal.* .text.*)
/* TEE test module */
*libtest_sec_srv.a:*(.literal .text .literal.* .text.*)
_tee_xip_text_end = ABSOLUTE(.);
_tee_xip_end = ABSOLUTE(.);
} > flash_text_seg
.iram.tee.text :
{
/* Vectors go to start of IRAM */
ASSERT(ABSOLUTE(.) % 0x100 == 0, "vector address must be 256 byte aligned");
_tee_vec_start = ABSOLUTE(.);
KEEP(*(.exception_vectors_table.text));
KEEP(*(.exception_vectors.text));
. = ALIGN(4);
_invalid_pc_placeholder = ABSOLUTE(.);
_tee_vec_end = ABSOLUTE(.);
_tee_iram_start = ABSOLUTE(.);
*(.literal .text .iram1 .literal.* .text.* .iram1.*)
*(.stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)
_tee_iram_end = ABSOLUTE(.);
} > iram_tee_seg
.riscv.attributes 0: { *(.riscv.attributes) }
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
.debug_pubtypes 0 : { *(.debug_pubtypes) }
/* DWARF 3 */
.debug_ranges 0 : { *(.debug_ranges) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* GNU DWARF 2 extensions */
.debug_gnu_pubnames 0 : { *(.debug_gnu_pubnames) }
.debug_gnu_pubtypes 0 : { *(.debug_gnu_pubtypes) }
/* DWARF 4 */
.debug_types 0 : { *(.debug_types) }
/* DWARF 5 */
.debug_addr 0 : { *(.debug_addr) }
.debug_line_str 0 : { *(.debug_line_str) }
.debug_loclists 0 : { *(.debug_loclists) }
.debug_macro 0 : { *(.debug_macro) }
.debug_names 0 : { *(.debug_names) }
.debug_rnglists 0 : { *(.debug_rnglists) }
.debug_str_offsets 0 : { *(.debug_str_offsets) }
.comment 0 : { *(.comment) }
.note.GNU-stack 0: { *(.note.GNU-stack) }
/**
* Discarding .rela.* sections results in the following mapping:
* .rela.text.* -> .text.*
* .rela.data.* -> .data.*
* And so forth...
*/
/DISCARD/ : { *(.rela.*) }
}
ASSERT ((_tee_iram_end < _tee_dram_start), "Error: TEE IRAM segment overflowed into the DRAM segment!");

View File

@ -8,10 +8,9 @@
#include "hal/aes_hal.h"
#include "soc/interrupts.h"
#include "esp_attr.h"
#include "esp_attr.h"
#include "esp_tee_intr.h"
#include "esp_tee_aes_intr.h"
volatile DRAM_ATTR bool intr_flag;

View File

@ -4,13 +4,12 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <assert.h>
#include "hal/apm_ll.h"
#include "soc/soc_caps.h"
#include "esp_bit_defs.h"
#include "hal/apm_hal.h"
#include "esp_tee.h"
#include "esp_tee_apm_intr.h"
#include "hal/apm_ll.h"
static const char *const excp_mid_strs[] = {
[APM_LL_MASTER_HPCORE] = "HPCORE",
@ -41,9 +40,9 @@ const char *esp_tee_apm_excp_type_to_str(uint8_t type)
{
char *excp_type = "APM - Unknown exception";
if (type & 0x01) {
if (type & BIT(0)) {
excp_type = "APM - Authority exception";
} else if (type & 0x02) {
} else if (type & BIT(1)) {
excp_type = "APM - Space exception";
}
@ -55,9 +54,11 @@ const char *esp_tee_apm_excp_ctrl_to_str(apm_ll_apm_ctrl_t apm_ctrl)
char *excp_ctrl = NULL;
switch (apm_ctrl) {
#if SOC_APM_LP_APM0_SUPPORTED
case LP_APM0_CTRL:
excp_ctrl = "LP_APM0";
break;
#endif
case HP_APM_CTRL:
excp_ctrl = "HP_APM";
break;

View File

@ -8,6 +8,7 @@
#include "riscv/rv_utils.h"
#include "riscv/encoding.h"
#include "esp_private/interrupt_plic.h"
#include "esp_cpu.h"
#include "esp_log.h"
@ -28,9 +29,6 @@
asm volatile("ecall" : :"r"(ra), "r"(a1) : ); \
})
#define SET_BIT(t, n) (t |= (1UL << (n)))
#define CLR_BIT(t, n) (t &= ~(1UL << (n)))
static const char *TAG = "esp_tee_secure_sys_cfg";
extern uint32_t _vector_table;
@ -58,9 +56,8 @@ void esp_tee_soc_secure_sys_init(void)
RV_WRITE_CSR(uie, 0x00);
/* All interrupts except the TEE secure interrupt are delegated to the U-mode */
uint32_t mideleg_val = UINT32_MAX;
CLR_BIT(mideleg_val, TEE_SECURE_INUM);
RV_WRITE_CSR(mideleg, mideleg_val);
RV_WRITE_CSR(mideleg, UINT32_MAX);
RV_CLEAR_CSR(mideleg, TEE_SECURE_INUM);
/* TODO: IDF-8958
* The values for the secure interrupt number and priority and
@ -71,7 +68,7 @@ void esp_tee_soc_secure_sys_init(void)
/* TODO: Currently, we do not allow interrupts to be set up with a priority greater than 7, see intr_alloc.c */
esprv_int_set_priority(TEE_SECURE_INUM, 7);
esprv_int_set_type(TEE_SECURE_INUM, ESP_CPU_INTR_TYPE_LEVEL);
esprv_int_set_threshold(1);
esprv_int_set_threshold(RVHAL_INTR_ENABLE_THRESH);
esprv_int_enable(BIT(TEE_SECURE_INUM));
#endif
@ -93,7 +90,6 @@ void esp_tee_soc_secure_sys_init(void)
esp_tee_protect_intr_src(ETS_HP_APM_M2_INTR_SOURCE); // HP_APM_M2
esp_tee_protect_intr_src(ETS_HP_APM_M3_INTR_SOURCE); // HP_APM_M3
esp_tee_protect_intr_src(ETS_LP_APM0_INTR_SOURCE); // LP_APM0
esp_tee_protect_intr_src(ETS_EFUSE_INTR_SOURCE); // eFuse
esp_tee_protect_intr_src(ETS_AES_INTR_SOURCE); // AES
esp_tee_protect_intr_src(ETS_SHA_INTR_SOURCE); // SHA
esp_tee_protect_intr_src(ETS_ECC_INTR_SOURCE); // ECC

View File

@ -0,0 +1,36 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "soc/interrupt_matrix_reg.h"
#ifdef __cplusplus
extern "C" {
#endif
// LP_APM_M0_INTR, LP_APM_M1_INTR
#define TEE_SECURE_INT_APM_MASK_0 (0x00300000)
// HP_APM_M0_INTR, HP_APM_M1_INTR, HP_APM_M2_INTR, HP_APM_M3_INTR, LP_APM0_INTR
#define TEE_SECURE_INT_APM_MASK_1 (0x000000F8)
// LP_RTC_TIMER_INTR
#define TEE_SECURE_INT_MASK_0 (TEE_SECURE_INT_APM_MASK_0 | 0x00008000)
#if !CONFIG_SECURE_TEE_TEST_MODE
#define TEE_SECURE_INT_MASK_1 (TEE_SECURE_INT_APM_MASK_1)
#else
// + TG0_T0_INTR (only for test mode)
#define TEE_SECURE_INT_MASK_1 (TEE_SECURE_INT_APM_MASK_1 | 0x00080000)
#endif
// AES_INTR, SHA_INTR, ECC_INTR
#define TEE_SECURE_INT_MASK_2 (0x00001600)
#define INTMTX_STATUS_REG_0 (INTMTX_CORE0_INT_STATUS_REG_0_REG)
#define INTMTX_STATUS_REG_1 (INTMTX_CORE0_INT_STATUS_REG_1_REG)
#define INTMTX_STATUS_REG_2 (INTMTX_CORE0_INT_STATUS_REG_2_REG)
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,303 @@
/*
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_log.h"
#include "esp_tee.h"
#include "esp_tee_intr.h"
#include "hal/apm_hal.h"
#include "soc/soc.h"
#include "soc/spi_mem_reg.h"
#include "soc/efuse_reg.h"
#include "soc/pcr_reg.h"
extern void tee_apm_violation_isr(void *arg);
static const char *TAG = "esp_tee_apm_prot_cfg";
/* NOTE: Figuring out the eFuse protection range based on where the TEE secure storage key is stored */
#if CONFIG_SECURE_TEE_SEC_STG_MODE_RELEASE
#if CONFIG_SECURE_TEE_SEC_STG_EFUSE_HMAC_KEY_ID < 0
#error "TEE: eFuse protection region for APM out of range! (see CONFIG_SECURE_TEE_SEC_STG_EFUSE_HMAC_KEY_ID)"
#endif
#define LP_APM_EFUSE_REG_START \
(EFUSE_RD_KEY0_DATA0_REG + (CONFIG_SECURE_TEE_SEC_STG_EFUSE_HMAC_KEY_ID * 0x20))
#define LP_APM_EFUSE_REG_END \
(EFUSE_RD_KEY1_DATA0_REG + (CONFIG_SECURE_TEE_SEC_STG_EFUSE_HMAC_KEY_ID * 0x20))
#elif CONFIG_SECURE_TEE_SEC_STG_MODE_DEVELOPMENT
#define LP_APM_EFUSE_REG_START EFUSE_RD_KEY5_DATA0_REG
#if CONFIG_SECURE_TEE_TEST_MODE
#define LP_APM_EFUSE_REG_END EFUSE_RD_SYS_PART2_DATA0_REG
#else
#define LP_APM_EFUSE_REG_END LP_APM_EFUSE_REG_START
#endif
#endif
/* NOTE: Flash protection over the SPI1 controller */
#define HP_APM_SPI1_REG_START DR_REG_SPI1_BASE
#if CONFIG_SECURE_TEE_EXT_FLASH_MEMPROT_SPI1
#define HP_APM_SPI1_REG_END DR_REG_I2C_EXT0_BASE
#else
#define HP_APM_SPI1_REG_END HP_APM_SPI1_REG_START
#endif
/*----------------------- HP APM range and filter configuration -----------------------*/
/* HP_APM: TEE mode accessible regions */
apm_ctrl_region_config_data_t hp_apm_pms_data_tee[] = {
/* Region 0: Entire memory region (RWX)*/
{
.regn_num = 0,
.regn_start_addr = 0x0,
.regn_end_addr = ~0x0,
.regn_pms = 0x7,
.filter_enable = 1,
},
};
/* HP_APM: REE0 mode accessible regions */
apm_ctrl_region_config_data_t hp_apm_pms_data[] = {
/* NOTE: Without this entry, the REE SRAM region becomes inaccessible to
* the MODEM master, resulting in an APM violation during Wi-Fi initialization.
*/
/* Region 1: REE SRAM region (RW) */
{
.regn_num = 1,
.regn_start_addr = SOC_NS_IRAM_START,
.regn_end_addr = SOC_IRAM_HIGH,
.regn_pms = 0x6,
.filter_enable = 1,
},
/* Region 2: RTC memory (RWX) */
{
.regn_num = 2,
.regn_start_addr = SOC_RTC_IRAM_LOW,
.regn_end_addr = SOC_RTC_IRAM_HIGH,
.regn_pms = 0x7,
.filter_enable = 1,
},
/* Region 3: Peripherals [Start - MMU] (RW) */
/* Protected: MMU */
{
.regn_num = 3,
.regn_start_addr = SOC_PERIPHERAL_LOW,
.regn_end_addr = (SPI_MEM_MMU_ITEM_CONTENT_REG(0) - 0x4),
.regn_pms = 0x6,
.filter_enable = 1,
},
/* Region 4: Peripherals [MMU - SPI1] (RW) */
/* Protected: SPI1 */
{
.regn_num = 4,
.regn_start_addr = SPI_MEM_MMU_POWER_CTRL_REG(0),
.regn_end_addr = (HP_APM_SPI1_REG_START - 0x4),
.regn_pms = 0x6,
.filter_enable = 1,
},
/* Region 5: Peripherals [SPI1 - Interrupt Matrix] (RW) */
/* Protected: Interrupt Matrix */
{
.regn_num = 5,
.regn_start_addr = HP_APM_SPI1_REG_END,
.regn_end_addr = (DR_REG_INTMTX_BASE - 0x4),
.regn_pms = 0x6,
.filter_enable = 1,
},
/* Region 6/7: Peripherals [H/W Lock - HMAC] (RW) */
/* Protected: AES, SHA, ECC, DS, HMAC */
{
.regn_num = 6,
.regn_start_addr = DR_REG_PCNT_BASE,
.regn_end_addr = (DR_REG_AES_BASE - 0x4),
.regn_pms = 0x6,
.filter_enable = 1,
},
{
.regn_num = 7,
.regn_start_addr = DR_REG_RSA_BASE,
.regn_end_addr = (DR_REG_ECC_MULT_BASE - 0x4),
.regn_pms = 0x6,
.filter_enable = 1,
},
/* Region 8/9/10: Peripherals [IO_MUX - TEE Controller & APM] (RW) */
/* Protected: AES, SHA, ECC, DS and HMAC PCRs, APM, TEE Controller */
{
.regn_num = 8,
.regn_start_addr = DR_REG_ECDSA_BASE,
.regn_end_addr = (PCR_AES_CONF_REG - 0x4),
.regn_pms = 0x6,
.filter_enable = 1,
},
{
.regn_num = 9,
.regn_start_addr = PCR_RSA_CONF_REG,
.regn_end_addr = (PCR_ECC_CONF_REG - 0x4),
.regn_pms = 0x6,
.filter_enable = 1,
},
{
.regn_num = 10,
.regn_start_addr = PCR_ECDSA_CONF_REG,
.regn_end_addr = (DR_REG_TEE_BASE - 0x4),
.regn_pms = 0x6,
.filter_enable = 1,
},
/* Region 11: Peripherals [Miscellaneous - PMU] (RW) */
{
.regn_num = 11,
.regn_start_addr = DR_REG_MISC_BASE,
.regn_end_addr = (DR_REG_PMU_BASE - 0x04),
.regn_pms = 0x6,
.filter_enable = 1,
},
/* Region 12: Peripherals [DEBUG - PWDET] (RW) */
{
.regn_num = 12,
.regn_start_addr = DR_REG_TRACE_BASE,
.regn_end_addr = 0x600D0000,
.regn_pms = 0x6,
.filter_enable = 1,
},
};
/* NOTE: Following are the master IDs for setting the security mode and access through APM:
* +---------+-------------+
* | Bit | Source |
* +---------+-------------+
* | 0 | HP CPU |
* | 1 | LP CPU |
* | 2 | reserved |
* | 3 | SDIO_SLV |
* | 4 | reserved |
* | 5 | MEM_MONITOR |
* | 6 | TRACE |
* | 7~15 | reserved |
* | 16 | SPI2 |
* | 17 | Dummy-1 |
* | 18 | UHCI |
* | 19 | I2S |
* | 20 | Dummy-4 |
* | 21 | Dummy-5 |
* | 22 | AES |
* | 23 | SHA |
* | 24 | ADC |
* | 25 | PARLIO |
* | 26~31 | Dummy-10~15 |
* +---------+-------------+
*/
/* HP_APM: TEE mode masters' configuration */
apm_ctrl_secure_mode_config_t hp_apm_sec_mode_data_tee = {
.apm_ctrl = HP_APM_CTRL,
.apm_m_cnt = HP_APM_MAX_ACCESS_PATH,
.sec_mode = APM_LL_SECURE_MODE_TEE,
/* Crypto DMA (AES/SHA) and HP_CPU */
.master_ids = 0xC00001,
.pms_data = hp_apm_pms_data_tee,
};
/* HP_APM: REE0 mode masters' configuration */
apm_ctrl_secure_mode_config_t hp_apm_sec_mode_data = {
.apm_ctrl = HP_APM_CTRL,
.apm_m_cnt = HP_APM_MAX_ACCESS_PATH,
.sec_mode = APM_LL_SECURE_MODE_REE0,
/* All masters except crypto DMA (AES/SHA) and HP CPU */
.master_ids = 0xFF3FFFFE,
.pms_data = hp_apm_pms_data,
};
/*----------------------- LP_APM range and filter configuration -----------------------*/
/* NOTE: Due to ESP32-H2's limited LP_APM module regions, neither TEE nor REE can directly
* access the protected eFuse region. However, since the HMAC peripheral can access the
* key stored in eFuse for TEE secure storage, this access restriction does not impact
* functionality.
*/
/* LP_APM: REE0 mode accessible regions */
apm_ctrl_region_config_data_t lp_apm_pms_data[] = {
/* Region 0: LP Peripherals [PMU - eFuse BLK x] (RW) */
/* Protected: eFuse BLK x */
{
.regn_num = 0,
.regn_start_addr = DR_REG_PMU_BASE,
.regn_end_addr = (LP_APM_EFUSE_REG_START - 0x04),
.regn_pms = 0x6,
.filter_enable = 1,
},
/* Region 1: LP Peripherals [eFuse - END] (RW) */
{
.regn_num = 1,
.regn_start_addr = LP_APM_EFUSE_REG_END,
.regn_end_addr = (DR_REG_TRACE_BASE - 0x04),
.regn_pms = 0x6,
.filter_enable = 1,
},
};
/* LP_APM: REE0 mode masters' configuration */
apm_ctrl_secure_mode_config_t lp_apm_sec_mode_data = {
.apm_ctrl = LP_APM_CTRL,
.apm_m_cnt = LP_APM_MAX_ACCESS_PATH,
.sec_mode = APM_LL_SECURE_MODE_REE0,
/* HP_CPU */
.master_ids = 0x1,
.pms_data = lp_apm_pms_data,
};
/*---------------- TEE APM API-----------------------*/
void esp_tee_apm_int_enable(apm_ctrl_secure_mode_config_t *sec_mode_data)
{
for (int i = 0; i < sec_mode_data->apm_m_cnt; i++) {
apm_ctrl_path_t *apm_excp_data = calloc(1, sizeof(apm_ctrl_path_t));
assert(apm_excp_data != NULL);
apm_excp_data->apm_ctrl = sec_mode_data->apm_ctrl;
apm_excp_data->apm_m_path = i;
int intr_src_num = apm_hal_apm_ctrl_get_int_src_num(apm_excp_data);
struct vector_desc_t apm_vd = {0};
apm_vd.source = intr_src_num;
apm_vd.isr = tee_apm_violation_isr;
apm_vd.arg = (void *)apm_excp_data;
/* Register interrupt handler with TEE. */
esp_tee_intr_register((void *)&apm_vd);
/* Enable APM Ctrl intewrrupt for access path(M[0:n]) */
apm_hal_apm_ctrl_exception_clear(apm_excp_data);
apm_hal_apm_ctrl_interrupt_enable(apm_excp_data, true);
}
}
void esp_tee_configure_apm_protection(void)
{
/* Disable all control filter first to have full access of address rage. */
apm_hal_apm_ctrl_filter_enable_all(false);
/* Switch HP_CPU to TEE mode */
apm_tee_hal_set_master_secure_mode(HP_APM_CTRL, APM_LL_MASTER_HPCORE, APM_LL_SECURE_MODE_TEE);
/* LP APM TEE configuration. */
lp_apm_sec_mode_data.regn_count = sizeof(lp_apm_pms_data) / sizeof(apm_ctrl_region_config_data_t);
apm_hal_apm_ctrl_master_sec_mode_config(&lp_apm_sec_mode_data);
/* LP APM interrupt configuration. */
esp_tee_apm_int_enable(&lp_apm_sec_mode_data);
ESP_LOGD(TAG, "[REE0] LP_APM configured");
/* HP APM TEE configuration. */
hp_apm_sec_mode_data_tee.regn_count = sizeof(hp_apm_pms_data_tee) / sizeof(apm_ctrl_region_config_data_t);
apm_hal_apm_ctrl_master_sec_mode_config(&hp_apm_sec_mode_data_tee);
ESP_LOGD(TAG, "[TEE] HP_APM configured");
/* HP APM configuration. */
hp_apm_sec_mode_data.regn_count = sizeof(hp_apm_pms_data) / sizeof(apm_ctrl_region_config_data_t);
apm_hal_apm_ctrl_master_sec_mode_config(&hp_apm_sec_mode_data);
/* HP APM interrupt configuration. */
esp_tee_apm_int_enable(&hp_apm_sec_mode_data);
ESP_LOGD(TAG, "[REE0] HP_APM configured");
}

View File

@ -0,0 +1,174 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include "sdkconfig.h"
#include "soc/soc.h"
#include "soc/ext_mem_defs.h"
#include "soc/lp_analog_peri_reg.h"
#include "soc/lp_wdt_reg.h"
#include "soc/plic_reg.h"
#include "soc/clint_reg.h"
#include "riscv/csr.h"
#include "esp_cpu.h"
#include "esp_fault.h"
#include "esp_tee.h"
#define CONDITIONAL_NONE 0x0
#define CONDITIONAL_R PMP_R
#define CONDITIONAL_RX PMP_R | PMP_X
#define CONDITIONAL_RW PMP_R | PMP_W
#define CONDITIONAL_RWX PMP_R | PMP_W | PMP_X
#define IS_PMA_ENTRY_UNLOCKED(ENTRY) \
((RV_READ_CSR((CSR_PMACFG0) + (ENTRY)) & PMA_L) == 0)
#define SWD_PROT_REG_START (LP_WDT_SWD_CONFIG_REG)
#define SWD_PROT_REG_END (LP_WDT_INT_CLR_REG)
#define BOD_PROT_REG_START (DR_REG_LP_ANALOG_PERI_BASE)
#define BOD_PROT_REG_END (DR_REG_LP_ANALOG_PERI_BASE + 0x40)
static void esp_tee_configure_invalid_regions(void)
{
const unsigned PMA_NONE = PMA_L | PMA_EN;
__attribute__((unused)) const unsigned PMA_RW = PMA_L | PMA_EN | PMA_R | PMA_W;
__attribute__((unused)) const unsigned PMA_RX = PMA_L | PMA_EN | PMA_R | PMA_X;
__attribute__((unused)) const unsigned PMA_RWX = PMA_L | PMA_EN | PMA_R | PMA_W | PMA_X;
// 1. Gap at bottom of address space
PMA_ENTRY_SET_TOR(0, SOC_CPU_SUBSYSTEM_LOW, PMA_TOR | PMA_NONE);
// 2. Gap between CPU subsystem region & IROM
PMA_ENTRY_SET_TOR(1, SOC_CPU_SUBSYSTEM_HIGH, PMA_NONE);
PMA_ENTRY_SET_TOR(2, SOC_IROM_MASK_LOW, PMA_TOR | PMA_NONE);
// 3. Gap between ROM & RAM
PMA_ENTRY_SET_TOR(3, SOC_DROM_MASK_HIGH, PMA_NONE);
PMA_ENTRY_SET_TOR(4, SOC_IRAM_LOW, PMA_TOR | PMA_NONE);
// 4. Gap between DRAM and I_Cache
PMA_ENTRY_SET_TOR(5, SOC_IRAM_HIGH, PMA_NONE);
PMA_ENTRY_SET_TOR(6, SOC_IROM_LOW, PMA_TOR | PMA_NONE);
// 5. Gap between D_Cache & LP_RAM
PMA_ENTRY_SET_TOR(7, SOC_DROM_HIGH, PMA_NONE);
PMA_ENTRY_SET_TOR(8, SOC_RTC_IRAM_LOW, PMA_TOR | PMA_NONE);
// 6. Gap between LP memory & peripheral addresses
PMA_ENTRY_SET_TOR(9, SOC_RTC_IRAM_HIGH, PMA_NONE);
PMA_ENTRY_SET_TOR(10, SOC_PERIPHERAL_LOW, PMA_TOR | PMA_NONE);
// 7. End of address space
PMA_ENTRY_SET_TOR(11, SOC_PERIPHERAL_HIGH, PMA_NONE);
PMA_ENTRY_SET_TOR(12, UINT32_MAX, PMA_TOR | PMA_NONE);
/* 8. Using PMA to configure the TEE text and data section access attribute. */
assert(IS_PMA_ENTRY_UNLOCKED(13));
assert(IS_PMA_ENTRY_UNLOCKED(14));
assert(IS_PMA_ENTRY_UNLOCKED(15));
PMA_RESET_AND_ENTRY_SET_TOR(13, SOC_S_IRAM_START, PMA_NONE);
PMA_RESET_AND_ENTRY_SET_TOR(14, SOC_S_IRAM_END, PMA_TOR | PMA_RX);
PMA_RESET_AND_ENTRY_SET_TOR(15, SOC_S_DRAM_END, PMA_TOR | PMA_RW);
}
void esp_tee_configure_region_protection(void)
{
/* Notes on implementation:
*
* 1) Note: ESP32-C6 CPU doesn't support overlapping PMP regions
*
* 2) ESP32-C6 supports 16 PMA regions so we use this feature to block all the invalid address ranges
*
* 3) We use combination of NAPOT (Naturally Aligned Power Of Two) and TOR (top of range)
* entries to map all the valid address space, bottom to top. This leaves us with some extra PMP entries
* which can be used to provide more granular access
*
* 4) Entries are grouped in order with some static asserts to try and verify everything is
* correct.
*/
const unsigned NONE = PMP_L;
const unsigned R = PMP_L | PMP_R;
const unsigned RW = PMP_L | PMP_R | PMP_W;
const unsigned RX = PMP_L | PMP_R | PMP_X;
const unsigned RWX = PMP_L | PMP_R | PMP_W | PMP_X;
//
// Configure all the invalid address regions using PMA
//
// We lock the PMA entries since they mark the invalid regions and is applicable to both the privilege modes
//
esp_tee_configure_invalid_regions();
// 1.1 I/D-ROM
const uint32_t pmpaddr0 = PMPADDR_NAPOT(SOC_IROM_MASK_LOW, SOC_IROM_MASK_HIGH);
PMP_ENTRY_SET(0, pmpaddr0, PMP_NAPOT | RX);
_Static_assert(SOC_IROM_MASK_LOW < SOC_IROM_MASK_HIGH, "Invalid I/D-ROM region");
/* TODO: Check whether changes are required here */
if (esp_cpu_dbgr_is_attached()) {
// Anti-FI check that cpu is really in ocd mode
ESP_FAULT_ASSERT(esp_cpu_dbgr_is_attached());
// 2. IRAM and DRAM
PMP_ENTRY_SET(1, SOC_IRAM_LOW, NONE);
PMP_ENTRY_SET(2, SOC_IRAM_HIGH, PMP_TOR | RWX);
_Static_assert(SOC_IRAM_LOW < SOC_IRAM_HIGH, "Invalid RAM region");
} else {
// 2. IRAM and DRAM
// Splitting the REE SRAM region into IRAM and DRAM
PMP_ENTRY_SET(1, (int)SOC_NS_IRAM_START, NONE);
PMP_ENTRY_SET(2, (int)esp_tee_app_config.ns_iram_end, PMP_TOR | RX);
PMP_ENTRY_SET(3, SOC_DRAM_HIGH, PMP_TOR | RW);
}
const uint32_t s_irom_resv_end = SOC_IROM_LOW + CONFIG_SECURE_TEE_IROM_SIZE + CONFIG_SECURE_TEE_DROM_SIZE;
const uint32_t ns_irom_resv_end = ALIGN_UP_TO_MMU_PAGE_SIZE((uint32_t)esp_tee_app_config.ns_irom_end);
const uint32_t ns_drom_resv_end = ALIGN_UP_TO_MMU_PAGE_SIZE((uint32_t)esp_tee_app_config.ns_drom_end);
const uint32_t ns_drom_mmap_end = (uint32_t)(SOC_S_MMU_MMAP_RESV_START_VADDR);
// 4. I_Cache / D_Cache (flash) - REE
PMP_ENTRY_CFG_RESET(5);
PMP_ENTRY_CFG_RESET(6);
PMP_ENTRY_CFG_RESET(7);
PMP_ENTRY_SET(4, s_irom_resv_end, NONE);
PMP_ENTRY_SET(5, ns_irom_resv_end, PMP_TOR | RX);
PMP_ENTRY_SET(6, ns_drom_resv_end, PMP_TOR | R);
PMP_ENTRY_SET(7, ns_drom_mmap_end, PMP_TOR | RX);
// 5. LP memory
/* Reset the corresponding PMP config because PMP_ENTRY_SET only sets the given bits
* Bootloader might have given extra permissions and those won't be cleared
*/
const uint32_t pmpaddr8 = PMPADDR_NAPOT(SOC_RTC_IRAM_LOW, SOC_RTC_IRAM_HIGH);
PMP_ENTRY_SET(8, pmpaddr8, PMP_NAPOT | RWX);
_Static_assert(SOC_RTC_IRAM_LOW < SOC_RTC_IRAM_HIGH, "Invalid RTC IRAM region");
// 6. Super WDT and Brownout detector
PMP_ENTRY_SET(9, SWD_PROT_REG_START, CONDITIONAL_NONE);
PMP_ENTRY_SET(10, SWD_PROT_REG_END, PMP_TOR | CONDITIONAL_NONE);
_Static_assert(SWD_PROT_REG_START < SWD_PROT_REG_END, "Invalid peripheral region");
/* NOTE: Due to the limited number of PMP entries, NAPOT address matching had to be
* utilized here. To meet the requirements of NAPOT, the adjacent 20 bytes have also
* been protected along with the intended region.
*/
const uint32_t pmpaddr11 = PMPADDR_NAPOT(BOD_PROT_REG_START, BOD_PROT_REG_END);
PMP_ENTRY_SET(11, pmpaddr11, PMP_NAPOT | CONDITIONAL_NONE);
_Static_assert(BOD_PROT_REG_START < BOD_PROT_REG_END, "Invalid peripheral region");
// 7. Peripheral addresses
const uint32_t pmpaddr12 = PMPADDR_NAPOT(SOC_PERIPHERAL_LOW, SOC_PERIPHERAL_HIGH);
PMP_ENTRY_SET(12, pmpaddr12, PMP_NAPOT | RW);
_Static_assert(SOC_PERIPHERAL_LOW < SOC_PERIPHERAL_HIGH, "Invalid peripheral region");
// 8. User-mode interrupt controller registers
const uint32_t pmpaddr13 = PMPADDR_NAPOT(DR_REG_PLIC_UX_BASE, DR_REG_PLIC_UX_END);
PMP_ENTRY_SET(13, pmpaddr13, PMP_NAPOT | RW);
_Static_assert(DR_REG_PLIC_UX_BASE < DR_REG_PLIC_UX_END, "Invalid User mode PLIC region");
const uint32_t pmpaddr14 = PMPADDR_NAPOT(DR_REG_CLINT_U_BASE, DR_REG_CLINT_U_END);
PMP_ENTRY_SET(14, pmpaddr14, PMP_NAPOT | RW);
_Static_assert(DR_REG_CLINT_U_BASE < DR_REG_CLINT_U_END, "Invalid User mode CLINT region");
}

View File

@ -0,0 +1,109 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdarg.h>
#include <stdint.h>
#include "riscv/rv_utils.h"
#include "riscv/encoding.h"
#include "esp_private/interrupt_plic.h"
#include "esp_cpu.h"
#include "esp_log.h"
#include "hal/apm_hal.h"
#include "hal/aes_ll.h"
#include "hal/sha_ll.h"
#include "hal/hmac_ll.h"
#include "hal/ds_ll.h"
#include "hal/ecc_ll.h"
#include "esp_tee.h"
#include "esp_tee_intr.h"
#define _m2u_switch(arg0, arg1) \
({ \
register uintptr_t ra asm("ra") = (uintptr_t)(arg0); \
register uintptr_t a1 asm("a1") = (uintptr_t)(arg1); \
asm volatile("ecall" : :"r"(ra), "r"(a1) : ); \
})
static const char *TAG = "esp_tee_secure_sys_cfg";
extern uint32_t _vector_table;
void esp_tee_soc_secure_sys_init(void)
{
ESP_LOGI(TAG, "Current privilege level - %d", esp_cpu_get_curr_privilege_level());
/* NOTE: M/U-mode PLIC Special Configuration Register
* Bit 0: Use the external PLIC registers (legacy) from the SoC (default)
* Bit 1: Use the internal PLIC registers as per the new SoC address map
*/
REG_SET_BIT(PLIC_MXINT_CONF_REG, BIT(0));
REG_SET_BIT(PLIC_UXINT_CONF_REG, BIT(0));
/* Setting the M-mode vector table */
rv_utils_set_mtvec((uint32_t)&_vector_table);
/* Disable global interrupts */
RV_CLEAR_CSR(mstatus, MSTATUS_UIE);
RV_CLEAR_CSR(mstatus, MSTATUS_MIE);
/* Clear all interrupts */
RV_WRITE_CSR(mie, 0x00);
RV_WRITE_CSR(uie, 0x00);
/* All interrupts except the TEE secure interrupt are delegated to the U-mode */
RV_WRITE_CSR(mideleg, UINT32_MAX);
RV_CLEAR_CSR(mideleg, TEE_SECURE_INUM);
/* TODO: IDF-8958
* The values for the secure interrupt number and priority and
* the interrupt priority threshold (for both M and U mode) need
* to be investigated further
*/
#ifdef SOC_CPU_HAS_FLEXIBLE_INTC
/* TODO: Currently, we do not allow interrupts to be set up with a priority greater than 7, see intr_alloc.c */
esprv_int_set_priority(TEE_SECURE_INUM, 7);
esprv_int_set_type(TEE_SECURE_INUM, ESP_CPU_INTR_TYPE_LEVEL);
esprv_int_set_threshold(RVHAL_INTR_ENABLE_THRESH);
esprv_int_enable(BIT(TEE_SECURE_INUM));
#endif
ESP_LOGD(TAG, "Initial interrupt config -");
ESP_LOGD(TAG, "mideleg: 0x%08x", RV_READ_CSR(mideleg));
ESP_LOGD(TAG, "mie: 0x%08x | uie: 0x%08x", RV_READ_CSR(mie), RV_READ_CSR(uie));
ESP_LOGD(TAG, "mstatus: 0x%08x | ustatus: 0x%08x", RV_READ_CSR(mstatus), RV_READ_CSR(ustatus));
ESP_LOGD(TAG, "[PLIC] MX: 0x%08x | UX: 0x%08x", REG_READ(PLIC_MXINT_ENABLE_REG), REG_READ(PLIC_UXINT_ENABLE_REG));
/* PMP, PMA and APM configuration to isolate the resources between TEE and REE. */
esp_tee_configure_region_protection();
esp_tee_configure_apm_protection();
/* Protect secure interrupt sources */
esp_tee_protect_intr_src(ETS_LP_APM_M0_INTR_SOURCE); // LP_APM_M0
esp_tee_protect_intr_src(ETS_HP_APM_M0_INTR_SOURCE); // HP_APM_M0
esp_tee_protect_intr_src(ETS_HP_APM_M1_INTR_SOURCE); // HP_APM_M1
esp_tee_protect_intr_src(ETS_HP_APM_M2_INTR_SOURCE); // HP_APM_M2
esp_tee_protect_intr_src(ETS_HP_APM_M3_INTR_SOURCE); // HP_APM_M3
esp_tee_protect_intr_src(ETS_AES_INTR_SOURCE); // AES
esp_tee_protect_intr_src(ETS_SHA_INTR_SOURCE); // SHA
esp_tee_protect_intr_src(ETS_ECC_INTR_SOURCE); // ECC
/* Disable protected crypto peripheral clocks; they will be toggled as needed when the peripheral is in use */
aes_ll_enable_bus_clock(false);
sha_ll_enable_bus_clock(false);
hmac_ll_enable_bus_clock(false);
ds_ll_enable_bus_clock(false);
ecc_ll_enable_bus_clock(false);
}
IRAM_ATTR inline void esp_tee_switch_to_ree(uint32_t ree_entry_addr)
{
/* 2nd argument is used as magic value to detect very first M2U switch */
/* TBD: clean this up and use proper temporary register instead of a1 */
/* Switch to non-secure world and launch App. */
_m2u_switch(ree_entry_addr, ESP_TEE_M2U_SWITCH_MAGIC << 12);
}

View File

@ -0,0 +1,34 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "soc/interrupt_matrix_reg.h"
#ifdef __cplusplus
extern "C" {
#endif
// LP_APM_M0_INTR, HP_APM_M0_INTR, HP_APM_M1_INTR, HP_APM_M2_INTR, HP_APM_M3_INTR
#define TEE_SECURE_INT_APM_MASK_0 (0x3C000040)
// LP_RTC_TIMER_INTR
#define TEE_SECURE_INT_MASK_0 (TEE_SECURE_INT_APM_MASK_0 | 0x00000004)
// AES_INTR, SHA_INTR, ECC_INTR
#if !CONFIG_SECURE_TEE_TEST_MODE
#define TEE_SECURE_INT_MASK_1 (0xB0000000)
#else
// + TG0_T0_INTR (only for test mode)
#define TEE_SECURE_INT_MASK_1 (0xB0000200)
#endif
#define TEE_SECURE_INT_MASK_2 (0U)
#define INTMTX_STATUS_REG_0 (INTMTX_CORE0_INT_STATUS_REG_0_REG)
#define INTMTX_STATUS_REG_1 (INTMTX_CORE0_INT_STATUS_REG_1_REG)
#define INTMTX_STATUS_REG_2 (INTMTX_CORE0_INT_STATUS_REG_2_REG)
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,132 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <assert.h>
#include "riscv/csr.h"
#include "riscv/interrupt.h"
#include "soc/interrupt_reg.h"
#include "soc/plic_reg.h"
#include "esp_attr.h"
#include "esp_tee.h"
#ifdef __cplusplus
extern "C" {
#endif
FORCE_INLINE_ATTR void rv_utils_tee_intr_global_enable(void)
{
/*
* Set the the U-mode previous enable global interrupts state
*
* NOTE: The TICK interrupt is setup before this service call and thus,
* it occurs in the return path of this call.
*
* Before entering the U-mode interrupt handler routine, USTATUS:UIE is
* cleared to disable U-mode interrupts temporarily.
*
* While exiting the above routine, URET is executed, setting USTATUS:UIE
* to the value of USTATUS:UPIE. However, since no interrupts were enabled
* previously, USTATUS:UPIE and thus, USTATUS:UIE is cleared.
*
* The service call completes and returns to U-mode with USTATUS:UIE disabled,
* preventing any further interrupts in U-mode.
*
*/
RV_SET_CSR(ustatus, USTATUS_UPIE);
/* Enabling the global M-mode and U-mode interrupts */
RV_SET_CSR(ustatus, USTATUS_UIE);
RV_SET_CSR(mstatus, MSTATUS_UIE);
RV_SET_CSR(mstatus, MSTATUS_MIE);
}
FORCE_INLINE_ATTR void rv_utils_tee_intr_global_disable(void)
{
RV_CLEAR_CSR(ustatus, USTATUS_UIE);
RV_CLEAR_CSR(mstatus, MSTATUS_UIE);
RV_CLEAR_CSR(mstatus, MSTATUS_MIE);
}
FORCE_INLINE_ATTR void rv_utils_tee_intr_enable(uint32_t intr_mask)
{
unsigned old_xstatus;
// Machine mode
// Disable all interrupts to make updating of the interrupt mask atomic.
old_xstatus = RV_CLEAR_CSR(mstatus, MSTATUS_MIE);
REG_SET_BIT(PLIC_MXINT_ENABLE_REG, intr_mask);
RV_SET_CSR(mie, intr_mask);
RV_SET_CSR(mstatus, old_xstatus & MSTATUS_MIE);
// User mode
// Disable all interrupts to make updating of the interrupt mask atomic.
old_xstatus = RV_CLEAR_CSR(ustatus, USTATUS_UIE);
REG_SET_BIT(PLIC_UXINT_ENABLE_REG, intr_mask);
RV_SET_CSR(uie, intr_mask);
RV_SET_CSR(ustatus, old_xstatus & USTATUS_UIE);
}
FORCE_INLINE_ATTR void rv_utils_tee_intr_disable(uint32_t intr_mask)
{
unsigned old_xstatus;
// Machine mode
// Disable all interrupts to make updating of the interrupt mask atomic.
old_xstatus = RV_CLEAR_CSR(mstatus, MSTATUS_MIE);
REG_CLR_BIT(PLIC_MXINT_ENABLE_REG, intr_mask);
RV_CLEAR_CSR(mie, intr_mask);
RV_SET_CSR(mstatus, old_xstatus & MSTATUS_MIE);
// User mode
// Disable all interrupts to make updating of the interrupt mask atomic.
old_xstatus = RV_CLEAR_CSR(ustatus, USTATUS_UIE);
REG_CLR_BIT(PLIC_UXINT_ENABLE_REG, intr_mask);
RV_CLEAR_CSR(uie, intr_mask);
RV_SET_CSR(ustatus, old_xstatus & USTATUS_UIE);
}
FORCE_INLINE_ATTR void rv_utils_tee_intr_set_type(int intr_num, enum intr_type type)
{
assert(intr_num >= 0 && intr_num < SOC_CPU_INTR_NUM);
if (type == INTR_TYPE_LEVEL) {
REG_CLR_BIT(PLIC_MXINT_TYPE_REG, BIT(intr_num));
REG_CLR_BIT(PLIC_UXINT_TYPE_REG, BIT(intr_num));
} else {
REG_SET_BIT(PLIC_MXINT_TYPE_REG, BIT(intr_num));
REG_SET_BIT(PLIC_UXINT_TYPE_REG, BIT(intr_num));
}
}
FORCE_INLINE_ATTR void rv_utils_tee_intr_set_priority(int rv_int_num, int priority)
{
assert(rv_int_num >= 0 && rv_int_num < SOC_CPU_INTR_NUM);
REG_WRITE(PLIC_MXINT_PRI_REG(rv_int_num), priority);
REG_WRITE(PLIC_UXINT_PRI_REG(rv_int_num), priority);
}
FORCE_INLINE_ATTR void rv_utils_tee_intr_set_threshold(int priority_threshold)
{
REG_WRITE(PLIC_MXINT_THRESH_REG, priority_threshold);
REG_WRITE(PLIC_UXINT_THRESH_REG, priority_threshold);
}
FORCE_INLINE_ATTR void rv_utils_tee_intr_edge_ack(int intr_num)
{
assert(intr_num >= 0 && intr_num < SOC_CPU_INTR_NUM);
REG_SET_BIT(PLIC_MXINT_CLEAR_REG, intr_num);
REG_SET_BIT(PLIC_UXINT_CLEAR_REG, intr_num);
}
#ifdef __cplusplus
}
#endif

View File

@ -7,5 +7,5 @@ components/esp_tee/test_apps/tee_cli_app:
components/esp_tee/test_apps/tee_test_fw:
disable:
- if: IDF_TARGET not in ["esp32c6"]
reason: only supported with esp32c6 for now
- if: IDF_TARGET not in ["esp32c6", "esp32h2"]
reason: only supported with esp32c6 and esp32h2 for now

View File

@ -1,5 +1,5 @@
| Supported Targets | ESP32-C6 |
| ----------------- | -------- |
| Supported Targets | ESP32-C6 | ESP32-H2 |
| ----------------- | -------- | -------- |
## ESP-TEE: Test Suite

View File

@ -63,6 +63,47 @@ esp_tee_empty_bin = {
0xF4, 0xA4, 0xCF, 0x06, 0xAE, 0x94, 0x75, 0x47, 0xBC, 0x88, 0xA2, 0xCA,
0x52, 0x97, 0x7A, 0x5C, 0x55, 0x43, 0xD9, 0xF5, 0xD3, 0x45, 0xD1, 0x34,
0xFC, 0x74, 0xB2, 0xB9, 0x34, 0x72, 0xC3, 0x00
],
'esp32h2': [
0xE9, 0x04, 0x02, 0x1F, 0x00, 0x00, 0x80, 0x40, 0xEE, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
# DROM segment
0x20, 0x00, 0x00, 0x42, 0x00, 0x02, 0x00, 0x00,
# esp_app_desc structure
0x32, 0x54, 0xCD, 0xAB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x76, 0x35, 0x2E, 0x35, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x65, 0x73, 0x70, 0x5F, 0x74, 0x65, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x30, 0x30, 0x3A, 0x30, 0x30, 0x3A, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x4E, 0x6F, 0x76, 0x20, 0x31, 0x31, 0x20, 0x32,
0x30, 0x32, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x35, 0x2E, 0x35,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x2D, 0x63, 0x66, 0x8B, 0x75, 0xFA, 0x59, 0x05,
0x53, 0x34, 0x91, 0x71, 0x51, 0x33, 0x91, 0xDD, 0xF8, 0xB1, 0xFE, 0x83,
0x06, 0xEB, 0x03, 0x80, 0x45, 0xC9, 0x18, 0x20, 0x83, 0x7E, 0x2E, 0x43,
*([0x00] * 0x58),
# Padding
*([0x00] * 0x100),
# IRAM segment
0x00, 0x00, 0x80, 0x40, 0x20, 0x00, 0x00, 0x00,
*([0x00] * 0x20),
# PADDING segment
0x00, 0x00, 0x00, 0x00, 0xC8, 0x7D, 0x00, 0x00,
*([0x00] * 0x7DC8),
# IROM segment
0x20, 0x80, 0x00, 0x42, 0x00, 0x01, 0x00, 0x00,
*([0x00] * 0x100),
# Padding
*([0x00] * 0x0F),
# CRC8 checksum
0x56,
# Image SHA256
0xDC, 0x60, 0x86, 0x6C, 0x37, 0x76, 0xAA, 0x30, 0x1F, 0x61, 0x48, 0x23,
0xEA, 0x34, 0xAA, 0x19, 0xE8, 0xDE, 0x04, 0x7D, 0x2A, 0x30, 0xC1, 0xDD,
0x61, 0x38, 0x9D, 0xB5, 0xCA, 0x13, 0x5A, 0x79
]
}
# fmt: on

View File

@ -119,7 +119,7 @@ TEST_CASE("Test TEE Secure Storage - Sign-verify (ecdsa_secp256r1)", "[sec_stora
}
}
#if CONFIG_SECURE_TEE_SEC_STG_SUPPORT_SECP192R1_SIGN
#if CONFIG_SECURE_TEE_SEC_STG_SUPPORT_SECP192R1_SIGN && !TEMPORARY_DISABLED_FOR_TARGETS(ESP32H2)
TEST_CASE("Test TEE Secure Storage - Sign-verify (ecdsa_secp192r1)", "[sec_storage]")
{
const size_t buf_sz = 16 * 1024 + 6; // NOTE: Not an exact multiple of SHA block size
@ -507,7 +507,7 @@ static void test_ecdsa_sign(mbedtls_ecp_group_id gid)
TEST_CASE("Test TEE Secure Storage - mbedtls ECDSA signing", "[mbedtls]")
{
test_ecdsa_sign(MBEDTLS_ECP_DP_SECP256R1);
#if CONFIG_SECURE_TEE_SEC_STG_SUPPORT_SECP192R1_SIGN
#if CONFIG_SECURE_TEE_SEC_STG_SUPPORT_SECP192R1_SIGN && !TEMPORARY_DISABLED_FOR_TARGETS(ESP32H2)
test_ecdsa_sign(MBEDTLS_ECP_DP_SECP192R1);
#endif
}

View File

@ -1,42 +1,57 @@
# SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
from enum import Enum
from typing import Any
from typing import Dict
from typing import Tuple
import pytest
from pytest_embedded_idf import IdfDut
from pytest_embedded_idf.utils import idf_parametrize
CONFIGS_DEFAULT = [pytest.param('default', marks=[pytest.mark.esp32c6])]
# ---------------- Pytest build parameters ----------------
CONFIGS_OTA = [pytest.param('ota', marks=[pytest.mark.esp32c6])]
SUPPORTED_TARGETS = ['esp32c6', 'esp32h2']
CONFIGS_ALL = [pytest.param('default', marks=[pytest.mark.esp32c6]), pytest.param('ota', marks=[pytest.mark.esp32c6])]
CONFIG_DEFAULT = [
# 'config, target, markers',
('default', target, (pytest.mark.generic,))
for target in SUPPORTED_TARGETS
]
TEE_VIOLATION_TEST_EXC_RSN: Dict[str, Any] = {
'esp32c6': {
('Reserved', 'W1'): 'Store access fault',
('Reserved', 'X1'): 'Instruction access fault',
('IRAM', 'W1'): 'Store access fault',
('IRAM', 'W2'): 'Store access fault',
('DRAM', 'X1'): 'Instruction access fault',
('DRAM', 'X2'): 'Instruction access fault',
}
CONFIG_OTA = [
# 'config, target, skip_autoflash, markers',
('ota', target, 'y', (pytest.mark.generic,))
for target in SUPPORTED_TARGETS
]
CONFIG_ALL = [
# 'config, target, markers',
(config, target, (pytest.mark.generic,))
for config in ['default', 'ota']
for target in SUPPORTED_TARGETS
]
# ---------------- Exception test-cases reasons ----------------
TEE_VIOLATION_TEST_EXC_RSN: Dict[Tuple[str, str], str] = {
('Reserved', 'W1'): 'Store access fault',
('Reserved', 'X1'): 'Instruction access fault',
('IRAM', 'W1'): 'Store access fault',
('IRAM', 'W2'): 'Store access fault',
('DRAM', 'X1'): 'Instruction access fault',
('DRAM', 'X2'): 'Instruction access fault',
}
REE_ISOLATION_TEST_EXC_RSN: Dict[str, Any] = {
'esp32c6': {
('DRAM', 'R1'): 'Load access fault',
('DRAM', 'W1'): 'Store access fault',
('IRAM', 'R1'): 'Load access fault',
('IRAM', 'W1'): 'Store access fault',
('IROM', 'R1'): 'Load access fault',
('IROM', 'W1'): 'Store access fault',
('DROM', 'R1'): 'Load access fault',
('DROM', 'W1'): 'Store access fault',
('SWDT/BOD', 'W'): 'Store access fault',
}
REE_ISOLATION_TEST_EXC_RSN: Dict[Tuple[str, str], str] = {
('DRAM', 'R1'): 'Load access fault',
('DRAM', 'W1'): 'Store access fault',
('IRAM', 'R1'): 'Load access fault',
('IRAM', 'W1'): 'Store access fault',
('IROM', 'R1'): 'Load access fault',
('IROM', 'W1'): 'Store access fault',
('DROM', 'R1'): 'Load access fault',
('DROM', 'W1'): 'Store access fault',
('SWDT/BOD', 'W'): 'Store access fault',
}
TEE_APM_VIOLATION_EXC_CHK = ['eFuse', 'MMU', 'AES', 'HMAC', 'DS', 'SHA PCR', 'ECC PCR']
@ -44,34 +59,42 @@ TEE_APM_VIOLATION_EXC_CHK = ['eFuse', 'MMU', 'AES', 'HMAC', 'DS', 'SHA PCR', 'EC
# ---------------- TEE default tests ----------------
@pytest.mark.generic
@idf_parametrize('config', ['default'], indirect=['config'])
@idf_parametrize('target', ['esp32c6'], indirect=['target'])
@idf_parametrize(
'config, target, markers',
CONFIG_DEFAULT,
indirect=['config', 'target'],
)
def test_esp_tee(dut: IdfDut) -> None:
dut.run_all_single_board_cases(group='basic')
dut.run_all_single_board_cases(group='heap')
@pytest.mark.generic
@idf_parametrize('config', ['default', 'ota'], indirect=['config'])
@idf_parametrize('target', ['esp32c6'], indirect=['target'])
@idf_parametrize(
'config, target, markers',
CONFIG_ALL,
indirect=['config', 'target'],
)
def test_esp_tee_crypto_aes(dut: IdfDut) -> None:
dut.run_all_single_board_cases(group='aes')
dut.run_all_single_board_cases(group='aes-gcm')
@pytest.mark.generic
@idf_parametrize('config', ['default', 'ota'], indirect=['config'])
@idf_parametrize('target', ['esp32c6'], indirect=['target'])
@idf_parametrize(
'config, target, markers',
CONFIG_ALL,
indirect=['config', 'target'],
)
def test_esp_tee_crypto_sha(dut: IdfDut) -> None:
dut.run_all_single_board_cases(group='mbedtls')
dut.run_all_single_board_cases(group='hw_crypto')
# NOTE: Stress testing the AES performance case for interrupt-related edge-cases
@pytest.mark.generic
@idf_parametrize('config', ['default', 'ota'], indirect=['config'])
@idf_parametrize('target', ['esp32c6'], indirect=['target'])
@idf_parametrize(
'config, target, markers',
CONFIG_ALL,
indirect=['config', 'target'],
)
def test_esp_tee_aes_perf(dut: IdfDut) -> None:
# start test
for i in range(24):
@ -86,21 +109,29 @@ def test_esp_tee_aes_perf(dut: IdfDut) -> None:
# ---------------- TEE Exceptions generation Tests ----------------
@pytest.mark.generic
@idf_parametrize('config', ['default'], indirect=['config'])
@idf_parametrize('target', ['esp32c6'], indirect=['target'])
@idf_parametrize(
'config, target, markers',
CONFIG_DEFAULT,
indirect=['config', 'target'],
)
def test_esp_tee_apm_violation(dut: IdfDut) -> None:
for check in TEE_APM_VIOLATION_EXC_CHK:
dut.expect_exact('Press ENTER to see the list of tests')
dut.write(f'"Test APM violation interrupt: {check}"')
exc = dut.expect(r'Core ([01]) panic\'ed \(([^)]+)\)', timeout=30).group(2).decode()
if exc != 'APM - Authority exception':
if dut.target == 'esp32h2' and check == 'eFuse':
exp_str = 'APM - Space exception'
else:
exp_str = 'APM - Authority exception'
if exc != exp_str:
raise RuntimeError('Incorrect exception received!')
@pytest.mark.generic
@idf_parametrize('config', ['default'], indirect=['config'])
@idf_parametrize('target', ['esp32c6'], indirect=['target'])
@idf_parametrize(
'config, target, markers',
CONFIG_DEFAULT,
indirect=['config', 'target'],
)
def test_esp_tee_illegal_instruction(dut: IdfDut) -> None:
dut.expect_exact('Press ENTER to see the list of tests')
dut.write('"Test TEE-TEE violation: Illegal Instruction"')
@ -109,11 +140,13 @@ def test_esp_tee_illegal_instruction(dut: IdfDut) -> None:
raise RuntimeError('Incorrect exception received!')
@pytest.mark.generic
@idf_parametrize('config', ['default'], indirect=['config'])
@idf_parametrize('target', ['esp32c6'], indirect=['target'])
@idf_parametrize(
'config, target, markers',
CONFIG_DEFAULT,
indirect=['config', 'target'],
)
def test_esp_tee_violation_checks(dut: IdfDut) -> None:
checks_list = TEE_VIOLATION_TEST_EXC_RSN[dut.target]
checks_list = TEE_VIOLATION_TEST_EXC_RSN
for test in checks_list:
memory, access_type = test
expected_exc = checks_list[test]
@ -126,11 +159,13 @@ def test_esp_tee_violation_checks(dut: IdfDut) -> None:
raise RuntimeError('Incorrect exception received!')
@pytest.mark.generic
@idf_parametrize('config', ['default'], indirect=['config'])
@idf_parametrize('target', ['esp32c6'], indirect=['target'])
@idf_parametrize(
'config, target, markers',
CONFIG_DEFAULT,
indirect=['config', 'target'],
)
def test_esp_tee_isolation_checks(dut: IdfDut) -> None:
checks_list = REE_ISOLATION_TEST_EXC_RSN[dut.target]
checks_list = REE_ISOLATION_TEST_EXC_RSN
for test in checks_list:
memory, access_type = test
expected_exc = checks_list[test]
@ -199,10 +234,11 @@ def run_multiple_stages(dut: IdfDut, test_case_num: int, stages: int, api: TeeFl
dut.expect_exact('Press ENTER to see the list of tests.')
@pytest.mark.generic
@idf_parametrize('config', ['ota'], indirect=['config'])
@idf_parametrize('skip_autoflash', ['y'], indirect=['skip_autoflash'])
@idf_parametrize('target', ['esp32c6'], indirect=['target'])
@idf_parametrize(
'config, target, skip_autoflash, markers',
CONFIG_OTA,
indirect=['config', 'target', 'skip_autoflash'],
)
def test_esp_tee_flash_prot_esp_partition_mmap(dut: IdfDut) -> None:
# Flash the bootloader, TEE and REE firmware
dut.serial.custom_flash()
@ -216,10 +252,11 @@ def test_esp_tee_flash_prot_esp_partition_mmap(dut: IdfDut) -> None:
continue
@pytest.mark.generic
@idf_parametrize('config', ['ota'], indirect=['config'])
@idf_parametrize('skip_autoflash', ['y'], indirect=['skip_autoflash'])
@idf_parametrize('target', ['esp32c6'], indirect=['target'])
@idf_parametrize(
'config, target, skip_autoflash, markers',
CONFIG_OTA,
indirect=['config', 'target', 'skip_autoflash'],
)
def test_esp_tee_flash_prot_spi_flash_mmap(dut: IdfDut) -> None:
# Flash the bootloader, TEE and REE firmware
dut.serial.custom_flash()
@ -233,10 +270,11 @@ def test_esp_tee_flash_prot_spi_flash_mmap(dut: IdfDut) -> None:
continue
@pytest.mark.generic
@idf_parametrize('config', ['ota'], indirect=['config'])
@idf_parametrize('skip_autoflash', ['y'], indirect=['skip_autoflash'])
@idf_parametrize('target', ['esp32c6'], indirect=['target'])
@idf_parametrize(
'config, target, skip_autoflash, markers',
CONFIG_OTA,
indirect=['config', 'target', 'skip_autoflash'],
)
def test_esp_tee_flash_prot_esp_rom_spiflash(dut: IdfDut) -> None:
# Flash the bootloader, TEE and REE firmware
dut.serial.custom_flash()
@ -250,10 +288,11 @@ def test_esp_tee_flash_prot_esp_rom_spiflash(dut: IdfDut) -> None:
continue
@pytest.mark.generic
@idf_parametrize('config', ['ota'], indirect=['config'])
@idf_parametrize('skip_autoflash', ['y'], indirect=['skip_autoflash'])
@idf_parametrize('target', ['esp32c6'], indirect=['target'])
@idf_parametrize(
'config, target, skip_autoflash, markers',
CONFIG_OTA,
indirect=['config', 'target', 'skip_autoflash'],
)
def test_esp_tee_flash_prot_esp_partition(dut: IdfDut) -> None:
# Flash the bootloader, TEE and REE firmware
dut.serial.custom_flash()
@ -267,10 +306,11 @@ def test_esp_tee_flash_prot_esp_partition(dut: IdfDut) -> None:
continue
@pytest.mark.generic
@idf_parametrize('config', ['ota'], indirect=['config'])
@idf_parametrize('skip_autoflash', ['y'], indirect=['skip_autoflash'])
@idf_parametrize('target', ['esp32c6'], indirect=['target'])
@idf_parametrize(
'config, target, skip_autoflash, markers',
CONFIG_OTA,
indirect=['config', 'target', 'skip_autoflash'],
)
def test_esp_tee_flash_prot_esp_flash(dut: IdfDut) -> None:
# Flash the bootloader, TEE and REE firmware
dut.serial.custom_flash()
@ -289,7 +329,7 @@ def test_esp_tee_flash_prot_esp_flash(dut: IdfDut) -> None:
@pytest.mark.generic
@idf_parametrize('config', ['ota'], indirect=['config'])
@idf_parametrize('target', ['esp32c6'], indirect=['target'])
@idf_parametrize('target', ['esp32c6', 'esp32h2'], indirect=['target'])
def test_esp_tee_ota_negative(dut: IdfDut) -> None:
# start test
dut.expect_exact('Press ENTER to see the list of tests')
@ -300,10 +340,11 @@ def test_esp_tee_ota_negative(dut: IdfDut) -> None:
dut.serial.erase_partition('tee_otadata')
@pytest.mark.generic
@idf_parametrize('config', ['ota'], indirect=['config'])
@idf_parametrize('skip_autoflash', ['y'], indirect=['skip_autoflash'])
@idf_parametrize('target', ['esp32c6'], indirect=['target'])
@idf_parametrize(
'config, target, skip_autoflash, markers',
CONFIG_OTA,
indirect=['config', 'target', 'skip_autoflash'],
)
def test_esp_tee_ota_corrupted_img(dut: IdfDut) -> None:
# Flashing the TEE app to the non-secure app's passive partition
dut.serial.custom_flash_w_test_tee_img_gen()
@ -338,10 +379,11 @@ def tee_ota_stage_checks(dut: IdfDut, stage: TeeOtaStage, offset: str) -> None:
raise ValueError('Undefined stage!')
@pytest.mark.generic
@idf_parametrize('config', ['ota'], indirect=['config'])
@idf_parametrize('skip_autoflash', ['y'], indirect=['skip_autoflash'])
@idf_parametrize('target', ['esp32c6'], indirect=['target'])
@idf_parametrize(
'config, target, skip_autoflash, markers',
CONFIG_OTA,
indirect=['config', 'target', 'skip_autoflash'],
)
def test_esp_tee_ota_reboot_without_ota_end(dut: IdfDut) -> None:
# Flashing the TEE app to the non-secure app's passive partition
dut.serial.custom_flash_w_test_tee_img_gen()
@ -363,10 +405,11 @@ def test_esp_tee_ota_reboot_without_ota_end(dut: IdfDut) -> None:
dut.serial.erase_partition('tee_otadata')
@pytest.mark.generic
@idf_parametrize('config', ['ota'], indirect=['config'])
@idf_parametrize('skip_autoflash', ['y'], indirect=['skip_autoflash'])
@idf_parametrize('target', ['esp32c6'], indirect=['target'])
@idf_parametrize(
'config, target, skip_autoflash, markers',
CONFIG_OTA,
indirect=['config', 'target', 'skip_autoflash'],
)
def test_esp_tee_ota_valid_img(dut: IdfDut) -> None:
# Flashing the TEE app to the non-secure app's passive partition
dut.serial.custom_flash_w_test_tee_img_gen()
@ -396,10 +439,11 @@ def test_esp_tee_ota_valid_img(dut: IdfDut) -> None:
dut.serial.erase_partition('tee_otadata')
@pytest.mark.generic
@idf_parametrize('config', ['ota'], indirect=['config'])
@idf_parametrize('skip_autoflash', ['y'], indirect=['skip_autoflash'])
@idf_parametrize('target', ['esp32c6'], indirect=['target'])
@idf_parametrize(
'config, target, skip_autoflash, markers',
CONFIG_OTA,
indirect=['config', 'target', 'skip_autoflash'],
)
def test_esp_tee_ota_rollback(dut: IdfDut) -> None:
# Flashing the TEE app to the non-secure app's passive partition
dut.serial.custom_flash_w_test_tee_img_rb()
@ -434,10 +478,11 @@ def test_esp_tee_ota_rollback(dut: IdfDut) -> None:
# ---------------- TEE Secure Storage tests ----------------
@pytest.mark.generic
@idf_parametrize('config', ['ota'], indirect=['config'])
@idf_parametrize('skip_autoflash', ['y'], indirect=['skip_autoflash'])
@idf_parametrize('target', ['esp32c6'], indirect=['target'])
@idf_parametrize(
'config, target, skip_autoflash, markers',
CONFIG_OTA,
indirect=['config', 'target', 'skip_autoflash'],
)
def test_esp_tee_secure_storage(dut: IdfDut) -> None:
# Flash image and erase the secure_storage partition
dut.serial.custom_flash_with_empty_sec_stg()
@ -445,10 +490,11 @@ def test_esp_tee_secure_storage(dut: IdfDut) -> None:
dut.run_all_single_board_cases(group='sec_storage')
@pytest.mark.generic
@idf_parametrize('config', ['ota'], indirect=['config'])
@idf_parametrize('skip_autoflash', ['y'], indirect=['skip_autoflash'])
@idf_parametrize('target', ['esp32c6'], indirect=['target'])
@idf_parametrize(
'config, target, skip_autoflash, markers',
CONFIG_OTA,
indirect=['config', 'target', 'skip_autoflash'],
)
def test_esp_tee_secure_storage_with_host_img(dut: IdfDut) -> None:
# Flash image and write the secure_storage partition with host-generated keys
dut.serial.custom_flash_with_host_gen_sec_stg_img()
@ -459,10 +505,11 @@ def test_esp_tee_secure_storage_with_host_img(dut: IdfDut) -> None:
# ---------------- TEE Attestation tests ----------------
@pytest.mark.generic
@idf_parametrize('config', ['ota'], indirect=['config'])
@idf_parametrize('skip_autoflash', ['y'], indirect=['skip_autoflash'])
@idf_parametrize('target', ['esp32c6'], indirect=['target'])
@idf_parametrize(
'config, target, skip_autoflash, markers',
CONFIG_OTA,
indirect=['config', 'target', 'skip_autoflash'],
)
def test_esp_tee_attestation(dut: IdfDut) -> None:
# Flash image and erase the secure_storage partition
dut.serial.custom_flash_with_empty_sec_stg()

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -12,6 +12,11 @@
#include "heap_memory_layout.h"
#include "esp_heap_caps.h"
#if CONFIG_SECURE_ENABLE_TEE
#define SRAM_DIRAM_TEE_ORG (SOC_DIRAM_IRAM_LOW)
#define SRAM_DIRAM_TEE_END (SRAM_DIRAM_TEE_ORG + CONFIG_SECURE_TEE_IRAM_SIZE + CONFIG_SECURE_TEE_DRAM_SIZE)
#endif
/**
* @brief Memory type descriptors. These describe the capabilities of a type of memory in the SoC.
* Each type of memory map consists of one or more regions in the address space.
@ -94,6 +99,14 @@ SOC_RESERVE_MEMORY_REGION((intptr_t)&_data_start, (intptr_t)&_heap_start, dram_d
// Target has a shared D/IRAM virtual address, no need to calculate I_D_OFFSET like previous chips
SOC_RESERVE_MEMORY_REGION((intptr_t)&_iram_start, (intptr_t)&_iram_end, iram_code);
/* NOTE: When ESP-TEE is enabled, the start of the internal SRAM
* is used by the TEE and is protected from any REE access using
* memory protection mechanisms employed by ESP-TEE.
*/
#if CONFIG_SECURE_ENABLE_TEE
SOC_RESERVE_MEMORY_REGION((intptr_t)SRAM_DIRAM_TEE_ORG, (intptr_t)(SRAM_DIRAM_TEE_END), tee_diram);
#endif
#ifdef CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP
SOC_RESERVE_MEMORY_REGION(SOC_RTC_DRAM_LOW, (intptr_t)&_rtc_force_slow_end, rtcram_data);
#endif

View File

@ -22,15 +22,18 @@
#if CONFIG_MBEDTLS_TEE_SEC_STG_ECDSA_SIGN
#include "esp_tee_sec_storage.h"
#else
#include "hal/ecc_ll.h"
#endif
#if SOC_ECDSA_SUPPORTED
#include "hal/ecdsa_ll.h"
#include "hal/ecdsa_hal.h"
#include "esp_efuse.h"
#endif
#if SOC_ECC_SUPPORTED
#include "hal/ecc_ll.h"
#endif
#if SOC_MPI_SUPPORTED
#include "hal/mpi_ll.h"
#endif
#include "esp_efuse.h"
#endif
#define ECDSA_KEY_MAGIC (short) 0xECD5A
#define ECDSA_KEY_MAGIC_TEE (short) 0xA5DCE

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -9,16 +9,36 @@
#include "soc/plic_reg.h"
#include "soc/soc_caps.h"
#ifdef __has_include
# if __has_include("sdkconfig.h")
# include "sdkconfig.h"
# endif
#endif
#if CONFIG_SECURE_ENABLE_TEE
#define INTERRUPT_PRIO_REG(n) (PLIC_UXINT0_PRI_REG + (n)*4)
#define INTERRUPT_CURRENT_CORE_INT_THRESH_REG PLIC_UXINT_THRESH_REG
#else
#define INTERRUPT_PRIO_REG(n) (PLIC_MXINT0_PRI_REG + (n)*4)
#define INTERRUPT_CURRENT_CORE_INT_THRESH_REG PLIC_MXINT_THRESH_REG
#endif
/**
* ESP32H2 should use the PLIC controller as the interrupt controller instead of INTC (SOC_INT_PLIC_SUPPORTED = y)
* Keep the following macros for backward compatibility reasons
*/
#if CONFIG_SECURE_ENABLE_TEE
#define INTERRUPT_CORE0_CPU_INT_ENABLE_REG PLIC_UXINT_ENABLE_REG
#define INTERRUPT_CORE0_CPU_INT_THRESH_REG PLIC_UXINT_THRESH_REG
#define INTERRUPT_CORE0_CPU_INT_CLEAR_REG PLIC_UXINT_CLEAR_REG
#define INTERRUPT_CORE0_CPU_INT_TYPE_REG PLIC_UXINT_TYPE_REG
#define INTC_INT_PRIO_REG(n) (PLIC_UXINT0_PRI_REG + (n)*4)
#else
#define INTERRUPT_CORE0_CPU_INT_ENABLE_REG PLIC_MXINT_ENABLE_REG
#define INTERRUPT_CORE0_CPU_INT_THRESH_REG PLIC_MXINT_THRESH_REG
#define INTERRUPT_CORE0_CPU_INT_CLEAR_REG PLIC_MXINT_CLEAR_REG
#define INTERRUPT_CORE0_CPU_INT_TYPE_REG PLIC_MXINT_TYPE_REG
#define INTC_INT_PRIO_REG(n) (PLIC_MXINT0_PRI_REG + (n)*4)
#endif
#define DR_REG_INTERRUPT_BASE DR_REG_INTMTX_BASE

View File

@ -11,6 +11,7 @@ extern "C" {
#define DR_REG_CLINT_M_BASE ( 0x20001800)
#define DR_REG_CLINT_U_BASE ( 0x20001C00)
#define DR_REG_CLINT_U_END ( 0x20002000)
/*CLINT MINT*/
#define CLINT_MINT_SIP_REG (DR_REG_CLINT_M_BASE + 0x0)

View File

@ -12,6 +12,7 @@ extern "C" {
#define DR_REG_PLIC_MX_BASE ( 0x20001000 )
#define DR_REG_PLIC_UX_BASE ( 0x20001400 )
#define DR_REG_PLIC_UX_END ( 0x20001800 )
#define PLIC_MXINT_CONF_REG ( 0x200013FC )
#define PLIC_UXINT_CONF_REG ( 0x200017FC )