feat(esp_tee): Support for ESP-TEE - riscv component

This commit is contained in:
Laukik Hase 2024-10-03 13:54:10 +05:30
parent 733741bbac
commit e51d2c1da3
No known key found for this signature in database
GPG Key ID: D6F3208C06086AC8
7 changed files with 306 additions and 26 deletions

View File

@ -1,5 +1,6 @@
idf_build_get_property(target IDF_TARGET)
idf_build_get_property(arch IDF_TARGET_ARCH)
idf_build_get_property(esp_tee_build ESP_TEE_BUILD)
if(NOT "${arch}" STREQUAL "riscv")
return()
@ -8,6 +9,11 @@ endif()
if(BOOTLOADER_BUILD)
set(priv_requires soc)
elseif(esp_tee_build)
set(priv_requires soc)
if(CONFIG_SOC_INT_PLIC_SUPPORTED)
set(srcs "interrupt_plic.c")
endif()
else()
set(priv_requires soc)
set(srcs

View File

@ -12,6 +12,7 @@
#include "soc/interrupt_reg.h"
#include "soc/soc_caps.h"
#include "riscv/csr.h"
#include "sdkconfig.h"
#if SOC_INT_PLIC_SUPPORTED
@ -84,12 +85,34 @@ FORCE_INLINE_ATTR void rv_utils_restore_intlevel_regval(uint32_t restoreval)
*/
FORCE_INLINE_ATTR uint32_t rv_utils_set_intlevel_regval(uint32_t intlevel)
{
#if CONFIG_SECURE_ENABLE_TEE
unsigned prv_mode = RV_READ_CSR(CSR_PRV_MODE);
unsigned old_xstatus;
if (prv_mode == PRV_M) {
old_xstatus = RV_CLEAR_CSR(mstatus, MSTATUS_MIE);
} else {
old_xstatus = RV_CLEAR_CSR(ustatus, USTATUS_UIE);
}
uint32_t old_thresh = REG_READ(INTERRUPT_CURRENT_CORE_INT_THRESH_REG);
rv_utils_restore_intlevel_regval(intlevel);
if (prv_mode == PRV_M) {
RV_SET_CSR(mstatus, old_xstatus & MSTATUS_MIE);
} else {
RV_SET_CSR(ustatus, old_xstatus & USTATUS_UIE);
}
return old_thresh;
#else
uint32_t old_mstatus = RV_CLEAR_CSR(mstatus, MSTATUS_MIE);
uint32_t old_thresh = REG_READ(INTERRUPT_CURRENT_CORE_INT_THRESH_REG);
rv_utils_restore_intlevel_regval(intlevel);
RV_SET_CSR(mstatus, old_mstatus & MSTATUS_MIE);
return old_thresh;
#endif
}

View File

@ -187,6 +187,13 @@ extern "C" {
#define STPC1 0xBF1
#define STPC2 0xBF2
/* Espressif's custom CSR for the current privilege mode */
#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
#define CSR_PRV_MODE 0xC10
#elif CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C61 || CONFIG_IDF_TARGET_ESP32P4
#define CSR_PRV_MODE 0x810
#endif
/* RISC-V CSR macros
* Adapted from https://github.com/michaeljclark/riscv-probe/blob/master/libfemto/include/arch/riscv/machine.h
*/

View File

@ -146,6 +146,21 @@ bool esprv_int_is_vectored(int rv_int_num);
*/
void esprv_int_set_vectored(int rv_int_num, bool vectored);
/*************************** ESP-TEE specific ***************************/
/** Function prototype executing interrupt configuration APIs as service calls */
typedef void (*esprv_int_mgmt_t)(int argc, ...);
/**
* @brief Setup the callback function which executes the interrupt
* configuration APIs as TEE service calls
*
* @note This function should be called right after landing in the REE application,
* before any system initialization
*
* @param fptr Pointer to the function
*/
void esprv_int_setup_mgmt_cb(void *fptr);
/**
* Include the deprecated functions last since they will alias the functions declared above

View File

@ -15,16 +15,38 @@
#include "riscv/csr.h"
#include "riscv/interrupt.h"
#include "riscv/csr_pie.h"
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Check whether the current privilege level is Machine (M) mode */
#if CONFIG_SECURE_ENABLE_TEE
#define IS_PRV_M_MODE() (RV_READ_CSR(CSR_PRV_MODE) == PRV_M)
#else
#define IS_PRV_M_MODE() (1UL)
#endif
#if CONFIG_SECURE_ENABLE_TEE && !ESP_TEE_BUILD
/* [ESP-TEE] Secure service call IDs for interrupt management */
#define TEE_INTR_ENABLE_SRV_ID (2)
#define TEE_INTR_DISABLE_SRV_ID (3)
#define TEE_INTR_SET_PRIORITY_SRV_ID (4)
#define TEE_INTR_SET_TYPE_SRV_ID (5)
#define TEE_INTR_SET_THRESHOLD_SRV_ID (6)
#define TEE_INTR_EDGE_ACK_SRV_ID (7)
#define TEE_INTR_GLOBAL_EN_SRV_ID (8)
/* [ESP-TEE] Callback function for accessing interrupt management services through REE */
extern esprv_int_mgmt_t esp_tee_intr_sec_srv_cb;
#endif
#if SOC_CPU_HAS_CSR_PC
/*performance counter*/
#define CSR_PCER_MACHINE 0x7e0
#define CSR_PCMR_MACHINE 0x7e1
#define CSR_PCCR_MACHINE 0x7e2
#define CSR_PCCR_USER 0x802
#endif /* SOC_CPU_HAS_CSR_PC */
#if SOC_BRANCH_PREDICTOR_SUPPORTED
@ -89,7 +111,11 @@ FORCE_INLINE_ATTR uint32_t __attribute__((always_inline)) rv_utils_get_cycle_cou
#if !SOC_CPU_HAS_CSR_PC
return RV_READ_CSR(mcycle);
#else
return RV_READ_CSR(CSR_PCCR_MACHINE);
if (IS_PRV_M_MODE()) {
return RV_READ_CSR(CSR_PCCR_MACHINE);
} else {
return RV_READ_CSR(CSR_PCCR_USER);
}
#endif
}
@ -98,7 +124,11 @@ FORCE_INLINE_ATTR void __attribute__((always_inline)) rv_utils_set_cycle_count(u
#if !SOC_CPU_HAS_CSR_PC
RV_WRITE_CSR(mcycle, ccount);
#else
RV_WRITE_CSR(CSR_PCCR_MACHINE, ccount);
if (IS_PRV_M_MODE()) {
RV_WRITE_CSR(CSR_PCCR_MACHINE, ccount);
} else {
RV_WRITE_CSR(CSR_PCCR_USER, ccount);
}
#endif
}
@ -113,32 +143,89 @@ FORCE_INLINE_ATTR void rv_utils_set_mtvec(uint32_t mtvec_val)
RV_WRITE_CSR(mtvec, mtvec_val | MTVEC_MODE_CSR);
}
FORCE_INLINE_ATTR void rv_utils_set_xtvec(uint32_t xtvec_val)
{
xtvec_val |= MTVEC_MODE_CSR; // Set MODE field to treat XTVEC as a vector base address
if (IS_PRV_M_MODE()) {
RV_WRITE_CSR(mtvec, xtvec_val);
} else {
RV_WRITE_CSR(utvec, xtvec_val);
}
}
// ------------------ Interrupt Control --------------------
FORCE_INLINE_ATTR void rv_utils_intr_enable(uint32_t intr_mask)
{
#if CONFIG_SECURE_ENABLE_TEE && !ESP_TEE_BUILD
esp_tee_intr_sec_srv_cb(2, TEE_INTR_ENABLE_SRV_ID, intr_mask);
#else
// Disable all interrupts to make updating of the interrupt mask atomic.
unsigned old_mstatus = RV_CLEAR_CSR(mstatus, MSTATUS_MIE);
esprv_int_enable(intr_mask);
RV_SET_CSR(mstatus, old_mstatus & MSTATUS_MIE);
#endif
}
FORCE_INLINE_ATTR void rv_utils_intr_disable(uint32_t intr_mask)
{
#if CONFIG_SECURE_ENABLE_TEE && !ESP_TEE_BUILD
esp_tee_intr_sec_srv_cb(2, TEE_INTR_DISABLE_SRV_ID, intr_mask);
#else
// Disable all interrupts to make updating of the interrupt mask atomic.
unsigned old_mstatus = RV_CLEAR_CSR(mstatus, MSTATUS_MIE);
esprv_int_disable(intr_mask);
RV_SET_CSR(mstatus, old_mstatus & MSTATUS_MIE);
#endif
}
FORCE_INLINE_ATTR void rv_utils_intr_global_enable(void)
{
#if CONFIG_SECURE_ENABLE_TEE && !ESP_TEE_BUILD
esp_tee_intr_sec_srv_cb(1, TEE_INTR_GLOBAL_EN_SRV_ID);
#else
RV_SET_CSR(mstatus, MSTATUS_MIE);
#endif
}
FORCE_INLINE_ATTR void rv_utils_intr_global_disable(void)
{
#if CONFIG_SECURE_ENABLE_TEE
if (IS_PRV_M_MODE()) {
RV_CLEAR_CSR(mstatus, MSTATUS_MIE);
} else {
RV_CLEAR_CSR(ustatus, USTATUS_UIE);
}
#else
RV_CLEAR_CSR(mstatus, MSTATUS_MIE);
#endif
}
FORCE_INLINE_ATTR void rv_utils_intr_set_type(int intr_num, enum intr_type type)
{
#if CONFIG_SECURE_ENABLE_TEE && !ESP_TEE_BUILD
esp_tee_intr_sec_srv_cb(3, TEE_INTR_SET_TYPE_SRV_ID, intr_num, type);
#else
esprv_int_set_type(intr_num, type);
#endif
}
FORCE_INLINE_ATTR void rv_utils_intr_set_priority(int rv_int_num, int priority)
{
#if CONFIG_SECURE_ENABLE_TEE && !ESP_TEE_BUILD
esp_tee_intr_sec_srv_cb(3, TEE_INTR_SET_PRIORITY_SRV_ID, rv_int_num, priority);
#else
esprv_int_set_priority(rv_int_num, priority);
#endif
}
FORCE_INLINE_ATTR void rv_utils_intr_set_threshold(int priority_threshold)
{
#if CONFIG_SECURE_ENABLE_TEE && !ESP_TEE_BUILD
esp_tee_intr_sec_srv_cb(2, TEE_INTR_SET_THRESHOLD_SRV_ID, priority_threshold);
#else
esprv_int_set_threshold(priority_threshold);
#endif
}
/**
@ -352,8 +439,12 @@ FORCE_INLINE_ATTR bool rv_utils_compare_and_set(volatile uint32_t *addr, uint32_
);
#else
// For a single core RV target has no atomic CAS instruction, we can achieve atomicity by disabling interrupts
unsigned old_mstatus;
old_mstatus = RV_CLEAR_CSR(mstatus, MSTATUS_MIE);
unsigned old_xstatus;
if (IS_PRV_M_MODE()) {
old_xstatus = RV_CLEAR_CSR(mstatus, MSTATUS_MIE);
} else {
old_xstatus = RV_CLEAR_CSR(ustatus, USTATUS_UIE);
}
// Compare and set
uint32_t old_value;
old_value = *addr;
@ -361,7 +452,11 @@ FORCE_INLINE_ATTR bool rv_utils_compare_and_set(volatile uint32_t *addr, uint32_
*addr = new_value;
}
// Restore interrupts
RV_SET_CSR(mstatus, old_mstatus & MSTATUS_MIE);
if (IS_PRV_M_MODE()) {
RV_SET_CSR(mstatus, old_xstatus & MSTATUS_MIE);
} else {
RV_SET_CSR(ustatus, old_xstatus & USTATUS_UIE);
}
#endif //__riscv_atomic
return (old_value == compare_value);

View File

@ -4,7 +4,10 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include "soc/soc_caps.h"
#include "riscv/csr.h"
#include "riscv/interrupt.h"
#include "riscv/rv_utils.h"
#include "esp_private/interrupt_plic.h"
#include "hal/interrupt_plic_ll.h"
@ -18,19 +21,35 @@ void intr_matrix_route(int intr_src, int intr_num)
uint32_t esprv_get_interrupt_unmask(void)
{
return interrupt_plic_ll_get_unmask();
if (IS_PRV_M_MODE()) {
return REG_READ(PLIC_MXINT_ENABLE_REG);
} else {
return REG_READ(PLIC_UXINT_ENABLE_REG);
}
}
enum intr_type esprv_int_get_type(int rv_int_num)
{
return interrupt_plic_ll_get_type(rv_int_num) ? INTR_TYPE_EDGE : INTR_TYPE_LEVEL;
uint32_t intr_type_reg;
if (IS_PRV_M_MODE()) {
intr_type_reg = REG_READ(PLIC_MXINT_TYPE_REG);
} else {
intr_type_reg = REG_READ(PLIC_UXINT_TYPE_REG);
}
return (intr_type_reg & (1 << rv_int_num)) ? INTR_TYPE_EDGE : INTR_TYPE_LEVEL;
}
int esprv_int_get_priority(int rv_int_num)
{
return interrupt_plic_ll_get_priority(rv_int_num);
if (IS_PRV_M_MODE()) {
return REG_READ(PLIC_MXINT0_PRI_REG + (rv_int_num) * 4);
} else {
return REG_READ(PLIC_UXINT0_PRI_REG + (rv_int_num) * 4);
}
}
@ -38,3 +57,44 @@ bool esprv_int_is_vectored(int rv_int_num)
{
return true;
}
#if CONFIG_SECURE_ENABLE_TEE && !ESP_TEE_BUILD
DRAM_ATTR esprv_int_mgmt_t esp_tee_intr_sec_srv_cb = NULL;
void esprv_int_setup_mgmt_cb(void *fptr)
{
esp_tee_intr_sec_srv_cb = (esprv_int_mgmt_t)fptr;
}
/* NOTE: Overriding ROM-based interrupt configuration symbols */
void esprv_int_enable(uint32_t unmask)
{
rv_utils_intr_enable(unmask);
}
void esprv_int_disable(uint32_t mask)
{
rv_utils_intr_disable(mask);
}
void esprv_int_set_type(int intr_num, enum intr_type type)
{
rv_utils_intr_set_type(intr_num, type);
}
void esprv_int_set_priority(int rv_int_num, int priority)
{
rv_utils_intr_set_priority(rv_int_num, priority);
}
void esprv_int_set_threshold(int priority_threshold)
{
rv_utils_intr_set_threshold(priority_threshold);
}
#endif

