Skip to content
README.rst 10.6 KiB
Newer Older
=========================================
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.

.. _Trusted Services: https://www.trustedfirmware.org/projects/trusted-services/
.. _TEE subsystem: https://www.kernel.org/doc/html/latest/staging/tee.html
.. _FF-A: https://developer.arm.com/documentation/den0077/latest
.. _FF-A driver: https://elixir.bootlin.com/linux/v5.14/source/drivers/firmware/arm_ffa

.. contents::

TEE subsystem
=============

Overview
--------

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. :code:`/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 :code:`open()` / :code:`close()` / :code:`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 |   | FF-A TEE |
              | driver |   |  driver  |
              +--------+   +----------+
                |     |         |
                |     V         V
                |    +-------------+
                |    | FF-A driver |
                |    +-------------+
                |           |
  ------------- | --------- | -------------------
                V           V
              +-----------------------+
      EL3     |         TF-A          |
              +-----------------------+

FF-A and TEE concepts
---------------------

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, an FF-A TEE driver can bridge this gap and provide an API
towards user space.

Mapping TEE concepts to FF-A terms:

- All FF-A SWd endpoints (SPs) associated with this TEE driver are represented by a single TEE
  device. Service providers are distributed across multiple participating SPs and all of these
  services are accessible through this single TEE device.

- Opening the TEE device and allocating the context doesn't have much to do:

  - FF-A is stateless, no need to initialize,
  - partition discovery already done by the FF-A driver,
  - compatible devices are bound to this TEE driver.

- An SP is represented as a session in the open context.

  - A single SP per context, the partition ID of the SP is passed to :code:`open_session()`.

- Shared memory handling in TEE subsystem is context specific, not session specific.

  - We need the destination SP ID for the share transaction, which is session specific.
  - Solution is to open a new context for each SP, and open only a single session in each context.

- Shared memory handling in the TEE subsystem is context specific, while FF-A defines a session
  specific mechanism (the destination SP ID needs to be passed as part of the share transaction).
  The solution is to limit TEE contexts to a single SP, and have only a single session in each
  context.

- Flexibility provided by :code:`invoke_func()` allows it to be used for:

  - FF-A direct messaging,
  - other functionality like information retrieval not involving FF-A messaging.

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 :code:`mmap()` this to access the buffer.

User space interface
====================

Summary
-------

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.

Requirements
------------

The minimal required functionality the driver should provide to a user space application is the
following:

- Query all partition IDs for a specific FF-A UUID.
- Synchronous messaging with a SP.
- Share/unshare buffer to a SP.

A service specific protocol should be implemented in user space, and the service should be accessed
through a service independent RPC protocol. Boundary between user and kernel space is at this RPC
level. The TEE driver can implement multiple RPC protocols, each one identified by a UUID. The
driver can decide which RPC to use based on the destination SP's UUID. The protocol specific
functionality can be separated into a dedicated file, or in a future version into a separate module.

Further details about the communication layering is available in the Trusted Services documentation:
https://trusted-services.readthedocs.io/en/latest/developer/service-access-protocols.html

Design
------

The TEE driver registers a single TEE device. After opening this TEE device, the following
functionality should be available:

+----------------------+----------------------------+--------------------------------+-----------------------+---------------------------------------+----------------------------+
| Function             | Input                      | Output                         | ioctl                 | What happens in TEE driver            | Comments                   |
+======================+============================+================================+=======================+=======================================+============================+
| Query partition list | FF-A UUID                  | Partition IDs                  | TEE_IOC_INVOKE        | Find devices among bound devices      | \-                         |
|                      |                            |                                |                       | with the particular UUID              |                            |
+----------------------+----------------------------+--------------------------------+-----------------------+---------------------------------------+----------------------------+
| Open session         | Partition ID               | \-                             | TEE_IOC_OPEN_SESSION  | Find bound device based on            | Only a single session can  |
|                      |                            |                                |                       | partition ID and store it in          | be opened per context      |
|                      |                            |                                |                       | context data                          |                            |
+----------------------+----------------------------+--------------------------------+-----------------------+---------------------------------------+----------------------------+
| Close session        | \-                         | \-                             | TEE_IOC_CLOSE_SESSION | Reset context data                    | \-                         |
+----------------------+----------------------------+--------------------------------+-----------------------+---------------------------------------+----------------------------+
| Init shared buffer   | Buffer size                | | File descriptor to mmap()    | TEE_IOC_SHM_ALLOC     | | Allocate buffer from kernel memory  | Deinit is done by munmap() |
|                      |                            | | ID of buffer                 |                       | | Share it to SWd with FF-A mem share |                            |
+----------------------+----------------------------+--------------------------------+-----------------------+---------------------------------------+----------------------------+
| Invoke               | | RPC protocol specific    | | RPC protocol specific        | TEE_IOC_INVOKE        | | Pack request arguments              | Destination partition ID   |
|                      | | E.g. for TS RPC:         | | E.g. for TS RPC:             |                       | | Send FF-A direct request            | known from context data    |
|                      | | Interface ID, opcode,    | | Response length, RPC status, |                       | | Unpack response arguments           |                            |
|                      |   request length, encoding |   operation status             |                       |                                       |                            |
+----------------------+----------------------------+--------------------------------+-----------------------+---------------------------------------+----------------------------+

For the specific parameter encodings please refer to uapi/arm_ffa_tee.h file.

--------------

Copyright (c) 2021-2022, Arm Limited. All rights reserved.

SPDX-License-Identifier: GPL-2.0-only