Skip to content

Commit 15a4d63

Browse files
committed
ci(hal): Add HAL/LL-based test app for the TEE and APM peripherals
1 parent d8601f8 commit 15a4d63

35 files changed

+3998
-4
lines changed

.gitlab/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@
125125
/components/freertos/ @esp-idf-codeowners/system
126126
/components/hal/ @esp-idf-codeowners/peripherals
127127
/components/hal/test_apps/crypto/ @esp-idf-codeowners/peripherals @esp-idf-codeowners/security
128+
/components/hal/test_apps/tee_apm/ @esp-idf-codeowners/peripherals @esp-idf-codeowners/security
128129
/components/heap/ @esp-idf-codeowners/system
129130
/components/http_parser/ @esp-idf-codeowners/app-utilities
130131
/components/idf_test/ @esp-idf-codeowners/peripherals @esp-idf-codeowners/system

components/esp_hw_support/port/esp32c5/cpu_region_protect.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ void esp_cpu_configure_region_protection(void)
136136
_Static_assert(SOC_CPU_SUBSYSTEM_LOW < SOC_CPU_SUBSYSTEM_HIGH, "Invalid CPU subsystem region");
137137

138138
// 2. I/D-ROM
139+
#if CONFIG_ESP_SYSTEM_PMP_IDRAM_SPLIT && !BOOTLOADER_BUILD
139140
const uint32_t drom_start = (uint32_t) (ets_rom_layout_p->drom_start);
140141
if ((drom_start & (SOC_CPU_PMP_REGION_GRANULARITY - 1)) == 0) {
141142
// We can skip configuring the PMP entry for the [SOC_IROM_MASK_LOW - drom_start]
@@ -144,9 +145,11 @@ void esp_cpu_configure_region_protection(void)
144145
// the region as cacheable. Thus, we save on one PMP entry.
145146
PMP_ENTRY_SET(1, drom_start, NONE);
146147
PMP_ENTRY_SET(2, SOC_DROM_MASK_HIGH, PMP_TOR | R);
147-
} else {
148+
} else
149+
#endif
150+
{
148151
PMP_ENTRY_SET(1, SOC_IROM_MASK_LOW, NONE);
149-
PMP_ENTRY_SET(2, SOC_IROM_MASK_HIGH, PMP_TOR | RX);
152+
PMP_ENTRY_SET(2, SOC_IROM_MASK_HIGH, PMP_TOR | CONDITIONAL_RX);
150153
_Static_assert(SOC_IROM_MASK_LOW < SOC_IROM_MASK_HIGH, "Invalid I/D-ROM region");
151154
}
152155

components/esp_hw_support/port/esp32c61/cpu_region_protect.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,14 +133,17 @@ void esp_cpu_configure_region_protection(void)
133133
_Static_assert(SOC_CPU_SUBSYSTEM_LOW < SOC_CPU_SUBSYSTEM_HIGH, "Invalid CPU subsystem region");
134134

135135
// 2. I/D-ROM
136+
#if CONFIG_ESP_SYSTEM_PMP_IDRAM_SPLIT && !BOOTLOADER_BUILD
136137
const uint32_t drom_start = (uint32_t) (ets_rom_layout_p->drom_start);
137138
if ((drom_start & (SOC_CPU_PMP_REGION_GRANULARITY - 1)) == 0) {
138139
PMP_ENTRY_SET(1, SOC_IROM_MASK_LOW, NONE);
139140
PMP_ENTRY_SET(2, drom_start, PMP_TOR | RX);
140141
PMP_ENTRY_SET(3, SOC_DROM_MASK_HIGH, PMP_TOR | RW);
141-
} else {
142+
} else
143+
#endif
144+
{
142145
const uint32_t pmpaddr1 = PMPADDR_NAPOT(SOC_IROM_MASK_LOW, SOC_IROM_MASK_HIGH);
143-
PMP_ENTRY_SET(1, pmpaddr1, PMP_NAPOT | RX);
146+
PMP_ENTRY_SET(1, pmpaddr1, PMP_NAPOT | CONDITIONAL_RX);
144147
_Static_assert(SOC_IROM_MASK_LOW < SOC_IROM_MASK_HIGH, "Invalid I/D-ROM region");
145148
}
146149

components/hal/.build-test-rules.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,7 @@ components/hal/test_apps/hal_i2c:
1111
components/hal/test_apps/hal_utils:
1212
enable:
1313
- if: IDF_TARGET == "linux"
14+
15+
components/hal/test_apps/tee_apm:
16+
disable:
17+
- if: IDF_TARGET not in ["esp32c6", "esp32h2", "esp32c5", "esp32c61"]

