Skip to content

linaro-swg/linux-trusted-services

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Trusted Services TEE driver documentation

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.

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 be mmap()-ed by user space. Deinit of the buffer is done via munmap(), no separate ioctl() 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: 1
    • params[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 the tee-vx branch.
  • To access the latest version compatible with the x.y minor version, use the tee-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

About

Mirror of https://git.gitlab.arm.com/linux-arm/linux-trusted-services.git for OP-TEE OS CI. PLEASE NO NOT CREATE PULL REQUESTS.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •