ci(hal): Enable the TEE-based interrupt test-cases for ESP32-P4

This commit is contained in:
Laukik Hase
2026-01-09 17:49:23 +05:30
parent b6eab8cac8
commit 99f6d7cd56
21 changed files with 302 additions and 295 deletions
@@ -9,4 +9,4 @@ components/esp_hal_security/test_apps/crypto:
components/esp_hal_security/test_apps/tee:
disable:
- if: IDF_TARGET not in ["esp32c6", "esp32h2", "esp32c5", "esp32c61"]
- if: IDF_TARGET not in ["esp32c6", "esp32h2", "esp32c5", "esp32c61", "esp32p4"]
@@ -1,5 +1,5 @@
| Supported Targets | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 |
| ----------------- | -------- | -------- | --------- | -------- |
| Supported Targets | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-P4 |
| ----------------- | -------- | -------- | --------- | -------- | -------- |
# TEE (Trusted Execution Environment) Test Application
@@ -1,13 +1,18 @@
cmake_minimum_required(VERSION 3.22)
idf_build_get_property(target IDF_TARGET)
set(srcs "src/common/test_apm_utils.c"
"src/common/test_intr_utils.c"
"src/common/test_setup_utils.c"
set(srcs "src/common/test_intr_utils.c"
"src/common/test_panic_handler.c")
list(APPEND srcs "src/pms/test_tee_sys_apm.c"
"src/pms/test_tee_vectors.S")
if(CONFIG_SOC_SUPPORT_TEE_SYS_APM_TEST)
if(CONFIG_SOC_APM_CTRL_FILTER_SUPPORTED)
list(APPEND srcs "src/common/test_apm_utils.c"
"src/common/test_setup_utils.c"
"src/pms/test_tee_sys_apm.c"
"src/pms/test_tee_vectors.S")
endif()
endif()
if(CONFIG_SOC_SUPPORT_TEE_PERI_APM_TEST)
list(APPEND srcs "src/pms/test_tee_peri_apm.c")
endif()
@@ -2,17 +2,17 @@ menu "Test-app related"
config SOC_SUPPORT_TEE_SYS_APM_TEST
bool
depends on SOC_APM_CTRL_FILTER_SUPPORTED
depends on SOC_APM_SUPPORTED
default y
config SOC_SUPPORT_TEE_PERI_APM_TEST
bool
depends on SOC_APM_SUPPORT_TEE_PERI_ACCESS_CTRL
depends on SOC_APM_SUPPORTED && SOC_APM_SUPPORT_TEE_PERI_ACCESS_CTRL
default y
config SOC_SUPPORT_TEE_INTR_TEST
bool
depends on IDF_TARGET_ESP32C5 || IDF_TARGET_ESP32C61
depends on IDF_TARGET_ESP32C5 || IDF_TARGET_ESP32C61 || (IDF_TARGET_ESP32P4 && !ESP32P4_SELECTS_REV_LESS_V3)
default y
endmenu
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -8,9 +8,20 @@
#define TEST_INTR_NUM_PASS_IN_SEC (31)
#include "soc/interrupt_matrix_reg.h"
#define INTMTX_SEC_STATUS_REG INTERRUPT_CORE0_SECURE_STATUS_REG
#define INTMTX_SIG_IDX_ASSERT_IN_SEC_REG INTERRUPT_CORE0_SIG_IDX_ASSERT_IN_SEC_REG
#ifndef __ASSEMBLER__
#include "soc/interrupts.h"
#include "soc/intpri_reg.h"
#include "esp_bit_defs.h"
#define TG0_T0_INTR_SRC (ETS_TG0_T0_LEVEL_INTR_SOURCE)
#define CPU_FROM_CPU_N_INTR_SRC(n) (ETS_FROM_CPU_INTR0_SOURCE + n)
#define CPU_INTR_FROM_CPU_N_REG(n) (INTPRI_CPU_INTR_FROM_CPU_0_REG + 4 * (n))
#define INTMTX_INT_SRC_PASS_IN_SEC_BIT BIT(8)
#endif
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -8,9 +8,20 @@
#define TEST_INTR_NUM_PASS_IN_SEC (31)
#include "soc/interrupt_matrix_reg.h"
#define INTMTX_SEC_STATUS_REG INTERRUPT_CORE0_SECURE_STATUS_REG
#define INTMTX_SIG_IDX_ASSERT_IN_SEC_REG INTERRUPT_CORE0_SIG_IDX_ASSERT_IN_SEC_REG
#ifndef __ASSEMBLER__
#include "soc/interrupts.h"
#include "soc/intpri_reg.h"
#include "esp_bit_defs.h"
#define TG0_T0_INTR_SRC (ETS_TG0_T0_INTR_SOURCE)
#define CPU_FROM_CPU_N_INTR_SRC(n) (ETS_CPU_INTR_FROM_CPU_0_SOURCE + n)
#define CPU_INTR_FROM_CPU_N_REG(n) (INTPRI_CPU_INTR_FROM_CPU_0_REG + 4 * (n))
#define INTMTX_INT_SRC_PASS_IN_SEC_BIT BIT(8)
#endif
@@ -1,148 +0,0 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <assert.h>
#include "esp_attr.h"
#include "soc/soc_caps.h"
#include "soc/clic_reg.h"
#include "hal/interrupt_clic_ll.h"
#include "riscv/csr.h"
#include "riscv/encoding.h"
#include "riscv/interrupt.h"
#include "esp_private/interrupt_clic.h"
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
FORCE_INLINE_ATTR void test_rv_utils_set_xtvec(uint32_t xtvec_val, int mode)
{
xtvec_val |= MTVEC_MODE_CSR;
if (mode == PRV_M) {
RV_WRITE_CSR(mtvec, xtvec_val);
} else {
RV_WRITE_CSR(utvec, xtvec_val);
}
}
FORCE_INLINE_ATTR void test_rv_utils_set_xtvt(uint32_t xtvt_val, int mode)
{
if (mode == PRV_M) {
RV_WRITE_CSR(MTVT_CSR, xtvt_val);
} else {
RV_WRITE_CSR(UTVT_CSR, xtvt_val);
}
}
FORCE_INLINE_ATTR void test_rv_utils_intr_global_enable(int mode)
{
if (mode == PRV_M) {
RV_SET_CSR(mstatus, MSTATUS_MIE);
RV_SET_CSR(mstatus, MSTATUS_UIE);
} else {
RV_SET_CSR(ustatus, USTATUS_UIE);
}
}
FORCE_INLINE_ATTR void test_rv_utils_intr_global_disable(int mode)
{
if (mode == PRV_M) {
RV_CLEAR_CSR(mstatus, MSTATUS_MIE);
RV_CLEAR_CSR(mstatus, MSTATUS_UIE);
} else {
RV_CLEAR_CSR(ustatus, USTATUS_UIE);
}
}
FORCE_INLINE_ATTR void test_rv_utils_intr_enable(uint32_t intr_mask)
{
// Machine mode
// Disable all interrupts to make updating of the interrupt mask atomic.
unsigned old_xstatus = RV_CLEAR_CSR(mstatus, MSTATUS_MIE);
while (intr_mask != 0) {
// __builtin_ffs returns one plus the index of the lsb 1-bit of x. If x is zero, returns zero
uint32_t intr_num = __builtin_ffs(intr_mask) - 1;
*(uint8_t volatile *)(BYTE_CLIC_INT_IE_REG(intr_num + CLIC_EXT_INTR_NUM_OFFSET)) = BYTE_CLIC_INT_IE;
intr_mask &= (intr_mask - 1);
}
RV_SET_CSR(mstatus, old_xstatus & MSTATUS_MIE);
}
FORCE_INLINE_ATTR void test_rv_utils_intr_disable(uint32_t intr_mask)
{
// Machine mode
// Disable all interrupts to make updating of the interrupt mask atomic.
unsigned old_xstatus = RV_CLEAR_CSR(mstatus, MSTATUS_MIE);
while (intr_mask != 0) {
// __builtin_ffs returns one plus the index of the lsb 1-bit of x. If x is zero, returns zero
uint32_t intr_num = __builtin_ffs(intr_mask) - 1;
*(uint8_t volatile *)(BYTE_CLIC_INT_IE_REG(intr_num + CLIC_EXT_INTR_NUM_OFFSET)) = 0;
intr_mask &= (intr_mask - 1);
}
RV_SET_CSR(mstatus, old_xstatus & MSTATUS_MIE);
}
FORCE_INLINE_ATTR void test_rv_utils_intr_set_type(int intr_num, enum intr_type type)
{
assert(intr_num >= 0 && intr_num < SOC_CPU_INTR_NUM);
/* TODO: CLIC supports both rising and falling edge triggered interrupts.
* Currently only rising edge is implemented.
*/
volatile uint8_t *attr_reg = (volatile uint8_t *)BYTE_CLIC_INT_ATTR_REG(intr_num + CLIC_EXT_INTR_NUM_OFFSET);
uint8_t attr = *attr_reg;
attr &= ~BYTE_CLIC_INT_ATTR_TRIG_M;
if (type == INTR_TYPE_EDGE) {
attr |= (INTR_TYPE_EDGE << BYTE_CLIC_INT_ATTR_TRIG_S);
}
*attr_reg = attr;
}
FORCE_INLINE_ATTR void test_rv_utils_intr_set_priority(int intr_num, int priority)
{
assert(intr_num >= 0 && intr_num < SOC_CPU_INTR_NUM);
*(uint8_t volatile *)(BYTE_CLIC_INT_CTL_REG(intr_num + CLIC_EXT_INTR_NUM_OFFSET)) = (priority << BYTE_CLIC_INT_CTL_S);
}
FORCE_INLINE_ATTR void test_rv_utils_intr_set_threshold(int priority_threshold, int mode)
{
uint32_t adj_threshold = ((priority_threshold << (8 - NLBITS)) | 0x1f);
if (mode == PRV_M) {
REG_SET_FIELD(CLIC_INT_THRESH_REG, CLIC_CPU_INT_THRESH, adj_threshold);
RV_WRITE_CSR(MINTTHRESH_CSR, adj_threshold);
} else {
RV_WRITE_CSR(UINTTHRESH_CSR, adj_threshold);
}
}
FORCE_INLINE_ATTR void test_rv_utils_intr_set_mode(int intr_num, int mode)
{
assert(intr_num >= 0 && intr_num < SOC_CPU_INTR_NUM);
REG_SET_FIELD(CLIC_INT_CTRL_REG(intr_num + CLIC_EXT_INTR_NUM_OFFSET), CLIC_INT_ATTR_MODE, mode);
}
FORCE_INLINE_ATTR void test_rv_utils_intr_set_vectored(int intr_num, bool vectored)
{
REG_SET_FIELD(CLIC_INT_CTRL_REG(intr_num + CLIC_EXT_INTR_NUM_OFFSET), CLIC_INT_ATTR_SHV, vectored ? 1 : 0);
}
FORCE_INLINE_ATTR void test_rv_utils_intr_enable_u_mode(bool enable)
{
REG_SET_FIELD(CLIC_INT_CONFIG_REG, CLIC_INT_CONFIG_NMBITS, enable ? 0x01 : 0x00);
REG_SET_FIELD(CLIC_INT_CONFIG_REG, CLIC_INT_CONFIG_UNLBITS, NLBITS);
REG_SET_FIELD(CLIC_INT_CONFIG_REG, CLIC_INT_CONFIG_MNLBITS, NLBITS);
}
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,27 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#define TEST_INTR_NUM_PASS_IN_SEC (31)
#include "soc/interrupt_core0_reg.h"
#define INTMTX_SEC_STATUS_REG INTERRUPT_CORE0_INTR_SEC_STATUS_REG
#define INTMTX_SIG_IDX_ASSERT_IN_SEC_REG INTERRUPT_CORE0_INTR_SIG_IDX_ASSERT_IN_SEC_REG
#ifndef __ASSEMBLER__
#include "soc/interrupts.h"
#include "soc/hp_system_reg.h"
#include "esp_bit_defs.h"
#define TG0_T0_INTR_SRC (ETS_TG0_T0_INTR_SOURCE)
#define CPU_FROM_CPU_N_INTR_SRC(n) (ETS_FROM_CPU_INTR0_SOURCE + n)
#define CPU_INTR_FROM_CPU_N_REG(n) (HP_SYSTEM_CPU_INT_FROM_CPU_0_REG + 4 * (n))
#define INTMTX_INT_SRC_PASS_IN_SEC_BIT BIT(6)
#endif
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -11,7 +11,13 @@
#include "soc/soc.h"
#include "soc/soc_caps.h"
#if SOC_LP_AON_SUPPORTED
#include "soc/lp_aon_reg.h"
#define LP_STORE_REG_PREFIX(reg) LP_AON_STORE##reg##_REG
#else
#include "soc/lp_system_reg.h"
#define LP_STORE_REG_PREFIX(reg) LP_SYSTEM_REG_LP_STORE##reg##_REG
#endif
#include "hal/apm_types.h"
/********* Panic Handler *********/
@@ -23,17 +29,17 @@
/********* HP_CPU - LP_CPU messaging *********/
#define SEND_MSG(msg) REG_WRITE(LP_AON_STORE0_REG, msg)
#define RECV_MSG() REG_READ(LP_AON_STORE0_REG)
#define SEND_MSG(msg) REG_WRITE(LP_STORE_REG_PREFIX(0), msg)
#define RECV_MSG() REG_READ(LP_STORE_REG_PREFIX(0))
#define SEND_ADDR(addr) REG_WRITE(LP_AON_STORE7_REG, addr)
#define RECV_ADDR() REG_READ(LP_AON_STORE7_REG)
#define SEND_ADDR(addr) REG_WRITE(LP_STORE_REG_PREFIX(7), addr)
#define RECV_ADDR() REG_READ(LP_STORE_REG_PREFIX(7))
#define SEND_SIZE(size) REG_WRITE(LP_AON_STORE8_REG, size)
#define RECV_SIZE() REG_READ(LP_AON_STORE8_REG)
#define SEND_SIZE(size) REG_WRITE(LP_STORE_REG_PREFIX(8), size)
#define RECV_SIZE() REG_READ(LP_STORE_REG_PREFIX(8))
#define SEND_EXCP(val) REG_WRITE(LP_AON_STORE9_REG, val)
#define RECV_EXCP() REG_READ(LP_AON_STORE9_REG)
#define SEND_EXCP(val) REG_WRITE(LP_STORE_REG_PREFIX(9), val)
#define RECV_EXCP() REG_READ(LP_STORE_REG_PREFIX(9))
#define MSG_SLAVE_READ 0x11221122
#define MSG_SLAVE_WRITE 0x33443344
@@ -50,6 +56,7 @@
} while (0)
#endif
#if SOC_APM_CTRL_FILTER_SUPPORTED
typedef struct {
apm_master_id_t master_id;
apm_ctrl_module_t ctrl_mod;
@@ -76,16 +83,17 @@ typedef struct {
uint64_t test_reg_resv_mask;
} test_peri_apm_periph_cfg_t;
void apm_hal_enable_region_filter_all(apm_ctrl_module_t ctrl_mod, bool enable);
void test_apm_ctrl_reset_all(void);
void test_apm_ctrl_enable_intr(apm_ctrl_module_t ctrl_mod, apm_ctrl_access_path_t path);
#endif
/* Utility functions */
void set_test_vector_table(void);
void restore_default_vector_table(void);
void test_m2u_switch(void);
void test_u2m_switch(void);
void apm_hal_enable_region_filter_all(apm_ctrl_module_t ctrl_mod, bool enable);
void test_apm_ctrl_reset_all(void);
void test_apm_ctrl_enable_intr(apm_ctrl_module_t ctrl_mod, apm_ctrl_access_path_t path);
void test_boot_lp_cpu(void);
void test_stop_lp_cpu(void);
void test_reset_lp_cpu(void);
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -138,9 +138,14 @@ FORCE_INLINE_ATTR void test_rv_utils_intr_set_vectored(int intr_num, bool vector
FORCE_INLINE_ATTR void test_rv_utils_intr_enable_u_mode(bool enable)
{
#if CONFIG_IDF_TARGET_ESP32P4
// TODO: Need to update soc/clic_reg.h for P4 ver3 (follows the CLIC standard)
REG_WRITE(CLIC_INT_CONFIG_REG, ~0U);
#else
REG_SET_FIELD(CLIC_INT_CONFIG_REG, CLIC_INT_CONFIG_NMBITS, enable ? 0x01 : 0x00);
REG_SET_FIELD(CLIC_INT_CONFIG_REG, CLIC_INT_CONFIG_UNLBITS, NLBITS);
REG_SET_FIELD(CLIC_INT_CONFIG_REG, CLIC_INT_CONFIG_MNLBITS, NLBITS);
#endif
}
#ifdef __cplusplus
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -9,7 +9,6 @@
#include "soc/soc_caps.h"
#include "soc/reg_base.h"
#include "soc/interrupts.h"
#include "soc/interrupt_matrix_reg.h"
#include "riscv/encoding.h"
#include "riscv/csr.h"
@@ -75,14 +74,6 @@ void test_u2m_switch(void)
/********************************** Interrupt Handler *************************************/
extern void _global_interrupt_handler(intptr_t sp, int mcause);
/* called from test_tee_vectors.S */
void _test_global_interrupt_handler(intptr_t sp, int mcause)
{
_global_interrupt_handler(sp, mcause);
}
#if CONFIG_SOC_SUPPORT_TEE_INTR_TEST
extern int _vector_table;
@@ -107,6 +98,43 @@ static void test_redirect_vector_table(bool redirect)
test_rv_utils_set_xtvec((uintptr_t)&_vector_table, PRV_M);
}
}
typedef struct {
intr_handler_t handler;
void *arg;
} intr_handler_item_t;
static intr_handler_item_t s_intr_handlers[SOC_CPU_CORES_NUM][RV_EXTERNAL_INT_OFFSET];
static intr_handler_item_t* intr_get_item(int int_no)
{
assert_valid_rv_int_num(int_no);
/* TODO: [DIG-795]
* Find a way to query the current core ID in
* U-mode for multicore SoCs. Thus, TEE interrupt tests
* will run only in unicore mode till then.
*/
const uint32_t id = 0;
return &s_intr_handlers[id][int_no];
}
void test_intr_handler_set(int int_no, intr_handler_t fn, void *arg)
{
intr_handler_item_t* item = intr_get_item(int_no);
*item = (intr_handler_item_t) {
.handler = fn,
.arg = arg
};
}
/* called from test_vectors_m/u.S */
void _test_global_interrupt_handler(intptr_t sp, int mcause)
{
assert(mcause >= RV_EXTERNAL_INT_OFFSET && "Interrupt sources must not be mapped to local interrupts");
const intr_handler_item_t* item = intr_get_item(mcause - RV_EXTERNAL_INT_OFFSET);
if (item->handler) {
(*item->handler)(item->arg);
}
}
/***************************** Miscellaneous: Interrupts (CLIC configuration save/restore) *****************************/
@@ -202,7 +230,7 @@ void test_intr_alloc(int mode, int priority, int intr_src, intr_handler_t func,
return; // No free interrupts
}
intr_handler_set(intr_num, func, arg);
test_intr_handler_set(intr_num, func, arg);
esp_rom_route_intr_matrix(0, intr_src, intr_num);
}
@@ -218,10 +246,11 @@ void test_intr_alloc(int mode, int priority, int intr_src, intr_handler_t func,
test_rv_utils_intr_set_mode(intr_num, mode);
if (mode == PRV_U) {
REG_SET_BIT(DR_REG_INTMTX_BASE + 4 * intr_src, BIT(8));
REG_SET_BIT(DR_REG_INTMTX_BASE + 4 * intr_src, INTMTX_INT_SRC_PASS_IN_SEC_BIT);
}
if (mode == PRV_M && intr_src == ETS_MAX_INTR_SOURCE) {
REG_WRITE(INTERRUPT_CORE0_SIG_IDX_ASSERT_IN_SEC_REG, intr_num + CLIC_EXT_INTR_NUM_OFFSET);
REG_WRITE(INTMTX_SIG_IDX_ASSERT_IN_SEC_REG, intr_num + CLIC_EXT_INTR_NUM_OFFSET);
}
test_rv_utils_intr_enable(BIT(intr_num));
@@ -235,13 +264,13 @@ void test_intr_free_all(void)
}
test_intr_entry_t *entry = &s_intr_table[TEST_INTR_IDX(intr_num)];
intr_handler_set(intr_num, NULL, NULL);
test_intr_handler_set(intr_num, NULL, NULL);
interrupt_clic_ll_route(0, entry->intr_src, ETS_INVALID_INUM);
if (entry->mode == PRV_U) {
REG_CLR_BIT(DR_REG_INTMTX_BASE + 4 * entry->intr_src, BIT(8));
REG_CLR_BIT(DR_REG_INTMTX_BASE + 4 * entry->intr_src, INTMTX_INT_SRC_PASS_IN_SEC_BIT);
}
if (entry->mode == PRV_M && entry->intr_src == ETS_MAX_INTR_SOURCE) {
REG_WRITE(INTERRUPT_CORE0_SIG_IDX_ASSERT_IN_SEC_REG, ETS_INVALID_INUM);
REG_WRITE(INTMTX_SIG_IDX_ASSERT_IN_SEC_REG, ETS_INVALID_INUM);
}
test_rv_utils_intr_disable(BIT(intr_num));
@@ -249,3 +278,24 @@ void test_intr_free_all(void)
}
}
#endif
/***************************** Miscellaneous *****************************/
IRAM_ATTR void test_delay_ms(uint32_t ms)
{
uint32_t us = ms * 1000U;
#if SOC_CPU_HAS_CSR_PC
esp_rom_delay_us(us);
#else
if (RV_READ_CSR(CSR_PRV_MODE) == PRV_M) {
esp_rom_delay_us(us);
} else {
uint32_t start = RV_READ_CSR(cycle);
uint32_t end = us * esp_rom_get_cpu_ticks_per_us();
while ((RV_READ_CSR(cycle) - start) < end) {
/* nothing to do */
}
}
#endif
}
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -18,9 +18,9 @@
#include "soc/gdma_struct.h"
#endif
#if CONFIG_ULP_COPROC_ENABLED
#include "soc/lp_aon_reg.h"
#include "soc/lpperi_reg.h"
#if CONFIG_ULP_COPROC_ENABLED
#include "ulp_lp_core.h"
#endif
@@ -223,24 +223,3 @@ void test_gdma_wait_done(void)
}
}
}
/***************************** Miscellaneous *****************************/
IRAM_ATTR void test_delay_ms(uint32_t ms)
{
uint32_t us = ms * 1000U;
#if SOC_CPU_HAS_CSR_PC
esp_rom_delay_us(us);
#else
if (RV_READ_CSR(CSR_PRV_MODE) == PRV_M) {
esp_rom_delay_us(us);
} else {
uint32_t start = RV_READ_CSR(cycle);
uint32_t end = us * esp_rom_get_cpu_ticks_per_us();
while ((RV_READ_CSR(cycle) - start) < end) {
/* nothing to do */
}
}
#endif
}
@@ -1,22 +1,23 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <assert.h>
#include <stdio.h>
#include "soc/soc.h"
#include "soc/soc_caps.h"
#include "soc/intpri_reg.h"
#include "soc/pcr_reg.h"
#include "hal/timer_ll.h"
#include "esp_cpu.h"
#include "esp_attr.h"
#include "esp_rom_sys.h"
#include "esp_private/periph_ctrl.h"
#include "esp_private/esp_clk_tree_common.h"
#include "test_rv_utils.h"
#include "unity.h"
@@ -26,6 +27,12 @@
#include "test_cpu_intr_priv.h"
#include "test_cpu_intr_params.h"
#if SOC_RCC_IS_INDEPENDENT
#define TIMER_RCC_ATOMIC()
#else /* !SOC_RCC_IS_INDEPENDENT */
#define TIMER_RCC_ATOMIC() PERIPH_RCC_ATOMIC()
#endif /* SOC_RCC_IS_INDEPENDENT */
#define TEST_INTR_MAX_COUNT (8)
/* ---------------------------------------------------- Utility - TIMER ---------------------------------------------------- */
@@ -41,11 +48,24 @@
static timg_dev_t *timg_dev = TIMER_LL_GET_HW(TEST_TIMER_GROUP);
/* ---------------------------------------------------- Utility - Common ---------------------------------------------------- */
#define TEST_INTR_TK_INIT 0x8BADF00D
#define TEST_INTR_TK_DONE 0xDEFEC8ED
typedef struct {
volatile int id;
volatile int curr_count;
volatile int max_count;
volatile int token;
volatile int expected_mode;
} test_intr_args_ctx_t;
IRAM_ATTR static void test_timer_isr(void *arg)
{
uint32_t *intr_count = (uint32_t *)arg;
*intr_count = *intr_count + 1;
esp_rom_printf("[mode: %d] TIMER-%d interrupt triggered (%d)\n", esp_cpu_get_curr_privilege_level(), TEST_TIMER_GROUP, *intr_count);
test_intr_args_ctx_t *ctx = (test_intr_args_ctx_t *)arg;
ctx->curr_count++;
TEST_ASSERT_EQUAL(ctx->expected_mode, esp_cpu_get_curr_privilege_level());
/* Clear interrupt and re-enable the alarm */
timer_ll_clear_intr_status(timg_dev, TIMER_LL_EVENT_ALARM(TEST_TIMER_ID));
@@ -70,10 +90,12 @@ static void test_timer_deinit(void)
timer_ll_trigger_soft_reload(timg_dev, timer_id);
timer_ll_set_reload_value(timg_dev, timer_id, prev_val);
timer_ll_enable_clock(TEST_TIMER_GROUP, timer_id, false);
TIMER_RCC_ATOMIC() {
timer_ll_enable_clock(TEST_TIMER_GROUP, timer_id, false);
}
}
static void test_timer_init(int mode, volatile uint32_t *arg)
static void test_timer_init(int mode, int priority, test_intr_args_ctx_t *arg)
{
const uint32_t group_id = TEST_TIMER_GROUP;
const uint32_t timer_id = TEST_TIMER_ID;
@@ -86,14 +108,16 @@ static void test_timer_init(int mode, volatile uint32_t *arg)
// Select clock source and enable module clock
// Enable the default clock source PLL_F80M
REG_SET_BIT(PCR_PLL_DIV_CLK_EN_REG, PCR_PLL_80M_CLK_EN);
timer_ll_set_clock_source(group_id, timer_id, GPTIMER_CLK_SRC_DEFAULT);
timer_ll_enable_clock(group_id, timer_id, true);
esp_clk_tree_enable_src(SOC_MOD_CLK_PLL_F80M, true);
TIMER_RCC_ATOMIC() {
timer_ll_set_clock_source(group_id, timer_id, GPTIMER_CLK_SRC_DEFAULT);
timer_ll_enable_clock(group_id, timer_id, true);
}
timer_ll_set_clock_prescale(timg_dev, timer_id, TEST_TIMER_DIVIDER);
timer_ll_set_count_direction(timg_dev, timer_id, GPTIMER_COUNT_UP);
// Register ISR
test_intr_alloc(mode, 2, TG0_T0_INTR_SRC, &test_timer_isr, (void *)arg);
test_intr_alloc(mode, priority, TG0_T0_INTR_SRC, &test_timer_isr, (void *)arg);
timer_ll_enable_intr(timg_dev, TIMER_LL_EVENT_ALARM(timer_id), true);
// Configure and enable timer alarm
@@ -105,18 +129,6 @@ static void test_timer_init(int mode, volatile uint32_t *arg)
/* ---------------------------------------------------- Utility - INTPRI ---------------------------------------------------- */
#define TEST_INTR_TK_INIT 0x8BADF00D
#define TEST_INTR_TK_DONE 0xDEFEC8ED
#define CPU_INTR_FROM_CPU_N_REG(n) (INTPRI_CPU_INTR_FROM_CPU_0_REG + 4 * (n))
typedef struct {
volatile int id;
volatile int curr_count;
volatile int max_count;
volatile int token;
} test_intr_args_ctx_t;
FORCE_INLINE_ATTR void intpri_cpu_clr_intr(uint32_t n)
{
WRITE_PERI_REG(CPU_INTR_FROM_CPU_N_REG(n), 0);
@@ -144,36 +156,41 @@ IRAM_ATTR static void test_intpri_isr(void *arg)
ctx->token = TEST_INTR_TK_DONE;
}
esp_rom_printf("[mode: %d] INTPRI-%d interrupt triggered (%d)\n", esp_cpu_get_curr_privilege_level(), ctx->id, ctx->curr_count);
TEST_ASSERT_EQUAL(ctx->expected_mode, esp_cpu_get_curr_privilege_level());
}
/* ---------------------------------------------------- Test-cases ---------------------------------------------------- */
void test_m_mode_intr_in_m_mode(void)
{
#if SOC_APM_CTRL_FILTER_SUPPORTED
test_apm_ctrl_reset_all();
#endif
test_intr_utils_init();
test_intr_args_ctx_t ctx = {
test_intr_args_ctx_t ctx1 = {
.id = 0,
.curr_count = 0,
.max_count = TEST_INTR_MAX_COUNT,
.token = TEST_INTR_TK_INIT,
.expected_mode = PRV_M,
};
test_intr_alloc(PRV_M, 1, CPU_FROM_CPU_N_INTR_SRC(ctx1.id), &test_intpri_isr, &ctx1);
test_intr_alloc(PRV_M, 1, CPU_FROM_CPU_N_INTR_SRC(ctx.id), &test_intpri_isr, &ctx);
test_intr_args_ctx_t ctx2 = {
.curr_count = 0,
.expected_mode = PRV_M,
};
test_timer_init(PRV_M, 2, &ctx2);
volatile uint32_t intr_count = 0;
test_timer_init(PRV_M, &intr_count);
while (ctx.token != TEST_INTR_TK_DONE) {
intpri_cpu_trig_intr(ctx.id);
while (ctx1.token != TEST_INTR_TK_DONE) {
intpri_cpu_trig_intr(ctx1.id);
test_delay_ms(TEST_INTPRI_PERIOD_S * 1000U);
}
TEST_ASSERT(ctx.curr_count == TEST_INTR_MAX_COUNT);
TEST_ASSERT(ctx1.curr_count == TEST_INTR_MAX_COUNT);
test_timer_deinit();
TEST_ASSERT(intr_count >= TEST_TIMER_EXP_COUNT);
TEST_ASSERT(ctx2.curr_count >= TEST_TIMER_EXP_COUNT);
test_intr_free_all();
test_intr_utils_deinit();
@@ -181,31 +198,36 @@ void test_m_mode_intr_in_m_mode(void)
void test_u_mode_intr_in_u_mode(void)
{
#if SOC_APM_CTRL_FILTER_SUPPORTED
test_apm_ctrl_reset_all();
#endif
test_intr_utils_init();
test_intr_args_ctx_t ctx = {
test_intr_args_ctx_t ctx1 = {
.id = 0,
.curr_count = 0,
.max_count = TEST_INTR_MAX_COUNT,
.token = TEST_INTR_TK_INIT,
.expected_mode = PRV_U,
};
test_intr_alloc(PRV_U, 1, CPU_FROM_CPU_N_INTR_SRC(ctx1.id), &test_intpri_isr, &ctx1);
test_intr_alloc(PRV_U, 1, CPU_FROM_CPU_N_INTR_SRC(ctx.id), &test_intpri_isr, &ctx);
volatile uint32_t intr_count = 0;
test_timer_init(PRV_U, &intr_count);
test_intr_args_ctx_t ctx2 = {
.curr_count = 0,
.expected_mode = PRV_U,
};
test_timer_init(PRV_U, 2, &ctx2);
test_m2u_switch();
while (ctx.token != TEST_INTR_TK_DONE) {
intpri_cpu_trig_intr(ctx.id);
while (ctx1.token != TEST_INTR_TK_DONE) {
intpri_cpu_trig_intr(ctx1.id);
test_delay_ms(TEST_INTPRI_PERIOD_S * 1000U);
}
test_u2m_switch();
TEST_ASSERT(ctx.curr_count == TEST_INTR_MAX_COUNT);
TEST_ASSERT(ctx1.curr_count == TEST_INTR_MAX_COUNT);
test_timer_deinit();
TEST_ASSERT(intr_count >= TEST_TIMER_EXP_COUNT);
TEST_ASSERT(ctx2.curr_count >= TEST_TIMER_EXP_COUNT);
test_intr_free_all();
test_intr_utils_deinit();
@@ -213,33 +235,38 @@ void test_u_mode_intr_in_u_mode(void)
void test_m_mode_intr_in_u_mode(void)
{
#if SOC_APM_CTRL_FILTER_SUPPORTED
test_apm_ctrl_reset_all();
#endif
test_intr_utils_init();
test_intr_args_ctx_t ctx = {
test_intr_alloc(PRV_M, 1, ETS_MAX_INTR_SOURCE, NULL, NULL);
test_intr_args_ctx_t ctx1 = {
.id = 0,
.curr_count = 0,
.max_count = TEST_INTR_MAX_COUNT,
.token = TEST_INTR_TK_INIT,
.expected_mode = PRV_M,
};
test_intr_alloc(PRV_M, 1, CPU_FROM_CPU_N_INTR_SRC(ctx1.id), &test_intpri_isr, &ctx1);
test_intr_alloc(PRV_M, 1, CPU_FROM_CPU_N_INTR_SRC(ctx.id), &test_intpri_isr, &ctx);
test_intr_alloc(PRV_M, 1, ETS_MAX_INTR_SOURCE, NULL, NULL);
volatile uint32_t intr_count = 0;
test_timer_init(PRV_U, &intr_count);
test_intr_args_ctx_t ctx2 = {
.curr_count = 0,
.expected_mode = PRV_U,
};
test_timer_init(PRV_U, 2, &ctx2);
test_m2u_switch();
while (ctx.token != TEST_INTR_TK_DONE) {
intpri_cpu_trig_intr(ctx.id);
while (ctx1.token != TEST_INTR_TK_DONE) {
intpri_cpu_trig_intr(ctx1.id);
test_delay_ms(TEST_INTPRI_PERIOD_S * 1000U);
}
test_u2m_switch();
TEST_ASSERT(ctx.curr_count == TEST_INTR_MAX_COUNT);
TEST_ASSERT(ctx1.curr_count == TEST_INTR_MAX_COUNT);
test_timer_deinit();
TEST_ASSERT(intr_count >= TEST_TIMER_EXP_COUNT);
TEST_ASSERT(ctx2.curr_count >= TEST_TIMER_EXP_COUNT);
test_intr_free_all();
test_intr_utils_deinit();
@@ -247,31 +274,36 @@ void test_m_mode_intr_in_u_mode(void)
void test_u_mode_intr_in_m_mode(void)
{
#if SOC_APM_CTRL_FILTER_SUPPORTED
test_apm_ctrl_reset_all();
#endif
test_intr_utils_init();
test_intr_alloc(PRV_M, 1, ETS_MAX_INTR_SOURCE, NULL, NULL);
test_intr_args_ctx_t ctx = {
test_intr_args_ctx_t ctx1 = {
.id = 0,
.curr_count = 0,
.max_count = TEST_INTR_MAX_COUNT,
.token = TEST_INTR_TK_INIT,
.expected_mode = PRV_U,
};
test_intr_alloc(PRV_U, 1, CPU_FROM_CPU_N_INTR_SRC(ctx1.id), &test_intpri_isr, &ctx1);
test_intr_alloc(PRV_U, 1, CPU_FROM_CPU_N_INTR_SRC(ctx.id), &test_intpri_isr, &ctx);
test_intr_args_ctx_t ctx2 = {
.curr_count = 0,
.expected_mode = PRV_M,
};
test_timer_init(PRV_M, 2, &ctx2);
volatile uint32_t intr_count = 0;
test_timer_init(PRV_M, &intr_count);
while (ctx.token != TEST_INTR_TK_DONE) {
intpri_cpu_trig_intr(ctx.id);
while (ctx1.token != TEST_INTR_TK_DONE) {
intpri_cpu_trig_intr(ctx1.id);
test_delay_ms(TEST_INTPRI_PERIOD_S * 1000U);
}
TEST_ASSERT(ctx.curr_count == TEST_INTR_MAX_COUNT);
TEST_ASSERT(ctx1.curr_count == TEST_INTR_MAX_COUNT);
test_timer_deinit();
TEST_ASSERT(intr_count >= TEST_TIMER_EXP_COUNT);
TEST_ASSERT(ctx2.curr_count >= TEST_TIMER_EXP_COUNT);
test_intr_free_all();
test_intr_utils_deinit();
@@ -1,13 +1,13 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/soc.h"
#include "soc/soc_caps.h"
#include "soc/clic_reg.h"
#include "soc/interrupt_reg.h"
#include "soc/interrupt_matrix_reg.h"
#include "riscv/encoding.h"
#include "riscv/rvruntime-frames.h"
@@ -23,9 +23,8 @@
.equ ECALL_M_MODE, 0xb
.equ INTR_M2U_MAGIC, 0x1f
.equ INTR_U2M_RTNVAL, 0xc0de
.equ INTMTX_SEC_STATUS_REG, INTERRUPT_CORE0_SECURE_STATUS_REG
.equ INTMTX_SIG_IDX_ASSERT_IN_SEC_REG, INTERRUPT_CORE0_SIG_IDX_ASSERT_IN_SEC_REG
.equ VECTORS_XCAUSE_XPIE_MASK, 0x08000000
.equ CSR_UINTTHRESH, 0x047
.equ panic_from_excp, test_panicHandler
.global _test_uintr_handler
@@ -415,12 +414,26 @@ _find_intr_loop:
li t1, -1
unimp
_found_intr:
addi t0, t1, CLIC_EXT_INTR_NUM_OFFSET
csrr t1, ucause
or t1, t1, t0
li t2, (VECTORS_MCAUSE_INTBIT_MASK | VECTORS_XCAUSE_XPIE_MASK)
or t1, t1, t2
csrw ucause, t1
addi t6, t1, CLIC_EXT_INTR_NUM_OFFSET
/* Update ucause */
csrr t0, ucause
li t1, VECTORS_MCAUSE_REASON_MASK
not t1, t1
and t0, t0, t1
or t0, t0, t6
li t1, VECTORS_MCAUSE_INTBIT_MASK
or t0, t0, t1
csrw ucause, t0
/* Update the U-mode interrupt threshold */
li t1, DR_REG_CLIC_CTRL_BASE
slli t2, t6, 2
add t1, t1, t2
lw t2, 0(t1)
fence
srli t2, t2, CLIC_INT_CTL_S
csrw CSR_UINTTHRESH, t2
/* Enable the U-mode interrupt delegation */
li t0, INTMTX_SIG_IDX_ASSERT_IN_SEC_REG
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -19,6 +19,7 @@
.equ SAVE_REGS, 32
.equ CONTEXT_SIZE, (SAVE_REGS * 4)
.equ UINTTHRESH_CSR, 0x047
.equ UINTSTATUS_CSR, 0xCB1
.equ RV_INTR_NUM, (CLIC_EXT_INTR_NUM_OFFSET + SOC_CPU_INTR_NUM)
/* Macro which first allocates space on the stack to save general
@@ -193,6 +194,15 @@ _test_uintr_handler:
/* Disable nested interrupts */
csrci ustatus, USTATUS_UIE
/* Restore the U-mode interrupt threshold level */
csrr t0, UINTSTATUS_CSR
bnez t0, _skip_thresh_reset
csrr t0, UINTTHRESH_CSR
li t1, (1 << (8 - NLBITS)) - 1
beq t0, t1, _skip_thresh_reset
csrw UINTTHRESH_CSR, t1
_skip_thresh_reset:
/* Restore the rest of the registers. */
csrw ucause, s1
csrw ustatus, s2
@@ -245,7 +245,7 @@ _test_user_ecall:
.global rtos_int_enter
.global rtos_int_exit
.global _test_global_interrupt_handler
.global _global_interrupt_handler
/* Interrupt handler */
.type _test_interrupt_handler, @function
_test_interrupt_handler:
@@ -296,7 +296,7 @@ _test_interrupt_handler:
/* mask off the interrupt flag of mcause */
li t0, VECTORS_MCAUSE_REASON_MASK
and a1, a1, t0
jal _test_global_interrupt_handler
jal _global_interrupt_handler
/* After dispatch c handler, disable interrupt to make freertos make context switch */
@@ -10,6 +10,7 @@
#include "sdkconfig.h"
#if SOC_APM_CTRL_FILTER_SUPPORTED
/**
* Test default access behavior for TEE mode
*
@@ -243,4 +244,5 @@ TEST_CASE("Test LP_CPU -> LP_PERI access", "[PERI_APM]")
test_peri_apm_master_lp_cpu_slave_lp_peri();
}
#endif /* CONFIG_ULP_COPROC_ENABLED */
#endif /* SOC_APM_SUPPORT_TEE_PERI_ACCESS_CTRL */
#endif
#endif /* SOC_APM_CTRL_FILTER_SUPPORTED */
@@ -8,7 +8,7 @@ from pytest_embedded_idf.utils import idf_parametrize
SOC_SUPPORT_SYS_APM_TEST = ['esp32c6', 'esp32h2', 'esp32c5', 'esp32c61']
SOC_SUPPORT_PERI_APM_TEST = ['esp32c5']
SOC_SUPPORT_INTR_TEST = ['esp32c5', 'esp32c61']
SOC_SUPPORT_INTR_TEST = ['esp32c5', 'esp32c61', 'esp32p4']
CONFIG_SYS_APM = [
# 'config, target, markers',
@@ -0,0 +1,4 @@
# TODO: Need to find a way to query the current core ID in
# U-mode for multicore SoCs. Thus, TEE interrupt tests will
# run only in unicore mode till then.
CONFIG_FREERTOS_UNICORE=y
@@ -5,7 +5,6 @@
*/
#pragma once
#include <stdint.h>
#include "soc/soc.h"
#ifdef __cplusplus
extern "C" {
@@ -5,7 +5,6 @@
*/
#pragma once
#include <stdint.h>
#include "soc/soc.h"
#ifdef __cplusplus
extern "C" {