components/hal/apm_hal.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,8 @@ void apm_hal_set_region_end_addr(apm_ctrl_module_t ctrl_mod, uint32_t regn_num,
268268

269269
void apm_hal_set_sec_mode_region_attr(apm_ctrl_module_t ctrl_mod, uint32_t regn_num, apm_security_mode_t mode, uint32_t regn_pms)
270270
{
271+
HAL_ASSERT(mode != APM_SEC_MODE_TEE);
272+
271273
switch (ctrl_mod) {
272274
case APM_CTRL_HP_APM:
273275
apm_ll_hp_apm_set_sec_mode_region_attr(regn_num, mode, regn_pms);
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#This is the project CMakeLists.txt file for the test subproject
2+
cmake_minimum_required(VERSION 3.16)
3+
4+
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
5+
set(COMPONENTS main)
6+
7+
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
8+
9+
project(test_tee_apm)
10+
11+
include($ENV{IDF_PATH}/tools/ci/check_register_rw_half_word.cmake)
12+
message(STATUS "Checking tee/apm registers are not read-write by half-word")
13+
check_register_rw_half_word(SOC_MODULES "*tee" # tee, lp_tee
14+
"*apm *apm0" # hp_apm, lp_apm, cpu_apm, lp_apm0
15+
HAL_MODULES "apm")
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
| Supported Targets | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 |
2+
| ----------------- | -------- | -------- | --------- | -------- |
3+
4+
# APM (Access Permission Management) Peripheral Test App
5+
6+
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.
7+
8+
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.
9+
10+
---
11+
12+
## Test Coverage
13+
14+
### TEE mode default access behavior
15+
16+
- **TEE Mode Default Access**
17+
18+
Validates whether TEE mode has unrestricted access to regions not covered by APM entries. Confirms filtering issues on ESP32-C6 and ESP32-H2.
19+
20+
### HP_CPU Access
21+
22+
- **HP_CPU → CPU_PERI**
23+
- **HP_CPU → HP_PERI**
24+
- **HP_CPU → LP_PERI**
25+
- **HP_CPU → HP_MEM** (if `SOC_APM_CPU_APM_SUPPORTED`)
26+
- **HP_CPU → LP_MEM** (if `SOC_RTC_MEM_SUPPORTED`)
27+
28+
Each scenario checks access permission enforcement for read-only and write-only settings across security modes.
29+
30+
### GDMA Access
31+
32+
- **GDMA → HP_MEM**
33+
- **GDMA → EXT_MEM** (if `CONFIG_SPIRAM`)
34+
35+
Validates region-based restrictions across modes using DMA transfers.
36+
37+
### LP_CPU Access (if `CONFIG_ULP_COPROC_ENABLED`)
38+
39+
- **LP_CPU → LP_PERI**
40+
- **LP_CPU → LP_MEM**
41+
- **LP_CPU → HP_MEM**
42+
43+
### PERI_APM Tests (if `SOC_APM_SUPPORT_TEE_PERI_ACCESS_CTRL`)
44+
45+
- **HP_CPU → HP_PERI**
46+
- **HP_CPU → LP_PERI**
47+
- **LP_CPU → HP_PERI**
48+
- **LP_CPU → LP_PERI**
49+
50+
Validates the per-peripheral access permissions for all security modes.
51+
52+
---
53+
54+
## Target Extension Guide
55+
56+
To add support for a new SoC target, create a test configuration header at:
57+
58+
```
59+
components/pms/priv_include/<target>/test_pms_params.h
60+
```
61+
62+
This header must define:
63+
64+
### 1. GDMA APM Master ID
65+
66+
Defined based on GDMA version:
67+
68+
```c
69+
#define TEST_GDMA_APM_MASTER_ID APM_MASTER_GDMA_GPSPI // For SOC_AHB_GDMA_VERSION == 1
70+
```
71+
72+
- `SOC_AHB_GDMA_VERSION == 1` → `GPSPI`
73+
- `SOC_AHB_GDMA_VERSION == 2` → `26` (e.g., `GDMA_DUMMY10`)
74+
75+
Refer to `hal/apm_types.h` or the SoC TRM.
76+
77+
### 2. APM Controller and Path Definitions
78+
79+
Specify APM controller and access path for each initiator-target pair:
80+
81+
```c
82+
#define HP_CPU_CPUPERI_APM_CTRL APM_CTRL_HP_APM
83+
#define HP_CPU_CPUPERI_APM_PATH APM_CTRL_ACCESS_PATH_M0
84+
#define TEST_HP_CPU_CPUPERI_REGN_NUM 4
85+
```
86+
87+
Use the TRM to determine path-controller mappings.
88+
89+
### 3. Peripheral Test Region Definitions
90+
91+
Split the peripheral address space into testable regions:
92+
93+
- Use `soc/reg_base.h` to get base addresses of peripherals.
94+
- Align non-contiguous region boundaries to 4 KB using:
95+
96+
```c
97+
#define ALIGN_TO_NEXT_4KB(addr) (((addr) + 0x1000) & ~0xFFF)
98+
```
99+
100+
#### CPU_PERI
101+
102+
- Typically monitored by `HP_APM`.
103+
- Includes blocks like `TRACE`, `ASSIST_DEBUG`, `INTPRI`, `CACHE`.
104+
- `CPU_PERI` typically includes ~4 peripherals, and thus, 4 APM regions are sufficient for test coverage.
105+
106+
#### LP_PERI
107+
108+
- Monitored by `LP_APM`.
109+
- Covers domains like `PMU`, `LP_IO`, `LP_AON`.
110+
- For SoCs with `LP_CPU`, reserve the regions containing `PMU`, `LP_AON`, `LP_PERI`. These are reserved to allow test-case control and avoid undesired APM violations.
111+
112+
```c
113+
#define TEST_LP_PERI_RESV_MASK BIT(0) | BIT(2) | BIT(6)
114+
```
115+
116+
#### HP_PERI
117+
118+
- Monitored by `HP_APM`.
119+
- Split into: `HP_PERI0`, `HP_PERI1`, and `HP_PERI2`.
120+
Test APM regions should be proportionally allocated to these segments based on address space size.
121+
- Reserve the region containing `UART0`, since it is often used by the log console.
122+
- If `PERI_APM` is supported, reserve the regions with `TEE`, `LP_TEE`, `HP_APM`, `LP_APM`, `LP_APM0`, and `CPU_APM`, as these are inaccessible to the REE modes.
123+
124+
```c
125+
#define TEST_HP_PERI_RESV_MASK BIT(0)
126+
```
127+
128+
---
129+
130+
## Building
131+
132+
```bash
133+
idf.py set-target <TARGET>
134+
idf.py build
135+
```
136+
137+
## Running the App
138+
139+
```bash
140+
idf.py flash monitor
141+
```
142+
143+
## Running Tests
144+
145+
```bash
146+
pytest --target <TARGET>
147+
```
148+
149+
---
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
cmake_minimum_required(VERSION 3.16)
2+
idf_build_get_property(target IDF_TARGET)
3+
4+
set(srcs "src/test_tee_vectors.S"
5+
"src/test_panic_handler.c"
6+
"src/test_intr_utils.c"
7+
"src/test_apm_utils.c"
8+
"src/test_setup_utils.c"
9+
"src/test_tee_sys_apm.c")
10+
if(CONFIG_SOC_APM_SUPPORT_TEE_PERI_ACCESS_CTRL)
11+
list(APPEND srcs "src/test_tee_peri_apm.c")
12+
endif()
13+
14+
idf_component_register(SRCS "${srcs}"
15+
INCLUDE_DIRS "include" "priv_include"
16+
PRIV_INCLUDE_DIRS "priv_include/${target}"
17+
REQUIRES ulp unity
18+
LDFRAGMENTS linker.lf)
19+
20+
if(CONFIG_ULP_COPROC_ENABLED)
21+
set(ulp_app_name ulp_lp_core_${COMPONENT_NAME})
22+
set(ulp_rv_srcs "src/ulp/ulp_lp_core_main.c" "src/ulp/ulp_vectors.S")
23+
set(ulp_exp_dep_srcs "src/test_tee_apm_pms.c")
24+
ulp_embed_binary(${ulp_app_name} "${ulp_rv_srcs}" "${ulp_exp_dep_srcs}")
25+
endif()
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/* Test-cases */
8+
void test_sys_apm_master_hp_cpu_slave_hp_peri(void);
9+
10+
void test_sys_apm_master_hp_cpu_slave_cpu_peri(void);
11+
12+
void test_sys_apm_master_gdma_slave_hpmem(void);
13+
14+
void test_sys_apm_master_hp_cpu_slave_lpmem(void);
15+
16+
void test_sys_apm_master_lp_cpu_slave_lp_peri(void);
17+
18+
void test_sys_apm_master_hp_cpu_slave_lp_peri(void);
19+
20+
void test_sys_apm_master_lp_cpu_slave_lpmem(void);
21+
22+
void test_sys_apm_master_lp_cpu_slave_hpmem(void);
23+
24+
void test_sys_apm_master_gdma_slave_extmem(void);
25+
26+
void test_sys_apm_master_hp_cpu_slave_hpmem(void);
27+
28+
void test_peri_apm_master_hp_cpu_slave_hp_peri(void);
29+
30+
void test_peri_apm_master_hp_cpu_slave_lp_peri(void);
31+
32+
void test_peri_apm_master_lp_cpu_slave_hp_peri(void);
33+
34+
void test_peri_apm_master_lp_cpu_slave_lp_peri(void);
35+
36+
void test_tee_mode_default_access(void);
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[mapping:pms]
2+
archive: libpms.a
3+
entries:
4+
test_intr_utils (noflash)
5+
test_panic_handler (noflash)

0 commit comments

Comments
 (0)