View File

@ -76,11 +76,39 @@
sw t6, RV_STK_T6(sp)
.endm
.macro save_mepc
/* Macro for saving special registers depending on the active execution
* environment - REE - U-mode / TEE - M-mode */
/* Save the XEPC register */
.macro save_xepc
#if CONFIG_SECURE_ENABLE_TEE
csrr t0, uepc
#else
csrr t0, mepc
#endif
sw t0, RV_STK_MEPC(sp)
.endm
/* Save the required CSRs */
.macro save_xcsr
#if CONFIG_SECURE_ENABLE_TEE
csrr t0, ustatus
sw t0, RV_STK_MSTATUS(sp)
csrr t0, utvec
sw t0, RV_STK_MTVEC(sp)
csrr t0, utval
sw t0, RV_STK_MTVAL(sp)
#else
csrr t0, mstatus
sw t0, RV_STK_MSTATUS(sp)
csrr t0, mtvec
sw t0, RV_STK_MTVEC(sp)
csrr t0, mhartid
sw t0, RV_STK_MHARTID(sp)
csrr t0, mtval
sw t0, RV_STK_MTVAL(sp)
#endif
.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. */
@ -117,11 +145,49 @@
addi sp,sp, \cxt_size
.endm
.macro restore_mepc
/* Macro for restoring special registers depending on the active execution
* environment - REE - U-mode / TEE - M-mode */
/* Restore the XEPC register depending on the active execution
* environment - REE - U-mode / TEE - M-mode */
.macro restore_xepc
lw t0, RV_STK_MEPC(sp)
#if CONFIG_SECURE_ENABLE_TEE
csrw uepc, t0
#else
csrw mepc, t0
#endif
.endm
/* Macros for enabling/disabling the global interrupts based on the
* active execution environment - REE - U-mode / TEE - M-mode */
.macro enable_intr
#if CONFIG_SECURE_ENABLE_TEE
li t0, 0x1
csrs ustatus, t0
#else
li t0, 0x8
csrs mstatus, t0
#endif
.endm
.macro disable_intr
#if CONFIG_SECURE_ENABLE_TEE
li t0, 0x1
csrc ustatus, t0
#else
li t0, 0x8
csrc mstatus, t0
#endif
.endm
.macro xret
#if CONFIG_SECURE_ENABLE_TEE
uret
#else
mret
#endif
.endm
.global rtos_int_enter
.global rtos_int_exit
@ -148,19 +214,15 @@ _panic_handler:
/* Save CSRs */
sw t0, RV_STK_SP(sp)
csrr t0, mepc
sw t0, RV_STK_MEPC(sp)
csrr t0, mstatus
sw t0, RV_STK_MSTATUS(sp)
csrr t0, mtvec
sw t0, RV_STK_MTVEC(sp)
csrr t0, mhartid
sw t0, RV_STK_MHARTID(sp)
csrr t0, mtval
sw t0, RV_STK_MTVAL(sp)
save_xepc
save_xcsr
/* Keep mcause in s0, only the exception code and interrupt bit are relevant */
#if CONFIG_SECURE_ENABLE_TEE
csrr s0, ucause
#else
csrr s0, mcause
#endif
li t1, VECTORS_MCAUSE_INTBIT_MASK | VECTORS_MCAUSE_REASON_MASK
and s0, s0, t1
@ -274,7 +336,7 @@ _store_mcause:
* Restore the registers and return from the exception.
*/
_return_from_exception:
restore_mepc
restore_xepc
/* MTVEC and SP are assumed to be unmodified.
* MSTATUS, MHARTID, MTVAL are read-only and not restored.
*/
@ -290,12 +352,14 @@ _return_from_exception:
* from the stack.
*/
.global _interrupt_handler
.global _tee_interrupt_handler
.type _interrupt_handler, @function
_interrupt_handler:
_tee_interrupt_handler:
/* Start by saving the general purpose registers and the PC value before
* the interrupt happened. */
save_general_regs
save_mepc
save_xepc
/* Though it is not necessary we save GP and SP here.
* SP is necessary to help GDB to properly unwind
@ -317,8 +381,13 @@ _interrupt_handler:
/* If this is a non-nested interrupt, SP now points to the interrupt stack */
/* Before dispatch c handler, restore interrupt to enable nested intr */
#if CONFIG_SECURE_ENABLE_TEE
csrr s1, ucause
csrr s2, ustatus
#else
csrr s1, mcause
csrr s2, mstatus
#endif
#if !SOC_INT_HW_NESTED_SUPPORTED
/* Save the interrupt threshold level */
@ -337,7 +406,7 @@ _interrupt_handler:
fence
#endif // !SOC_INT_HW_NESTED_SUPPORTED
csrsi mstatus, 0x8
enable_intr
/* MIE set. Nested interrupts can now occur */
#ifdef CONFIG_PM_TRACE
@ -366,7 +435,7 @@ _interrupt_handler:
/* After dispatch c handler, disable interrupt to make freertos make context switch */
csrci mstatus, 0x8
disable_intr
/* MIE cleared. Nested interrupts are disabled */
#if !SOC_INT_HW_NESTED_SUPPORTED
@ -386,10 +455,15 @@ _interrupt_handler:
* In case the target uses the CLIC, it is mandatory to restore `mcause` register since it contains
* the former CPU priority. When executing `mret`, the hardware will restore the former threshold,
* from `mcause` to `mintstatus` CSR */
#if CONFIG_SECURE_ENABLE_TEE
csrw ucause, s1
csrw ustatus, a0
#else
csrw mcause, s1
csrw mstatus, a0
restore_mepc
#endif
restore_xepc
restore_general_regs
/* exit, this will also re-enable the interrupts */
mret
xret
.size _interrupt_handler, .-_interrupt_handler