Re: [PATCH v3 3/4] arm_ffa: introduce Arm FF-A low-level driver

Abdellatif El Khlifi
2022-09-26T11:12:07Z

On Fri, Aug 12, 2022 at 10:39:23AM +0300, Ilias Apalodimas wrote:
> Hi Abdellatif,
>
> On Mon, 1 Aug 2022 at 20:21, Abdellatif El Khlifi
> <abdellatif.elkhlifi@arm.com> wrote:
> >
> > Add the driver implementing Arm Firmware Framework for Armv8-A v1.0
> >
> > The Firmware Framework for Arm A-profile processors (FF-A)
> > describes interfaces (ABIs) that standardize communication
> > between the Secure World and Normal World leveraging TrustZone
> > technology.
> >
> > This driver uses 64-bit registers as per SMCCCv1.2 spec and comes
> > on top of the SMCCC layer. The driver provides the FF-A ABIs needed for
> > querying the FF-A framework from the secure world.
> >
> > 32-bit version of the ABIs is supported and 64-bit version of FFA_RXTX_MAP
> > and FFA_MSG_SEND_DIRECT_{REQ, RESP}.
> >
> > In u-boot FF-A design, FF-A is considered as a discoverable bus.
> > The Secure World is considered as one entity to communicate with
> > using the FF-A bus. FF-A communication is handled by one device and
> > one instance (the bus). This FF-A driver takes care of all the
> > interactions between Normal world and Secure World.
> >
> > The driver exports its operations to be used by upper layers.
> >
> > Exported operations:
> >
> > - partition_info_get
> > - sync_send_receive
> > - rxtx_unmap
> >
> > This implementation provides an optional feature to copy the driver data
> > to EFI runtime area.
> >
>
> [...]
>
> > +config ARM_FFA_TRANSPORT
> > + bool "Enable Arm Firmware Framework for Armv8-A driver"
> > + depends on DM && ARM64
> > + select ARM_SMCCC
> > + select LIB_UUID
> > + select DEVRES
> > + help
> > + The Firmware Framework for Arm A-profile processors (FF-A)
> > + describes interfaces (ABIs) that standardize communication
> > + between the Secure World and Normal World leveraging TrustZone
> > + technology.
> > +
> > + This driver is based on FF-A specification v1.0 and uses SMC32
> > + calling convention.
> > +
> > + FF-A specification:
> > +
> > + https://developer.arm.com/documentation/den0077/a/?lang=en
> > +
> > + In u-boot FF-A design, FF-A is considered as a discoverable bus.
> > + The Secure World is considered as one entity to communicate with
> > + using the FF-A bus.
> > + FF-A communication is handled by one device and one instance (the bus).
> > + This FF-A driver takes care of all the interactions between Normal world
> > + and Secure World.
> > +
> > +config ARM_FFA_EFI_RUNTIME_MODE
> > + bool "Enable EFI runtime support for FF-A data and code "
> > + depends on ARM_FFA_TRANSPORT && EFI_LOADER
> > + help
> > + Allows FF-A driver data structures and code to be accessible at EFI runtime
>
> Is there a reason we want to opt-in on that? What prevents it from
> always being there?

Yes, we agreed that FF-A driver needs to be independent from EFI.
This is reflected in the v4 patchset.
The intent is to be able to compile the core driver without EFI
support. When using EFI, FF-A core driver data needs to be copied to
the EFI runtime section so it can be accessed at runtime. For that
specific case, CONFIG_ARM_FFA_EFI_RUNTIME_MODE has been created to
enable the feature of copying the data to the runtime section.
The code that copies the data is provided by
drivers/firmware/arm-ffa/efi_ffa_runtime_data_mgr.c
When EFI is needed CONFIG_ARM_FFA_EFI_RUNTIME_MODE should be turned
on. If no EFI needed the FF-A driver can still be used independently.

>
> [...]
>
> > +
> > +/* Endpoint ID mask (u-boot endpoint ID) */
> > +
> > +#define GET_SELF_ENDPOINT_ID_MASK GENMASK(15, 0)
> > +#define GET_SELF_ENDPOINT_ID(x) \
> > + ((u16)(FIELD_GET(GET_SELF_ENDPOINT_ID_MASK, (x))))
> > +
> > +#define PREP_SELF_ENDPOINT_ID_MASK GENMASK(31, 16)
> > +#define PREP_SELF_ENDPOINT_ID(x) \
> > + (FIELD_PREP(PREP_SELF_ENDPOINT_ID_MASK, (x)))
> > +
> > +/* Partition endpoint ID mask (partition with which u-boot communicates with) */
> > +
> > +#define PREP_PART_ENDPOINT_ID_MASK GENMASK(15, 0)
> > +#define PREP_PART_ENDPOINT_ID(x) \
> > + (FIELD_PREP(PREP_PART_ENDPOINT_ID_MASK, (x)))
> > +
> > +/*
> > + * Definitions of the Arm FF-A interfaces supported by the Arm FF-A driver
> > + */
> > +
> > +#define FFA_SMC(calling_convention, func_num) \
> > + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, (calling_convention), \
> > + ARM_SMCCC_OWNER_STANDARD, (func_num))
> > +
> > +#define FFA_SMC_32(func_num) FFA_SMC(ARM_SMCCC_SMC_32, (func_num))
> > +#define FFA_SMC_64(func_num) FFA_SMC(ARM_SMCCC_SMC_64, (func_num))
> > +
> > +#define FFA_VERSION FFA_SMC_32(0x63)
> > +#define FFA_ID_GET FFA_SMC_32(0x69)
> > +#define FFA_FEATURES FFA_SMC_32(0x64)
> > +#define FFA_PARTITION_INFO_GET FFA_SMC_32(0x68)
> > +#define FFA_RXTX_UNMAP FFA_SMC_32(0x67)
> > +#define FFA_RX_RELEASE FFA_SMC_32(0x65)
> > +#define FFA_RUN FFA_SMC_32(0x6D)
> > +#define FFA_ERROR FFA_SMC_32(0x60)
> > +#define FFA_SUCCESS FFA_SMC_32(0x61)
> > +#define FFA_INTERRUPT FFA_SMC_32(0x62)
> > +#define FFA_RXTX_MAP FFA_SMC_64(0x66)
> > +#define FFA_MSG_SEND_DIRECT_REQ FFA_SMC_64(0x6F)
> > +#define FFA_MSG_SEND_DIRECT_RESP FFA_SMC_64(0x70)
> > +
> > +/* The FF-A SMC function definitions */
> > +
> > +typedef struct arm_smccc_1_2_regs ffa_value_t;
> > +typedef void (*invoke_ffa_fn_t)(ffa_value_t args, ffa_value_t *res);
> > +
> > +/* FF-A error codes */
> > +#define FFA_ERR_STAT_NOT_SUPPORTED (-1)
> > +#define FFA_ERR_STAT_INVALID_PARAMETERS (-2)
> > +#define FFA_ERR_STAT_NO_MEMORY (-3)
> > +#define FFA_ERR_STAT_BUSY (-4)
> > +#define FFA_ERR_STAT_INTERRUPTED (-5)
> > +#define FFA_ERR_STAT_DENIED (-6)
> > +#define FFA_ERR_STAT_RETRY (-7)
> > +#define FFA_ERR_STAT_ABORTED (-8)
> > +
> > +/* UUID data size */
> > +#define UUID_SIZE (16)
>
> Please drop () on these
>
> > +
> > +/*
> > + * union ffa_partition_uuid - Data union hosting the UUID
> > + * transmitted by FFA_PARTITION_INFO_GET
> > + * @words: data structure giving 32-bit words access to the UUID data
> > + * @bytes: data structure giving byte access to the UUID data
> > + *
> > + * The structure holds little-endian UUID data.
> > + */
> > +union ffa_partition_uuid {
> > + struct __packed words {
> > + u32 a1; /* w1 */
> > + u32 a2; /* w2 */
> > + u32 a3; /* w3 */
> > + u32 a4; /* w4 */
> > + } words;
> > + u8 bytes[UUID_SIZE];
> > +};
>
> is the bytes field used anywhere?

removed in v4. Please see https://lore.kernel.org/all/20220926101723.9965-5-abdellatif.elkhlifi@arm.com/

