ci(esp_tee): Refactor the ESP-TEE test-cases

- Improve the interrupt-related test cases
- Fix potential issues in the task-switching test
  during secure service calls
This commit is contained in:
Laukik Hase
2025-05-29 19:21:04 +05:30
parent 340de9823a
commit ab8400df4a
8 changed files with 321 additions and 372 deletions

View File

@@ -9,36 +9,11 @@
extern "C" {
#endif
#include <stdint.h>
#include "esp_attr.h"
#define TEE_TEST_INT_COUNT 3
#define ESP_TEE_TEST_INTR_ITER (4)
uint32_t NOINLINE_ATTR esp_tee_service_add(uint32_t a, uint32_t b);
uint32_t NOINLINE_ATTR esp_tee_service_sub(uint32_t a, uint32_t b);
uint32_t NOINLINE_ATTR esp_tee_service_mul(uint32_t a, uint32_t b);
uint32_t NOINLINE_ATTR esp_tee_service_div(uint32_t a, uint32_t b);
int esp_tee_secure_int_test(void);
int esp_tee_non_secure_int_test(volatile uint32_t* volatile ns_int_count);
int esp_tee_test_int_count(uint32_t *secure_int_count);
int esp_tee_test_store_prohibited(uint32_t type);
int esp_tee_test_illegal_instr(void);
int esp_tee_test_instr_fetch_prohibited(uint32_t type);
void NOINLINE_ATTR dummy_secure_service(int a, int b, int c, int d, int e, int f, int g, int h, int *i);
uint32_t add_in_loop(uint32_t a, uint32_t b, uint32_t iter);
int _ss_esp_tee_test_heap_malloc_write_free(void);
void NOINLINE_ATTR esp_tee_test_dummy_sec_srv(int a, int b, int c, int d, int e, int f, int g, int h, int *i);
#ifdef __cplusplus
}

View File

@@ -3,73 +3,69 @@ secure_services:
entries:
- id: 200
type: custom
function: esp_tee_service_add
function: esp_tee_test_service_add
args: 2
- id: 201
type: custom
function: esp_tee_service_sub
function: esp_tee_test_service_sub
args: 2
- id: 202
type: custom
function: esp_tee_service_mul
function: esp_tee_test_service_mul
args: 2
- id: 203
type: custom
function: esp_tee_service_div
function: esp_tee_test_service_div
args: 2
- id: 204
type: custom
function: esp_tee_test_timer_init
args: 1
function: esp_tee_test_tee_intr_in_tee
args: 0
- id: 205
type: custom
function: esp_tee_secure_int_test
args: 0
function: esp_tee_test_ree_intr_in_tee
args: 1
- id: 206
type: custom
function: esp_tee_non_secure_int_test
args: 1
function: esp_tee_test_tee_intr_in_ree
args: 2
- id: 207
type: custom
function: esp_tee_test_int_count
args: 1
- id: 208
type: custom
function: esp_tee_test_resv_reg1_write_violation
args: 0
- id: 209
- id: 208
type: custom
function: esp_tee_test_resv_reg1_exec_violation
args: 0
- id: 210
- id: 209
type: custom
function: esp_tee_test_iram_reg1_write_violation
args: 0
- id: 211
- id: 210
type: custom
function: esp_tee_test_iram_reg2_write_violation
args: 0
- id: 212
- id: 211
type: custom
function: esp_tee_test_dram_reg1_exec_violation
args: 0
- id: 213
- id: 212
type: custom
function: esp_tee_test_dram_reg2_exec_violation
args: 0
- id: 214
- id: 213
type: custom
function: esp_tee_test_illegal_instruction
args: 0
- id: 214
type: custom
function: esp_tee_test_dummy_sec_srv
args: 9
- id: 215
type: custom
function: dummy_secure_service
args: 9
function: esp_tee_test_priv_mode_switch
args: 2
- id: 216
type: custom
function: add_in_loop
args: 3
- id: 217
type: custom
function: esp_tee_test_heap_malloc_write_free
args: 0

View File

