[PATCH v5 10/24] fwu_arm_psa: Read the FWU directory through get_image_info()

Sughosh Ganu sughosh.ganu at linaro.org
Tue Nov 11 09:44:31 CET 2025


On Fri, 26 Sept 2025 at 19:44, <abdellatif.elkhlifi at arm.com> wrote:
>
> From: Abdellatif El Khlifi <abdellatif.elkhlifi at arm.com>
>
> Implement efi_fill_image_desc_array()
>
> Arm PSA implementation of efi_fill_image_desc_array() reads
> the images information from the cached directory in Secure
> world then populates the images descriptors.
>
> The FWU Arm PSA setup ABIs have been implemented to allow
> reading the directory data.
>
> The ABIs are specified by the Platform Security Firmware Update for
> the A-profile Arm Architecture specification [1].
>
> For more details about PSA please see [2].
>
> The implemented ABIs are as follows:
>
> FWU_DISCOVER
> FWU_OPEN
> FWU_READ_STREAM
> FWU_COMMIT
>
> [1]: DEN0118, 1.0 A:
>     https://developer.arm.com/documentation/den0118/latest/
> [2]: https://www.psacertified.org/
>
> Signed-off-by: Abdellatif El Khlifi <abdellatif.elkhlifi at arm.com>
> Signed-off-by: Davidson kumaresan <davidson.kumaresan at arm.com>
> Cc: Sughosh Ganu <sughosh.ganu at linaro.org>
> Cc: Tom Rini <trini at konsulko.com>
> Cc: Ilias Apalodimas <ilias.apalodimas at linaro.org>
> Cc: Simon Glass <sjg at chromium.org>
> Cc: Michal Simek <michal.simek at amd.com>
> Cc: Marek Vasut <marek.vasut+renesas at mailbox.org>
> Cc: Casey Connolly <casey.connolly at linaro.org>
>
> ---
>
> Changelog of changes:
> ===========================
>
> v5:
>
> * As suggested by Ilias: Implement efi_fill_image_desc_array() for PSA
>    instead of changing efi_firmware_get_image_info()
> * Address kernel-doc warnings
>
> v4:
>
> * Update the function headers in fwu_arm_psa.c to pass kernel-doc tests
>
> v2:
>
> * As suggested by Michal: Add /** for marking kernel-doc format
>
> v1:
>
> * Implement get_image_info()
>
>  include/fwu_arm_psa.h         | 187 +++++++++++
>  lib/fwu_updates/fwu_arm_psa.c | 573 +++++++++++++++++++++++++++++++++-
>  2 files changed, 759 insertions(+), 1 deletion(-)
>
> diff --git a/include/fwu_arm_psa.h b/include/fwu_arm_psa.h
> index 5e1229f3bdb..9eb67ef4243 100644
> --- a/include/fwu_arm_psa.h
> +++ b/include/fwu_arm_psa.h
> @@ -10,9 +10,16 @@
>  #ifndef __FWU_ARM_PSA_H
>  #define __FWU_ARM_PSA_H
>
> +#include <efi_loader.h>
>  #include <linux/bitfield.h>
>  #include <u-boot/uuid.h>
>
> +#define DEFAULT_HW_INSTANCE            (1)
> +
> +/* Default values of the ESRT fields which are not supported at this stage */
> +#define PACKAGE_VERSION_NOT_SUP                (0xffffffff)
> +#define LAST_ATTEMPT_NOT_SUP           (0)
> +
>  #define FWU_BUFFER_PAGES               (1024)
>
>  /* 4 MB buffer shared with secure world */
> @@ -26,6 +33,13 @@
>  #define TS_FWU_SERVICE_UUID            "38a82368-061b-0e47-7497-fd53fb8bce0c"
>  /* In little-endian equivalent to:  6823a838-1b06-470e-9774-0cce8bfb53fd */
>
> +/* TS FWU directory UUID string (in big-endian format) */
> +#define FWU_DIRECTORY_CANONICAL_UUID   "d958eede-4751-d34a-90a2-a541236e6677"
> +/* In little-endian equivalent to:  deee58d9-5147-4ad3-a290-77666e2341a5 */
> +
> +/* The entries correspond to the payloads in the storage device and the fake ESRT image */
> +#define FWU_DIRECTORY_IMAGE_ENTRIES_COUNT (CONFIG_FWU_NUM_IMAGES_PER_BANK + 1)
> +
>  #define TS_RPC_MEM_RETRIEVE            (0xff0001)
>  #define TS_RPC_SERVICE_INFO_GET                (0xff0003)
>  #define RPC_SUCCESS                    (0)
> @@ -34,6 +48,11 @@
>  #define GET_SVC_IFACE_ID(x)            \
>                          ((u8)(FIELD_GET(SVC_IFACE_ID_GET_MASK, (x))))
>
> +#define SVC_ID_MASK                    GENMASK(15, 0)
> +#define SVC_IFACE_ID_SET_MASK          GENMASK(23, 16)
> +#define PACK_SVC_IFACE_ID(svc, iface)  (FIELD_PREP(SVC_ID_MASK, (svc)) | \
> +                                       FIELD_PREP(SVC_IFACE_ID_SET_MASK, (iface)))
> +
>  #define HANDLE_MSW_MASK                        GENMASK(63, 32)
>  #define HANDLE_LSW_MASK                        GENMASK(31, 0)
>  #define GET_FWU_BUF_MSW(x)             \
> @@ -41,6 +60,174 @@
>  #define GET_FWU_BUF_LSW(x)             \
>                                 ((u32)(FIELD_GET(HANDLE_LSW_MASK, (x))))
>
> +enum fwu_abis {
> +       FWU_DISCOVER = 0,
> +       FWU_OPEN = 19,
> +       FWU_READ_STREAM = 21,
> +       FWU_COMMIT = 22,
> +       /* To be updated when adding new FWU IDs */
> +       FWU_FIRST_ID = FWU_DISCOVER, /* Lowest number ID */
> +       FWU_LAST_ID = FWU_COMMIT, /* Highest number ID */
> +};
> +
> +enum fwu_abi_errcode {
> +       FWU_UNKNOWN = 1,
> +       FWU_BUSY,
> +       FWU_OUT_OF_BOUNDS,
> +       FWU_AUTH_FAIL,
> +       FWU_NO_PERMISSION,
> +       FWU_DENIED,
> +       FWU_RESUME,
> +       FWU_NOT_AVAILABLE,
> +       MAX_NUMBER_FWU_ERR
> +};
> +
> +/* Container structure and helper macros to map between an FF-A error and relevant error log */
> +struct fwu_abi_errmap {
> +       char *err_str[MAX_NUMBER_FWU_ERR];
> +};
> +
> +#define FWU_ERRMAP_COUNT (FWU_LAST_ID - FWU_FIRST_ID + 1)
> +#define FWU_ID_TO_ERRMAP_ID(fwu_id) ((fwu_id) - FWU_FIRST_ID)
> +
> +/**
> + * struct fwu_open_args - fwu_open ABI arguments
> + * @function_id: fwu_open service ID
> + * @image_type_guid: GUID of the image to be opened
> + * @op_type: The operation that the Client will perform on the image
> + */
> +struct __packed fwu_open_args {
> +       u32 function_id;
> +       efi_guid_t image_type_guid;
> +#define FWU_OP_TYPE_READ 0
> +#define FWU_OP_TYPE_WRITE 1
> +       u8  op_type;
> +};
> +
> +/**
> + * struct fwu_open_resp - fwu_open ABI returns
> + * @status: The ABI return status
> + * @handle: Staging context identifier
> + */
> +struct __packed fwu_open_resp {
> +       int status;
> +       u32  handle;
> +};
> +
> +/**
> + * struct fwu_discover_args - fwu_discover ABI arguments
> + * @function_id: fwu_discover service ID
> + */
> +struct __packed fwu_discover_args {
> +       u32 function_id;
> +};
> +
> +/**
> + * struct fwu_discover_resp - fwu_discover ABI returns
> + * @status: The ABI return status
> + * @service_status: the status of the service provider
> + * @version_major: the ABI major version
> + * @version_minor: the ABI minor version
> + * @off_function_presence: the offset (in bytes) of the function_presence array
> + *                         relative to the start of this data structure
> + * @num_func: the number of entries in the function_presence array
> + * @max_payload_size: the maximum number of bytes that a payload can contain
> + * @flags: flags listing the update capabilities
> + * @vendor_specific_flags: Vendor specific update capabilities flags
> + * @function_presence: array of bytes indicating functions that are implemented
> + */
> +struct __packed fwu_discover_resp {
> +       int status;
> +       u16 service_status;
> +       u8 version_major;
> +       u8 version_minor;
> +       u16 off_function_presence;
> +       u16 num_func;
> +       u64 max_payload_size;
> +       u32 flags;
> +       u32 vendor_specific_flags;
> +       void *function_presence;
> +};
> +
> +/**
> + * struct fwu_read_stream_args - fwu_read_stream ABI arguments
> + * @function_id: fwu_read_stream service ID
> + * @handle: The handle of the context being read from
> + */
> +struct __packed fwu_read_stream_args {
> +       u32 function_id;
> +       u32  handle;
> +};
> +
> +/**
> + * struct fwu_read_stream_resp - fwu_read_stream ABI returns
> + * @status: The ABI return status
> + * @read_bytes: Number of bytes read by the current ABI call
> + * @total_bytes: Total number of bytes that can be read
> + * @payload: The read data by the current ABI call
> + */
> +struct __packed fwu_read_stream_resp {
> +       int status;
> +       u32  read_bytes;
> +       u32  total_bytes;
> +       u8  payload[];
> +};
> +
> +/**
> + * struct fwu_commit_args - fwu_commit ABI arguments
> + * @function_id: fwu_commit service ID
> + * @handle: The handle of the context being closed
> + * @acceptance_req: If positive, the Client requests the image to be marked as
> + *                  unaccepted
> + * @max_atomic_len: Hint, maximum time (in ns) that the Update Agent can execute
> + *                  continuously without yielding back to the Client state
> + */
> +struct __packed fwu_commit_args {
> +       u32 function_id;
> +       u32 handle;
> +#define FWU_IMG_ACCEPTED 0
> +#define FWU_IMG_NOT_ACCEPTED 1
> +       u32 acceptance_req;
> +       u32 max_atomic_len;
> +};
> +
> +/**
> + * struct fwu_commit_resp - fwu_commit ABI returns
> + * @status: The ABI return status
> + * @progress: Units of work already completed by the Update Agent
> + * @total_work: Units of work the Update Agent must perform until fwu_commit
> + *              returns successfully
> + */
> +struct __packed fwu_commit_resp {
> +       int status;
> +       u32 progress;
> +       u32 total_work;
> +};
> +
> +/*
> + * FWU directory information structures
> + */
> +
> +struct __packed fwu_image_info_entry {
> +       efi_guid_t image_guid;
> +       u32 client_permissions;
> +       u32 img_max_size;
> +       u32 lowest_acceptable_version;
> +       u32 img_version;
> +       u32 accepted;
> +       u32 reserved;
> +};
> +
> +struct __packed fwu_image_directory {
> +       u32 directory_version;
> +       u32 img_info_offset;
> +       u32 num_images;
> +       u32 correct_boot;
> +       u32 img_info_size;
> +       u32 reserved;
> +       struct fwu_image_info_entry entries[FWU_DIRECTORY_IMAGE_ENTRIES_COUNT];

This can be a runtime allocation, similar to how it is implemented for
the v2 metadata structure. That way, there won't be an issue of a
mismatch between the above macro and the num_images field.

> +};
> +
>  /**
>   * fwu_agent_init() - Setup the FWU agent
>   * Perform the initializations required to communicate
> diff --git a/lib/fwu_updates/fwu_arm_psa.c b/lib/fwu_updates/fwu_arm_psa.c
> index 8ac53cc9152..589a6283611 100644
> --- a/lib/fwu_updates/fwu_arm_psa.c
> +++ b/lib/fwu_updates/fwu_arm_psa.c
> @@ -9,7 +9,6 @@
>  #include <arm_ffa.h>
>  #include <dm.h>
>  #include <fwu_arm_psa.h>
> -#include <efi_loader.h>
>  #include <fwu.h>
>  #include <log.h>
>  #include <malloc.h>
> @@ -21,7 +20,465 @@ static u64 g_fwu_buf_handle;
>  static u16 g_fwu_sp_id;
>  static struct udevice *g_dev;
>  static u16 g_svc_interface_id;
> +static u64 g_max_payload_size;
> +static u8 g_fwu_version_major;
> +static u8 g_fwu_version_minor;
>  static bool g_fwu_initialized;
> +struct fwu_image_directory g_fwu_cached_directory;
> +
> +/* Error mapping declarations */
> +
> +int fwu_to_std_errmap[MAX_NUMBER_FWU_ERR] = {
> +       [FWU_UNKNOWN] = -EOPNOTSUPP,
> +       [FWU_OUT_OF_BOUNDS] = -ERANGE,
> +       [FWU_AUTH_FAIL] = -EFAULT,
> +       [FWU_BUSY] = -EBUSY,
> +       [FWU_NO_PERMISSION] = -EPERM,
> +       [FWU_DENIED] = -EACCES,
> +       [FWU_RESUME] = -EAGAIN,
> +       [FWU_NOT_AVAILABLE] = -ENAVAIL,
> +};
> +
> +static struct fwu_abi_errmap err_msg_map[FWU_ERRMAP_COUNT] = {
> +       [FWU_ID_TO_ERRMAP_ID(FWU_OPEN)] = {
> +               {
> +                       [FWU_UNKNOWN] =
> +                       "FWU_UNKNOWN: Image type with GUID=image_type_guid does not exist",
> +                       [FWU_DENIED] =
> +                       "FWU_DENIED: An image cannot be opened for writing outside of this Staging state",
> +                       [FWU_NOT_AVAILABLE] =
> +                       "FWU_NOT_AVAILABLE: The Update Agent does not support the op_type for this image",
> +               },
> +       },
> +       [FWU_ID_TO_ERRMAP_ID(FWU_READ_STREAM)] = {
> +               {
> +                       [FWU_UNKNOWN] =
> +                       "FWU_UNKNOWN: Handle is not recognized",
> +                       [FWU_DENIED] =
> +                       "FWU_DENIED: The image cannot be temporarily read from",
> +                       [FWU_NO_PERMISSION] =
> +                       "FWU_NO_PERMISSION: The image cannot be read from",
> +               },
> +       },
> +       [FWU_ID_TO_ERRMAP_ID(FWU_COMMIT)] = {
> +               {
> +                       [FWU_UNKNOWN] =
> +                       "FWU_UNKNOWN: Handle is not recognized",
> +                       [FWU_DENIED] =
> +                       "FWU_DENIED: The image can only be accepted after activation",
> +                       [FWU_AUTH_FAIL] =
> +                       "FWU_AUTH_FAIL: Image closed, authentication failed",
> +                       [FWU_RESUME] =
> +                       "FWU_RESUME: The Update Agent yielded",
> +               },
> +       },
> +};
> +
> +/**
> + * fwu_to_std_errno() - convert FWU error code to standard error code
> + * @fwu_errno: Error code returned by the FWU ABI
> + *
> + * Description: Map the given FWU error code as specified
> + * by the spec to a U-Boot standard error code.
> + *
> + * Return: The standard error code on success. . Otherwise, failure.
> + */
> +static int fwu_to_std_errno(int fwu_errno)
> +{
> +       int err_idx = -fwu_errno;
> +
> +       /* Map the FWU error code to the standard u-boot error code */
> +       if (err_idx > 0 && err_idx < MAX_NUMBER_FWU_ERR)
> +               return fwu_to_std_errmap[err_idx];
> +       return -EINVAL;
> +}
> +
> +/**
> + * fwu_print_error_log() - print the error log of the selected FWU ABI
> + * @fwu_id:    FWU ABI ID
> + * @fwu_errno: Error code returned by the FWU ABI
> + *
> + * Description: Map the FWU error code to the error log relevant to the
> + * selected FWU ABI. Then the error log is printed.
> + *
> + * Return: 0 on success. Otherwise, failure.
> + */
> +static int fwu_print_error_log(u32 fwu_id, int fwu_errno)
> +{
> +       int err_idx = -fwu_errno, abi_idx = 0;
> +
> +       /* Map the FWU error code to the corresponding error log */
> +
> +       if (err_idx <= 0 || err_idx >= MAX_NUMBER_FWU_ERR)
> +               return -EINVAL;
> +
> +       if (fwu_id < FWU_FIRST_ID || fwu_id > FWU_LAST_ID)
> +               return -EINVAL;
> +
> +       abi_idx = FWU_ID_TO_ERRMAP_ID(fwu_id);
> +
> +       if (!err_msg_map[abi_idx].err_str[err_idx])
> +               return -EINVAL;
> +
> +       log_err("%s\n", err_msg_map[abi_idx].err_str[err_idx]);
> +
> +       return 0;
> +}
> +
> +/**
> + * fwu_invoke_svc() - FWU service call request
> + * @svc_id: FWU ABI function ID
> + * @svc_name: FWU ABI function name
> + * @req_args_sz: Size in bytes of the arguments of the FWU ABI function
> + * @expect_resp_sz: Size in bytes of the response of the FWU ABI function
> + * @extra_resp_bytes: Size in bytes of the extra response data
> + *
> + * Description: Invoke a FWU ABI by issuing a TS service call request.
> + *
> + * Return: 0 on success. Otherwise, failure.
> + */
> +static int fwu_invoke_svc(u32 svc_id, const char *svc_name,
> +                         u32 req_args_sz, u32 expect_resp_sz,
> +                         u32 *extra_resp_bytes)
> +{
> +       struct ffa_send_direct_data msg;
> +       int ret;
> +       int *svc_status_in_buf = g_fwu_buf, svc_status_in_reg;
> +       u32 expect_total_resp_sz;
> +
> +       log_debug("FWU: Invoking %s\n", svc_name);
> +
> +       if (!expect_resp_sz || !svc_name || !req_args_sz) {
> +               log_err("%s: Invalid invoke arguments\n", svc_name);
> +               return -EINVAL;
> +       }
> +
> +       msg.data0 = PACK_SVC_IFACE_ID(svc_id, g_svc_interface_id);
> +       msg.data1 = GET_FWU_BUF_LSW(g_fwu_buf_handle);
> +       msg.data2 = GET_FWU_BUF_MSW(g_fwu_buf_handle);
> +       msg.data3 = req_args_sz;
> +       msg.data4 = 0;
> +
> +       ret = ffa_sync_send_receive(g_dev, g_fwu_sp_id, &msg, 0);
> +       if (ret) {
> +               log_err("%s: FF-A error %d\n", svc_name, ret);
> +               return ret;
> +       }
> +
> +       if (msg.data0 != PACK_SVC_IFACE_ID(svc_id, g_svc_interface_id)) {
> +               log_err("%s: Unexpected service/interface ID 0x%lx\n",
> +                       svc_name, msg.data0);
> +               return -EINVAL;
> +       }
> +
> +       if (msg.data1 != RPC_SUCCESS) {
> +               log_err("%s: TS RPC error 0x%lx\n", svc_name, msg.data1);
> +               return -ECOMM;
> +       }
> +
> +       svc_status_in_reg = (int)msg.data2;
> +       if (*svc_status_in_buf != svc_status_in_reg) {
> +               log_err("%s: Status mismatch (reg %d , buf %d)\n",
> +                       svc_name, svc_status_in_reg, *svc_status_in_buf);
> +               return -EINVAL;
> +       }
> +
> +       if (svc_status_in_reg < 0) {
> +               fwu_print_error_log(svc_id, svc_status_in_reg);
> +               if (svc_status_in_reg != -FWU_RESUME)
> +                       return fwu_to_std_errno(svc_status_in_reg);
> +       }
> +
> +       if (!extra_resp_bytes)
> +               expect_total_resp_sz = expect_resp_sz;
> +       else
> +               expect_total_resp_sz = expect_resp_sz + *extra_resp_bytes;
> +
> +       if (msg.data3 != expect_total_resp_sz) {
> +               log_err("%s: Unexpected response size (%ld , %d)\n",
> +                       svc_name, msg.data3, expect_total_resp_sz);
> +               return -EINVAL;
> +       }
> +
> +       if (svc_status_in_reg == -FWU_RESUME)
> +               return fwu_to_std_errno(svc_status_in_reg);
> +
> +       return 0;
> +}
> +
> +/**
> + * fwu_discover() -  fwu_discover ABI
> + *
> + * Description: This call indicates the version of the ABI alongside a list of
> + * the implemented functions (aka services).
> + * Only max_payload_size is saved for future use.
> + *
> + * Return: 0 on success. Otherwise, failure.
> + */
> +static int fwu_discover(void)
> +{
> +       int ret;
> +       struct fwu_discover_args *args = g_fwu_buf;
> +       struct fwu_discover_resp *resp = g_fwu_buf;
> +       char *svc_name = "FWU_DISCOVER";
> +
> +       /* Filling the arguments in the shared buffer */
> +       args->function_id = FWU_DISCOVER;
> +
> +       /* Executing the FWU ABI through the FF-A bus */
> +       ret = fwu_invoke_svc(args->function_id, svc_name, sizeof(*args),
> +                            sizeof(int), NULL);
> +       if (ret) {
> +               log_debug("FWU_DISCOVER: error %d\n", ret);
> +               return ret;
> +       }
> +
> +       g_max_payload_size = resp->max_payload_size;
> +       g_fwu_version_major = resp->version_major;
> +       g_fwu_version_minor = resp->version_minor;
> +
> +       log_debug("FWU: max_payload_size %llu\n", g_max_payload_size);
> +       log_info("FWU: ABI version %d.%d detected\n", g_fwu_version_major,
> +                g_fwu_version_minor);
> +
> +       return 0;
> +}
> +
> +/**
> + * fwu_open() -  fwu_open ABI
> + * @guid: GUID of the image to be opened
> + * @op_type: The operation that the Client will perform on the image
> + * @handle: Staging context identifier
> + *
> + * Description: Returns a handle to the image with a given GUID.
> + *
> + * Return: 0 on success. Otherwise, failure.
> + */
> +static int fwu_open(const efi_guid_t *guid, u8  op_type,
> +                   u32 *handle)
> +{
> +       int ret;
> +       struct fwu_open_args *args = g_fwu_buf;
> +       struct fwu_open_resp *resp = g_fwu_buf;
> +       char *svc_name = "FWU_OPEN";
> +
> +       if (!guid || !handle)
> +               return -EINVAL;
> +
> +       /* Filling the arguments in the shared buffer */
> +       args->function_id = FWU_OPEN;
> +
> +       guidcpy(&args->image_type_guid, guid);
> +       args->op_type = op_type;
> +
> +       /* Executing the FWU ABI through the FF-A bus */
> +       ret = fwu_invoke_svc(args->function_id, svc_name,
> +                            sizeof(*args), sizeof(*resp), NULL);
> +       if (ret)
> +               return ret;
> +
> +       *handle = resp->handle;
> +
> +       return 0;
> +}
> +
> +/**
> + * fwu_read_stream() -  fwu_read_stream ABI
> + * @handle: The handle of the context being read from
> + * @buffer: The destination buffer where the data will be copied to
> + * @buffer_size: The size of the destination buffer
> + *
> + * Description: The call reads at most g_max_payload_size bytes from the Update
> + * Agent context pointed to by handle.
> + *
> + * Return: 0 on success. Otherwise, failure.
> + */
> +static int fwu_read_stream(u32 handle, u8 *buffer, u32 buffer_size)
> +{
> +       int ret;
> +       u32 curr_read_offset = 0, new_read_offset, fwu_buf_bytes_left;
> +       struct fwu_read_stream_args *args = g_fwu_buf;
> +       struct fwu_read_stream_resp *resp = g_fwu_buf;
> +       char *svc_name = "FWU_READ_STREAM";
> +
> +       if (!buffer || !buffer_size)
> +               return -EINVAL;
> +
> +       do {
> +               /* Filling the arguments in the shared buffer */
> +               args->function_id = FWU_READ_STREAM;
> +               args->handle = handle;
> +
> +               /* Executing the FWU ABI through the FF-A bus */
> +               ret = fwu_invoke_svc(args->function_id, svc_name, sizeof(*args),
> +                                    sizeof(*resp), &resp->read_bytes);
> +               if (ret)
> +                       return ret;
> +
> +               if (resp->read_bytes > g_max_payload_size) {
> +                       log_err("%s: Bytes read > max_payload_size (%d , %llu)\n",
> +                               svc_name, resp->read_bytes,
> +                               g_max_payload_size);
> +                       return -EINVAL;
> +               }
> +
> +               fwu_buf_bytes_left = FWU_BUFFER_SIZE - sizeof(*resp);
> +
> +               if (resp->read_bytes > fwu_buf_bytes_left) {
> +                       log_err("%s: Bytes read > shared buffer (%d , %d)\n",
> +                               svc_name, resp->read_bytes, fwu_buf_bytes_left);
> +                       return -EINVAL;
> +               }
> +
> +               if (resp->total_bytes > buffer_size) {
> +                       log_err("%s: Total bytes > dest buffer (%d , %d)\n",
> +                               svc_name, resp->total_bytes, buffer_size);
> +                       return -EINVAL;
> +               }
> +
> +               new_read_offset = resp->read_bytes + curr_read_offset;
> +
> +               if (new_read_offset > buffer_size) {
> +                       log_err("%s: Bytes read > dest buffer (%d , %d)\n",
> +                               svc_name, new_read_offset, buffer_size);
> +                       return -EINVAL;
> +               }
> +
> +               memcpy(buffer + curr_read_offset, resp->payload,
> +                      resp->read_bytes);
> +
> +               curr_read_offset = new_read_offset;
> +
> +               if (curr_read_offset > resp->total_bytes) {
> +                       log_err("%s: Offset bypassed total bytes (%d , %d)\n",
> +                               svc_name, curr_read_offset, resp->total_bytes);
> +                       return -EINVAL;
> +               }
> +
> +       } while (curr_read_offset != resp->total_bytes);
> +
> +       return ret;
> +}
> +
> +/**
> + * fwu_commit() -  fwu_commit ABI
> + * @handle: The handle of the context being closed
> + * @acceptance_req: Acceptance status set by the Client
> + * @max_atomic_len: Hint, maximum time (in ns) that the Update Agent can execute
> + *                  continuously without yielding back to the Client state
> + *
> + * Description: The call closes the image pointed to by handle. The image can be
> + * any entity opened with fwu_open().
> + *
> + * Return: 0 on success. Otherwise, failure.
> + */
> +static int fwu_commit(u32 handle, u32 acceptance_req, u32 max_atomic_len)
> +{
> +       struct fwu_commit_args *args = g_fwu_buf;
> +       struct fwu_commit_resp *resp = g_fwu_buf;
> +       char *svc_name = "FWU_COMMIT";
> +       int ret;
> +
> +       /* Filling the arguments in the shared buffer */
> +       args->function_id = FWU_COMMIT;
> +       args->handle = handle;
> +       args->acceptance_req = acceptance_req;
> +       args->max_atomic_len = max_atomic_len;
> +
> +       /* Executing the FWU ABI through the FF-A bus */
> +       ret = fwu_invoke_svc(args->function_id, svc_name,
> +                            sizeof(*args), sizeof(*resp), NULL);
> +
> +       while (resp->status == -FWU_RESUME)
> +               ret = fwu_invoke_svc(args->function_id, svc_name, sizeof(*args),
> +                                    sizeof(*resp), NULL);
> +
> +       if (ret)
> +               return ret;
> +
> +       log_debug("%s:  Progress %d/%d\n", svc_name, resp->progress,
> +                 resp->total_work);
> +
> +       return 0;
> +}
> +
> +/**
> + * fwu_read_directory() - Read FWU directory information
> + *
> + * Description: Read FWU directory information.
> + * For more details see fwu_image_directory structure.
> + *
> + * Return: 0 on success. Otherwise, failure.
> + */
> +static int fwu_read_directory(void)
> +{
> +       int ret, close_ret;
> +       u32 handle = 0;
> +       efi_guid_t dir_guid = {0};
> +       char *uuid_str = FWU_DIRECTORY_CANONICAL_UUID;

This has been defined in the spec as a GUID. Why are you declaring it
as a UUID and then doing the conversion. Why can this not be used
directly as a GUID?

-sughosh

> +
> +       if (!uuid_str) {
> +               log_err("FWU: No directory UUID provided\n");
> +               return -EINVAL;
> +       }
> +
> +       if (uuid_str_to_le_bin(uuid_str, dir_guid.b)) {
> +               log_err("FWU: Invalid directory UUID\n");
> +               return -EINVAL;
> +       }
> +
> +       ret = fwu_open(&dir_guid, FWU_OP_TYPE_READ, &handle);
> +       if (ret) {
> +               log_err("FWU: Open image directory failed (err: %d)\n",
> +                       ret);
> +               return ret;
> +       }
> +
> +       log_debug("FWU: Image directory handle (0x%x)\n", handle);
> +
> +       ret = fwu_read_stream(handle, (u8 *)&g_fwu_cached_directory,
> +                             sizeof(g_fwu_cached_directory));
> +       if (ret) {
> +               log_err("FWU: Read image directory failed (err: %d)\n",
> +                       ret);
> +               goto close_handle;
> +       }
> +
> +       log_debug("FWU: directory_version (%d)\n",
> +                 g_fwu_cached_directory.directory_version);
> +
> +       /*
> +        * Note: The expected images in the directory are:
> +        * - The images to be updated
> +        * - The ESRT image (an image containing ESRT data)
> +        * The ESRT image is not involved in the FWU.
> +        * It should be removed from the count.
> +        */
> +       g_fwu_cached_directory.num_images -= 1;
> +
> +       if (g_fwu_cached_directory.num_images !=
> +           CONFIG_FWU_NUM_IMAGES_PER_BANK) {
> +               log_err("FWU: Unexpected image count (%d , %d)\n",
> +                       g_fwu_cached_directory.num_images,
> +                       CONFIG_FWU_NUM_IMAGES_PER_BANK);
> +               ret = -EINVAL;
> +               goto close_handle;
> +       }
> +
> +       log_debug("FWU: images to be updated (%d)\n",
> +                 g_fwu_cached_directory.num_images);
> +       log_debug("FWU: img_info_size (%d)\n",
> +                 g_fwu_cached_directory.img_info_size);
> +
> +close_handle:
> +       /* The Update Agent can execute for an unbounded time */
> +       close_ret = fwu_commit(handle, FWU_IMG_NOT_ACCEPTED, 0);
> +       if (close_ret)
> +               log_err("FWU: Close image directory handle failed (err: %d)\n",
> +                       close_ret);
> +
> +       return ret;
> +}
>
>  /**
>   * fwu_discover_ts_sp_id() - Query the FWU partition ID
> @@ -257,7 +714,121 @@ int fwu_agent_init(void)
>         if (ret)
>                 return ret;
>
> +       ret = fwu_discover();
> +       if (ret)
> +               goto failure;
> +
>         g_fwu_initialized = true;
>
>         return 0;
> +
> +failure:
> +       fwu_shared_buf_reclaim();
> +       return ret;
> +}
> +
> +/**
> + * efi_fill_image_desc_array - PSA implementation for populating image descriptors
> + * @image_info_size:           Size of @image_info
> + * @image_info:                        Image information
> + * @descriptor_version:                Pointer to version number
> + * @descriptor_count:          Image count
> + * @descriptor_size:           Pointer to descriptor size
> + * @package_version:           Package version
> + * @package_version_name:      Package version's name
> + *
> + * Initialize the update agent in secure world if not initialized.
> + * Then, read the FWU directory information including the current
> + * images information. For more details refer to fwu_image_directory structure.
> + *
> + * Return information about the current firmware image in @image_info.
> + * @image_info will consist of a number of descriptors.
> + * Each descriptor will be created based on efi_fw_image array.
> + *
> + * Return: EFI_SUCCESS on success. Otherwise, failure
> + */
> +efi_status_t efi_fill_image_desc_array(efi_uintn_t *image_info_size,
> +                                      struct efi_firmware_image_descriptor *image_info,
> +                                      u32 *descriptor_version,
> +                                      u8 *descriptor_count,
> +                                      efi_uintn_t *descriptor_size,
> +                                      u32 *package_version,
> +                                      u16 **package_version_name)
> +{
> +       int ret;
> +       int required_image_info_size;
> +       size_t image_info_desc_size = sizeof(*image_info);
> +
> +       if (!g_fwu_initialized) {
> +               ret = fwu_agent_init();
> +               if (ret) {
> +                       log_err("FWU: Update agent init failed, ret = %d\n",
> +                               ret);
> +                       return EFI_EXIT(EFI_DEVICE_ERROR);
> +               }
> +       }
> +
> +       ret = fwu_read_directory();
> +       if (ret)
> +               return EFI_NOT_READY;
> +
> +       required_image_info_size = g_fwu_cached_directory.num_images *
> +               image_info_desc_size;
> +
> +       if (*image_info_size < required_image_info_size) {
> +               *image_info_size = required_image_info_size;
> +               return EFI_BUFFER_TOO_SMALL;
> +       }
> +
> +       *descriptor_version = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION;
> +       *descriptor_count = g_fwu_cached_directory.num_images;
> +       *descriptor_size = image_info_desc_size;
> +       *package_version = PACKAGE_VERSION_NOT_SUP; /* Not supported */
> +       *package_version_name = NULL; /* Not supported */
> +
> +       for (int i = 0; i < g_fwu_cached_directory.num_images; i++) {
> +               /* Only image indexes starting from 1 are supported */
> +               image_info[i].image_index = i + 1;
> +
> +               /* Corresponding ESRT field: FwClass */
> +               guidcpy(&image_info[i].image_type_id,
> +                       &g_fwu_cached_directory.entries[i].image_guid);
> +
> +               image_info[i].image_id = image_info[i].image_index;
> +               image_info[i].image_id_name = NULL; /* Not supported */
> +
> +               /* Corresponding ESRT field: FwVersion */
> +               image_info[i].version =
> +                       g_fwu_cached_directory.entries[i].img_version;
> +
> +               image_info[i].version_name = NULL; /* Not supported */
> +               image_info[i].size =
> +                       g_fwu_cached_directory.entries[i].img_max_size;
> +
> +               image_info[i].attributes_supported =
> +                       IMAGE_ATTRIBUTE_IMAGE_UPDATABLE |
> +                       IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED;
> +               image_info[i].attributes_setting =
> +                               IMAGE_ATTRIBUTE_IMAGE_UPDATABLE;
> +
> +               /* Check if the capsule authentication is enabled */
> +               if (IS_ENABLED(CONFIG_EFI_CAPSULE_AUTHENTICATE))
> +                       image_info[i].attributes_setting |=
> +                               IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED;
> +
> +               /* Corresponding ESRT field: LowestSupportedFwVersion */
> +               image_info[i].lowest_supported_image_version =
> +                       g_fwu_cached_directory.entries[i].lowest_acceptable_version;
> +
> +               /* Corresponding ESRT field: LastAttemptVersion (not supported) */
> +               image_info[i].last_attempt_version = LAST_ATTEMPT_NOT_SUP;
> +
> +               /* Corresponding ESRT field: LastAttemptStatus (not supported) */
> +               image_info[i].last_attempt_status = LAST_ATTEMPT_NOT_SUP;
> +
> +               image_info[i].hardware_instance = DEFAULT_HW_INSTANCE;
> +               image_info[i].dependencies = NULL; /* Not supported */
> +       }
> +
> +       return EFI_SUCCESS;
>  }
> --
> 2.43.0
>


More information about the U-Boot mailing list