type
status
date
slug
summary
tags
category
icon
password
The code is based on: https://gitlab.com/riseproject/riscv-optee/linux/-/tree/dev-optee-mpxy
Commit ID:
df5dc01764820f113312f7a39f221b49985bbd7a- OP-TEE provides a pseudo Trusted Application (PTA):
drivers/tee/optee/device.cin order to support device enumeration. In other words, OP-TEE driver invokes this application to retrieve a list of Trusted Applications which can be registered as devices on the TEE bus.
do_initcalls()
optee_core_init()optee_smc_abi_register()optee_ffa_abi_register()- Not supported in RISC-V.
optee_smc_abi_register()- Register
optee_driver.
optee_probe()sbi_mpxy_tee_probe()- Get invoke function.
- E.g.
optee_smccc_smc() - P.S. SMCCC = SMC Calling Convention, defined by ARM.
optee_msg_api_uid_is_optee_api()- Check UUID:
- Call the invoke function, e.g.
optee_smccc_smc()with function ID:OPTEE_SMC_CALLS_UIDto retrieve the UUID. - OP-TEE will return UUID. Return
trueif the returned UUID isOPTEE_MSG_UID(384fb3e0-e7f8-11e3-af63-0002a5d5c51b),falseotherwise. optee_msg_get_os_revision()- Get OS revision
- Call the invoke function, e.g.
optee_smccc_smc()with function ID:OPTEE_SMC_CALL_GET_OS_REVISIONto get OS version. - OP-TEE will return the OS revision.
optee_msg_api_revision_is_compatible()- Check whether the API revision is compatible:
- Call the invoke function, e.g.
optee_smccc_smc()with function ID:OPTEE_SMC_CALLS_REVISIONto retrieve the API revision. - OP-TEE will return the API revision. Return
trueif the returned API revision isOPTEE_MSG_REVISION(2.0),falseotherwise. optee_msg_get_thread_count()- Get OP-TEE thread count:
- Call the invoke function, e.g.
optee_smccc_smc()with function ID:OPTEE_SMC_GET_THREAD_COUNTto get the OP-TEE thread count. optee_msg_exchange_capabilities()- Exchange capabilities between Linux and OP-TEE:
- Linux sets:
- If UP,
OPTEE_SMC_NSEC_CAP_UNIPROCESSOR. - Call the invoke function, e.g.
optee_smccc_smc()with function ID:OPTEE_SMC_EXCHANGE_CAPABILITIESto exchange the capabilities between Linux and OP-TEE. - OP-TEE sets:
- If reserved shared memory is enabled in secure world:
OPTEE_ABI_SEC_CAP_HAVE_RESERVED_SHM. - If dynamic shared memory is enabled in secure world:
OPTEE_ABI_SEC_CAP_DYNAMIC_SHM. - If virtualization is enabled in secure world:
OPTEE_ABI_SEC_CAP_VIRTUALIZATION. - Shared memory with a NULL reference is supported in secure world:
OPTEE_ABI_SEC_CAP_MEMREF_NULL. - If asynchronous notification of normal world is supported in secure world:
OPTEE_ABI_SEC_CAP_ASYNC_NOTIF. - Pre-allocating RPC arg struct is supported in secure world:
OPTEE_ABI_SEC_CAP_RPC_ARG. - If the capabilities has
OPTEE_ABI_SEC_CAP_DYNAMIC_SHM, create page-based allocator pool based onalloc_pages(). - If the capabilities has
OPTEE_ABI_SEC_CAP_HAVE_RESERVED_SHM, use the static memory pool. - Call the invoke function, e.g.
optee_smccc_smc()with function ID:OPTEE_SMC_GET_SHM_CONFIGto get the base address and the size of the static memory pool allocated by OP-TEE. - OP-TEE returns
default_nsec_shm_paddranddefault_nsec_shm_sizeindicating the physical base address and the size of the non-secure shared memory initialized inteecore_init_pub_ram(). - Non-secured shared memory is declared statically in OP-TEE:
teecore_init_pub_ram()is declared withearly_init()whenCFG_CORE_RESERVED_SHMis defined.- Allocate
struct optee: optee->ops = &optee_ops- Call
tee_device_alloc()to allocate a newstruct tee_deviceinstance for TEE client device:optee-clntwithoptee_clnt_desc.struct opteeis passed asdriver_data. - The allocated TEE client device is assigned to
optee->teedev. - Call
tee_device_alloc()to allocate a newstruct tee_deviceinstance for TEE supplicant device:optee-suppwithoptee_supp_desc.struct opteeis passed asdriver_data. - The allocated TEE supplicant device is assigned to
optee->supp_teedev. - Call
tee_device_register()to registeroptee-clntdevice. - Call
tee_device_register()to registeroptee-suppdevice. - Call
platform_set_drvdata()to setopteedevice driver data to:struct optee. - Open OP-TEE client device (
optee->teedev): tee_open()- This will call
optee_clnt_desc->open(): optee_smc_open()- If
OPTEE_SMC_SEC_CAP_ASYNC_NOTIFcapability is supported: - Call
platform_get_irq()to get (non-secure) IRQ 0. - Call
optee_smc_notif_init_irq()to request IRQ. - If
irq_is_percpu_devid(): init_pcpu_irq()request_percpu_irq()- IRQ handler:
notif_pcpu_irq_handler() irq_handler()- Init work:
optee->smc.notif_pcpu_work: - Handler:
notif_pcpu_irq_work_fn() - Create work queue:
optee->smc.notif_pcpu_wq optee->smc.notif_pcpu_workis queued intooptee->scm.notif_pcpu_wqinnotif_pcpu_irq_handler()- Otherwise:
init_irq()request_threaded_irq()- IRQ handler:
notif_irq_handler() irq_handler()- Handler thread:
notif_irq_thread_fn() - Call
optee_enumerate_devices()to enumerate PTA devices (PTA_CMD_GET_DEVICES).
optee_smccc_smc()- Call to message ID:
OPTEED_MSG_COMMUNICATE(0x01).
optee_open()- Allocate
struct optee_context_data. - If
tee_deviceis a OP-TEE supplicant devices: - If
!optee->scan_bus_done: - Initialize
scan_bus_workwork queue. - Handler:
optee_bus_scan() - Schedule the work queue.
- Set
optee->scan_bus_donetotrue. - Assign the allocated
struct optee_context_datatotee_context->data.
optee_open_session()- Call
optee_get_msg_arg()to allocate the shared memory for the message arg (struct optee_msg_arg). - Call
tee_session_calc_client_uuid()to create Linux environment client UUID from the session arg. - Initialize message arg and add the meta parameters needed when opening a session with the session arg and Linux environment client UUID.
- Call
optee->ops->to_msg_param()to convert the passed-instruct tee_paramtoOPTEE_MSGparameters (struct optee_msg_arg). Save the convertedOPTEE_MSGparameters to message arg. - E.g.
optee_to_msg_param() - Call
optee->ops->do_call_with_arg()with the command:OPTEE_MSG_CMD_OPEN_SESSIONto enter OP-TEE in secure world with the message arg. - E.g.
optee_smc_do_call_with_arg() - OP-TEE will call to open the session based on the UUID (
tee_ioctl_open_session_arg->uuid, e.g. PTA UUID) passed from Linux. The UUID is used to look up or initialize the TA with the same UUID. The opened session ID is saved to the message arg and passed back to Linux. - If
optee_smc_do_call_with_arg()returns success, add the session to the sessions list (ctxdata->sess_list) - Call
optee->ops->from_msg_param()to convert the returned sessionOPTEE_MSGparameters tostruct tee_param. Update the results to session arg. - E.g.
optee_from_msg_param() - Store the open session ID to
struct tee_ioctl_open_session_arg->session. - If conversion fails, call
optee_close_session()to close the session. - Call
optee_free_msg_arg()to free the allocated message arg.
optee_smc_do_call_with_arg()- Initialize RPC parameter (
struct optee_rpc_param) from the message arg. - message arg is stored in the shared memory indicated by
shmandoffs. - Call
optee->smc.invoke_fn()to enter OP-TEE in secure world with the message arg. - E.g.
optee_smccc_smc() - P.S. SMCCC = SMC Calling Convention, defined by ARM.
- If SMC return is a RPC:
- Call
optee_handle_rpc()to handle the RPC from OP-TEE.
optee_invoke_func()- Similar flow to
optee_open_session(). Except callingoptee->ops->do_call_with_arg()with the command:OPTEE_MSG_CMD_INVOKE_COMMANDto enter OP-TEE in secure world with the message arg. - E.g.
optee_smc_do_call_with_arg() - OP-TEE will call to invoke the command based on the passed-in function (e.g.
PTA_CMD_GET_DEVICES) in the opened session. - E.g. If the opened session is registered for pseudo TA (OP-TEE:
core/pta/pseudo_ta.c). Theenter_invoke_cmd()callback in OP-TEE is: .
optee_bus_scan()- Call
optee_enumerate_devices()to enumerate PTA supplicant devices (PTA_CMD_GET_DEVICES_SUPP).
optee_do_bottom_half()- Call
optee->ops->do_call_with_arg()with the command:OPTEE_MSG_CMD_DO_BOTTOM_HALFto schedule bottom half processing of a driver.
optee_enumerate_devices()- Enumerate the TA devices.
__optee_enumerate_devices()- PTA UUID:
- Call to open TEE devices with OP-TEE driver.
- Prepare session arg (
struct tee_ioctl_open_session_arg). - Call to open session with device enumeration pseudo Trusted Application with the session arg using PTA UUID.
- Call
get_devices()to get the required shared memory size for UUIDs of pseudo TAs. - Shared memory size = sizeof(UUID) * Number of pseudo TAs
- After retrieving the shared memory size, call
tee_shm_alloc_kernel_buf()to allocate the shared memory buffer for UUIDs of pseudo TAs. - Call
get_devices()again to get the UUIDs of pseudo TAs. The UUIDs of psuedo TA are stored in the allocated shared memory by OP-TEE. - For each pseudo TA, call
optee_register_device()to register the device to TEE bus (tee_bus_type). - This will eventually call
tee_client_device_match()to match the driver for the TA device based on UUID. Driver’sprobe()callback will be called if matches. - For example:
optee-rngsdriver (drivers/char/hw_random/optee-rngs.c). - OP-TEE driver is implemented as a module and is initialized through
module_init(). OP-TEE driver sets itsbustotee_bus_type.
get_devices()- Call to invoke the function (e.g.
PTA_CMD_GET_DEVICESto get the pseudo TAs) to OP-TEE.
optee_handle_rpc()- If
optee_rpc_param->a0: OPTEE_SMC_RPC_FUNC_CMDfunction:- Get
arg(struct optee_msg_arg) from the shared memory. handle_rpc_func_cmd()witharg.- …
- Set
param->a0toOPTEE_SMC_CALL_RETURN_FROM_RPCto indicate that we have successfully handled the RPC.
handle_rpc_func_cmd()- If
arg->cmd: OPTEE_RPC_CMD_SHM_ALLOC:handle_rpc_func_cmd_shm_alloc()OPTEE_RPC_CMD_SHM_FREE:handle_rpc_func_cmd_shm_free()- Otherwise:
optee_rpc_cmd()- If
arg->cmd: OPTEE_RPC_CMD_GET_TIME:handle_rpc_func_cmd_get_time()- …
- Otherwise:
handle_rpc_supp_cmd()
optee_supp_thrd_req()- Insert the RPC request into the request list (
supp->reqs). - Call
complete(&supp->reqs_c)to tell an eventual waiter there's a new request. - This will unblock TEE supplicant: Otherwise, call
wait_for_completion_interruptible(&supp->reqs_c)to wait for the new request from OP-TEE. - Call
wait_for_completion_interruptible(&req->c)to wait for TEE supplicant to process. - This will be blocked until TEE supplicant handles the RPC.
- Return the result.
optee_supp_recv()- TEE supplicant waits for OP-TEE’s request- Check if we could pop the entry from the request list (
supp->reqs). If yes, extract the RPC parameters. - Otherwise, call
wait_for_completion_interruptible(&supp->reqs_c)to wait for the new request from OP-TEE.
optee_supp_send()- TEE supplicant handles the RPC and sends the response to OP-TEE.- Set the return parameters (
struct tee_param). - Call
complete(&req->c)to unblock Callwait_for_completion_interruptible(&req->c)to wait for TEE supplicant to process.