>
> [...]
>
> > + *
> > + * Each partition has its descriptor containing the partitions information and the UUID
> > + */
> > +struct ffa_partition_desc {
> > + struct ffa_partition_info info;
> > + union ffa_partition_uuid UUID;
>
> lower case please and perhaps a better name e.g partition_uuid

Done in v4.

>
> > +};
> > +
> > +/**
> > + * struct ffa_partitions - descriptors for all secure partitions
> > + * @count: The number of partitions descriptors
> > + * @descs The partitions descriptors table
> > + *
> > + * This data structure contains the partitions descriptors table
> > + */
> > +struct ffa_partitions {
> > + u32 count;
> > + struct ffa_partition_desc *descs; /* virtual address */
> > +};
> > +
> > +/**
> > + * struct ffa_prvdata - the driver private data structure
> > + *
> > + * @dev: The arm_ffa device under u-boot driver model
> > + * @ffa_ops: The driver operations structure
> > + * @fwk_version: FF-A framework version
> > + * @id: u-boot endpoint ID
> > + * @partitions: The partitions descriptors structure
> > + * @pair: The RX/TX buffers pair
> > + * @invoke_ffa_fn: The function executing the FF-A function
> > + * @features: Table of the FF-A functions having features
> > + *
> > + * The driver data structure hosting all resident data.
> > + */
> > +struct ffa_prvdata {
> > + struct udevice *dev;
> > + struct ffa_bus_ops ffa_ops;
> > + u32 fwk_version;
> > + u16 id;
> > + struct ffa_partitions partitions;
> > + struct ffa_rxtxpair pair;
> > + invoke_ffa_fn_t invoke_ffa_fn;
> > + struct ffa_features_desc features[FFA_FEATURE_DESC_CNT];
> > +};
> > +
> > +/**
> > + * ffa_device_get - create, bind and probe the arm_ffa device
> > + */
> > +int ffa_device_get(void);
> > +
> > +/**
> > + * ffa_bus_prvdata_get - bus driver private data getter
> > + */
> > +struct ffa_prvdata **ffa_bus_prvdata_get(void);
> > +
> > +#endif
> > diff --git a/drivers/arm-ffa/core.c b/drivers/arm-ffa/core.c
> > new file mode 100644
> > index 0000000000..40d140fc3e
> > --- /dev/null
> > +++ b/drivers/arm-ffa/core.c
> > @@ -0,0 +1,1338 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * (C) Copyright 2022 ARM Limited
> > + * Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
> > + */
> > +
> > +#include "arm_ffa_prv.h"
> > +#include <asm/global_data.h>
> > +#include <common.h>
> > +#include <dm.h>
> > +#include <dm/device-internal.h>
> > +#include <dm/devres.h>
> > +#include <dm/root.h>
> > +#include <linux/errno.h>
> > +#include <linux/sizes.h>
> > +#include <log.h>
> > +#include <malloc.h>
> > +#include <string.h>
> > +#include <uuid.h>
> > +
> > +DECLARE_GLOBAL_DATA_PTR;
> > +
> > +/**
> > + * The device private data structure containing all the resident
> > + * data read from secure world
> > + */
> > +__ffa_runtime_data struct ffa_prvdata *ffa_priv_data;
>
> I think it's better if we just keep this as efi_runtime, especially
> since the rest of the declarations you use are marked as efi_*

In v4 the core driver is no longer dependent on EFI. The intent is to
be able to compile it without EFI support. So, we can't use
__efi_runtime* in the FFA driver when EFI is off.

__ffa_runtime* keywords are created in include/arm_ffa.h

Based on wether CONFIG_ARM_FFA_EFI_RUNTIME_MODE is on or off
__ffa_runtime* are set to __efi_runtime* or kept empty if the config
is off.

