The Trusted Services TEE driver is a Linux kernel module providing user space access to Trusted Services. The implementation extends the TEE subsystem and uses FF-A compliant messaging between the NWd and SWd. The driver depends on the FF-A driver, which is available upstream since v5.14.
Contents
The TEE subsystem in the Linux kernel,
- handles the registration of a TEE driver and its callbacks,
- provides a generic API towards user space for different TEEs,
- helps with managing shared memory between Linux and the TEE.
A TEE device (i.e. /dev/tee[0-9]*
) is a generic device, registered by a TEE driver (e.g.
OP-TEE driver). At registration, the TEE driver provides its specific callbacks which will be
registered for the TEE device. The open()
/ close()
/ ioctl()
calls on a TEE
device are handled by the generic TEE subsystem code, which will invoke the driver specific
callbacks. Among the callbacks there is one to query information about the driver type and
capabilities. Using this, user space can find out which TEE belongs to a particular TEE device. When
opening a TEE device, a context is allocated. This represents the connection between the client app
and the Trusted OS. Inside this context one or more sessions can be opened, which represent the
connection between the client app and a Trusted OS app (e.g. a TA in the case of OP-TEE). The TEE
subsystem's model is independent of OP-TEE, multiple TEE drivers can coexist in a single system.
Example system with OP-TEE and Trusted Services:
+-------+ +-------+ | App 1 | | App 2 | +-------+ +-------+ User space | | EL0 V V +--------+ +-------+ | OP-TEE | | libts | | client | +-------+ +--------+ | | | V V +-----------------------+ ----------- | Generic TEE API ioctl | ---------- +-----------------------+ | V +-----------------------+ | TEE subsystem | +-----------------------+ Kernel space | | EL1 V V +--------+ +----------+ | OP-TEE | | TS TEE | | driver | | driver | +--------+ +----------+ | | | | V V | +-------------+ | | FF-A driver | | +-------------+ | | ------------- | --------- | ------------------- V V +-----------------------+ EL3 | TF-A | +-----------------------+
The FF-A driver only provides an in-kernel API to invoke FF-A operations. To be able to communicate with SPs from a Linux app, a TEE driver can bridge this gap and provide an API towards user space.
Mapping TEE concepts to FF-A and TS terms, a short summary of the key implementation decisions:
- There is 1:1 mapping between SPs and TEE devices, i.e. a TEE device gets registered for each compatible FF-A device found on the kernel FF-A bus.
- "Opening" an SP corresponds to opening the TEE device and creating a TEE context. An SP hosts one or more services, opening a service corresponds to opening a session in the given tee_context.
- The register ABI (i.e. TS_RPC_*) used by the driver is the standardised RPC protocol for accessing Trusted Services. The protocol definition will be published shortly in the project documentation. All Trusted Services SPs talk this protocol, so they all have the same FF-A UUID, which identifies this protocol.
- A service type (e.g. PSA Crypto) is identified by a service UUID. The same type of service can be present in multiple SPs, but not twice in the same SP. During SP boot each service in the SP gets assigned an interface ID, this is just a short ID to simplify message addressing.
The TEE subsystem has two mechanisms for memory sharing:
- Registration: memory is allocated by user space client. TEE subsystem will pin the user pages and register the shared memory in the TEE, using the TEE specific callback provided by the TEE driver.
- Allocation: memory is allocated in kernel space by the TEE subsystem, from a pool provided by the
TEE driver. After allocation, the shared memory is registered using the TEE specific callback.
Then a file descriptor is returned, user space needs to
mmap()
this to access the buffer. Currently only this mechanism is supported by the Trusted Services TEE driver.
The TEE subsystem provides a set of ioctl calls. Some of these have generic parameters, which allows the concrete TEE implementation to define usage of the parameters in alignment with the driver's specific requirements.
List of TEE subsystem ioctl calls and its parameters used by this driver:
TEE_IOC_OPEN_SESSION: Open service if it's implemented by the SP.
Used parameters:
struct tee_ioctl_open_session_arg
uuid
: service UUID (in)session
: session ID (out)
TEE_IOC_CLOSE_SESSION: Close service.
Used parameters:
struct tee_ioctl_close_session_arg
session
: session ID (in)
TEE_IOC_SHM_ALLOC: Initialize a shared memory buffer. A buffer is allocated from kernel memory and shared with the SP. The return value of the
ioctl()
call is a file descriptor which should bemmap()
-ed by user space. Deinit of the buffer is done viamunmap()
, no separateioctl()
call to this driver is necessary.Used parameters:
struct tee_ioctl_shm_alloc_data
size
: requested shared buffer size (in), actual shared buffer size (out)id
: shared memory ID (out)
TEE_IOC_INVOKE: Invoke function of a particular service. Needs to have a session already open to the service. If the call doesn't use a shared buffer, the shared memory ID and request/response length must be zero.
Used parameters:
struct tee_ioctl_invoke_arg
func
: opcode, service specific (in)session
: session ID (in)ret
: result of the operation, service specific (out)num_params
: 1params[0].a
: shared memory ID (in)params[0].b
: request/response length in the shared memory (in/out)
The project uses semantic versioning.
- To access the latest version of the driver, use the
main
branch. - To access the latest version compatible with the
x
major version, use thetee-vx
branch. - To access the latest version compatible with the
x.y
minor version, use thetee-vx.y
branch. - To access a specific version of the driver, use the
tee-vx.y.z
tag.
Initially instead of branches, the repo was using moving tags to describe the
major and minor versions. This is a git anti-pattern, so it was deprecated.
However, to avoid breaking any existing systems, we decided to keep the original
tags too. Please consider the tee-v1
and tee-v1.1
tags obsolete
and use the branches instead as descibed above.
Copyright (c) 2021-2023, Arm Limited. All rights reserved.
SPDX-License-Identifier: GPL-2.0-only