mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-02 20:24:32 +02:00
ci(hal): Extend the PMS hal test-app for verifying TEE-based interrupt scenarios
This commit is contained in:
@@ -128,7 +128,7 @@
|
||||
/components/freertos/ @esp-idf-codeowners/system
|
||||
/components/hal/ @esp-idf-codeowners/peripherals
|
||||
/components/hal/test_apps/crypto/ @esp-idf-codeowners/peripherals @esp-idf-codeowners/security
|
||||
/components/hal/test_apps/tee_apm/ @esp-idf-codeowners/peripherals @esp-idf-codeowners/security
|
||||
/components/hal/test_apps/tee/ @esp-idf-codeowners/peripherals @esp-idf-codeowners/security
|
||||
/components/heap/ @esp-idf-codeowners/system
|
||||
/components/http_parser/ @esp-idf-codeowners/app-utilities
|
||||
/components/idf_test/ @esp-idf-codeowners/peripherals @esp-idf-codeowners/system
|
||||
|
@@ -12,6 +12,6 @@ components/hal/test_apps/hal_utils:
|
||||
enable:
|
||||
- if: IDF_TARGET == "linux"
|
||||
|
||||
components/hal/test_apps/tee_apm:
|
||||
components/hal/test_apps/tee:
|
||||
disable:
|
||||
- if: IDF_TARGET not in ["esp32c6", "esp32h2", "esp32c5", "esp32c61"]
|
||||
|
@@ -6,7 +6,7 @@ set(COMPONENTS main)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
|
||||
project(test_tee_apm)
|
||||
project(test_tee_pms_cpu_intr)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/ci/check_register_rw_half_word.cmake)
|
||||
message(STATUS "Checking tee/apm registers are not read-write by half-word")
|
@@ -1,15 +1,21 @@
|
||||
| Supported Targets | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 |
|
||||
| ----------------- | -------- | -------- | --------- | -------- |
|
||||
|
||||
# APM (Access Permission Management) Peripheral Test App
|
||||
# TEE (Trusted Execution Environment) Test Application
|
||||
|
||||
This application validates region-based memory and peripheral access control via the APM (Access Permission Management) subsystem. It is primarily intended for bring-up and SoC-level functional testing.
|
||||
This application is designed to validate the key components of the **ESP-TEE** framework, with a focus on:
|
||||
|
||||
Tests exercise various master-to-region accesses under different security modes (`TEE`, `REE0`, `REE1`, `REE2`). Outcomes are validated against expected APM behavior and known SoC-specific quirks.
|
||||
1. **Permission Management (PMS: TEE controller + APM module)**
|
||||
- Region-based memory and peripheral access control using the TEE controller and the Access Permission Management (APM) module
|
||||
|
||||
2. **Interrupts**
|
||||
- Interrupt handling in Machine mode (M), User mode (U), and cross-mode contexts
|
||||
|
||||
It is primarily intended for early bring-up and SoC-level functional validation.
|
||||
|
||||
---
|
||||
|
||||
## Test Coverage
|
||||
## Test Coverage: PMS (TEE + APM module)
|
||||
|
||||
### TEE mode default access behavior
|
||||
|
||||
@@ -51,6 +57,13 @@ Validates the per-peripheral access permissions for all security modes.
|
||||
|
||||
---
|
||||
|
||||
## Test Coverage: Interrupts
|
||||
|
||||
- **M-mode interrupts in M-mode**
|
||||
- **U-mode interrupts in U-mode**
|
||||
- **M-mode interrupts in U-mode**
|
||||
- **U-mode interrupts in M-mode**
|
||||
|
||||
## Target Extension Guide
|
||||
|
||||
To add support for a new SoC target, create a test configuration header at:
|
@@ -1,14 +1,21 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
idf_build_get_property(target IDF_TARGET)
|
||||
|
||||
set(srcs "src/test_tee_vectors.S"
|
||||
"src/test_panic_handler.c"
|
||||
"src/test_intr_utils.c"
|
||||
"src/test_apm_utils.c"
|
||||
"src/test_setup_utils.c"
|
||||
"src/test_tee_sys_apm.c")
|
||||
if(CONFIG_SOC_APM_SUPPORT_TEE_PERI_ACCESS_CTRL)
|
||||
list(APPEND srcs "src/test_tee_peri_apm.c")
|
||||
set(srcs "src/common/test_apm_utils.c"
|
||||
"src/common/test_intr_utils.c"
|
||||
"src/common/test_setup_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_PERI_APM_TEST)
|
||||
list(APPEND srcs "src/pms/test_tee_peri_apm.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_SUPPORT_TEE_INTR_TEST)
|
||||
list(APPEND srcs "src/cpu_intr/test_interrupt.c"
|
||||
"src/cpu_intr/test_vectors_m.S"
|
||||
"src/cpu_intr/test_vectors_u.S")
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
@@ -20,6 +27,5 @@ idf_component_register(SRCS "${srcs}"
|
||||
if(CONFIG_ULP_COPROC_ENABLED)
|
||||
set(ulp_app_name ulp_lp_core_${COMPONENT_NAME})
|
||||
set(ulp_rv_srcs "src/ulp/ulp_lp_core_main.c" "src/ulp/ulp_vectors.S")
|
||||
set(ulp_exp_dep_srcs "src/test_tee_apm_pms.c")
|
||||
ulp_embed_binary(${ulp_app_name} "${ulp_rv_srcs}" "${ulp_exp_dep_srcs}")
|
||||
endif()
|
@@ -0,0 +1,18 @@
|
||||
menu "Test-app related"
|
||||
|
||||
config SOC_SUPPORT_TEE_SYS_APM_TEST
|
||||
bool
|
||||
depends on SOC_APM_CTRL_FILTER_SUPPORTED
|
||||
default y
|
||||
|
||||
config SOC_SUPPORT_TEE_PERI_APM_TEST
|
||||
bool
|
||||
depends on SOC_APM_SUPPORT_TEE_PERI_ACCESS_CTRL
|
||||
default y
|
||||
|
||||
config SOC_SUPPORT_TEE_INTR_TEST
|
||||
bool
|
||||
depends on IDF_TARGET_ESP32C5 || IDF_TARGET_ESP32C61
|
||||
default y
|
||||
|
||||
endmenu
|
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/* Test-cases */
|
||||
void test_m_mode_intr_in_m_mode(void);
|
||||
|
||||
void test_u_mode_intr_in_u_mode(void);
|
||||
|
||||
void test_m_mode_intr_in_u_mode(void);
|
||||
|
||||
void test_u_mode_intr_in_m_mode(void);
|
@@ -1,5 +1,5 @@
|
||||
[mapping:pms]
|
||||
archive: libpms.a
|
||||
[mapping:test_pms_and_cpu_intr]
|
||||
archive: libpms_and_cpu_intr.a
|
||||
entries:
|
||||
test_intr_utils (noflash)
|
||||
test_panic_handler (noflash)
|
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define TEST_INTR_NUM_PASS_IN_SEC (31)
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
#include "soc/interrupts.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)
|
||||
#endif
|
@@ -198,3 +198,45 @@
|
||||
#define TEST_LP_PERI_ADDR7 TEST_LP_PERI_REGION7_START
|
||||
|
||||
#define TEST_LP_PERI_RESV_MASK BIT(0) | BIT(2)
|
||||
|
||||
/********* For PERI_APM *********/
|
||||
|
||||
#include "soc/reg_base.h"
|
||||
|
||||
/********* For PERI_APM *********/
|
||||
#include "soc/uart_reg.h"
|
||||
#include "soc/i2c_reg.h"
|
||||
#include "soc/i2s_reg.h"
|
||||
#include "soc/mcpwm_reg.h"
|
||||
#include "soc/twaifd_reg.h"
|
||||
#include "soc/ahb_dma_reg.h"
|
||||
#include "soc/pau_reg.h"
|
||||
#include "soc/interrupt_matrix_reg.h"
|
||||
#include "soc/apb_saradc_reg.h"
|
||||
#include "soc/timer_group_reg.h"
|
||||
#include "soc/pcnt_reg.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/hp_system_reg.h"
|
||||
#include "soc/pcr_reg.h"
|
||||
#include "soc/spi_mem_reg.h"
|
||||
#include "soc/hp_apm_reg.h"
|
||||
#include "soc/cpu_apm_reg.h"
|
||||
#include "soc/sha_reg.h"
|
||||
#include "soc/cache_reg.h"
|
||||
#include "soc/spi_reg.h"
|
||||
#include "soc/bitscrambler_reg.h"
|
||||
#include "soc/keymng_reg.h"
|
||||
#include "soc/sdio_slc_host_reg.h"
|
||||
|
||||
#include "soc/efuse_reg.h"
|
||||
#include "soc/pmu_reg.h"
|
||||
#include "soc/lp_clkrst_reg.h"
|
||||
#include "soc/lp_aon_reg.h"
|
||||
#include "soc/lp_wdt_reg.h"
|
||||
#include "soc/lpperi_reg.h"
|
||||
#include "soc/lp_analog_peri_reg.h"
|
||||
#include "soc/lp_uart_reg.h"
|
||||
#include "soc/lp_i2c_reg.h"
|
||||
#include "soc/lp_i2c_ana_mst_reg.h"
|
||||
#include "soc/huk_reg.h"
|
||||
#include "soc/lp_apm_reg.h"
|
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
#define UTVT_CSR (0x007)
|
||||
#define UINTSTATUS_CSR (0xCB1)
|
||||
#define UINTTHRESH_CSR (0x047)
|
||||
|
||||
#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,16 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define TEST_INTR_NUM_PASS_IN_SEC (31)
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
#include "soc/interrupts.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)
|
||||
#endif
|
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
#define UTVT_CSR (0x007)
|
||||
#define UINTSTATUS_CSR (0xCB1)
|
||||
#define UINTTHRESH_CSR (0x047)
|
||||
|
||||
#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,17 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/********************************** Utility *********************************/
|
||||
|
||||
void test_intr_utils_init(void);
|
||||
void test_intr_utils_deinit(void);
|
||||
|
||||
void test_intr_alloc(int mode, int priority, int intr_src, intr_handler_t func, void *arg);
|
||||
void test_intr_free_all(void);
|
@@ -96,4 +96,4 @@ void test_gdma_deinit(void);
|
||||
void test_gdma_m2m_transfer(uint8_t *src, uint8_t *dest, size_t size);
|
||||
void test_gdma_wait_done(void);
|
||||
|
||||
void test_delay_us(uint32_t us);
|
||||
void test_delay_ms(uint32_t ms);
|
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#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"
|
||||
#include "riscv/rv_utils.h"
|
||||
|
||||
#include "esp_cpu.h"
|
||||
#include "esp_rom_sys.h"
|
||||
|
||||
#if SOC_INT_PLIC_SUPPORTED
|
||||
#include "esp_private/interrupt_plic.h"
|
||||
#elif SOC_INT_CLIC_SUPPORTED
|
||||
#include "esp_private/interrupt_clic.h"
|
||||
#else
|
||||
#include "esp_private/interrupt_intc.h"
|
||||
#endif
|
||||
|
||||
#if CONFIG_SOC_SUPPORT_TEE_INTR_TEST
|
||||
#include "test_rv_utils.h"
|
||||
#include "test_cpu_intr_params.h"
|
||||
#endif
|
||||
|
||||
/********************************** Vector Table Redirection *******************************/
|
||||
|
||||
void set_test_vector_table(void)
|
||||
{
|
||||
extern int _test_vector_table;
|
||||
rv_utils_intr_global_disable();
|
||||
rv_utils_set_mtvec((uintptr_t)&_test_vector_table);
|
||||
rv_utils_intr_global_enable();
|
||||
}
|
||||
|
||||
void restore_default_vector_table(void)
|
||||
{
|
||||
extern int _vector_table;
|
||||
rv_utils_intr_global_disable();
|
||||
rv_utils_set_mtvec((uintptr_t)&_vector_table);
|
||||
rv_utils_intr_global_enable();
|
||||
}
|
||||
|
||||
/********************************** Privilege Mode Switch *********************************/
|
||||
|
||||
void test_m2u_switch(void)
|
||||
{
|
||||
int mode = esp_cpu_get_curr_privilege_level();
|
||||
assert(mode == PRV_M);
|
||||
|
||||
asm volatile("ecall\n");
|
||||
|
||||
mode = esp_cpu_get_curr_privilege_level();
|
||||
assert(mode == PRV_U);
|
||||
}
|
||||
|
||||
void test_u2m_switch(void)
|
||||
{
|
||||
int mode = esp_cpu_get_curr_privilege_level();
|
||||
assert(mode == PRV_U);
|
||||
|
||||
asm volatile("ecall\n");
|
||||
|
||||
mode = esp_cpu_get_curr_privilege_level();
|
||||
assert(mode == PRV_M);
|
||||
}
|
||||
|
||||
/********************************** 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;
|
||||
extern int _mtvt_table;
|
||||
extern int _test_mtvec_table;
|
||||
extern int _test_mtvt_table;
|
||||
extern int _test_utvec_table;
|
||||
extern int _test_utvt_table;
|
||||
|
||||
static void test_redirect_vector_table(bool redirect)
|
||||
{
|
||||
if (redirect) {
|
||||
test_rv_utils_set_xtvec((uintptr_t)&_test_mtvec_table, PRV_M);
|
||||
test_rv_utils_set_xtvt((uintptr_t)&_test_mtvt_table, PRV_M);
|
||||
test_rv_utils_set_xtvec((uintptr_t)&_test_utvec_table, PRV_U);
|
||||
test_rv_utils_set_xtvt((uintptr_t)&_test_utvt_table, PRV_U);
|
||||
#if !SOC_CPU_HAS_CSR_PC
|
||||
RV_SET_CSR(mcounteren, 0x07);
|
||||
#endif
|
||||
} else {
|
||||
test_rv_utils_set_xtvt((uintptr_t)&_mtvt_table, PRV_M);
|
||||
test_rv_utils_set_xtvec((uintptr_t)&_vector_table, PRV_M);
|
||||
}
|
||||
}
|
||||
|
||||
/***************************** Miscellaneous: Interrupts (CLIC configuration save/restore) *****************************/
|
||||
|
||||
#define INTMTX_REG(i) (DR_REG_INTMTX_BASE + ((i) * 4))
|
||||
|
||||
static uint32_t s_intr_src_map[ETS_MAX_INTR_SOURCE];
|
||||
static uint32_t s_intr_clic_ctrl_reg[SOC_CPU_INTR_NUM];
|
||||
|
||||
static bool is_intr_ctx_saved = false;
|
||||
|
||||
static void test_save_intr_ctx(void)
|
||||
{
|
||||
// Save and unroute all interrupt matrix sources
|
||||
for (int i = 0; i < ETS_MAX_INTR_SOURCE; i++) {
|
||||
uint32_t offs = INTMTX_REG(i);
|
||||
s_intr_src_map[i] = REG_READ(offs);
|
||||
REG_WRITE(offs, 0x00U);
|
||||
}
|
||||
|
||||
// Save CLIC configuration registers
|
||||
for (int i = 0; i < SOC_CPU_INTR_NUM; i++) {
|
||||
s_intr_clic_ctrl_reg[i] = REG_READ(CLIC_INT_CTRL_REG(CLIC_EXT_INTR_NUM_OFFSET + i));
|
||||
REG_WRITE(CLIC_INT_CTRL_REG(i), 0x00U);
|
||||
}
|
||||
|
||||
is_intr_ctx_saved = true;
|
||||
}
|
||||
|
||||
static void test_restore_intr_ctx(void)
|
||||
{
|
||||
if (!is_intr_ctx_saved) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Restore interrupt matrix sources
|
||||
for (int i = 0; i < ETS_MAX_INTR_SOURCE; i++) {
|
||||
REG_WRITE(INTMTX_REG(i), s_intr_src_map[i]);
|
||||
}
|
||||
|
||||
// Restore CLIC configuration registers
|
||||
for (int i = 0; i < SOC_CPU_INTR_NUM; i++) {
|
||||
REG_WRITE(CLIC_INT_CTRL_REG(CLIC_EXT_INTR_NUM_OFFSET + i), s_intr_clic_ctrl_reg[i]);
|
||||
}
|
||||
|
||||
is_intr_ctx_saved = false;
|
||||
}
|
||||
|
||||
void test_intr_utils_init(void)
|
||||
{
|
||||
test_rv_utils_intr_global_disable(PRV_M);
|
||||
test_save_intr_ctx();
|
||||
test_redirect_vector_table(true);
|
||||
test_rv_utils_intr_set_threshold(RVHAL_INTR_ENABLE_THRESH, PRV_M);
|
||||
test_rv_utils_intr_set_threshold(RVHAL_INTR_ENABLE_THRESH, PRV_U);
|
||||
test_rv_utils_intr_enable_u_mode(true);
|
||||
test_rv_utils_intr_global_enable(PRV_M);
|
||||
}
|
||||
|
||||
void test_intr_utils_deinit(void)
|
||||
{
|
||||
test_rv_utils_intr_global_disable(PRV_M);
|
||||
test_rv_utils_intr_enable_u_mode(false);
|
||||
test_redirect_vector_table(false);
|
||||
test_restore_intr_ctx();
|
||||
test_rv_utils_intr_global_enable(PRV_M);
|
||||
}
|
||||
|
||||
/***************************** Miscellaneous: Interrupts (test allocation/freeing) *****************************/
|
||||
|
||||
#define TEST_INTR_NUM_MIN (12)
|
||||
#define TEST_INTR_NUM_MAX (16)
|
||||
#define TEST_INTR_NUM_COUNT (TEST_INTR_NUM_MAX - TEST_INTR_NUM_MIN)
|
||||
#define TEST_INTR_ALLOC_MASK (((1U << TEST_INTR_NUM_COUNT) - 1) << TEST_INTR_NUM_MIN)
|
||||
#define TEST_INTR_IDX(num) ((num) - TEST_INTR_NUM_MIN)
|
||||
|
||||
typedef struct {
|
||||
int mode;
|
||||
int intr_src;
|
||||
} test_intr_entry_t;
|
||||
|
||||
static uint32_t s_intr_status = 0x00U;
|
||||
static test_intr_entry_t s_intr_table[TEST_INTR_NUM_COUNT];
|
||||
|
||||
void test_intr_alloc(int mode, int priority, int intr_src, intr_handler_t func, void *arg)
|
||||
{
|
||||
int intr_num = -1;
|
||||
|
||||
if (intr_src == ETS_MAX_INTR_SOURCE) {
|
||||
intr_num = TEST_INTR_NUM_PASS_IN_SEC;
|
||||
} else {
|
||||
intr_num = __builtin_ctz(~s_intr_status & TEST_INTR_ALLOC_MASK);
|
||||
if (intr_num < TEST_INTR_NUM_MIN || intr_num > TEST_INTR_NUM_MAX) {
|
||||
return; // No free interrupts
|
||||
}
|
||||
|
||||
intr_handler_set(intr_num, func, arg);
|
||||
esp_rom_route_intr_matrix(0, intr_src, intr_num);
|
||||
}
|
||||
|
||||
s_intr_status |= BIT(intr_num);
|
||||
s_intr_table[TEST_INTR_IDX(intr_num)] = (test_intr_entry_t){
|
||||
.mode = mode,
|
||||
.intr_src = intr_src,
|
||||
};
|
||||
|
||||
test_rv_utils_intr_set_type(intr_num, INTR_TYPE_LEVEL);
|
||||
test_rv_utils_intr_set_priority(intr_num, priority);
|
||||
test_rv_utils_intr_set_vectored(intr_num, true);
|
||||
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));
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
test_rv_utils_intr_enable(BIT(intr_num));
|
||||
}
|
||||
|
||||
void test_intr_free_all(void)
|
||||
{
|
||||
for (int intr_num = TEST_INTR_NUM_MIN; intr_num <= TEST_INTR_NUM_MAX; intr_num++) {
|
||||
if (!(s_intr_status & BIT(intr_num))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
test_intr_entry_t *entry = &s_intr_table[TEST_INTR_IDX(intr_num)];
|
||||
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));
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
test_rv_utils_intr_disable(BIT(intr_num));
|
||||
s_intr_status &= ~BIT(intr_num);
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -51,10 +51,16 @@ void test_panicHandler(RvExcFrame *frame, int exccause)
|
||||
}
|
||||
|
||||
if (mcause == MCAUSE_ILLEGAL_INSTRUCTION) {
|
||||
frame->mepc = frame->ra;
|
||||
uint32_t mscratch = RV_READ_CSR(mscratch);
|
||||
/* Check if panic is from the interrupt or PMS related test-cases */
|
||||
if (mscratch == 0xDEADC0DE) {
|
||||
frame->mepc += 0x04U;
|
||||
RV_WRITE_CSR(mscratch, 0x00U);
|
||||
} else {
|
||||
frame->mepc = frame->ra;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* PERI_APM access fault */
|
||||
#if SOC_APM_SUPPORT_TEE_PERI_ACCESS_CTRL
|
||||
if (regs->mtval >= SOC_PERIPHERAL_LOW && regs->mtval < SOC_PERIPHERAL_HIGH) {
|
@@ -38,8 +38,8 @@
|
||||
/***************************** Utility - LP_CPU *****************************/
|
||||
|
||||
#if CONFIG_ULP_COPROC_ENABLED
|
||||
extern const uint8_t ulp_lp_core_main_bin_start[] asm("_binary_ulp_lp_core_pms_bin_start");
|
||||
extern const uint8_t ulp_lp_core_main_bin_end[] asm("_binary_ulp_lp_core_pms_bin_end");
|
||||
extern const uint8_t ulp_lp_core_main_bin_start[] asm("_binary_ulp_lp_core_pms_and_cpu_intr_bin_start");
|
||||
extern const uint8_t ulp_lp_core_main_bin_end[] asm("_binary_ulp_lp_core_pms_and_cpu_intr_bin_end");
|
||||
|
||||
void test_boot_lp_cpu(void)
|
||||
{
|
||||
@@ -226,8 +226,9 @@ void test_gdma_wait_done(void)
|
||||
|
||||
/***************************** Miscellaneous *****************************/
|
||||
|
||||
IRAM_ATTR void test_delay_us(uint32_t us)
|
||||
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
|
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#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 "test_rv_utils.h"
|
||||
|
||||
#include "unity.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "test_pms_priv.h"
|
||||
#include "test_cpu_intr_priv.h"
|
||||
#include "test_cpu_intr_params.h"
|
||||
|
||||
#define TEST_INTR_MAX_COUNT (8)
|
||||
|
||||
/* ---------------------------------------------------- Utility - TIMER ---------------------------------------------------- */
|
||||
|
||||
#define TEST_TIMER_GROUP (0)
|
||||
#define TEST_TIMER_ID (0)
|
||||
#define TEST_TIMER_DIVIDER (80)
|
||||
|
||||
#define TEST_TIMER_RESOLUTION_HZ (1000000ULL) // 1MHz, 1 tick = 1us
|
||||
#define TEST_TIMER_PERIOD_S (0.01f) // 10ms @ resolution 1MHz
|
||||
#define TEST_INTPRI_PERIOD_S (0.10f) // 100ms (intpri trigger interval)
|
||||
#define TEST_TIMER_EXP_COUNT (TEST_INTR_MAX_COUNT * (TEST_INTPRI_PERIOD_S / TEST_TIMER_PERIOD_S))
|
||||
|
||||
static timg_dev_t *timg_dev = TIMER_LL_GET_HW(TEST_TIMER_GROUP);
|
||||
|
||||
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);
|
||||
|
||||
/* Clear interrupt and re-enable the alarm */
|
||||
timer_ll_clear_intr_status(timg_dev, TIMER_LL_EVENT_ALARM(TEST_TIMER_ID));
|
||||
timer_ll_enable_alarm(timg_dev, TEST_TIMER_ID, true);
|
||||
}
|
||||
|
||||
static void test_timer_deinit(void)
|
||||
{
|
||||
const uint32_t timer_id = TEST_TIMER_ID;
|
||||
|
||||
// Disable and clear timer state
|
||||
timer_ll_enable_counter(timg_dev, timer_id, false);
|
||||
timer_ll_enable_auto_reload(timg_dev, timer_id, false);
|
||||
timer_ll_enable_alarm(timg_dev, timer_id, false);
|
||||
|
||||
timer_ll_enable_intr(timg_dev, TIMER_LL_EVENT_ALARM(timer_id), false);
|
||||
timer_ll_clear_intr_status(timg_dev, TIMER_LL_EVENT_ALARM(timer_id));
|
||||
|
||||
// Reset the counter
|
||||
uint64_t prev_val = timer_ll_get_reload_value(timg_dev, timer_id);
|
||||
timer_ll_set_reload_value(timg_dev, timer_id, 0);
|
||||
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);
|
||||
}
|
||||
|
||||
static void test_timer_init(int mode, volatile uint32_t *arg)
|
||||
{
|
||||
const uint32_t group_id = TEST_TIMER_GROUP;
|
||||
const uint32_t timer_id = TEST_TIMER_ID;
|
||||
|
||||
test_timer_deinit();
|
||||
|
||||
// Enable peripheral clock and reset hardware
|
||||
_timer_ll_enable_bus_clock(group_id, true);
|
||||
_timer_ll_reset_register(group_id);
|
||||
|
||||
// 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);
|
||||
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);
|
||||
timer_ll_enable_intr(timg_dev, TIMER_LL_EVENT_ALARM(timer_id), true);
|
||||
|
||||
// Configure and enable timer alarm
|
||||
timer_ll_set_alarm_value(timg_dev, timer_id, TEST_TIMER_PERIOD_S * TEST_TIMER_RESOLUTION_HZ);
|
||||
timer_ll_enable_auto_reload(timg_dev, timer_id, true);
|
||||
timer_ll_enable_alarm(timg_dev, timer_id, true);
|
||||
timer_ll_enable_counter(timg_dev, timer_id, true);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------- 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);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR void intpri_cpu_trig_intr(uint32_t n)
|
||||
{
|
||||
WRITE_PERI_REG(CPU_INTR_FROM_CPU_N_REG(n), 1);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR uint32_t intpri_cpu_get_intr_state(uint32_t n)
|
||||
{
|
||||
return READ_PERI_REG(CPU_INTR_FROM_CPU_N_REG(n));
|
||||
}
|
||||
|
||||
IRAM_ATTR static void test_intpri_isr(void *arg)
|
||||
{
|
||||
test_intr_args_ctx_t *ctx = (test_intr_args_ctx_t *)arg;
|
||||
|
||||
/* Clear interrupt */
|
||||
intpri_cpu_clr_intr(ctx->id);
|
||||
|
||||
ctx->curr_count++;
|
||||
if (ctx->curr_count >= ctx->max_count) {
|
||||
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-cases ---------------------------------------------------- */
|
||||
|
||||
void test_m_mode_intr_in_m_mode(void)
|
||||
{
|
||||
test_apm_ctrl_reset_all();
|
||||
test_intr_utils_init();
|
||||
|
||||
test_intr_args_ctx_t ctx = {
|
||||
.id = 0,
|
||||
.curr_count = 0,
|
||||
.max_count = TEST_INTR_MAX_COUNT,
|
||||
.token = TEST_INTR_TK_INIT,
|
||||
};
|
||||
|
||||
test_intr_alloc(PRV_M, 1, CPU_FROM_CPU_N_INTR_SRC(ctx.id), &test_intpri_isr, &ctx);
|
||||
|
||||
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);
|
||||
test_delay_ms(TEST_INTPRI_PERIOD_S * 1000U);
|
||||
}
|
||||
TEST_ASSERT(ctx.curr_count == TEST_INTR_MAX_COUNT);
|
||||
|
||||
test_timer_deinit();
|
||||
TEST_ASSERT(intr_count >= TEST_TIMER_EXP_COUNT);
|
||||
|
||||
test_intr_free_all();
|
||||
test_intr_utils_deinit();
|
||||
}
|
||||
|
||||
void test_u_mode_intr_in_u_mode(void)
|
||||
{
|
||||
test_apm_ctrl_reset_all();
|
||||
test_intr_utils_init();
|
||||
|
||||
test_intr_args_ctx_t ctx = {
|
||||
.id = 0,
|
||||
.curr_count = 0,
|
||||
.max_count = TEST_INTR_MAX_COUNT,
|
||||
.token = TEST_INTR_TK_INIT,
|
||||
};
|
||||
|
||||
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_m2u_switch();
|
||||
while (ctx.token != TEST_INTR_TK_DONE) {
|
||||
intpri_cpu_trig_intr(ctx.id);
|
||||
test_delay_ms(TEST_INTPRI_PERIOD_S * 1000U);
|
||||
}
|
||||
test_u2m_switch();
|
||||
TEST_ASSERT(ctx.curr_count == TEST_INTR_MAX_COUNT);
|
||||
|
||||
test_timer_deinit();
|
||||
TEST_ASSERT(intr_count >= TEST_TIMER_EXP_COUNT);
|
||||
|
||||
test_intr_free_all();
|
||||
test_intr_utils_deinit();
|
||||
}
|
||||
|
||||
void test_m_mode_intr_in_u_mode(void)
|
||||
{
|
||||
test_apm_ctrl_reset_all();
|
||||
test_intr_utils_init();
|
||||
|
||||
test_intr_args_ctx_t ctx = {
|
||||
.id = 0,
|
||||
.curr_count = 0,
|
||||
.max_count = TEST_INTR_MAX_COUNT,
|
||||
.token = TEST_INTR_TK_INIT,
|
||||
};
|
||||
|
||||
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_m2u_switch();
|
||||
while (ctx.token != TEST_INTR_TK_DONE) {
|
||||
intpri_cpu_trig_intr(ctx.id);
|
||||
test_delay_ms(TEST_INTPRI_PERIOD_S * 1000U);
|
||||
}
|
||||
test_u2m_switch();
|
||||
TEST_ASSERT(ctx.curr_count == TEST_INTR_MAX_COUNT);
|
||||
|
||||
test_timer_deinit();
|
||||
TEST_ASSERT(intr_count >= TEST_TIMER_EXP_COUNT);
|
||||
|
||||
test_intr_free_all();
|
||||
test_intr_utils_deinit();
|
||||
}
|
||||
|
||||
void test_u_mode_intr_in_m_mode(void)
|
||||
{
|
||||
test_apm_ctrl_reset_all();
|
||||
test_intr_utils_init();
|
||||
|
||||
test_intr_alloc(PRV_M, 1, ETS_MAX_INTR_SOURCE, NULL, NULL);
|
||||
|
||||
test_intr_args_ctx_t ctx = {
|
||||
.id = 0,
|
||||
.curr_count = 0,
|
||||
.max_count = TEST_INTR_MAX_COUNT,
|
||||
.token = TEST_INTR_TK_INIT,
|
||||
};
|
||||
|
||||
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_M, &intr_count);
|
||||
|
||||
while (ctx.token != TEST_INTR_TK_DONE) {
|
||||
intpri_cpu_trig_intr(ctx.id);
|
||||
test_delay_ms(TEST_INTPRI_PERIOD_S * 1000U);
|
||||
}
|
||||
TEST_ASSERT(ctx.curr_count == TEST_INTR_MAX_COUNT);
|
||||
|
||||
test_timer_deinit();
|
||||
TEST_ASSERT(intr_count >= TEST_TIMER_EXP_COUNT);
|
||||
|
||||
test_intr_free_all();
|
||||
test_intr_utils_deinit();
|
||||
}
|
@@ -0,0 +1,467 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#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/panic_reason.h"
|
||||
#include "esp_private/vectors_const.h"
|
||||
|
||||
#include "test_cpu_intr_params.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
.equ SAVE_REGS, 32
|
||||
.equ CONTEXT_SIZE, (SAVE_REGS * 4)
|
||||
.equ ECALL_U_MODE, 0x8
|
||||
.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 panic_from_excp, test_panicHandler
|
||||
|
||||
.global _test_uintr_handler
|
||||
|
||||
.section .data
|
||||
|
||||
.align 4
|
||||
.global _m_sp
|
||||
_m_sp:
|
||||
.word 0
|
||||
|
||||
/* Macro which first allocates space on the stack to save general
|
||||
* purpose registers, and then save them. GP register is excluded.
|
||||
* The default size allocated on the stack is CONTEXT_SIZE, but it
|
||||
* can be overridden. */
|
||||
.macro save_general_regs cxt_size=CONTEXT_SIZE
|
||||
addi sp, sp, -\cxt_size
|
||||
sw ra, RV_STK_RA(sp)
|
||||
sw tp, RV_STK_TP(sp)
|
||||
sw t0, RV_STK_T0(sp)
|
||||
sw t1, RV_STK_T1(sp)
|
||||
sw t2, RV_STK_T2(sp)
|
||||
sw s0, RV_STK_S0(sp)
|
||||
sw s1, RV_STK_S1(sp)
|
||||
sw a0, RV_STK_A0(sp)
|
||||
sw a1, RV_STK_A1(sp)
|
||||
sw a2, RV_STK_A2(sp)
|
||||
sw a3, RV_STK_A3(sp)
|
||||
sw a4, RV_STK_A4(sp)
|
||||
sw a5, RV_STK_A5(sp)
|
||||
sw a6, RV_STK_A6(sp)
|
||||
sw a7, RV_STK_A7(sp)
|
||||
sw s2, RV_STK_S2(sp)
|
||||
sw s3, RV_STK_S3(sp)
|
||||
sw s4, RV_STK_S4(sp)
|
||||
sw s5, RV_STK_S5(sp)
|
||||
sw s6, RV_STK_S6(sp)
|
||||
sw s7, RV_STK_S7(sp)
|
||||
sw s8, RV_STK_S8(sp)
|
||||
sw s9, RV_STK_S9(sp)
|
||||
sw s10, RV_STK_S10(sp)
|
||||
sw s11, RV_STK_S11(sp)
|
||||
sw t3, RV_STK_T3(sp)
|
||||
sw t4, RV_STK_T4(sp)
|
||||
sw t5, RV_STK_T5(sp)
|
||||
sw t6, RV_STK_T6(sp)
|
||||
.endm
|
||||
|
||||
.macro save_mepc
|
||||
csrr t0, mepc
|
||||
sw t0, RV_STK_MEPC(sp)
|
||||
.endm
|
||||
|
||||
.macro save_mcsr
|
||||
csrr t0, mstatus
|
||||
sw t0, RV_STK_MSTATUS(sp)
|
||||
csrr t0, mtvec
|
||||
sw t0, RV_STK_MTVEC(sp)
|
||||
csrr t0, mcause
|
||||
sw t0, RV_STK_MCAUSE(sp)
|
||||
csrr t0, mtval
|
||||
sw t0, RV_STK_MTVAL(sp)
|
||||
csrr t0, mhartid
|
||||
sw t0, RV_STK_MHARTID(sp)
|
||||
.endm
|
||||
|
||||
/* Restore the general purpose registers (excluding gp) from the context on
|
||||
* the stack. The context is then deallocated. The default size is CONTEXT_SIZE
|
||||
* but it can be overridden. */
|
||||
.macro restore_general_regs cxt_size=CONTEXT_SIZE
|
||||
lw ra, RV_STK_RA(sp)
|
||||
lw tp, RV_STK_TP(sp)
|
||||
lw t0, RV_STK_T0(sp)
|
||||
lw t1, RV_STK_T1(sp)
|
||||
lw t2, RV_STK_T2(sp)
|
||||
lw s0, RV_STK_S0(sp)
|
||||
lw s1, RV_STK_S1(sp)
|
||||
lw a0, RV_STK_A0(sp)
|
||||
lw a1, RV_STK_A1(sp)
|
||||
lw a2, RV_STK_A2(sp)
|
||||
lw a3, RV_STK_A3(sp)
|
||||
lw a4, RV_STK_A4(sp)
|
||||
lw a5, RV_STK_A5(sp)
|
||||
lw a6, RV_STK_A6(sp)
|
||||
lw a7, RV_STK_A7(sp)
|
||||
lw s2, RV_STK_S2(sp)
|
||||
lw s3, RV_STK_S3(sp)
|
||||
lw s4, RV_STK_S4(sp)
|
||||
lw s5, RV_STK_S5(sp)
|
||||
lw s6, RV_STK_S6(sp)
|
||||
lw s7, RV_STK_S7(sp)
|
||||
lw s8, RV_STK_S8(sp)
|
||||
lw s9, RV_STK_S9(sp)
|
||||
lw s10, RV_STK_S10(sp)
|
||||
lw s11, RV_STK_S11(sp)
|
||||
lw t3, RV_STK_T3(sp)
|
||||
lw t4, RV_STK_T4(sp)
|
||||
lw t5, RV_STK_T5(sp)
|
||||
lw t6, RV_STK_T6(sp)
|
||||
addi sp,sp, \cxt_size
|
||||
.endm
|
||||
|
||||
.macro restore_mepc
|
||||
lw t0, RV_STK_MEPC(sp)
|
||||
csrw mepc, t0
|
||||
.endm
|
||||
|
||||
.macro restore_mcsr
|
||||
lw t0, RV_STK_MSTATUS(sp)
|
||||
csrw mstatus, t0
|
||||
lw t0, RV_STK_MTVEC(sp)
|
||||
csrw mtvec, t0
|
||||
lw t0, RV_STK_MCAUSE(sp)
|
||||
csrw mcause, t0
|
||||
lw t0, RV_STK_MTVAL(sp)
|
||||
csrw mtval, t0
|
||||
lw t0, RV_STK_MHARTID(sp)
|
||||
csrw mhartid, t0
|
||||
.endm
|
||||
|
||||
.macro store_magic_general_regs
|
||||
lui ra, INTR_M2U_MAGIC
|
||||
lui tp, INTR_M2U_MAGIC
|
||||
lui t0, INTR_M2U_MAGIC
|
||||
lui t1, INTR_M2U_MAGIC
|
||||
lui t2, INTR_M2U_MAGIC
|
||||
lui s0, INTR_M2U_MAGIC
|
||||
lui s1, INTR_M2U_MAGIC
|
||||
lui a0, INTR_M2U_MAGIC
|
||||
lui a1, INTR_M2U_MAGIC
|
||||
lui a2, INTR_M2U_MAGIC
|
||||
lui a3, INTR_M2U_MAGIC
|
||||
lui a4, INTR_M2U_MAGIC
|
||||
lui a5, INTR_M2U_MAGIC
|
||||
lui a6, INTR_M2U_MAGIC
|
||||
lui a7, INTR_M2U_MAGIC
|
||||
lui s2, INTR_M2U_MAGIC
|
||||
lui s3, INTR_M2U_MAGIC
|
||||
lui s4, INTR_M2U_MAGIC
|
||||
lui s5, INTR_M2U_MAGIC
|
||||
lui s6, INTR_M2U_MAGIC
|
||||
lui s7, INTR_M2U_MAGIC
|
||||
lui s8, INTR_M2U_MAGIC
|
||||
lui s9, INTR_M2U_MAGIC
|
||||
lui s10, INTR_M2U_MAGIC
|
||||
lui s11, INTR_M2U_MAGIC
|
||||
lui t3, INTR_M2U_MAGIC
|
||||
lui t4, INTR_M2U_MAGIC
|
||||
lui t5, INTR_M2U_MAGIC
|
||||
lui t6, INTR_M2U_MAGIC
|
||||
.endm
|
||||
|
||||
.section .iram1, "ax"
|
||||
|
||||
/* Prevent the compiler from generating 2-byte instruction in the vector tables */
|
||||
.option push
|
||||
.option norvc
|
||||
|
||||
/**
|
||||
* Vectored interrupt table. MTVT CSR points here.
|
||||
*
|
||||
* If an interrupt occurs and is configured as (hardware) vectored, the CPU will jump to
|
||||
* MTVT[31:0] + 4 * interrupt_id
|
||||
*
|
||||
*/
|
||||
.balign 0x40
|
||||
.global _test_mtvt_table
|
||||
.type _test_mtvt_table, @function
|
||||
_test_mtvt_table:
|
||||
/* First 16 (CLIC_EXT_INTR_NUM_OFFSET) entries are system interrupts */
|
||||
.rept CLIC_EXT_INTR_NUM_OFFSET
|
||||
.word _test_panic_handler
|
||||
.endr
|
||||
/* Next 31 entries are free interrupts (indices 16 to 46) */
|
||||
.rept 31
|
||||
.word _test_mintr_handler
|
||||
.endr
|
||||
/* Entry 47 is special - used for U-mode interrupt delegation */
|
||||
.word _test_uintr_deleg
|
||||
.size _test_mtvt_table, .-_test_mtvt_table
|
||||
|
||||
/*
|
||||
* Non-hardware vectored interrupt entry. MTVEC CSR points here.
|
||||
*
|
||||
* On targets that use CLIC as their interrupt controller, when an exception occurs, the CPU
|
||||
* jumps to the address stored in MTVEC[31:6] << 6. The CPU will also jump to this location
|
||||
* if an interrupt is configured as non-vectored (CLIC_INT_ATTR.shv = 0).
|
||||
*
|
||||
*/
|
||||
.balign 0x40
|
||||
.global _test_mtvec_table
|
||||
.type _test_mtvec_table, @function
|
||||
_test_mtvec_table:
|
||||
/* Backup t0, t1 on the stack before using it */
|
||||
addi sp, sp, -16
|
||||
sw t0, 0(sp)
|
||||
sw t1, 4(sp)
|
||||
|
||||
/* Check whether the exception is an M-mode ecall */
|
||||
csrr t0, mcause
|
||||
li t1, VECTORS_MCAUSE_REASON_MASK
|
||||
and t0, t0, t1
|
||||
li t1, ECALL_M_MODE
|
||||
beq t0, t1, _test_machine_ecall
|
||||
|
||||
/* Check whether the exception is an U-mode ecall */
|
||||
li t1, ECALL_U_MODE
|
||||
beq t0, t1, _test_user_ecall
|
||||
|
||||
/* Restore t0, t1 from the stack */
|
||||
lw t1, 4(sp)
|
||||
lw t0, 0(sp)
|
||||
addi sp, sp, 16
|
||||
|
||||
/* Not an exception raised by the ecall instruction */
|
||||
_test_panic_handler:
|
||||
/* Save the register and CSR context */
|
||||
save_general_regs RV_STK_FRMSZ
|
||||
sw gp, RV_STK_GP(sp)
|
||||
addi t0, sp, RV_STK_FRMSZ
|
||||
sw t0, RV_STK_SP(sp)
|
||||
save_mepc
|
||||
save_mcsr
|
||||
|
||||
/* Executing the panic handler */
|
||||
li t0, 0xDEADC0DE
|
||||
csrr t0, mscratch
|
||||
mv a0, sp
|
||||
csrr a1, mcause
|
||||
li t0, VECTORS_MCAUSE_REASON_MASK
|
||||
and a1, a1, t0
|
||||
jal panic_from_excp
|
||||
|
||||
/* We arrive here if the exception handler has returned. */
|
||||
restore_mepc
|
||||
restore_general_regs RV_STK_FRMSZ
|
||||
mret
|
||||
|
||||
.size _test_mtvec_table, .-_test_mtvec_table
|
||||
|
||||
/* ECALL handler. */
|
||||
.type _test_ecall_handler, @function
|
||||
_test_ecall_handler:
|
||||
/* M-mode ecall handler */
|
||||
/* Currently in M-mode and switch to U-mode */
|
||||
_test_machine_ecall:
|
||||
csrr t0, mepc
|
||||
addi t0, t0, 4
|
||||
csrw mepc, t0
|
||||
li t1, MSTATUS_MPP
|
||||
csrc mstatus, t1
|
||||
|
||||
/* Restore t0, t1 from the stack */
|
||||
lw t1, 4(sp)
|
||||
lw t0, 0(sp)
|
||||
addi sp, sp, 16
|
||||
mret
|
||||
|
||||
/* U-mode ecall handler */
|
||||
/* Currently in U-mode and switch to M-mode */
|
||||
_test_user_ecall:
|
||||
/* Check whether we are returning after servicing an U-mode interrupt */
|
||||
lui t0, INTR_U2M_RTNVAL
|
||||
csrrw t1, mscratch, zero
|
||||
beq t0, t1, _rtn_from_u_intr
|
||||
|
||||
csrr t0, mepc
|
||||
addi t0, t0, 4
|
||||
csrw mepc, t0
|
||||
li t1, MSTATUS_MPP
|
||||
csrs mstatus, t1
|
||||
|
||||
/* Restore t0, t1 from the stack */
|
||||
lw t1, 4(sp)
|
||||
lw t0, 0(sp)
|
||||
addi sp, sp, 16
|
||||
mret
|
||||
|
||||
/* This point is reached after servicing a U-mode interrupt occurred in M-mode */
|
||||
_rtn_from_u_intr:
|
||||
/* Disable the U-mode delegation of all interrupts */
|
||||
li t0, INTMTX_SIG_IDX_ASSERT_IN_SEC_REG
|
||||
li t1, TEST_INTR_NUM_PASS_IN_SEC + CLIC_EXT_INTR_NUM_OFFSET
|
||||
sw t1, 0(t0)
|
||||
fence
|
||||
/* Verify the interrupt remap */
|
||||
_1:
|
||||
lw t2, 0(t0)
|
||||
bne t2, t1, _1
|
||||
|
||||
/* Restore the secure stack pointer */
|
||||
la t0, _m_sp
|
||||
lw sp, 0(t0)
|
||||
|
||||
/* Set the privilege mode to transition to after mret to M-mode */
|
||||
li t0, MSTATUS_MPP
|
||||
csrs mstatus, t0
|
||||
|
||||
/* Restore register context and resume the secure service */
|
||||
restore_mepc
|
||||
restore_general_regs
|
||||
|
||||
mret
|
||||
|
||||
.size _test_ecall_handler, .-_test_ecall_handler
|
||||
|
||||
/* Interrupt handler */
|
||||
.type _test_mintr_handler, @function
|
||||
_test_mintr_handler:
|
||||
/* Start by saving the general purpose registers and the PC value before
|
||||
* the interrupt happened. */
|
||||
save_general_regs
|
||||
save_mepc
|
||||
|
||||
/* Save GP and SP here. */
|
||||
sw gp, RV_STK_GP(sp)
|
||||
addi a0, sp, CONTEXT_SIZE
|
||||
sw a0, RV_STK_SP(sp)
|
||||
|
||||
/* Save mcause */
|
||||
csrr s1, mcause
|
||||
csrr s2, mstatus
|
||||
|
||||
/* Enable nested interrupts */
|
||||
csrsi mstatus, MSTATUS_MIE
|
||||
|
||||
/* call the C dispatcher */
|
||||
mv a0, sp /* argument 1, stack pointer */
|
||||
mv a1, s1 /* argument 2, interrupt number (mcause) */
|
||||
/* mask off the interrupt flag of mcause */
|
||||
li t0, VECTORS_MCAUSE_REASON_MASK
|
||||
and a1, a1, t0
|
||||
jal _test_global_interrupt_handler
|
||||
|
||||
/* Disable nested interrupts */
|
||||
csrci mstatus, MSTATUS_MIE
|
||||
|
||||
/* Restore the rest of the registers. */
|
||||
csrw mcause, s1
|
||||
csrw mstatus, s2
|
||||
|
||||
restore_mepc
|
||||
restore_general_regs
|
||||
/* exit, this will also re-enable the interrupts */
|
||||
mret
|
||||
|
||||
.size _test_mintr_handler, .-_test_mintr_handler
|
||||
|
||||
/* U-mode to M-mode switch */
|
||||
.balign 4
|
||||
.global _test_u2m_switch
|
||||
.type _test_u2m_switch, @function
|
||||
_test_u2m_switch:
|
||||
ecall
|
||||
fence
|
||||
ret
|
||||
|
||||
.size _test_u2m_switch, .-_test_u2m_switch
|
||||
|
||||
/* U-mode interrupt delegation */
|
||||
.global _test_uintr_deleg
|
||||
.type _test_uintr_deleg, @function
|
||||
_test_uintr_deleg:
|
||||
/* Start by saving the general purpose registers and the PC value before
|
||||
* the interrupt happened. */
|
||||
save_general_regs
|
||||
save_mepc
|
||||
|
||||
/* Save GP and SP here. */
|
||||
sw gp, RV_STK_GP(sp)
|
||||
addi a0, sp, CONTEXT_SIZE
|
||||
sw a0, RV_STK_SP(sp)
|
||||
|
||||
/* Pass the interrupt ID to be serviced to U-mode */
|
||||
li t2, INTMTX_SEC_STATUS_REG
|
||||
lw t0, 0(t2)
|
||||
li t1, 0
|
||||
|
||||
_find_intr_loop:
|
||||
and t2, t0, 1
|
||||
bnez t2, _found_intr
|
||||
srai t0, t0, 1
|
||||
addi t1, t1, 1
|
||||
bnez t0, _find_intr_loop
|
||||
|
||||
/* should not reach here */
|
||||
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
|
||||
|
||||
/* Enable the U-mode interrupt delegation */
|
||||
li t0, INTMTX_SIG_IDX_ASSERT_IN_SEC_REG
|
||||
li t1, 0x00
|
||||
sw t1, 0(t0)
|
||||
fence
|
||||
/* Verify the interrupt remap */
|
||||
_2:
|
||||
lw t2, 0(t0)
|
||||
bne t2, t1, _2
|
||||
|
||||
/* For U-mode interrupts, we use mret to switch to U-mode after executing the below steps - */
|
||||
/* Disable the U-mode global interrupts */
|
||||
csrci ustatus, USTATUS_UIE
|
||||
|
||||
/* Configure `uepc` with the U-mode ecall handler (see _test_u2m_switch) so that we can
|
||||
* return to M-mode after handling the interrupt */
|
||||
la t0, _test_u2m_switch
|
||||
csrw uepc, t0
|
||||
|
||||
/* Set the program counter to the U-mode global interrupt handler (see _test_uintr_handler) */
|
||||
la t0, _test_uintr_handler
|
||||
csrw mepc, t0
|
||||
|
||||
/* Set the privilege mode to transition to after mret to U-mode */
|
||||
li t1, MSTATUS_MPP
|
||||
csrc mstatus, t1
|
||||
|
||||
/* Save the current secure stack pointer */
|
||||
la t0, _m_sp
|
||||
sw sp, 0(t0)
|
||||
|
||||
/* Set a flag to identify the next U2M switch would be after handling a U-mode interrupt */
|
||||
lui t0, INTR_U2M_RTNVAL
|
||||
csrw mscratch, t0
|
||||
|
||||
/* Place magic bytes in all the general registers */
|
||||
store_magic_general_regs
|
||||
|
||||
mret
|
||||
|
||||
.size _test_uintr_deleg, .-_test_uintr_deleg
|
||||
|
||||
.option pop
|
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 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 "riscv/encoding.h"
|
||||
#include "riscv/rvruntime-frames.h"
|
||||
#include "esp_private/panic_reason.h"
|
||||
#include "esp_private/vectors_const.h"
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
.equ SAVE_REGS, 32
|
||||
.equ CONTEXT_SIZE, (SAVE_REGS * 4)
|
||||
.equ UINTTHRESH_CSR, 0x047
|
||||
.equ RV_INTR_NUM, (CLIC_EXT_INTR_NUM_OFFSET + SOC_CPU_INTR_NUM)
|
||||
|
||||
/* Macro which first allocates space on the stack to save general
|
||||
* purpose registers, and then save them. GP register is excluded.
|
||||
* The default size allocated on the stack is CONTEXT_SIZE, but it
|
||||
* can be overridden. */
|
||||
.macro save_general_regs cxt_size=CONTEXT_SIZE
|
||||
addi sp, sp, -\cxt_size
|
||||
sw ra, RV_STK_RA(sp)
|
||||
sw tp, RV_STK_TP(sp)
|
||||
sw t0, RV_STK_T0(sp)
|
||||
sw t1, RV_STK_T1(sp)
|
||||
sw t2, RV_STK_T2(sp)
|
||||
sw s0, RV_STK_S0(sp)
|
||||
sw s1, RV_STK_S1(sp)
|
||||
sw a0, RV_STK_A0(sp)
|
||||
sw a1, RV_STK_A1(sp)
|
||||
sw a2, RV_STK_A2(sp)
|
||||
sw a3, RV_STK_A3(sp)
|
||||
sw a4, RV_STK_A4(sp)
|
||||
sw a5, RV_STK_A5(sp)
|
||||
sw a6, RV_STK_A6(sp)
|
||||
sw a7, RV_STK_A7(sp)
|
||||
sw s2, RV_STK_S2(sp)
|
||||
sw s3, RV_STK_S3(sp)
|
||||
sw s4, RV_STK_S4(sp)
|
||||
sw s5, RV_STK_S5(sp)
|
||||
sw s6, RV_STK_S6(sp)
|
||||
sw s7, RV_STK_S7(sp)
|
||||
sw s8, RV_STK_S8(sp)
|
||||
sw s9, RV_STK_S9(sp)
|
||||
sw s10, RV_STK_S10(sp)
|
||||
sw s11, RV_STK_S11(sp)
|
||||
sw t3, RV_STK_T3(sp)
|
||||
sw t4, RV_STK_T4(sp)
|
||||
sw t5, RV_STK_T5(sp)
|
||||
sw t6, RV_STK_T6(sp)
|
||||
.endm
|
||||
|
||||
.macro save_uepc
|
||||
csrr t0, uepc
|
||||
sw t0, RV_STK_MEPC(sp)
|
||||
.endm
|
||||
|
||||
.macro save_ucsr
|
||||
csrr t0, ustatus
|
||||
sw t0, RV_STK_MSTATUS(sp)
|
||||
csrr t0, utvec
|
||||
sw t0, RV_STK_MTVEC(sp)
|
||||
csrr t0, ucause
|
||||
sw t0, RV_STK_MCAUSE(sp)
|
||||
.endm
|
||||
|
||||
/* Restore the general purpose registers (excluding gp) from the context on
|
||||
* the stack. The context is then deallocated. The default size is CONTEXT_SIZE
|
||||
* but it can be overridden. */
|
||||
.macro restore_general_regs cxt_size=CONTEXT_SIZE
|
||||
lw ra, RV_STK_RA(sp)
|
||||
lw tp, RV_STK_TP(sp)
|
||||
lw t0, RV_STK_T0(sp)
|
||||
lw t1, RV_STK_T1(sp)
|
||||
lw t2, RV_STK_T2(sp)
|
||||
lw s0, RV_STK_S0(sp)
|
||||
lw s1, RV_STK_S1(sp)
|
||||
lw a0, RV_STK_A0(sp)
|
||||
lw a1, RV_STK_A1(sp)
|
||||
lw a2, RV_STK_A2(sp)
|
||||
lw a3, RV_STK_A3(sp)
|
||||
lw a4, RV_STK_A4(sp)
|
||||
lw a5, RV_STK_A5(sp)
|
||||
lw a6, RV_STK_A6(sp)
|
||||
lw a7, RV_STK_A7(sp)
|
||||
lw s2, RV_STK_S2(sp)
|
||||
lw s3, RV_STK_S3(sp)
|
||||
lw s4, RV_STK_S4(sp)
|
||||
lw s5, RV_STK_S5(sp)
|
||||
lw s6, RV_STK_S6(sp)
|
||||
lw s7, RV_STK_S7(sp)
|
||||
lw s8, RV_STK_S8(sp)
|
||||
lw s9, RV_STK_S9(sp)
|
||||
lw s10, RV_STK_S10(sp)
|
||||
lw s11, RV_STK_S11(sp)
|
||||
lw t3, RV_STK_T3(sp)
|
||||
lw t4, RV_STK_T4(sp)
|
||||
lw t5, RV_STK_T5(sp)
|
||||
lw t6, RV_STK_T6(sp)
|
||||
addi sp,sp, \cxt_size
|
||||
.endm
|
||||
|
||||
.macro restore_uepc
|
||||
lw t0, RV_STK_MEPC(sp)
|
||||
csrw uepc, t0
|
||||
.endm
|
||||
|
||||
.macro restore_ucsr
|
||||
lw t0, RV_STK_MSTATUS(sp)
|
||||
csrw ustatus, t0
|
||||
lw t0, RV_STK_MTVEC(sp)
|
||||
csrw utvec, t0
|
||||
lw t0, RV_STK_MCAUSE(sp)
|
||||
csrw ucause, t0
|
||||
.endm
|
||||
|
||||
.section .iram1, "ax"
|
||||
|
||||
/* Prevent the compiler from generating 2-byte instruction in the vector tables */
|
||||
.option push
|
||||
.option norvc
|
||||
|
||||
/**
|
||||
* Vectored interrupt table. MTVT CSR points here.
|
||||
*
|
||||
* If an interrupt occurs and is configured as (hardware) vectored, the CPU will jump to
|
||||
* MTVT[31:0] + 4 * interrupt_id
|
||||
*
|
||||
*/
|
||||
.balign 0x40
|
||||
.global _test_utvt_table
|
||||
.type _test_utvt_table, @function
|
||||
_test_utvt_table:
|
||||
.rept RV_INTR_NUM
|
||||
.word _test_uintr_handler
|
||||
.endr
|
||||
.size _test_utvt_table, .-_test_utvt_table
|
||||
|
||||
/*
|
||||
* Non-hardware vectored interrupt entry. MTVEC CSR points here.
|
||||
*
|
||||
* On targets that use CLIC as their interrupt controller, when an exception occurs, the CPU
|
||||
* jumps to the address stored in MTVEC[31:6] << 6. The CPU will also jump to this location
|
||||
* if an interrupt is configured as non-vectored (CLIC_INT_ATTR.shv = 0).
|
||||
*
|
||||
*/
|
||||
.balign 0x40
|
||||
.global _test_utvec_table
|
||||
.type _test_utvec_table, @function
|
||||
_test_utvec_table:
|
||||
/* Do nothing */
|
||||
mret
|
||||
|
||||
.size _test_utvec_table, .-_test_utvec_table
|
||||
|
||||
/* Interrupt handler */
|
||||
.global _test_uintr_handler
|
||||
.type _test_uintr_handler, @function
|
||||
_test_uintr_handler:
|
||||
/* Start by saving the general purpose registers and the PC value before
|
||||
* the interrupt happened. */
|
||||
save_general_regs
|
||||
save_uepc
|
||||
|
||||
/* Save GP and SP here. */
|
||||
sw gp, RV_STK_GP(sp)
|
||||
addi a0, sp, CONTEXT_SIZE
|
||||
sw a0, RV_STK_SP(sp)
|
||||
|
||||
/* Save ucause */
|
||||
csrr s1, ucause
|
||||
csrr s2, ustatus
|
||||
|
||||
/* Enable nested interrupts */
|
||||
csrsi ustatus, USTATUS_UIE
|
||||
|
||||
/* call the C dispatcher */
|
||||
mv a0, sp /* argument 1, stack pointer */
|
||||
mv a1, s1 /* argument 2, interrupt number (mcause) */
|
||||
/* mask off the interrupt flag of mcause */
|
||||
li t0, VECTORS_MCAUSE_REASON_MASK
|
||||
and a1, a1, t0
|
||||
jal _test_global_interrupt_handler
|
||||
|
||||
/* Disable nested interrupts */
|
||||
csrci ustatus, USTATUS_UIE
|
||||
|
||||
/* Restore the rest of the registers. */
|
||||
csrw ucause, s1
|
||||
csrw ustatus, s2
|
||||
|
||||
restore_uepc
|
||||
restore_general_regs
|
||||
|
||||
/* exit, this will also re-enable the interrupts */
|
||||
uret
|
||||
|
||||
.size _test_uintr_handler, .-_test_uintr_handler
|
||||
|
||||
.option pop
|
@@ -20,7 +20,6 @@
|
||||
|
||||
#include "test_pms_priv.h"
|
||||
#include "test_pms_params.h"
|
||||
#include "test_peri_apm_reg.h"
|
||||
|
||||
#include "unity.h"
|
||||
|
||||
@@ -114,7 +113,7 @@ IRAM_ATTR static void hp_cpu_peri_addr_rw(uint32_t peri_addr, uint32_t attr)
|
||||
RV_WRITE_CSR(uscratch, 0x00);
|
||||
|
||||
reg_write(peri_addr, TEST_VAL);
|
||||
test_delay_us(10000);
|
||||
test_delay_ms(10);
|
||||
|
||||
bool can_write = (attr & APM_PERM_W);
|
||||
if (!can_write) {
|
||||
@@ -125,7 +124,7 @@ IRAM_ATTR static void hp_cpu_peri_addr_rw(uint32_t peri_addr, uint32_t attr)
|
||||
|
||||
volatile uint32_t val = reg_read(peri_addr);
|
||||
(void)val;
|
||||
test_delay_us(10000);
|
||||
test_delay_ms(10);
|
||||
|
||||
bool can_read = (attr & APM_PERM_R);
|
||||
if (!can_read) {
|
||||
@@ -142,7 +141,7 @@ IRAM_ATTR static void lp_cpu_peri_addr_rw(uint32_t peri_addr, uint32_t attr)
|
||||
SEND_EXCP(0);
|
||||
SEND_MSG(MSG_SLAVE_WRITE);
|
||||
SEND_ADDR(peri_addr);
|
||||
test_delay_us(10000);
|
||||
test_delay_ms(10);
|
||||
|
||||
bool can_write = (attr & APM_PERM_W);
|
||||
if (!can_write) {
|
||||
@@ -154,7 +153,7 @@ IRAM_ATTR static void lp_cpu_peri_addr_rw(uint32_t peri_addr, uint32_t attr)
|
||||
SEND_EXCP(0);
|
||||
SEND_MSG(MSG_SLAVE_READ);
|
||||
SEND_ADDR(peri_addr);
|
||||
test_delay_us(10000);
|
||||
test_delay_ms(10);
|
||||
|
||||
bool can_read = (attr & APM_PERM_R);
|
||||
if (!can_read) {
|
@@ -84,12 +84,12 @@ static void gdma_xmem_addr_rw(uint8_t *src, uint8_t *dest, size_t size, uint32_t
|
||||
#endif
|
||||
|
||||
if (!test_attr) {
|
||||
test_delay_us(10000);
|
||||
test_delay_ms(10);
|
||||
TEST_ASSERT(apm_master_excp_flag[TEST_GDMA_APM_MASTER_ID]);
|
||||
test_gdma_wait_done();
|
||||
} else {
|
||||
test_gdma_wait_done();
|
||||
test_delay_us(10000);
|
||||
test_delay_ms(10);
|
||||
TEST_ASSERT_FALSE(apm_master_excp_flag[TEST_GDMA_APM_MASTER_ID]);
|
||||
TEST_ASSERT_EQUAL_HEX8_ARRAY(src, dest, size);
|
||||
}
|
||||
@@ -202,7 +202,7 @@ static void hp_cpu_peri_addr_rw(uint32_t peri_addr, uint32_t attr)
|
||||
apm_master_excp_flag[APM_MASTER_HPCORE] = false;
|
||||
|
||||
REG_WRITE(peri_addr, TEST_VAL);
|
||||
test_delay_us(10000);
|
||||
test_delay_ms(10);
|
||||
|
||||
bool can_write = (attr & APM_PERM_W);
|
||||
TEST_ASSERT(apm_master_excp_flag[APM_MASTER_HPCORE] != can_write);
|
||||
@@ -211,7 +211,7 @@ static void hp_cpu_peri_addr_rw(uint32_t peri_addr, uint32_t attr)
|
||||
|
||||
volatile uint32_t val = REG_READ(peri_addr);
|
||||
(void)val;
|
||||
test_delay_us(10000);
|
||||
test_delay_ms(10);
|
||||
|
||||
bool can_read = (attr & APM_PERM_R);
|
||||
TEST_ASSERT(apm_master_excp_flag[APM_MASTER_HPCORE] != can_read);
|
||||
@@ -227,7 +227,7 @@ static void lp_cpu_peri_addr_rw(uint32_t peri_addr, uint32_t attr)
|
||||
|
||||
SEND_MSG(MSG_SLAVE_WRITE);
|
||||
SEND_ADDR(peri_addr);
|
||||
test_delay_us(10000);
|
||||
test_delay_ms(10);
|
||||
|
||||
bool can_write = (attr & APM_PERM_W);
|
||||
TEST_ASSERT(apm_master_excp_flag[APM_MASTER_LPCORE] != can_write);
|
||||
@@ -236,7 +236,7 @@ static void lp_cpu_peri_addr_rw(uint32_t peri_addr, uint32_t attr)
|
||||
|
||||
SEND_MSG(MSG_SLAVE_READ);
|
||||
SEND_ADDR(peri_addr);
|
||||
test_delay_us(10000);
|
||||
test_delay_ms(10);
|
||||
|
||||
bool can_read = (attr & APM_PERM_R);
|
||||
TEST_ASSERT(apm_master_excp_flag[APM_MASTER_LPCORE] != can_read);
|
||||
@@ -490,7 +490,7 @@ static void hp_cpu_xmem_addr_rw(uint32_t mem_addr, size_t size, uint32_t attr)
|
||||
for (uint32_t offs = 0; offs < num_words; offs += step) {
|
||||
addr[offs] = TEST_VAL;
|
||||
asm volatile ("nop");
|
||||
test_delay_us(10000);
|
||||
test_delay_ms(10);
|
||||
|
||||
bool can_write = (attr & APM_PERM_W);
|
||||
TEST_ASSERT(apm_master_excp_flag[APM_MASTER_HPCORE] != can_write);
|
||||
@@ -500,7 +500,7 @@ static void hp_cpu_xmem_addr_rw(uint32_t mem_addr, size_t size, uint32_t attr)
|
||||
uint32_t val = addr[offs];
|
||||
(void)val;
|
||||
asm volatile ("fence");
|
||||
test_delay_us(10000);
|
||||
test_delay_ms(10);
|
||||
|
||||
bool can_read = (attr & APM_PERM_R);
|
||||
TEST_ASSERT(apm_master_excp_flag[APM_MASTER_HPCORE] != can_read);
|
||||
@@ -520,7 +520,7 @@ static void hp_cpu_xmem_addr_x(uint32_t mem_addr, size_t size, uint32_t attr)
|
||||
void (*func_ptr)(void);
|
||||
func_ptr = (void(*)(void))(mem_addr);
|
||||
func_ptr();
|
||||
test_delay_us(10000);
|
||||
test_delay_ms(10);
|
||||
|
||||
bool can_execute = attr & APM_PERM_X;
|
||||
TEST_ASSERT(apm_master_excp_flag[APM_MASTER_HPCORE] != can_execute);
|
||||
@@ -538,7 +538,7 @@ static void lp_cpu_xmem_addr_rw(uint32_t mem_addr, size_t size, uint32_t attr)
|
||||
SEND_MSG(MSG_SLAVE_WRITE);
|
||||
SEND_ADDR(mem_addr);
|
||||
SEND_SIZE(sizeof(uint32_t));
|
||||
test_delay_us(10000);
|
||||
test_delay_ms(10);
|
||||
|
||||
bool can_write = (attr & APM_PERM_W);
|
||||
TEST_ASSERT(apm_master_excp_flag[APM_MASTER_LPCORE] != can_write);
|
||||
@@ -547,7 +547,7 @@ static void lp_cpu_xmem_addr_rw(uint32_t mem_addr, size_t size, uint32_t attr)
|
||||
|
||||
SEND_MSG(MSG_SLAVE_READ);
|
||||
SEND_ADDR(mem_addr);
|
||||
test_delay_us(10000);
|
||||
test_delay_ms(10);
|
||||
|
||||
bool can_read = (attr & APM_PERM_R);
|
||||
TEST_ASSERT(apm_master_excp_flag[APM_MASTER_LPCORE] != can_read);
|
||||
@@ -564,7 +564,7 @@ static void lp_cpu_xmem_addr_x(uint32_t mem_addr, size_t size, uint32_t attr)
|
||||
|
||||
SEND_MSG(MSG_SLAVE_EXEC);
|
||||
SEND_ADDR(mem_addr);
|
||||
test_delay_us(10000);
|
||||
test_delay_ms(10);
|
||||
|
||||
bool can_execute = (attr & APM_PERM_X);
|
||||
TEST_ASSERT(apm_master_excp_flag[APM_MASTER_LPCORE] != can_execute);
|
9
components/hal/test_apps/tee/main/CMakeLists.txt
Normal file
9
components/hal/test_apps/tee/main/CMakeLists.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
set(srcs "test_main.c" "test_pms.c")
|
||||
if(CONFIG_SOC_SUPPORT_TEE_INTR_TEST)
|
||||
list(APPEND srcs "test_cpu_intr.c")
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
INCLUDE_DIRS ""
|
||||
PRIV_REQUIRES pms_and_cpu_intr esp_psram
|
||||
WHOLE_ARCHIVE)
|
66
components/hal/test_apps/tee/main/test_cpu_intr.c
Normal file
66
components/hal/test_apps/tee/main/test_cpu_intr.c
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "test_cpu_intr.h"
|
||||
|
||||
#include "unity.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
/**
|
||||
* @brief Test M-mode interrupts in M-mode
|
||||
*
|
||||
* This test verifies interrupt handling behavior in M-mode:
|
||||
* - Sets up a timer interrupt firing every 10ms (priority 2) in M-mode
|
||||
* - Triggers INTPRI interrupt every 100ms (priority 1) in M-mode
|
||||
* - Verifies that both interrupts are handled correctly
|
||||
* - Checks interrupt counts match expected values
|
||||
*/
|
||||
TEST_CASE("Test M-mode interrupts in M-mode", "[CPU]")
|
||||
{
|
||||
test_m_mode_intr_in_m_mode();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test U-mode interrupts in U-mode
|
||||
*
|
||||
* This test verifies interrupt handling behavior in U-mode:
|
||||
* - Sets up a timer interrupt firing every 10ms (priority 2) in U-mode
|
||||
* - Triggers INTPRI interrupt every 100ms (priority 1) in U-mode
|
||||
* - Verifies that both interrupts are handled correctly
|
||||
* - Checks interrupt counts match expected values
|
||||
*/
|
||||
TEST_CASE("Test U-mode interrupts in U-mode", "[CPU]")
|
||||
{
|
||||
test_u_mode_intr_in_u_mode();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test M-mode interrupts in U-mode
|
||||
*
|
||||
* This test verifies interrupt handling behavior in U-mode:
|
||||
* - Sets up a timer interrupt firing every 10ms (priority 2) in U-mode
|
||||
* - Triggers INTPRI interrupt every 100ms (priority 1) in M-mode
|
||||
* - Verifies that both interrupts are handled correctly
|
||||
* - Checks interrupt counts match expected values
|
||||
*/
|
||||
TEST_CASE("Test M-mode interrupts in U-mode", "[CPU]")
|
||||
{
|
||||
test_m_mode_intr_in_u_mode();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test U-mode interrupts in M-mode
|
||||
*
|
||||
* This test verifies interrupt handling behavior in M-mode:
|
||||
* - Sets up a timer interrupt firing every 10ms (priority 2) in M-mode
|
||||
* - Triggers INTPRI interrupt every 100ms (priority 1) in U-mode
|
||||
* - Verifies that both interrupts are handled correctly
|
||||
* - Checks interrupt counts match expected values
|
||||
*/
|
||||
TEST_CASE("Test U-mode interrupts in M-mode", "[CPU]")
|
||||
{
|
||||
test_u_mode_intr_in_m_mode();
|
||||
}
|
@@ -6,22 +6,29 @@ from pytest_embedded_idf.utils import idf_parametrize
|
||||
|
||||
# ---------------- Pytest build parameters ----------------
|
||||
|
||||
SOC_SYS_APM_SUPPORTED = ['esp32c6', 'esp32h2', 'esp32c5', 'esp32c61']
|
||||
SOC_PERI_APM_SUPPORTED = ['esp32c5']
|
||||
SOC_SUPPORT_SYS_APM_TEST = ['esp32c6', 'esp32h2', 'esp32c5', 'esp32c61']
|
||||
SOC_SUPPORT_PERI_APM_TEST = ['esp32c5']
|
||||
SOC_SUPPORT_INTR_TEST = ['esp32c5', 'esp32c61']
|
||||
|
||||
CONFIG_SYS_APM = [
|
||||
# 'config, target, markers',
|
||||
('default', target, (pytest.mark.generic,))
|
||||
for target in SOC_SYS_APM_SUPPORTED
|
||||
for target in SOC_SUPPORT_SYS_APM_TEST
|
||||
]
|
||||
|
||||
CONFIG_PERI_APM = [
|
||||
# 'config, target, markers',
|
||||
('default', target, (pytest.mark.generic,))
|
||||
for target in SOC_PERI_APM_SUPPORTED
|
||||
for target in SOC_SUPPORT_PERI_APM_TEST
|
||||
]
|
||||
|
||||
# ---------------- TEE default tests ----------------
|
||||
CONFIG_INTR_TEST = [
|
||||
# 'config, target, markers',
|
||||
('default', target, (pytest.mark.generic,))
|
||||
for target in SOC_SUPPORT_INTR_TEST
|
||||
]
|
||||
|
||||
# ---------------- TEE APM tests ----------------
|
||||
|
||||
|
||||
@idf_parametrize(
|
||||
@@ -40,3 +47,15 @@ def test_tee_sys_apm(dut: IdfDut) -> None:
|
||||
)
|
||||
def test_tee_peri_apm(dut: IdfDut) -> None:
|
||||
dut.run_all_single_board_cases(group='PERI_APM')
|
||||
|
||||
|
||||
# ---------------- TEE Interrupt tests ----------------
|
||||
|
||||
|
||||
@idf_parametrize(
|
||||
'config, target, markers',
|
||||
CONFIG_INTR_TEST,
|
||||
indirect=['config', 'target'],
|
||||
)
|
||||
def test_tee_interrupts(dut: IdfDut) -> None:
|
||||
dut.run_all_single_board_cases()
|
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "soc/reg_base.h"
|
||||
|
||||
/********* For PERI_APM *********/
|
||||
#include "soc/uart_reg.h"
|
||||
#include "soc/i2c_reg.h"
|
||||
#include "soc/i2s_reg.h"
|
||||
#include "soc/mcpwm_reg.h"
|
||||
#include "soc/twaifd_reg.h"
|
||||
#include "soc/ahb_dma_reg.h"
|
||||
#include "soc/pau_reg.h"
|
||||
#include "soc/interrupt_matrix_reg.h"
|
||||
#include "soc/apb_saradc_reg.h"
|
||||
#include "soc/timer_group_reg.h"
|
||||
#include "soc/pcnt_reg.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/hp_system_reg.h"
|
||||
#include "soc/pcr_reg.h"
|
||||
#include "soc/spi_mem_reg.h"
|
||||
#include "soc/hp_apm_reg.h"
|
||||
#include "soc/cpu_apm_reg.h"
|
||||
#include "soc/sha_reg.h"
|
||||
#include "soc/cache_reg.h"
|
||||
#include "soc/spi_reg.h"
|
||||
#include "soc/bitscrambler_reg.h"
|
||||
#include "soc/keymng_reg.h"
|
||||
#include "soc/sdio_slc_host_reg.h"
|
||||
|
||||
#include "soc/efuse_reg.h"
|
||||
#include "soc/pmu_reg.h"
|
||||
#include "soc/lp_clkrst_reg.h"
|
||||
#include "soc/lp_aon_reg.h"
|
||||
#include "soc/lp_wdt_reg.h"
|
||||
#include "soc/lpperi_reg.h"
|
||||
#include "soc/lp_analog_peri_reg.h"
|
||||
#include "soc/lp_uart_reg.h"
|
||||
#include "soc/lp_i2c_reg.h"
|
||||
#include "soc/lp_i2c_ana_mst_reg.h"
|
||||
#include "soc/huk_reg.h"
|
||||
#include "soc/lp_apm_reg.h"
|
@@ -1,77 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "soc/soc_caps.h"
|
||||
#include "esp_cpu.h"
|
||||
|
||||
#include "riscv/encoding.h"
|
||||
#include "riscv/csr.h"
|
||||
#include "riscv/rv_utils.h"
|
||||
|
||||
#include "esp_rom_sys.h"
|
||||
|
||||
#if SOC_INT_PLIC_SUPPORTED
|
||||
#include "esp_private/interrupt_plic.h"
|
||||
#elif SOC_INT_CLIC_SUPPORTED
|
||||
#include "esp_private/interrupt_clic.h"
|
||||
#else
|
||||
#include "esp_private/interrupt_intc.h"
|
||||
#endif
|
||||
|
||||
/********************************** Vector Table Redirection *******************************/
|
||||
|
||||
extern int _vector_table;
|
||||
extern int _test_vector_table;
|
||||
|
||||
void set_test_vector_table(void)
|
||||
{
|
||||
rv_utils_intr_global_disable();
|
||||
rv_utils_set_mtvec((uintptr_t)&_test_vector_table);
|
||||
rv_utils_intr_global_enable();
|
||||
}
|
||||
|
||||
void restore_default_vector_table(void)
|
||||
{
|
||||
rv_utils_intr_global_disable();
|
||||
rv_utils_set_mtvec((uintptr_t)&_vector_table);
|
||||
rv_utils_intr_global_enable();
|
||||
}
|
||||
|
||||
/********************************** Privilege Mode Switch *********************************/
|
||||
|
||||
void test_m2u_switch(void)
|
||||
{
|
||||
int mode = esp_cpu_get_curr_privilege_level();
|
||||
assert(mode == PRV_M);
|
||||
|
||||
asm volatile("ecall\n");
|
||||
|
||||
mode = esp_cpu_get_curr_privilege_level();
|
||||
assert(mode == PRV_U);
|
||||
}
|
||||
|
||||
void test_u2m_switch(void)
|
||||
{
|
||||
int mode = esp_cpu_get_curr_privilege_level();
|
||||
assert(mode == PRV_U);
|
||||
|
||||
asm volatile("ecall\n");
|
||||
|
||||
mode = esp_cpu_get_curr_privilege_level();
|
||||
assert(mode == PRV_M);
|
||||
}
|
||||
|
||||
/********************************** 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);
|
||||
}
|
@@ -1,4 +0,0 @@
|
||||
idf_component_register(SRCS "test_main.c" "test_pms.c"
|
||||
INCLUDE_DIRS ""
|
||||
PRIV_REQUIRES pms esp_psram
|
||||
WHOLE_ARCHIVE)
|
@@ -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" {
|
||||
|
Reference in New Issue
Block a user