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

Ilias Apalodimas
2022-08-12T07:40:13Z

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?

[...]

> +
> +/* 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?

[...]

> + *
> + * 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

> +};
> +
> +/**
> + * 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_*

[...]

> +
> +/**
> + * 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

[...]

> +
> + 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?

[...]

> + * 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

> + 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
>