>
> [...]
>
> > +
> > +/**
> > + * ffa_device_get - create, bind and probe the arm_ffa device
> > + *
> > + * This boot time function makes sure the arm_ffa device is
> > + * created, bound to this driver, probed and ready to use.
> > + * Arm FF-A transport is implemented through a single u-boot
> > + * device managing the FF-A bus (arm_ffa).
> > + *
> > + * Return:
> > + *
> > + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure
> > + */
> > +int ffa_device_get(void)
> > +{
> > + int ret;
> > + struct udevice *dev = NULL;
> > +
> > + if (ffa_priv_data && ffa_priv_data->dev)
> > + return FFA_ERR_STAT_SUCCESS;
> > +
> > + ret = device_bind(dm_root(),
> > + DM_DRIVER_GET(arm_ffa),
> > + FFA_DRV_NAME,
> > + NULL,
> > + ofnode_null(),
> > + &dev);
> > + if (ret)
> > + return ret;
> > +
> > + /* The FF-A bus discovery succeeds when probing is successful */
> > + ret = device_probe(dev);
> > + if (ret) {
> > + ffa_err("arm_ffa device probing failed");
> > + ffa_remove_device(dev);
> > + return ret;
> > + }
> > +
> > + return FFA_ERR_STAT_SUCCESS;
>
> The return values in most of the functions are confusing. I think you
> should just get rid of FFA_ERR_STAT_SUCCESS and just return 0

Error handling and panics have been addressed in v4 patchset.
As stated in the v3 cover letter, error handling and panics will
be addressed in v4.

Please refer to this patch for the latest work:
https://lore.kernel.org/all/20220926101723.9965-5-abdellatif.elkhlifi@arm.com/

>
> [...]
>
> > +
> > + if (!ffa_priv_data->invoke_ffa_fn)
> > + panic("[FFA] no private data found\n");
>
> Get rid of all the panicking please. We've discussed this on a
> previous email. Isn't an error message enough?

Error handling and panics have been addressed in v4 patchset.
As stated in the v3 cover letter, error handling and panics will
be addressed in v4.

Please refer to this patch for the latest work:
https://lore.kernel.org/all/20220926101723.9965-5-abdellatif.elkhlifi@arm.com/

>
> [...]
>
> > + * ffa_map_rxtx_buffers - FFA_RXTX_MAP handler function
> > + * @buf_4k_pages: the minimum number of pages in each of the RX/TX
> > + * buffers
> > + *
> > + * This is the boot time function that implements FFA_RXTX_MAP FF-A function
> > + * to map the RX/TX buffers
> > + *
> > + * Return:
> > + *
> > + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure
> > + */
> > +static int ffa_map_rxtx_buffers(size_t buf_4k_pages)
> > +{
> > + int ret;
> > + ffa_value_t res = {0};
> > +
> > + if (!ffa_priv_data->invoke_ffa_fn)
> > + panic("[FFA] no private data found\n");
> > +
> > + ret = ffa_alloc_rxtx_buffers(buf_4k_pages);
> > + if (ret != FFA_ERR_STAT_SUCCESS)
> > + return ret;
> > +
> > + /*
> > + * we need to pass the physical addresses of the RX/TX buffers
> > + * in u-boot physical/virtual mapping is 1:1
> > + *no need to convert from virtual to physical
> > + */
> > +
> > + ffa_priv_data->invoke_ffa_fn((ffa_value_t){
> > + .a0 = FFA_RXTX_MAP,
> > + .a1 = ffa_priv_data->pair.txbuf,
> > + .a2 = ffa_priv_data->pair.rxbuf,
> > + .a3 = buf_4k_pages,
> > + .a4 = 0, .a5 = 0, .a6 = 0, .a7 = 0,
> > + }, &res);
> > +
> > + switch (res.a0) {
> > + case FFA_ERROR:
> > + {
>
> There are comments in v2 that are ignored throughout the patchset.
> Please check the remarks in v2 before sending a new patchset

Error handling and panics have been addressed in v4 patchset.
As stated in the v3 cover letter, error handling and panics will
be addressed in v4.

Please refer to this patch for the latest work:
https://lore.kernel.org/all/20220926101723.9965-5-abdellatif.elkhlifi@arm.com/

>
>
> > + switch (((int)res.a2)) {
> > + case FFA_ERR_STAT_INVALID_PARAMETERS:
> > + ffa_err("One or more fields in input parameters is incorrectly encoded");
> > + ret = -EPERM;
> > + break;
> > + case FFA_ERR_STAT_NO_MEMORY:
> > + ffa_err("Not enough memory");
> > + ret = -ENOMEM;
> > + break;
> > + case FFA_ERR_STAT_DENIED:
> > + ffa_err("Buffer pair already registered");
> > + ret = -EACCES;
> > + break;
> > + case FFA_ERR_STAT_NOT_SUPPORTED:
> > + ffa_err("This function is not implemented at this FF-A instance");
> > + ret = -EOPNOTSUPP;
> > + break;
> > + default:
> > + ffa_err("Undefined error (%d)",
> > + ((int)res.a2));
> > + ret = -EINVAL;
> > + }
> > + break;
> > + }
> > + case FFA_SUCCESS:
> > + ffa_info("RX/TX buffers mapped");
> > + return FFA_ERR_STAT_SUCCESS;
> > + default:
> > + ffa_err("Undefined response function (0x%lx)",
> > + res.a0);
> > + ret = -EINVAL;
> > + }
> > +
> > + ffa_free_rxtx_buffers();
> > +
> > + return ret;
> > +}
> > +
> > +/**
> [...]
>
> Regards
> /Ilias
>
>
> > +
> > +/**
> > + * Declaring the arm_ffa driver under UCLASS_FFA
> > + */
> > +
> > +U_BOOT_DRIVER(arm_ffa) = {
> > + .name = FFA_DRV_NAME,
> > + .id = UCLASS_FFA,
> > + .probe = ffa_probe,
> > +};
> > diff --git a/drivers/arm-ffa/efi_ffa_runtime_data_mgr.c b/drivers/arm-ffa/efi_ffa_runtime_data_mgr.c
> > new file mode 100644
> > index 0000000000..942601a7ba
> > --- /dev/null
> > +++ b/drivers/arm-ffa/efi_ffa_runtime_data_mgr.c
> > @@ -0,0 +1,94 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * (C) Copyright 2022 ARM Limited
> > + * Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
> > + */
> > +
> > +#include "arm_ffa_prv.h"
> > +
> > +/**
> > + * ffa_copy_runtime_data - copy the private data structure to the runtime area
> > + *
> > + * This boot time function copies the arm_ffa driver data structures including
> > + * partitions data to the EFI runtime data section.
> > + *
> > + * Return:
> > + *
> > + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure
> > + */
> > +efi_status_t ffa_copy_runtime_data(void)
> > +{
> > + efi_status_t efi_ret;
> > + efi_uintn_t prvdata_pages;
> > + efi_uintn_t descs_pages;
> > + struct ffa_prvdata **prvdata = NULL; /* Pointer to the current structure */
> > + struct ffa_prvdata *runtime_prvdata = NULL; /* Pointer to the structure runtime copy */
> > + u64 runtime_descs = 0;
> > +
> > + prvdata = ffa_bus_prvdata_get();
> > +
> > + printf("INFO: EFI: FFA: prv data area at 0x%llx\n", (u64)prvdata);
> > +
> > + /* allocate private data runtime area */
> > +
> > + prvdata_pages = efi_size_in_pages(sizeof(struct ffa_prvdata));
> > + efi_ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES,
> > + EFI_RUNTIME_SERVICES_DATA,
> > + prvdata_pages,
> > + (u64 *)&runtime_prvdata);
> > +
> > + if (efi_ret != EFI_SUCCESS) {
> > + printf("ERROR: EFI: FFA: allocating runtime data (err: 0x%lx, addr 0x%llx)\n",
> > + efi_ret, (u64)runtime_prvdata);
> > +
> > + return efi_ret;
> > + }
> > +
> > + printf("INFO: EFI: FFA: runtime data area at 0x%llx\n", (u64)runtime_prvdata);
> > +
> > + if (!runtime_prvdata)
> > + return EFI_INVALID_PARAMETER;
> > +
> > + /* allocate the partition data runtime area */
> > +
> > + descs_pages = efi_size_in_pages((*prvdata)->partitions.count *
> > + sizeof(struct ffa_partition_desc));
> > + efi_ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES,
> > + EFI_RUNTIME_SERVICES_DATA,
> > + descs_pages,
> > + &runtime_descs);
> > +
> > + if (efi_ret != EFI_SUCCESS) {
> > + printf("ERROR: EFI: FFA: allocating runtime SPs data (err: 0x%lx, addr 0x%llx)\n",
> > + efi_ret, runtime_descs);
> > +
> > + efi_free_pages((u64)runtime_prvdata, prvdata_pages);
> > +
> > + return efi_ret;
> > + }
> > +
> > + printf("INFO: EFI: FFA: SPs runtime area at 0x%llx\n", (u64)runtime_descs);
> > +
> > + if (!runtime_descs)
> > + return EFI_INVALID_PARAMETER;
> > +
> > + *runtime_prvdata = **prvdata;
> > +
> > + runtime_prvdata->dev = NULL;
> > + runtime_prvdata->ffa_ops.partition_info_get = NULL;
> > + runtime_prvdata->ffa_ops.rxtx_unmap = NULL;
> > + runtime_prvdata->partitions.descs = (struct ffa_partition_desc *)runtime_descs;
> > + runtime_prvdata->pair.rxbuf = 0;
> > + runtime_prvdata->pair.txbuf = 0;
> > +
> > + /*
> > + * Update the private data structure pointer in the driver
> > + * no need to free the old structure. devm takes care of that
> > + */
> > + *prvdata = runtime_prvdata;
> > +
> > + printf("INFO: EFI: FFA: runtime prv data now at 0x%llx , SPs count %d\n",
> > + (u64)*prvdata, (*prvdata)->partitions.count);
> > +
> > + return FFA_ERR_STAT_SUCCESS;
> > +}
> > diff --git a/include/arm_ffa.h b/include/arm_ffa.h
> > new file mode 100644
> > index 0000000000..ee9ce2d99d
> > --- /dev/null
> > +++ b/include/arm_ffa.h
> > @@ -0,0 +1,132 @@
> > +/* SPDX-License-Identifier: GPL-2.0+ */
> > +/*
> > + * (C) Copyright 2022 ARM Limited
> > + * Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
> > + */
> > +
> > +#ifndef __ARM_FFA_H
> > +#define __ARM_FFA_H
> > +
> > +#include <linux/printk.h>
> > +
> > +/*
> > + * This header is public. It can be used by clients to access
> > + * data structures and definitions they need
> > + */
> > +
> > +/*
> > + * Macros for displaying logs
> > + */
> > +
> > +#define ffa_info(fmt, ...) pr_info("[FFA] " fmt "\n", ##__VA_ARGS__)
> > +#define ffa_err(fmt, ...) pr_err("[FFA] " fmt "\n", ##__VA_ARGS__)
> > +
> > +/*
> > + * The driver operations success error code
> > + */
> > +#define FFA_ERR_STAT_SUCCESS (0)
> > +
> > +/*
> > + * struct ffa_partition_info - Partition information descriptor
> > + * @id: Partition ID
> > + * @exec_ctxt: Execution context count
> > + * @properties: Partition properties
> > + *
> > + * Data structure containing information about partitions instantiated in the system
> > + * This structure is filled with the data queried by FFA_PARTITION_INFO_GET
> > + */
> > +struct __packed ffa_partition_info {
> > + u16 id;
> > + u16 exec_ctxt;
> > +/* partition supports receipt of direct requests */
> > +#define FFA_PARTITION_DIRECT_RECV BIT(0)
> > +/* partition can send direct requests. */
> > +#define FFA_PARTITION_DIRECT_SEND BIT(1)
> > +/* partition can send and receive indirect messages. */
> > +#define FFA_PARTITION_INDIRECT_MSG BIT(2)
> > + u32 properties;
> > +};
> > +
> > +/*
> > + * struct ffa_send_direct_data - Data structure hosting the data
> > + * used by FFA_MSG_SEND_DIRECT_{REQ,RESP}
> > + * @data0-4: Data read/written from/to x3-x7 registers
> > + *
> > + * Data structure containing the data to be sent by FFA_MSG_SEND_DIRECT_REQ
> > + * or read from FFA_MSG_SEND_DIRECT_RESP
> > + */
> > +
> > +/* For use with FFA_MSG_SEND_DIRECT_{REQ,RESP} which pass data via registers */
> > +struct __packed ffa_send_direct_data {
> > + unsigned long data0; /* w3/x3 */
> > + unsigned long data1; /* w4/x4 */
> > + unsigned long data2; /* w5/x5 */
> > + unsigned long data3; /* w6/x6 */
> > + unsigned long data4; /* w7/x7 */
> > +};
> > +
> > +#if CONFIG_IS_ENABLED(ARM_FFA_EFI_RUNTIME_MODE)
> > +
> > +#include <efi_loader.h>
> > +
> > +/*
> > + * __ffa_runtime - controls whether functions are
> > + * available after calling the EFI ExitBootServices service.
> > + * Functions tagged with these keywords are resident (available at boot time and
> > + * at runtime)
> > + */
> > +
> > +#define __ffa_runtime_data __efi_runtime_data
> > +#define __ffa_runtime __efi_runtime
> > +
> > +#else
> > +
> > +/*
> > + * The FF-A driver is independent from EFI
> > + */
> > +
> > +#define __ffa_runtime_data
> > +#define __ffa_runtime
> > +
> > +#endif
> > +
> > +/**
> > + * struct ffa_bus_ops - The driver operations structure
> > + * @partition_info_get: callback for the FFA_PARTITION_INFO_GET
> > + * @sync_send_receive: callback for the FFA_MSG_SEND_DIRECT_REQ
> > + * @rxtx_unmap: callback for the FFA_RXTX_UNMAP
> > + *
> > + * The data structure providing all the operations supported by the driver.
> > + * This structure is EFI runtime resident.
> > + */
> > +struct ffa_bus_ops {
> > + int (*partition_info_get)(const char *uuid_str,
> > + u32 *parts_size, struct ffa_partition_info *buffer);
> > + int (*sync_send_receive)(u16 dst_part_id, struct ffa_send_direct_data *msg);
> > + int (*rxtx_unmap)(void);
> > +};
> > +
> > +/**
> > + * The device driver and the Uclass driver public functions
> > + */
> > +
> > +/**
> > + * ffa_bus_ops_get - driver operations getter
> > + */
> > +const struct ffa_bus_ops * __ffa_runtime ffa_bus_ops_get(void);
> > +
> > +/**
> > + * ffa_bus_discover - discover FF-A bus and probes the arm_ffa device
> > + */
> > +int ffa_bus_discover(void);
> > +
> > +#if CONFIG_IS_ENABLED(ARM_FFA_EFI_RUNTIME_MODE)
> > +
> > +/**
> > + * ffa_copy_runtime_data - copy the private data structure and the SPs data to the runtime area
> > + */
> > +efi_status_t ffa_copy_runtime_data(void);
> > +
> > +#endif
> > +
> > +#endif
> > diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
> > index a432e43871..6eebbe9c7d 100644
> > --- a/include/dm/uclass-id.h
> > +++ b/include/dm/uclass-id.h
> > @@ -55,6 +55,7 @@ enum uclass_id {
> > UCLASS_EFI_MEDIA, /* Devices provided by UEFI firmware */
> > UCLASS_ETH, /* Ethernet device */
> > UCLASS_ETH_PHY, /* Ethernet PHY device */
> > + UCLASS_FFA, /* Arm Firmware Framework for Armv8-A */
> > UCLASS_FIRMWARE, /* Firmware */
> > UCLASS_FUZZING_ENGINE, /* Fuzzing engine */
> > UCLASS_FS_FIRMWARE_LOADER, /* Generic loader */
> > diff --git a/include/uuid.h b/include/uuid.h
> > index 4a4883d3b5..789f8e0f15 100644
> > --- a/include/uuid.h
> > +++ b/include/uuid.h
> > @@ -44,4 +44,12 @@ int uuid_guid_get_bin(const char *guid_str, unsigned char *guid_bin);
> > const char *uuid_guid_get_str(const unsigned char *guid_bin);
> > void gen_rand_uuid(unsigned char *uuid_bin);
> > void gen_rand_uuid_str(char *uuid_str, int str_format);
> > +
> > +#ifdef CONFIG_ARM_FFA_TRANSPORT
> > +/**
> > + * ffa_uuid_str_to_bin - Converts a big endian UUID string to a little endian buffer
> > + */
> > +int ffa_uuid_str_to_bin(const char *uuid_str, unsigned char *uuid_bin);
> > +#endif
> > +
> > #endif
> > diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
> > index 4da64b5d29..e02bb445f5 100644
> > --- a/lib/efi_loader/efi_boottime.c
> > +++ b/lib/efi_loader/efi_boottime.c
> > @@ -23,6 +23,10 @@
> > #include <asm/setjmp.h>
> > #include <linux/libfdt_env.h>
> >
> > +#if defined(CONFIG_ARM_FFA_TRANSPORT)
> > +#include <arm_ffa.h>
> > +#endif
> > +
> > DECLARE_GLOBAL_DATA_PTR;
> >
> > /* Task priority level */
> > @@ -2113,6 +2117,10 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle,
> > struct efi_event *evt, *next_event;
> > efi_status_t ret = EFI_SUCCESS;
> >
> > +#if defined(CONFIG_ARM_FFA_TRANSPORT)
> > + int ffa_ret;
> > +#endif
> > +
> > EFI_ENTRY("%p, %zx", image_handle, map_key);
> >
> > /* Check that the caller has read the current memory map */
> > @@ -2173,6 +2181,15 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle,
> > dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL);
> > }
> >
> > +#if defined(CONFIG_ARM_FFA_TRANSPORT)
> > + /* unmap FF-A RX/TX buffers */
> > + ffa_ret = ffa_bus_ops_get()->rxtx_unmap();
> > + if (ffa_ret)
> > + debug("[efi_boottime][ERROR]: can not unmap FF-A RX/TX buffers\n");
> > + else
> > + debug("[efi_boottime][INFO]: FF-A RX/TX buffers unmapped\n");
> > +#endif
> > +
> > /* Patch out unsupported runtime function */
> > efi_runtime_detach();
> >
> > diff --git a/lib/uuid.c b/lib/uuid.c
> > index 284f8113ff..50b3e61d59 100644
> > --- a/lib/uuid.c
> > +++ b/lib/uuid.c
> > @@ -1,6 +1,7 @@
> > // SPDX-License-Identifier: GPL-2.0+
> > /*
> > * Copyright 2011 Calxeda, Inc.
> > + * Copyright 2022 ARM Limited
> > */
> >
> > #include <common.h>
> > @@ -342,6 +343,70 @@ int uuid_str_to_bin(const char *uuid_str, unsigned char *uuid_bin,
> > return 0;
> > }
> >
> > +#ifdef CONFIG_ARM_FFA_TRANSPORT
> > +/**
> > + * ffa_uuid_str_to_bin - Converts a big endian UUID string to a little endian buffer
> > + * @uuid_str: UUID string in big endian format (36 bytes wide + '/0')
> > + * @uuid_bin: preallocated 16 bytes UUID buffer in little endian format
> > + *
> > + * UUID string is 36 characters (36 bytes):
> > + *
> > + * xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
> > + * be be be be be
> > + *
> > + * where x is a hexadecimal character. Fields are separated by '-'s.
> > + * When converting to a binary UUID, these endianness rules apply:
> > + * be: means the field in the string is considered a big endian hex number
> > + * and should be converted to little endian binary format
> > + *
> > + * Return:
> > + *
> > + * uuid_bin filled with little endian UUID data
> > + * On success 0 is returned. Otherwise, failure code.
> > + */
> > +int ffa_uuid_str_to_bin(const char *uuid_str, unsigned char *uuid_bin)
> > +{
> > + u16 tmp16 = 0;
> > + u32 tmp32 = 0;
> > + u64 tmp64 = 0;
> > +
> > + if (!uuid_str_valid(uuid_str) || !uuid_bin)
> > + return -EINVAL;
> > +
> > + /*
> > + * reverse bytes from big to little endian
> > + */
> > + tmp32 = simple_strtoul(uuid_str, NULL, 16);
> > + memcpy(uuid_bin, &tmp32, 4);
> > +
> > + /*
> > + * reverse bytes from big to little endian
> > + */
> > + tmp16 = simple_strtoul(uuid_str + 9, NULL, 16);
> > + memcpy(uuid_bin + 4, &tmp16, 2);
> > +
> > + /*
> > + * reverse bytes from big to little endian
> > + */
> > + tmp16 = simple_strtoul(uuid_str + 14, NULL, 16);
> > + memcpy(uuid_bin + 6, &tmp16, 2);
> > +
> > + /*
> > + * reverse bytes from big to little endian
> > + */
> > + tmp16 = simple_strtoul(uuid_str + 19, NULL, 16);
> > + memcpy(uuid_bin + 8, &tmp16, 2);
> > +
> > + /*
> > + * reverse bytes from big to little endian
> > + */
> > + tmp64 = simple_strtoull(uuid_str + 24, NULL, 16);
> > + memcpy(uuid_bin + 10, (char *)&tmp64, 6);
> > +
> > + return 0;
> > +}
> > +#endif
> > +
> > /*
> > * uuid_bin_to_str() - convert big endian binary data to string UUID or GUID.
> > *
> > --
> > 2.17.1
> >