![]() |
RT-Thread RTOS
An open source embedded real-time operating system
|
Header: **components/drivers/include/drivers/tee.h**. Core: **components/drivers/tee/tee.c**.
The TEE layer provides a GlobalPlatform-style client API for talking to a Trusted Execution Environment from the normal world. Hardware or firmware backends implement **rt_tee_ops** (version query, session management, command invocation, shared memory registration). The core serializes access with a per-device mutex, tracks registered shared-memory objects, and registers a searchable device node (tee0, tee1, …).
An OP-TEE backend lives under **components/drivers/tee/optee/** and is selected when **RT_TEE_OPTEE** is enabled.
Requires **RT_USING_TEE** (Kconfig) and **RT_USING_DM**.
| Use TEE when… | Prefer something else when… |
|---|---|
| The platform runs OP-TEE (or another GP-compliant TEE) and exposes Trusted Applications (TAs). | Secrets can stay in normal-world software with adequate isolation — no TEE required. |
| You need crypto, secure storage, or RNG inside a TA with a defined UUID/command model. | Single-purpose on-chip crypto — a dedicated hwcrypto driver may suffice. |
Firmware provides a DT node such as **linaro,optee-tz**. | No secure world firmware — enable and port a TEE OS first. |
SoC-specific backends may be added under **/Kconfig** when present.
| Role | Responsibility |
|---|---|
| TEE backend driver | Embeds **struct rt_tee_device**, fills **rt_tee_ops**, calls **rt_tee_device_register**. Translates GP requests to SMC/HVC, mailbox, or other transport. |
| Client / TA user | Finds **tee0**, opens a session to a TA UUID, registers shared memory, invokes TA commands. Checks both **rt_err_t** (transport) and **arg->ret** (TEE status). |
The core registers each device as **RT_Device_Class_Char** with **RT_DEVICE_FLAG_DEACTIVATE**. There is no generic read/write/control path in **tee.c** — use the **rt_tee_*** helpers.
All public entry points take **tdev->mutex** except registration helpers.
Parameters follow GlobalPlatform attribute encoding:
attr | Meaning |
|---|---|
TEE_PARAM_ATTR_TYPE_NONE | Unused slot |
TEE_PARAM_ATTR_TYPE_VALUE_IN/OUT/IN_OUT | Three 64-bit values in **value.a/b/c** |
TEE_PARAM_ATTR_TYPE_MEMREF_IN/OUT/IN_OUT | Shared memory reference via **memref.shm**, offset, size |
Flexible arrays append parameters to the end of open/invoke argument blocks:
| Flag | Usage |
|---|---|
**TEE_SHM_SYS** | Core allocates backing store in **rt_tee_shm_register** via **rt_tee_shm_alloc_helper** (page allocator or aligned malloc). Caller must **rt_tee_shm_free_helper** after unregister. |
**TEE_SHM_USER** | Caller supplies **vaddr** (and optionally **paddr**); core resolves physical address when missing. |
**TEE_SHM_DRV** | Driver-owned buffer; registration requires **vaddr** already set. |
Transport failures use **rt_err_t** (-RT_EINVAL, -RT_ENOMEM, -RT_ENOSYS, …). TEE-side status is returned in **arg->ret** with origin **arg->ret_origin**:
| Code | Macro |
|---|---|
| Success | **RT_TEE_SUCCESS** (0) |
| Bad parameters | **RT_TEE_ERROR_BAD_PARAMETERS** |
| Not supported | **RT_TEE_ERROR_NOT_SUPPORTED** |
| Out of memory | **RT_TEE_ERROR_OUT_OF_MEMORY** |
| Communication error | **RT_TEE_ERROR_COMMUNICATION** |
| … | See **tee.h** for the full list |
Origins: **RT_TEE_ORIGIN_COMMS**, **RT_TEE_ORIGIN_TEE**, **RT_TEE_ORIGIN_TRUSTED_APP**.
Always check both the function return value and **arg->ret** on open/invoke.
**rt_tee_device_register** requires **tdev** and **tdev->ops**. Device name is **tee<N>**.
**rt_tee_device_unregister**:
ref_count != 0**shm_nodes**mutex** after successful device unregisterTypical flow:
open_session_arg** with room for trailing **params[]**uuid** (TA) and optional client identity fieldsrt_tee_open_session** — on success read **arg->session**, verify **arg->ret == RT_TEE_SUCCESS**invoke_arg**, set **func**, **session**, parametersrt_tee_invoke** — verify **arg->ret**rt_tee_close_session**, unregister/free SHM, close device**rt_tee_shm_register**:
TEE_SHM_SYS** (without **TEE_SHM_DRV**): allocates memory, then calls **ops->shm_register**shm** into **tdev->shm_nodes****rt_tee_shm_unregister** removes the node and calls **ops->shm_unregister**. Call **rt_tee_shm_free_helper** afterward when the core allocated the buffer.
Files: components/drivers/tee/optee/optee.c, optee_msg.h, optee_smc.h
Platform driver: optee-smc, compatible **linaro,optee-tz**
| Property | Values | Notes |
|---|---|---|
**compatible** | "linaro,optee-tz" | Required |
**method** | "smc" (default) or "hvc" | Selects **arm_smccc_smc** vs **arm_smccc_hvc** |
At probe time the driver:
method**OPTEE_SMC_CALLS_UID**OPTEE_SMC_SEC_CAP_DYNAMIC_SHM** from capability exchangestruct rt_tee_device** with **optee_ops****call_with_arg** handles OP-TEE RPC returns while a secure-world call is in flight:
| RPC function | Handled behavior |
|---|---|
**OPTEE_SMC_RPC_FUNC_ALLOC / FREE** | Temporary RPC buffer alloc/free |
**OPTEE_SMC_RPC_FUNC_CMD** | **supplicant_cmd**: SHM alloc/free, optional I2C transfer (RT_USING_I2C) |
**OPTEE_SMC_RPC_FUNC_FOREIGN_INTR** | No-op placeholder |
Shared memory passed to the secure world uses non-contiguous page lists built from physically contiguous normal-world pages.
With **RT_TEE_OPTEE_EXAMPLES**, build OP-TEE for your platform with the hwrng TA (see OP-TEE QEMU documentation), then run:
The example opens **tee0**, opens a session to the hwrng TA UUID, registers a 32-byte output buffer, invokes command **0x0 (GET_ENTROPY)**, and prints the result.
Source: **components/drivers/tee/optee/optee_examples.c**
| Issue | Mitigation |
|---|---|
Ignoring arg->ret | **RT_EOK** from **rt_tee_invoke** only means the message reached the backend; check **invoke->ret**. |
| SHM leak | Always **rt_tee_shm_unregister** then **rt_tee_shm_free_helper** for **TEE_SHM_SYS** buffers. |
| Unregister with active refs | **rt_tee_device_unregister** fails when **ref_count != 0** — close clients first. |
| OP-TEE without dynamic SHM | Probe fails if **OPTEE_SMC_SEC_CAP_DYNAMIC_SHM** is absent — use a matching OP-TEE build. |
| Missing TA | **RT_TEE_ERROR_ITEM_NOT_FOUND** / session open failure — deploy the TA binary to OP-TEE. |
| I2C RPC | OP-TEE I2C supplicant calls require **RT_USING_I2C** and a bus named **i2c<N>**. |
| Cache coherency | OP-TEE backend flushes/invalidates caches around shared message buffers; user SHM must remain in memory visible to both worlds. |
components/drivers/tee/tee.ccomponents/drivers/tee/optee/optee.ccomponents/drivers/include/drivers/tee.h