[RFC PATCH] tee: tstee: Add initial Trusted Services TEE driver

Sumit Garg sumit.garg at linaro.org
Tue Oct 31 04:39:26 PDT 2023


Hi Balint,

Thanks for the detailed insights.

On Tue, 31 Oct 2023 at 00:05, Balint Dobszay <balint.dobszay at arm.com> wrote:
>
> On 26 Oct 2023, at 8:52, Sumit Garg wrote:
> > On Fri, 20 Oct 2023 at 19:22, Balint Dobszay <balint.dobszay at arm.com> wrote:
> >> On 13 Oct 2023, at 14:47, Sumit Garg wrote:
> >>> On Wed, 27 Sept 2023 at 20:56, Balint Dobszay <balint.dobszay at arm.com> wrote:
> >>
> >> [snip]
> >>
> >>>> diff --git a/drivers/tee/tstee/core.c b/drivers/tee/tstee/core.c
> >>>> new file mode 100644
> >>>> index 000000000000..c0194638b7da
> >>>> --- /dev/null
> >>>> +++ b/drivers/tee/tstee/core.c
> >>>> @@ -0,0 +1,473 @@
> >>>> +// SPDX-License-Identifier: GPL-2.0-only
> >>>> +/*
> >>>> + * Copyright (c) 2023, Arm Limited
> >>>> + */
> >>>> +
> >>>> +#define DRIVER_NAME "Arm TSTEE"
> >>>> +#define pr_fmt(fmt) DRIVER_NAME ": " fmt
> >>>> +
> >>>> +#include <linux/arm_ffa.h>
> >>>> +#include <linux/err.h>
> >>>> +#include <linux/errno.h>
> >>>> +#include <linux/kernel.h>
> >>>> +#include <linux/limits.h>
> >>>> +#include <linux/list.h>
> >>>> +#include <linux/mm.h>
> >>>> +#include <linux/module.h>
> >>>> +#include <linux/scatterlist.h>
> >>>> +#include <linux/slab.h>
> >>>> +#include <linux/stat.h>
> >>>> +#include <linux/tee_drv.h>
> >>>> +#include <linux/types.h>
> >>>> +#include <linux/uaccess.h>
> >>>> +
> >>>> +#include "tstee_private.h"
> >>>> +
> >>>> +#define FFA_INVALID_MEM_HANDLE U64_MAX
> >>>> +
> >>>> +static void arg_list_to_ffa_data(const u32 *args, struct ffa_send_direct_data *data)
> >>>> +{
> >>>> +       data->data0 = args[0];
> >>>> +       data->data1 = args[1];
> >>>> +       data->data2 = args[2];
> >>>> +       data->data3 = args[3];
> >>>> +       data->data4 = args[4];
> >>>> +}
> >>>> +
> >>>> +static void arg_list_from_ffa_data(const struct ffa_send_direct_data *data, u32 *args)
> >>>> +{
> >>>> +       args[0] = lower_32_bits(data->data0);
> >>>> +       args[1] = lower_32_bits(data->data1);
> >>>> +       args[2] = lower_32_bits(data->data2);
> >>>> +       args[3] = lower_32_bits(data->data3);
> >>>> +       args[4] = lower_32_bits(data->data4);
> >>>> +}
> >>>> +
> >>>> +static void tstee_get_version(struct tee_device *teedev, struct tee_ioctl_version_data *vers)
> >>>> +{
> >>>> +       struct tstee *tstee = tee_get_drvdata(teedev);
> >>>> +       struct tee_ioctl_version_data v = {
> >>>> +               .impl_id = TEE_IMPL_ID_TSTEE,
> >>>> +               .impl_caps = tstee->ffa_dev->vm_id,
> >>>
> >>> So while exploring the user-space interface, I observed an anomaly
> >>> here. The ".impl_caps" refers to "Implementation specific
> >>> capabilities" meant to support backwards compatibility of a particular
> >>> TEE implementation. But here I observe you are using it instead for
> >>> endpoint_id. Can you provide the reasoning behind it? Also, do you
> >>> plan to support multiple endpoints via this driver?
> >>
> >> The mapping between Trusted Services SPs and TEE devices is 1:1, i.e.
> >> each /dev/tee<n> device represents exactly one FF-A endpoint. To answer
> >> your second question, each instance of the driver represents a single
> >> endpoint, multiple endpoints are supported by having multiple instances
> >> of the driver.
> >
> > I don't follow you here. How multiple instances of "arm_tstee" driver
> > going to work? Also, I can only see a single FF-A based device:
> > TS_RPC_UUID being probed here.
>
> My terminology regarding "multiple instances of the driver" was
> incorrect, apologies. What I meant was that tstee_probe() gets called
> multiple times, thus allocating multiple instances of "struct tstee".
>
> All of the Trusted Services SPs use the same FF-A UUID (TS_RPC_UUID).
> These will show up on the FF-A bus in Linux as multiple devices, having
> the same FF-A UUID, but different endpoint IDs, e.g.
>
> Name            FF-A EP ID    FF-A UUID
> ------------    ----------    -----------------------------------
> OP-TEE          0x8001        486178e0-e7f8-11e3-bc5e0002a5d5c51b
> TS ITS SP       0x8002        bdcd76d7-825e-4751-963b86d4f84943ac
> TS Crypto SP    0x8003        bdcd76d7-825e-4751-963b86d4f84943ac
> TS Attest SP    0x8003        bdcd76d7-825e-4751-963b86d4f84943ac
>
> Each of the Trusted Services FF-A devices will match the single UUID
> present in tstee_device_ids[], so tstee_probe() will be called multiple
> times, each time with a different FF-A device as argument. In the probe
> function a new TEE device is allocated, and a new "struct tstee" which
> represents the connection between a particular ffa_device and
> tee_device.

I can see now how it works but allocation of a tee_device for every
ffa_device seems an overkill here. I suppose standalone secure
partitions are somewhat analogous to trusted applications. I don't
think we really need separate TEE devices in order to communicate with
different secure partitions.

Based on whatever I have understood as of now regarding this
interface, it should work with single TEE device as follows:

- During tstee_probe(), create a list of FF-A devices (representing
SPs) and create a single TEE device representing TSTEE RPC protocol.
- During open session IOCTL, pass endpoint ID as an argument and check
if corresponding FF-A device is present in the list. If present then
you can return session ID derived from the endpoint ID to the
user-space client.
- For all further invoke commands IOCTL, you can retrieve endpoint ID
from session ID and then talk to corresponding FF-A device.

IMO, this way it would be more scalable and efficient usage of a TEE device.

On a side note, I would suggest you document Trusted Services TEE for
the next patch revision.

>
> I think a similar scenario would be if we had e.g. Hafnium as S-EL2 SPMC
> and two OP-TEE instances as S-EL1 SPs running under Hafnium. In this
> case the FF-A devices representing the OP-TEE instances would have the
> same FF-A UUID but different endpoint IDs. The OP-TEE driver in Linux
> would register two TEE devices for the two OP-TEE SPs.

Do you have any particular use-case where two or more OP-TEE instances
will be required by a single VM (Linux)? Those different TEE devices
are intended to represent different TEE implementations (following
unique communication protocol stack).

-Sumit

>
> > Do you have any working example for this?
>
> The end-to-end integration for FVP I mentioned earlier does build, boot
> and test multiple endpoints.
>
> >> Therefore we always return a single endpoint ID in this
> >> field.
> >>
> >> The reason behind the usage of this field is that somehow user space has
> >> to be able to discover which TEE device represents which FF-A endpoint.
> >> This is required when a client wants to invoke an SP with a specific
> >> endpoint ID, e.g. in a system where the SP's endpoint IDs is static and
> >> known by the client.
> >>
> >> I understand this is not a conventional usage of this field, I couldn't
> >> find a better way to "fit" this information into the ABI. My
> >> understanding is this solution shouldn't cause any issues for other
> >> TEEs, since this implementation specific field should only be parsed by
> >> a client if it has already matched on the TEE implementation ID. Please
> >> correct me if this assumption is wrong, or if you have any suggestions
> >> on other ways to expose the endpoint ID to user space.
> >
> > When you say "each /dev/tee<n> device represents exactly one FF-A
> > endpoint" then "impl_id" should be sufficient to represent endpoint ID
> > too. But I am still confused regarding how you are going to support
> > multiple endpoints?
>
> Hopefully my answer above covers this question too.
>
> > Looking at this driver TEE_IMPL_ID_TSTEE represents an underlying FF-A
> > based TS_RPC_UUID device.
>
> Yes, that is correct. The FF-A UUID here acts as a protocol identifier,
> multiple FF-A endpoints can implement the same protocol, therefore can
> have the same UUID. The mechanism to discover what services a particular
> TS SP provides is not defined by FF-A, in this case it's done by the TS
> RPC protocol which is one layer above FF-A.
>
> Regards,
> Balint



More information about the linux-arm-kernel mailing list