@@ -9,7 +9,7 @@
#include "multi_heap.h"
void NOINLINE_ATTR _ss_dummy_secure_service(int a, int b, int c, int d, int e, int f, int g, int h, int *i)
void NOINLINE_ATTR _ss_esp_tee_test_dummy_sec_srv(int a, int b, int c, int d, int e, int f, int g, int h, int *i)
{
esp_rom_printf("Dummy secure service\n");
*i = a + b + c + d + e + f + g + h;

View File

@@ -1,14 +1,14 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdarg.h>
#include "secure_service_num.h"
#include "esp_tee.h"
#include "esp_err.h"
#include "esp_attr.h"
void dummy_secure_service(int a, int b, int c, int d, int e, int f, int g, int h, int *i)
void NOINLINE_ATTR esp_tee_test_dummy_sec_srv(int a, int b, int c, int d, int e, int f, int g, int h, int *i)
{
esp_tee_service_call(10, SS_DUMMY_SECURE_SERVICE, a, b, c, d, e, f, g, h, i);
esp_tee_service_call(10, SS_ESP_TEE_TEST_DUMMY_SEC_SRV, a, b, c, d, e, f, g, h, i);
}

View File

@@ -4,174 +4,168 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include <assert.h>
#include "esp_cpu.h"
#include "esp_log.h"
#include "riscv/csr.h"
#include "esp_rom_sys.h"
#include "hal/timer_ll.h"
#include "hal/clk_gate_ll.h"
#include "soc/timer_group_reg.h"
#include "soc/soc.h"
#include "soc/interrupts.h"
#include "soc/interrupt_matrix_reg.h"
#include "soc/pcr_reg.h"
#include "hal/timer_ll.h"
#include "esp_tee.h"
#include "esp_tee_intr.h"
#include "esp_tee_test.h"
#define TIMER_DIVIDER 80 // Hardware timer clock divider
#define TIMER_RESOLUTION_HZ 1000000 // 1MHz resolution
#define TIMER_ALARM_PERIOD_S 0.10 // sample test interval for the first timer
static const char *TAG __attribute__((unused)) = "esp_tee_intr_test";
/* TEE uses Group0 Timer0 */
#define TEE_SECURE_GROUP 0
#define TEE_SECURE_TIMER 0
/* ---------------------------------------------------- Utility functions ---------------------------------------------------- */
static const char *TAG = "esp_tee_intr_test";
#define TEST_TIMER_GROUP (0)
#define TEST_TIMER_ID (0)
#define TEST_TIMER_DIVIDER (80)
static timg_dev_t *timg_hw = (&TIMERG0);
#define TEST_TIMER_RESOLUTION_HZ (1000000ULL) // 1MHz, 1 tick = 1us
#define TIMER_ALARM_PERIOD_S (0.25f) // 250ms @ resolution 1MHz
uint32_t *psecure_int_count = NULL;
static timg_dev_t *timg_dev = TIMER_LL_GET_HW(TEST_TIMER_GROUP);
static void IRAM_ATTR timer_group0_isr(void *arg)
static void IRAM_ATTR test_timer_isr(void *arg)
{
ESP_LOGI(TAG, "Timer ISR Handler from World %d!", esp_cpu_get_curr_privilege_level());
uint32_t *intr_count = (uint32_t *)arg;
*intr_count = *intr_count + 1;
esp_rom_printf("[mode: %d] Interrupt triggered (%d)\n", esp_cpu_get_curr_privilege_level(), *intr_count);
/* For interrupt test. */
*psecure_int_count = *psecure_int_count + 1;
/* Clear interrupt */
timer_ll_clear_intr_status(timg_hw, TIMER_LL_EVENT_ALARM(TEE_SECURE_TIMER));
/* Re-enable the alarm. */
timer_ll_enable_alarm(timg_hw, TEE_SECURE_TIMER, true);
/* 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 tee_timer_enable(void)
static void test_timer_deinit(void)
{
struct vector_desc_t timer_vd = { 0, NULL, NULL, NULL };
const uint32_t timer_id = TEST_TIMER_ID;
// init timer_vc
timer_vd.source = ETS_TG0_T0_LEVEL_INTR_SOURCE;
timer_vd.isr = timer_group0_isr;
// 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);
ESP_LOGI(TAG, "Enabling test timer from secure world");
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));
/* Enable TG0 peripheral module */
_timer_ll_enable_bus_clock(TEE_SECURE_GROUP, true);
_timer_ll_reset_register(TEE_SECURE_GROUP);
/* Stop counter, alarm, auto-reload at first place */
timer_ll_enable_clock(TEE_SECURE_GROUP, TEE_SECURE_TIMER, true);
timer_ll_enable_counter(timg_hw, TEE_SECURE_TIMER, false);
timer_ll_enable_auto_reload(timg_hw, TEE_SECURE_TIMER, false);
timer_ll_enable_alarm(timg_hw, TEE_SECURE_TIMER, false);
// Set clock source
timer_ll_set_clock_source(TEE_SECURE_GROUP, TEE_SECURE_TIMER, GPTIMER_CLK_SRC_DEFAULT);
timer_ll_set_clock_prescale(timg_hw, TEE_SECURE_TIMER, TIMER_DIVIDER);
// Initialize counter value to zero
timer_ll_set_reload_value(timg_hw, TEE_SECURE_TIMER, 0);
timer_ll_trigger_soft_reload(timg_hw, TEE_SECURE_TIMER);
// set counting direction
timer_ll_set_count_direction(timg_hw, TEE_SECURE_TIMER, GPTIMER_COUNT_UP);
// disable interrupt
timer_ll_enable_intr(timg_hw, TIMER_LL_EVENT_ALARM(TEE_SECURE_TIMER), false);
// clear pending interrupt event
timer_ll_clear_intr_status(timg_hw, TIMER_LL_EVENT_ALARM(TEE_SECURE_TIMER));
esp_tee_intr_register((void *)&timer_vd);
timer_ll_enable_intr(timg_hw, TIMER_LL_EVENT_ALARM(TEE_SECURE_TIMER), true);
timer_ll_set_reload_value(timg_hw, TEE_SECURE_TIMER, 0);
// enable timer interrupt
timer_ll_enable_intr(timg_hw, TIMER_LL_EVENT_ALARM(TEE_SECURE_TIMER), true);
// set timer alarm
uint64_t alarm_value = (TIMER_ALARM_PERIOD_S * TIMER_RESOLUTION_HZ);
timer_ll_set_alarm_value(timg_hw, TEE_SECURE_TIMER, alarm_value);
timer_ll_enable_auto_reload(timg_hw, TEE_SECURE_TIMER, true);
timer_ll_enable_alarm(timg_hw, TEE_SECURE_TIMER, true);
timer_ll_enable_counter(timg_hw, TEE_SECURE_TIMER, true);
}
static void tee_timer_disable(void)
{
ESP_LOGI(TAG, "Disabling test timer from secure world");
/* Init timer interrupt vector descriptor */
struct vector_desc_t timer_vd = { 0, NULL, NULL, NULL };
timer_vd.source = ETS_TG0_T0_LEVEL_INTR_SOURCE;
timer_vd.isr = timer_group0_isr;
// 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);
// Deregister ISR
struct vector_desc_t timer_vd = {
.source = ETS_TG0_T0_LEVEL_INTR_SOURCE,
};
esp_tee_intr_deregister((void *)&timer_vd);
/* Disable timer */
timer_ll_enable_counter(timg_hw, TEE_SECURE_TIMER, false);
timer_ll_enable_auto_reload(timg_hw, TEE_SECURE_TIMER, false);
timer_ll_enable_alarm(timg_hw, TEE_SECURE_TIMER, false);
/* Disable and clear interrupt */
timer_ll_enable_intr(timg_hw, TIMER_LL_EVENT_ALARM(TEE_SECURE_TIMER), false);
timer_ll_clear_intr_status(timg_hw, TIMER_LL_EVENT_ALARM(TEE_SECURE_TIMER));
/* Disable TG0 peripheral module */
// periph_ll_disable_clk_set_rst(PERIPH_TIMG0_MODULE);
timer_ll_enable_clock(TEST_TIMER_GROUP, timer_id, false);
}
void _ss_esp_tee_test_timer_init(bool enable)
static void test_timer_init(volatile uint32_t *arg)
{
if (enable) {
tee_timer_enable();
} else {
tee_timer_disable();
}
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
struct vector_desc_t timer_vd = {
.source = ETS_TG0_T0_LEVEL_INTR_SOURCE,
.isr = test_timer_isr,
.arg = (void *)arg,
};
esp_tee_intr_register((void *)&timer_vd);
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, TIMER_ALARM_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);
}
/**
* Secure interrupt in secure world test.
*/
int _ss_esp_tee_secure_int_test(void)
/* ---------------------------------------------------- Test cases ---------------------------------------------------- */
uint32_t _ss_esp_tee_test_tee_intr_in_tee(void)
{
ESP_LOGD(TAG, "In WORLD %d", esp_cpu_get_curr_privilege_level());
volatile uint32_t secure_int_count = 0;
psecure_int_count = (uint32_t *)&secure_int_count;
esp_cpu_priv_mode_t mode = esp_cpu_get_curr_privilege_level();
assert((mode == ESP_CPU_S_MODE) && "Incorrect privilege mode!");
_ss_esp_tee_test_timer_init(true);
while (secure_int_count < TEE_TEST_INT_COUNT);
_ss_esp_tee_test_timer_init(false);
volatile uint32_t tee_intr_count = 0;
test_timer_init(&tee_intr_count);
ESP_LOGD(TAG, "Exiting WORLD %d", esp_cpu_get_curr_privilege_level());
return secure_int_count;
}
/**
* Non-Secure interrupt in secure world test.
*/
int _ss_esp_tee_non_secure_int_test(volatile uint32_t *volatile ns_int_count)
{
ESP_LOGD(TAG, "In WORLD %d", esp_cpu_get_curr_privilege_level());
uint32_t count = 0;
count = *ns_int_count;
while ((*ns_int_count < TEE_TEST_INT_COUNT)) {
if (*ns_int_count > count) {
count = *ns_int_count;
ESP_LOGI(TAG, "Interrupt count %d", count);
}
while (tee_intr_count < ESP_TEE_TEST_INTR_ITER) {
esp_rom_delay_us(10 * 1000U);
}
ESP_LOGD(TAG, "Exiting WORLD %d", esp_cpu_get_curr_privilege_level());
test_timer_deinit();
mode = esp_cpu_get_curr_privilege_level();
assert((mode == ESP_CPU_S_MODE) && "Incorrect privilege mode!");
return tee_intr_count;
}
uint32_t _ss_esp_tee_test_tee_intr_in_ree(int stage, volatile uint32_t *volatile intr_count)
{
esp_cpu_priv_mode_t mode = esp_cpu_get_curr_privilege_level();
assert((mode == ESP_CPU_S_MODE) && "Incorrect privilege mode!");
switch (stage) {
case 0:
test_timer_init(intr_count);
break;
case 1:
test_timer_deinit();
break;
default:
assert(false && "Invalid stage!");
break;
}
mode = esp_cpu_get_curr_privilege_level();
assert((mode == ESP_CPU_S_MODE) && "Incorrect privilege mode!");
return 0;
}
int _ss_esp_tee_test_int_count(uint32_t *secure_int_count)
uint32_t _ss_esp_tee_test_ree_intr_in_tee(volatile uint32_t *volatile intr_count)
{
psecure_int_count = secure_int_count;
return (*psecure_int_count);
esp_cpu_priv_mode_t mode = esp_cpu_get_curr_privilege_level();
assert((mode == ESP_CPU_S_MODE) && "Incorrect privilege mode!");
uint32_t prev_count = 0;
while (true) {
uint32_t curr_count = *intr_count;
if (curr_count > prev_count) {
prev_count = curr_count;
esp_rom_printf("[mode: %d] Interrupt received (%d)\n", esp_cpu_get_curr_privilege_level(), curr_count);
}
if (curr_count >= ESP_TEE_TEST_INTR_ITER) {
break;
}
esp_rom_delay_us(1000U);
}
mode = esp_cpu_get_curr_privilege_level();
assert((mode == ESP_CPU_S_MODE) && "Incorrect privilege mode!");
return 0;
}

View File

@@ -12,37 +12,45 @@ static const char *TAG = "test_sec_srv";
/* Sample Trusted App */
uint32_t NOINLINE_ATTR _ss_esp_tee_service_add(uint32_t a, uint32_t b)
uint32_t NOINLINE_ATTR _ss_esp_tee_test_service_add(uint32_t a, uint32_t b)
{
ESP_LOGD(TAG, "SS: %s", __func__);
return (a + b);
}
uint32_t NOINLINE_ATTR _ss_esp_tee_service_sub(uint32_t a, uint32_t b)
uint32_t NOINLINE_ATTR _ss_esp_tee_test_service_sub(uint32_t a, uint32_t b)
{
ESP_LOGD(TAG, "SS: %s", __func__);
return (a - b);
}
uint32_t NOINLINE_ATTR _ss_esp_tee_service_mul(uint32_t a, uint32_t b)
uint32_t NOINLINE_ATTR _ss_esp_tee_test_service_mul(uint32_t a, uint32_t b)
{
ESP_LOGD(TAG, "SS: %s", __func__);
return (a * b);
}
uint32_t NOINLINE_ATTR _ss_esp_tee_service_div(uint32_t a, uint32_t b)
uint32_t NOINLINE_ATTR _ss_esp_tee_test_service_div(uint32_t a, uint32_t b)
{
ESP_LOGD(TAG, "SS: %s", __func__);
return (a / b);
}
uint32_t _ss_add_in_loop(uint32_t a, uint32_t b, uint32_t iter)
uint32_t _ss_esp_tee_test_priv_mode_switch(uint32_t *a, uint32_t *b)
{
ESP_LOGD(TAG, "SS: %s", __func__);
for (int i = 0; i < iter; i++) {
a += b;
esp_rom_delay_us(1000000);
esp_rom_printf("[mode: %d] val: %d\n", esp_cpu_get_curr_privilege_level(), a);
*a = 1;
*b = 1;
uint32_t c = 0;
while (c < ESP_TEE_TEST_INTR_ITER * 2) {
c = *a + *b;
esp_rom_delay_us(500 * 1000U);
esp_rom_printf("[mode: %d] val: %d\n", esp_cpu_get_curr_privilege_level(), c);
*a += 1;
*b += 1;
}
return a;
return c;
}

View File

@@ -4,32 +4,46 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include "unity.h"
#include "esp_tee.h"
#include "secure_service_num.h"
#include "esp_tee_test.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_cpu.h"
#include "esp_tee.h"
#include "esp_tee_test.h"
#include "secure_service_num.h"
#include "unity.h"
#include "sdkconfig.h"
#define TEST_TASK_1_DONE_BIT (BIT0)
#define TEST_TASK_2_DONE_BIT (BIT1)
typedef struct {
uint32_t id;
uint32_t *val;
EventBits_t done_bit;
} test_task_args_t;
static EventGroupHandle_t test_task_eg;
static void test_op(int sec_srv_num, uint32_t a, uint32_t b)
{
esp_cpu_priv_mode_t world = esp_cpu_get_curr_privilege_level();
TEST_ASSERT_MESSAGE((world == ESP_CPU_NS_MODE), "Current world is not NS");
esp_cpu_priv_mode_t mode = esp_cpu_get_curr_privilege_level();
TEST_ASSERT_MESSAGE((mode == ESP_CPU_NS_MODE), "Incorrect privilege mode!");
uint32_t lval = 0;
switch (sec_srv_num) {
case SS_ESP_TEE_SERVICE_ADD:
case SS_ESP_TEE_TEST_SERVICE_ADD:
lval = (a + b);
break;
case SS_ESP_TEE_SERVICE_SUB:
case SS_ESP_TEE_TEST_SERVICE_SUB:
lval = (a - b);
break;
case SS_ESP_TEE_SERVICE_MUL:
case SS_ESP_TEE_TEST_SERVICE_MUL:
lval = (a * b);
break;
case SS_ESP_TEE_SERVICE_DIV:
case SS_ESP_TEE_TEST_SERVICE_DIV:
lval = (a / b);
break;
default:
@@ -40,60 +54,94 @@ static void test_op(int sec_srv_num, uint32_t a, uint32_t b)
uint32_t val = esp_tee_service_call(3, sec_srv_num, a, b);
TEST_ASSERT_EQUAL_UINT32(lval, val);
world = esp_cpu_get_curr_privilege_level();
TEST_ASSERT_MESSAGE((world == ESP_CPU_NS_MODE), "Sample app world switch failed");
mode = esp_cpu_get_curr_privilege_level();
TEST_ASSERT_MESSAGE((mode == ESP_CPU_NS_MODE), "Incorrect privilege mode!");
}
TEST_CASE("Test single calls to sample app (basic services)", "[basic]")
{
const uint32_t a = 200, b = 100;
test_op(SS_ESP_TEE_SERVICE_ADD, a, b);
test_op(SS_ESP_TEE_SERVICE_SUB, a, b);
test_op(SS_ESP_TEE_SERVICE_MUL, a, b);
test_op(SS_ESP_TEE_SERVICE_DIV, a, b);
test_op(SS_ESP_TEE_TEST_SERVICE_ADD, a, b);
test_op(SS_ESP_TEE_TEST_SERVICE_SUB, a, b);
test_op(SS_ESP_TEE_TEST_SERVICE_MUL, a, b);
test_op(SS_ESP_TEE_TEST_SERVICE_DIV, a, b);
}
TEST_CASE("Test multiple calls to sample app (basic services)", "[basic]")
{
esp_cpu_priv_mode_t world = esp_cpu_get_curr_privilege_level();
TEST_ASSERT_MESSAGE((world == ESP_CPU_NS_MODE), "Current world is not NS");
esp_cpu_priv_mode_t mode = esp_cpu_get_curr_privilege_level();
TEST_ASSERT_MESSAGE((mode == ESP_CPU_NS_MODE), "Incorrect privilege mode!");
for (int i = 0; i < 1024; i++) {
uint32_t val = esp_tee_service_call(3, SS_ESP_TEE_SERVICE_ADD, i, i + 1);
uint32_t val = esp_tee_service_call(3, SS_ESP_TEE_TEST_SERVICE_ADD, i, i + 1);
TEST_ASSERT_EQUAL_UINT32((2 * i + 1), val);
world = esp_cpu_get_curr_privilege_level();
TEST_ASSERT_MESSAGE((world == ESP_CPU_NS_MODE), "Sample app world switch failed");
mode = esp_cpu_get_curr_privilege_level();
TEST_ASSERT_MESSAGE((mode == ESP_CPU_NS_MODE), "Incorrect privilege mode!");
}
}
TEST_CASE("Custom secure service call", "[basic]")
TEST_CASE("Test custom secure service call", "[basic]")
{
int res = -1;
dummy_secure_service(1, 2, 3, 4, 5, 6, 7, 8, &res);
esp_tee_test_dummy_sec_srv(1, 2, 3, 4, 5, 6, 7, 8, &res);
TEST_ASSERT_EQUAL_UINT32(36, res);
}
void test_task(void *pvParameters)
static void test_task(void *pvParameters)
{
for (int i = 0; i < 8; i++) {
esp_rom_printf("[mode: %d] test_task - %d\n", esp_cpu_get_curr_privilege_level(), i);
vTaskDelay(pdMS_TO_TICKS(1000));
test_task_args_t *args = (test_task_args_t *)pvParameters;
uint32_t *val = args->val;
uint32_t id = args->id;
uint32_t prev_val = *val;
while (*val <= ESP_TEE_TEST_INTR_ITER) {
uint32_t curr_val = *val;
if (curr_val != prev_val) {
esp_rom_printf("[mode: %d] test_task - %d | val - %d\n", esp_cpu_get_curr_privilege_level(), id, curr_val);
prev_val = curr_val;
}
vTaskDelay(pdMS_TO_TICKS(100));
}
xEventGroupSetBits(test_task_eg, args->done_bit);
vTaskDelete(NULL);
}
TEST_CASE("Task switching during secure service calls", "[basic]")
TEST_CASE("Test task switching during secure service calls", "[basic]")
{
esp_cpu_priv_mode_t world = esp_cpu_get_curr_privilege_level();
TEST_ASSERT_MESSAGE((world == ESP_CPU_NS_MODE), "Current world is not NS");
esp_cpu_priv_mode_t mode = esp_cpu_get_curr_privilege_level();
TEST_ASSERT_MESSAGE((mode == ESP_CPU_NS_MODE), "Incorrect privilege mode!");
xTaskCreate(test_task, "test_task", 4096, NULL, CONFIG_UNITY_FREERTOS_PRIORITY + 3, NULL);
test_task_eg = xEventGroupCreate();
TEST_ASSERT_NOT_NULL(test_task_eg);
const uint32_t a = 100, b = 200, iter = 8;
TEST_ASSERT_EQUAL_UINT32(a + b * iter, esp_tee_service_call(4, SS_ADD_IN_LOOP, a, b, iter));
uint32_t a = 0, b = 0;
world = esp_cpu_get_curr_privilege_level();
TEST_ASSERT_MESSAGE((world == ESP_CPU_NS_MODE), "Current world is not NS");
test_task_args_t task_args_1 = {
.id = 1,
.val = &a,
.done_bit = TEST_TASK_1_DONE_BIT
};
test_task_args_t task_args_2 = {
.id = 2,
.val = &b,
.done_bit = TEST_TASK_2_DONE_BIT
};
xTaskCreate(test_task, "test_task_1", 4096, (void *)&task_args_1, CONFIG_UNITY_FREERTOS_PRIORITY + 3, NULL);
xTaskCreate(test_task, "test_task_2", 4096, (void *)&task_args_2, CONFIG_UNITY_FREERTOS_PRIORITY + 3, NULL);
uint32_t val = esp_tee_service_call(3, SS_ESP_TEE_TEST_PRIV_MODE_SWITCH, &a, &b);
TEST_ASSERT_EQUAL_UINT32(ESP_TEE_TEST_INTR_ITER * 2, val);
EventBits_t bits = xEventGroupWaitBits(test_task_eg, TEST_TASK_1_DONE_BIT | TEST_TASK_2_DONE_BIT, pdTRUE, pdTRUE, portMAX_DELAY);
TEST_ASSERT_MESSAGE((bits & TEST_TASK_1_DONE_BIT), "Task 1 did not complete");
TEST_ASSERT_MESSAGE((bits & TEST_TASK_2_DONE_BIT), "Task 2 did not complete");
vEventGroupDelete(test_task_eg);
mode = esp_cpu_get_curr_privilege_level();
TEST_ASSERT_MESSAGE((mode == ESP_CPU_NS_MODE), "Incorrect privilege mode!");
}
TEST_CASE("Test TEE Heap: Malloc-write-free cycles", "[heap]")

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -17,90 +17,47 @@
#include "unity.h"
static const char *TAG = "test_esp_tee_intr";
#define TEST_TIMER_RESOLUTION_HZ (1000000ULL) // 1MHz, 1 tick = 1us
#define TIMER_ALARM_PERIOD_S (0.25f) // 250ms @ resolution 1MHz
static const char __attribute__((unused)) *TAG = "test_esp_tee_intr";
/* ---------------------------------------------------- Utility functions ---------------------------------------------------- */
typedef struct {
uint64_t event_count;
} test_queue_element_t;
static QueueHandle_t s_timer_queue;
static gptimer_handle_t gptimer = NULL;
static volatile uint32_t ns_int_count;
static bool IRAM_ATTR test_timer_on_alarm_cb(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data)
{
ESP_EARLY_LOGI(TAG, "Timer ISR Handler from World %d!", esp_cpu_get_curr_privilege_level());
BaseType_t high_task_awoken = pdFALSE;
QueueHandle_t queue = (QueueHandle_t)user_data;
// Retrieve count value and send to queue
test_queue_element_t ele = {
.event_count = edata->count_value
};
ns_int_count += 1;
xQueueSendFromISR(queue, &ele, &high_task_awoken);
// return whether we need to yield at the end of ISR
return (high_task_awoken == pdTRUE);
uint32_t *intr_count = (uint32_t *)user_data;
*intr_count = *intr_count + 1;
esp_rom_printf("[mode: %d] Interrupt triggered (%d)\n", esp_cpu_get_curr_privilege_level(), *intr_count);
return true;
}
static void IRAM_ATTR timer_evt_task(void *arg)
static void test_timer_init(volatile uint32_t *arg)
{
int record = 3;
while (1) {
test_queue_element_t ele;
if (xQueueReceive(s_timer_queue, &ele, pdMS_TO_TICKS(2000))) {
ESP_LOGI(TAG, "Timer reloaded, count=%llu", ele.event_count);
record--;
} else {
ESP_LOGW(TAG, "Missed one count event");
}
if (!record) {
break;
}
}
}
static void test_timer_init(bool for_ns_world)
{
s_timer_queue = xQueueCreate(10, sizeof(test_queue_element_t));
if (!s_timer_queue) {
ESP_LOGE(TAG, "Creating queue failed");
return;
}
ns_int_count = 0;
/* Select and initialize basic parameters of the timer */
gptimer_config_t timer_config = {
.clk_src = GPTIMER_CLK_SRC_DEFAULT,
.direction = GPTIMER_COUNT_UP,
.resolution_hz = 1000000, // 1MHz, 1 tick=1us
.resolution_hz = TEST_TIMER_RESOLUTION_HZ,
};
ESP_ERROR_CHECK(gptimer_new_timer(&timer_config, &gptimer));
gptimer_event_callbacks_t cbs = {
.on_alarm = test_timer_on_alarm_cb,
};
ESP_ERROR_CHECK(gptimer_register_event_callbacks(gptimer, &cbs, s_timer_queue));
ESP_ERROR_CHECK(gptimer_register_event_callbacks(gptimer, &cbs, (void *)arg));
ESP_ERROR_CHECK(gptimer_enable(gptimer));
gptimer_alarm_config_t alarm_config2 = {
.reload_count = 0,
.alarm_count = 250000, // Alarm target = 250ms @ resolution 1MHz
.alarm_count = TIMER_ALARM_PERIOD_S * TEST_TIMER_RESOLUTION_HZ,
.flags.auto_reload_on_alarm = true,
};
ESP_ERROR_CHECK(gptimer_set_alarm_action(gptimer, &alarm_config2));
ESP_ERROR_CHECK(gptimer_start(gptimer));
if (for_ns_world) {
timer_evt_task(NULL);
}
}
static void test_timer_deinit(void)
@@ -108,109 +65,80 @@ static void test_timer_deinit(void)
ESP_ERROR_CHECK(gptimer_stop(gptimer));
ESP_ERROR_CHECK(gptimer_disable(gptimer));
ESP_ERROR_CHECK(gptimer_del_timer(gptimer));
if (s_timer_queue != NULL) {
vQueueDelete(s_timer_queue);
s_timer_queue = NULL;
}
}
/* ---------------------------------------------------- Test cases ---------------------------------------------------- */
TEST_CASE("Test Secure interrupt in Non-Secure World", "[basic]")
TEST_CASE("Test TEE interrupt in TEE", "[basic]")
{
esp_cpu_priv_mode_t world = esp_cpu_get_curr_privilege_level();
TEST_ASSERT_MESSAGE((world == ESP_CPU_NS_MODE), "Current world is not NS");
esp_cpu_priv_mode_t mode = esp_cpu_get_curr_privilege_level();
TEST_ASSERT_MESSAGE((mode == ESP_CPU_NS_MODE), "Incorrect privilege mode!");
volatile uint32_t lsecure_int_count = 0;
uint32_t val = esp_tee_service_call(1, SS_ESP_TEE_TEST_TEE_INTR_IN_TEE);
TEST_ASSERT_EQUAL_UINT32(ESP_TEE_TEST_INTR_ITER, val);
/* Pass the variable to secure world to record the interrupt count. */
esp_tee_service_call(2, SS_ESP_TEE_TEST_INT_COUNT, &lsecure_int_count);
world = esp_cpu_get_curr_privilege_level();
TEST_ASSERT_MESSAGE((world == ESP_CPU_NS_MODE), "World switch failed");
esp_tee_service_call(2, SS_ESP_TEE_TEST_TIMER_INIT, true);
world = esp_cpu_get_curr_privilege_level();
TEST_ASSERT_MESSAGE((world == ESP_CPU_NS_MODE), "World switch failed");
/* Secure timer initialized.
* As secure timer interrupt will fire; CPU will switch to secure world.
* Secure world ISR handler will be called, Secure ISR log can be observed on console.
* After handling the secure interrupt, CPU will return to non-secure world
* and resume this loop and wait for the next secure timer interrupt.
* CPU will wait for TEE_TEST_INT_COUNT number of secure interrupts.
*/
while (lsecure_int_count < TEE_TEST_INT_COUNT);
/* After waiting for TEE_TEST_INT_COUNT secure interrupt,
* disable the secure timer and assert the test status.
*/
esp_tee_service_call(2, SS_ESP_TEE_TEST_TIMER_INIT, false);
world = esp_cpu_get_curr_privilege_level();
TEST_ASSERT_MESSAGE((world == ESP_CPU_NS_MODE), "World switch failed");
/* Assert the number of secure interrupt occurred again. */
TEST_ASSERT_EQUAL_UINT32(TEE_TEST_INT_COUNT, lsecure_int_count);
mode = esp_cpu_get_curr_privilege_level();
TEST_ASSERT_MESSAGE((mode == ESP_CPU_NS_MODE), "Incorrect privilege mode!");
}
TEST_CASE("Test Secure interrupt in Secure World", "[basic]")
TEST_CASE("Test REE interrupt in REE", "[basic]")
{
esp_cpu_priv_mode_t world = esp_cpu_get_curr_privilege_level();
TEST_ASSERT_MESSAGE((world == ESP_CPU_NS_MODE), "Current world is not NS");
esp_cpu_priv_mode_t mode = esp_cpu_get_curr_privilege_level();
TEST_ASSERT_MESSAGE((mode == ESP_CPU_NS_MODE), "Incorrect privilege mode!");
uint32_t cnt = esp_tee_service_call(1, SS_ESP_TEE_SECURE_INT_TEST);
TEST_ASSERT_EQUAL_UINT32(TEE_TEST_INT_COUNT, cnt);
world = esp_cpu_get_curr_privilege_level();
TEST_ASSERT_MESSAGE((world == ESP_CPU_NS_MODE), "World switch failed");
volatile uint32_t ree_intr_count = 0;
test_timer_init(&ree_intr_count);
while (ree_intr_count < ESP_TEE_TEST_INTR_ITER) {
vTaskDelay(pdMS_TO_TICKS(250));
}
test_timer_deinit();
}
static volatile uint32_t *get_ns_int_count(void)
TEST_CASE("Test REE interrupt in TEE", "[basic]")
{
return &ns_int_count;
}
esp_cpu_priv_mode_t mode = esp_cpu_get_curr_privilege_level();
TEST_ASSERT_MESSAGE((mode == ESP_CPU_NS_MODE), "Incorrect privilege mode!");
TEST_CASE("Test Non-secure interrupt in Secure World", "[basic]")
{
esp_cpu_priv_mode_t world = esp_cpu_get_curr_privilege_level();
TEST_ASSERT_MESSAGE((world == ESP_CPU_NS_MODE), "Current world is not W1");
volatile uint32_t ree_intr_count = 0;
volatile uint32_t *volatile ree_intr_count_ptr = &ree_intr_count;
/* Non-secure world timer initialization. */
ESP_LOGI(TAG, "Enabling test timer from non-secure world");
test_timer_init(false);
test_timer_init(ree_intr_count_ptr);
volatile uint32_t *volatile lns_int_count;
lns_int_count = get_ns_int_count();
/* After non-secure timer initialization,
* CPU will switch to secure world by using a service call to test API.
* CPU will wait in finite loop in secure world.
* And as non-secure timer interrupt fires, CPU will switch to non-secure world.
* Non-secure world ISR handler will be called, non-secure ISR log can be obsereved on console.
* After handling the interrupt in non-secure world, CPU will switch back to secure world
* and wait for the next timer interrupt.
* In secure world CPU will wait for TEE_TEST_INT_COUNT non-secure interrupts.
*/
uint32_t val = esp_tee_service_call(2, SS_ESP_TEE_NON_SECURE_INT_TEST, lns_int_count);
uint32_t val = esp_tee_service_call(2, SS_ESP_TEE_TEST_REE_INTR_IN_TEE, ree_intr_count_ptr);
TEST_ASSERT_EQUAL_UINT32(0, val);
world = esp_cpu_get_curr_privilege_level();
TEST_ASSERT_MESSAGE((world == ESP_CPU_NS_MODE), "World switch failed");
ESP_LOGI(TAG, "Disabling test timer from non-secure world");
test_timer_deinit();
mode = esp_cpu_get_curr_privilege_level();
TEST_ASSERT_MESSAGE((mode == ESP_CPU_NS_MODE), "Incorrect privilege mode!");
}
TEST_CASE("Test Non-secure interrupt in Non-Secure World", "[basic]")
TEST_CASE("Test TEE interrupt in REE", "[basic]")
{
esp_cpu_priv_mode_t world = esp_cpu_get_curr_privilege_level();
TEST_ASSERT_MESSAGE((world == ESP_CPU_NS_MODE), "Current world is not NS");
esp_cpu_priv_mode_t mode = esp_cpu_get_curr_privilege_level();
TEST_ASSERT_MESSAGE((mode == ESP_CPU_NS_MODE), "Incorrect privilege mode!");
ESP_LOGI(TAG, "Enabling test timer from non-secure world");
test_timer_init(true);
volatile uint32_t tee_intr_count = 0;
volatile uint32_t *volatile tee_intr_count_ptr = &tee_intr_count;
esp_tee_service_call(3, SS_ESP_TEE_TEST_TEE_INTR_IN_REE, 0, tee_intr_count_ptr);
vTaskDelay(pdMS_TO_TICKS(1000));
uint32_t prev_count = 0;
while (true) {
uint32_t curr_count = *tee_intr_count_ptr;
if (curr_count > prev_count) {
prev_count = curr_count;
esp_rom_printf("[mode: %d] Interrupt received (%d)\n", esp_cpu_get_curr_privilege_level(), curr_count);
}
if (curr_count >= ESP_TEE_TEST_INTR_ITER) {
break;
}
vTaskDelay(pdMS_TO_TICKS(1));
}
ESP_LOGI(TAG, "Disabling test timer from non-secure world");
test_timer_deinit();
esp_tee_service_call(3, SS_ESP_TEE_TEST_TEE_INTR_IN_REE, 1, NULL);
TEST_ASSERT_EQUAL_UINT32(ESP_TEE_TEST_INTR_ITER, tee_intr_count);
mode = esp_cpu_get_curr_privilege_level();
TEST_ASSERT_MESSAGE((mode == ESP_CPU_NS_MODE), "Incorrect privilege mode!");
}