[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