[PATCH v5 11/24] fwu_arm_psa: Add staging ABIs
Sughosh Ganu
sughosh.ganu at linaro.org
Tue Nov 11 09:49:13 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 the ABIs and logic for updating images
>
> The staging process defined by the Platform Security Firmware
> Update for the A-profile Arm Architecture specification [1] is
> executed through the staging ABIs.
>
> The capsule should contain at least 3 payloads (2 dummy payloads
> to indicate the start and the end of the staging process.
> In addition, one or multiple payloads to write in the storage device).
>
> The implemented ABIs are as follows:
>
> FWU_BEGIN_STAGING
> FWU_END_STAGING
> FWU_CANCEL_STAGING
> FWU_WRITE_STREAM
>
> [1]: DEN0118, 1.0 A:
> https://developer.arm.com/documentation/den0118/latest/
>
> Signed-off-by: Abdellatif El Khlifi <abdellatif.elkhlifi at arm.com>
> Signed-off-by: Davidson kumaresan <davidson.kumaresan at arm.com>
> Cc: Heinrich Schuchardt <xypron.glpk at gmx.de>
> Cc: Ilias Apalodimas <ilias.apalodimas at linaro.org>
> Cc: Tom Rini <trini at konsulko.com>
> Cc: Simon Glass <sjg at chromium.org>
> Cc: Adriano Cordova <adrianox at gmail.com>
> Cc: Sughosh Ganu <sughosh.ganu at linaro.org>
> Cc: Michal Simek <michal.simek at amd.com>
>
> ---
>
> Changelog of changes:
> ===========================
>
> v5:
>
> * 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:
>
> * Add staging ABIs
>
> include/efi_api.h | 8 +
> include/efi_loader.h | 8 +
> include/fwu_arm_psa.h | 128 +++++++++++++
> lib/efi_loader/efi_capsule.c | 23 ++-
> lib/fwu_updates/fwu_arm_psa.c | 350 ++++++++++++++++++++++++++++++++++
> 5 files changed, 515 insertions(+), 2 deletions(-)
>
> diff --git a/include/efi_api.h b/include/efi_api.h
> index eb61eafa028..cd19ec5e22c 100644
> --- a/include/efi_api.h
> +++ b/include/efi_api.h
> @@ -10,6 +10,11 @@
> * David Mosberger-Tang <davidm at hpl.hp.com>
> * Stephane Eranian <eranian at hpl.hp.com>
> *
> + * Copyright 2025 Arm Limited and/or its affiliates <open-source-office at arm.com>
> + *
> + * Author:
> + * Abdellatif El Khlifi <abdellatif.elkhlifi at arm.com>
> + *
Again, I am not sure if adding a couple of macros warrants putting a
copyright. This is applicable to multiple of your patches. Maybe
Ilias/Heinrich can comment here.
> * From include/linux/efi.h in kernel 4.1 with some additions/subtractions
> */
>
> @@ -25,6 +30,9 @@
> */
> #define EFI_SPECIFICATION_VERSION (2 << 16 | 110)
>
> +#define EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_VERSION 0x00000001
> +#define EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_VERSION 0x00000003
> +
> /* Types and defines for EFI CreateEvent */
> enum efi_timer_delay {
> EFI_TIMER_STOP = 0,
> diff --git a/include/efi_loader.h b/include/efi_loader.h
> index 8fd09aad2d0..3ad1d84a113 100644
> --- a/include/efi_loader.h
> +++ b/include/efi_loader.h
> @@ -3,6 +3,11 @@
> * EFI application loader
> *
> * Copyright (c) 2016 Alexander Graf
> + *
> + * Copyright 2025 Arm Limited and/or its affiliates <open-source-office at arm.com>
> + *
> + * Author:
> + * Abdellatif El Khlifi <abdellatif.elkhlifi at arm.com>
> */
>
> #ifndef _EFI_LOADER_H
> @@ -392,6 +397,9 @@ extern const efi_guid_t smbios3_guid;
> extern const efi_guid_t efi_guid_text_input_protocol;
> extern const efi_guid_t efi_guid_text_output_protocol;
>
> +/*The current processed capsule */
> +extern struct efi_capsule_header *g_capsule_data;
> +
> /**
> * struct efi_open_protocol_info_item - open protocol info item
> *
> diff --git a/include/fwu_arm_psa.h b/include/fwu_arm_psa.h
> index 9eb67ef4243..a7b7faf2b59 100644
> --- a/include/fwu_arm_psa.h
> +++ b/include/fwu_arm_psa.h
> @@ -40,6 +40,21 @@
> /* 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)
>
> +/*
> + * GUIDs for dummy payloads
> + *
> + * The GUIDs are generated with the UUIDv5 format.
> + * Namespace: 7b5c472e-5671-4fb7-a824-36a8e86f05c1
> + * Names: DUMMY_START, DUMMY_END
> + */
> +#define FWU_DUMMY_START_IMAGE_GUID \
> + EFI_GUID(0x6f784cbf, 0x7938, 0x5c23, 0x8d, 0x6e, \
> + 0x24, 0xd2, 0xf1, 0x41, 0x0f, 0xa9)
> +
> +#define FWU_DUMMY_END_IMAGE_GUID \
> + EFI_GUID(0xb57e432b, 0xa250, 0x5c73, 0x93, 0xe3, \
> + 0x90, 0x20, 0x5e, 0x64, 0xba, 0xba)
> +
> #define TS_RPC_MEM_RETRIEVE (0xff0001)
> #define TS_RPC_SERVICE_INFO_GET (0xff0003)
> #define RPC_SUCCESS (0)
> @@ -62,7 +77,11 @@
>
> enum fwu_abis {
> FWU_DISCOVER = 0,
> + FWU_BEGIN_STAGING = 16,
> + FWU_END_STAGING = 17,
> + FWU_CANCEL_STAGING = 18,
> FWU_OPEN = 19,
> + FWU_WRITE_STREAM = 20,
> FWU_READ_STREAM = 21,
> FWU_COMMIT = 22,
> /* To be updated when adding new FWU IDs */
> @@ -82,6 +101,14 @@ enum fwu_abi_errcode {
> MAX_NUMBER_FWU_ERR
> };
>
> +/* Enum to classify the possible type of payloads */
> +enum fwu_payload_type {
> + FWU_PAYLOAD_TYPE_REAL = 1, /* Real payload */
> + FWU_PAYLOAD_TYPE_DUMMY_START, /* The start dummy payload */
> + FWU_PAYLOAD_TYPE_DUMMY_END, /* The end dummy payload */
> + FWU_PAYLOAD_TYPE_INVALID, /* Invalid image_index */
> +};
> +
> /* 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];
> @@ -173,6 +200,63 @@ struct __packed fwu_read_stream_resp {
> u8 payload[];
> };
>
> +/**
> + * struct fwu_begin_staging_args - fwu_begin_staging ABI arguments
> + * @function_id: fwu_begin_staging service ID
> + * @reserved: Reserved, must be zero
> + * @vendor_flags: Vendor specific staging flags
> + * @partial_update_count: The number of elements in the update_guid
> + * @update_guid: An array of image type GUIDs that the update Client will update
> + * during the Staging state
> + */
> +struct __packed fwu_begin_staging_args {
> + u32 function_id;
> + u32 reserved;
> + u32 vendor_flags;
> + u32 partial_update_count;
> + efi_guid_t update_guid[];
> +};
> +
> +/**
> + * struct fwu_begin_staging_resp - fwu_begin_staging ABI returns
> + * @status: The ABI return status
> + */
> +struct __packed fwu_begin_staging_resp {
> + int status;
> +};
> +
> +/**
> + * struct fwu_end_staging_args - fwu_end_staging ABI arguments
> + * @function_id: fwu_end_staging service ID state
> + */
> +struct __packed fwu_end_staging_args {
> + u32 function_id;
> +};
> +
> +/**
> + * struct fwu_end_staging_resp - fwu_end_staging ABI returns
> + * @status: The ABI return status
> + */
> +struct __packed fwu_end_staging_resp {
> + int status;
> +};
> +
> +/**
> + * struct fwu_cancel_staging_args - fwu_cancel_staging ABI arguments
> + * @function_id: fwu_cancel_staging service ID state
> + */
> +struct __packed fwu_cancel_staging_args {
> + u32 function_id;
> +};
> +
> +/**
> + * struct fwu_cancel_staging_resp - fwu_cancel_staging ABI returns
> + * @status: The ABI return status
> + */
> +struct __packed fwu_cancel_staging_resp {
> + int status;
> +};
> +
> /**
> * struct fwu_commit_args - fwu_commit ABI arguments
> * @function_id: fwu_commit service ID
> @@ -204,6 +288,28 @@ struct __packed fwu_commit_resp {
> u32 total_work;
> };
>
> +/**
> + * struct fwu_write_stream_args - fwu_write_stream ABI arguments
> + * @function_id: fwu_write_stream service ID
> + * @handle: The handle of the context being written to
> + * @data_len: Size of the data present in the payload
> + * @payload: The data to be transferred
> + */
> +struct __packed fwu_write_stream_args {
> + u32 function_id;
> + u32 handle;
> + u32 data_len;
> + u8 payload[];
> +};
> +
> +/**
> + * struct fwu_write_stream_resp - fwu_write_stream ABI returns
> + * @status: The ABI return status
> + */
> +struct __packed fwu_write_stream_resp {
> + int status;
> +};
> +
> /*
> * FWU directory information structures
> */
> @@ -239,4 +345,26 @@ struct __packed fwu_image_directory {
> */
> int fwu_agent_init(void);
>
> +/**
> + * fwu_update_image() - Update an image
> + * @image: Pointer to the payload
> + * @image_index: Payload index
> + * @image_size: Payload size in bytes
> + *
> + * Perform staging with multiple payloads support.
> + *
> + * Return: 0 on success
> + */
> +int fwu_update_image(const void *image, u8 image_index, u32 image_size);
> +
> +/**
> + * fwu_get_payload_type() - Identifies the payload type
> + * @image_index: The payload index
> + *
> + * Identifies the FWU payload type based on the image index.
> + *
> + * Return: See @fwu_payload_type for details
> + */
> +enum fwu_payload_type fwu_get_payload_type(u32 image_index);
> +
> #endif
> diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c
> index f19e78ae9d1..234e3c1b3c0 100644
> --- a/lib/efi_loader/efi_capsule.c
> +++ b/lib/efi_loader/efi_capsule.c
> @@ -4,6 +4,11 @@
> *
> * Copyright (c) 2018 Linaro Limited
> * Author: AKASHI Takahiro
> + *
> + * Copyright 2025 Arm Limited and/or its affiliates <open-source-office at arm.com>
> + *
> + * Author:
> + * Abdellatif El Khlifi <abdellatif.elkhlifi at arm.com>
> */
Same here as well.
-sughosh
>
> #define LOG_CATEGORY LOGC_EFI
> @@ -15,6 +20,7 @@
> #include <fdtdec.h>
> #include <fs.h>
> #include <fwu.h>
> +#include <fwu_arm_psa.h>
> #include <hang.h>
> #include <malloc.h>
> #include <mapmem.h>
> @@ -40,6 +46,8 @@ const efi_guid_t fwu_guid_os_request_fw_revert =
> const efi_guid_t fwu_guid_os_request_fw_accept =
> FWU_OS_REQUEST_FW_ACCEPT_GUID;
>
> +struct efi_capsule_header *g_capsule_data;
> +
> #define FW_ACCEPT_OS (u32)0x8000
>
> #ifdef CONFIG_EFI_CAPSULE_ON_DISK
> @@ -196,6 +204,12 @@ efi_fmp_find(efi_guid_t *image_type, u8 image_index, u64 instance,
> continue;
> fmp = fmp_handler->protocol_interface;
>
> + if (IS_ENABLED(CONFIG_FWU_ARM_PSA)) {
> + if (fwu_get_payload_type(image_index) !=
> + FWU_PAYLOAD_TYPE_REAL)
> + return fmp;
> + }
> +
> /* get device's image info */
> info_size = 0;
> image_info = NULL;
> @@ -586,7 +600,7 @@ static efi_status_t efi_capsule_update_firmware(
> capsule_size = capsule_data->capsule_image_size
> - capsule_data->header_size;
>
> - if (capsule->version != 0x00000001)
> + if (capsule->version != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_VERSION)
> return EFI_UNSUPPORTED;
>
> handles = NULL;
> @@ -597,6 +611,10 @@ static efi_status_t efi_capsule_update_firmware(
> if (ret != EFI_SUCCESS)
> return EFI_UNSUPPORTED;
>
> + if (IS_ENABLED(CONFIG_FWU_ARM_PSA)) {
> + g_capsule_data = capsule_data;
> + }
> +
> /* Payload */
> for (item = capsule->embedded_driver_count;
> item < capsule->embedded_driver_count
> @@ -611,7 +629,8 @@ static efi_status_t efi_capsule_update_firmware(
>
> image = (void *)capsule + capsule->item_offset_list[item];
>
> - if (image->version != 0x00000003) {
> + if (image->version !=
> + EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_VERSION) {
> ret = EFI_UNSUPPORTED;
> goto out;
> }
> diff --git a/lib/fwu_updates/fwu_arm_psa.c b/lib/fwu_updates/fwu_arm_psa.c
> index 589a6283611..5dad906a021 100644
> --- a/lib/fwu_updates/fwu_arm_psa.c
> +++ b/lib/fwu_updates/fwu_arm_psa.c
> @@ -25,6 +25,7 @@ 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;
> +efi_guid_t g_update_guid[CONFIG_FWU_NUM_IMAGES_PER_BANK];
>
> /* Error mapping declarations */
>
> @@ -60,6 +61,18 @@ static struct fwu_abi_errmap err_msg_map[FWU_ERRMAP_COUNT] = {
> "FWU_NO_PERMISSION: The image cannot be read from",
> },
> },
> + [FWU_ID_TO_ERRMAP_ID(FWU_WRITE_STREAM)] = {
> + {
> + [FWU_UNKNOWN] =
> + "FWU_UNKNOWN: Unrecognized handle",
> + [FWU_DENIED] =
> + "FWU_DENIED: The system is not in a Staging state",
> + [FWU_NO_PERMISSION] =
> + "FWU_NO_PERMISSION: The image cannot be written to",
> + [FWU_OUT_OF_BOUNDS] =
> + "FWU_OUT_OF_BOUNDS: less than data_len bytes available in the image",
> + },
> + },
> [FWU_ID_TO_ERRMAP_ID(FWU_COMMIT)] = {
> {
> [FWU_UNKNOWN] =
> @@ -72,6 +85,34 @@ static struct fwu_abi_errmap err_msg_map[FWU_ERRMAP_COUNT] = {
> "FWU_RESUME: The Update Agent yielded",
> },
> },
> + [FWU_ID_TO_ERRMAP_ID(FWU_BEGIN_STAGING)] = {
> + {
> + [FWU_UNKNOWN] =
> + "FWU_UNKNOWN: One of more GUIDs in the update_guid field are unknown to the Update Agent",
> + [FWU_DENIED] =
> + "FWU_DENIED: The Firmware Store is in the Trial state or the platform did not boot correctly",
> + [FWU_BUSY] =
> + "FWU_BUSY: The Client is temporarily prevented from entering the Staging state",
> + },
> + },
> + [FWU_ID_TO_ERRMAP_ID(FWU_END_STAGING)] = {
> + {
> + [FWU_BUSY] =
> + "FWU_BUSY: There are open image handles",
> + [FWU_DENIED] =
> + "FWU_DENIED: The system is not in a Staging state",
> + [FWU_AUTH_FAIL] =
> + "FWU_AUTH_FAIL: At least one of the updated images fails to authenticate",
> + [FWU_NOT_AVAILABLE] =
> + "FWU_NOT_AVAILABLE: The Update Agent does not support partial updates",
> + },
> + },
> + [FWU_ID_TO_ERRMAP_ID(FWU_CANCEL_STAGING)] = {
> + {
> + [FWU_DENIED] =
> + "FWU_DENIED: The system is not in a Staging state",
> + },
> + },
> };
>
> /**
> @@ -125,6 +166,104 @@ static int fwu_print_error_log(u32 fwu_id, int fwu_errno)
> return 0;
> }
>
> +/**
> + * fwu_get_payload_type() - Identifies the payload type
> + * @image_index: The payload index
> + *
> + * Description: Identifies the FWU payload type based on the image index.
> + *
> + * Return: See @fwu_payload_type for details
> + */
> +enum fwu_payload_type fwu_get_payload_type(u32 image_index)
> +{
> + efi_guid_t *image_guid = NULL;
> + int i;
> + struct efi_fw_image *fw_array;
> +
> + fw_array = update_info.images;
> + for (i = 0; i < update_info.num_images; i++) {
> + if (fw_array[i].image_index == image_index) {
> + image_guid = &fw_array[i].image_type_id;
> + break;
> + }
> + }
> +
> + if (!image_guid)
> + return FWU_PAYLOAD_TYPE_INVALID;
> +
> + if (!guidcmp(image_guid,
> + &((efi_guid_t)FWU_DUMMY_START_IMAGE_GUID)))
> + return FWU_PAYLOAD_TYPE_DUMMY_START;
> +
> + if (!guidcmp(image_guid,
> + &((efi_guid_t)FWU_DUMMY_END_IMAGE_GUID)))
> + return FWU_PAYLOAD_TYPE_DUMMY_END;
> +
> + return FWU_PAYLOAD_TYPE_REAL;
> +}
> +
> +/**
> + * fwu_get_capsule_guids() - Detect the payloads GUIDs in the caspsule
> + *
> + * @partial_update_count: A pointer to the number of payloads to update
> + * @saved_guids: A pointer to a GUIDs array for the payloads GUIDs
> + *
> + * Description: Parse the current capsule and detect the payloads GUIDs.
> + *
> + * Return: EFI_SUCCESS on success. Otherwise, failure.
> + */
> +static efi_status_t fwu_get_capsule_guids(u32 *partial_update_count,
> + efi_guid_t saved_guids[])
> +{
> + struct efi_firmware_management_capsule_header *capsule;
> + struct efi_firmware_management_capsule_image_header *image;
> + int item;
> + size_t capsule_size;
> + efi_status_t ret = EFI_SUCCESS;
> +
> + if (!saved_guids || !partial_update_count)
> + return EFI_INVALID_PARAMETER;
> +
> + *partial_update_count = 0;
> + capsule = (void *)g_capsule_data + g_capsule_data->header_size;
> + capsule_size = g_capsule_data->capsule_image_size
> + - g_capsule_data->header_size;
> +
> + /* Payload */
> + for (item = capsule->embedded_driver_count;
> + item < capsule->embedded_driver_count
> + + capsule->payload_item_count; item++) {
> + /* sanity check */
> + if ((capsule->item_offset_list[item] + sizeof(*image)
> + >= capsule_size)) {
> + ret = EFI_INVALID_PARAMETER;
> + log_err("FWU: Insufficient data, err (0x%lx)\n", ret);
> + break;
> + }
> +
> + image = (void *)capsule + capsule->item_offset_list[item];
> +
> + if (image->version !=
> + EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_VERSION) {
> + ret = EFI_UNSUPPORTED;
> + log_err("FWU: Version check failed, err (0x%lx)\n",
> + ret);
> + break;
> + }
> +
> + if (fwu_get_payload_type(image->update_image_index) !=
> + FWU_PAYLOAD_TYPE_REAL)
> + continue;
> +
> + guidcpy(&saved_guids[*partial_update_count],
> + &image->update_image_type_id);
> +
> + (*partial_update_count)++;
> + }
> +
> + return ret;
> +}
> +
> /**
> * fwu_invoke_svc() - FWU service call request
> * @svc_id: FWU ABI function ID
> @@ -360,6 +499,86 @@ static int fwu_read_stream(u32 handle, u8 *buffer, u32 buffer_size)
> return ret;
> }
>
> +/**
> + * fwu_begin_staging() - fwu_begin_staging ABI
> + *
> + * Description: This call indicates to the Update Agent that a new staging
> + * process will commence.
> + *
> + * Return: 0 on success. Otherwise, failure.
> + */
> +static int fwu_begin_staging(void)
> +{
> + struct fwu_begin_staging_args *args = g_fwu_buf;
> + struct fwu_begin_staging_resp *resp = g_fwu_buf;
> + char *svc_name = "FWU_BEGIN_STAGING";
> + efi_status_t ret;
> +
> + /* Filling the arguments in the shared buffer */
> + args->function_id = FWU_BEGIN_STAGING;
> +
> + args->reserved = 0;
> + args->vendor_flags = 0;
> +
> + ret = fwu_get_capsule_guids(&args->partial_update_count,
> + args->update_guid);
> + if (ret) {
> + log_err("FWU: Failure to get the payloads GUIDs\n");
> + return -ENODATA;
> + }
> +
> + log_info("FWU: Updating %d payload(s)\n", args->partial_update_count);
> +
> + /* Executing the FWU ABI through the FF-A bus */
> + return fwu_invoke_svc(args->function_id, svc_name,
> + sizeof(*args), sizeof(*resp), NULL);
> +}
> +
> +/**
> + * fwu_end_staging() - fwu_end_staging ABI
> + *
> + * Description: The Client informs the Update Agent that all the images, meant
> + * to be updated, have been transferred to the Update Agent and that the staging
> + * has terminated.
> + *
> + * Return: 0 on success. Otherwise, failure.
> + */
> +static int fwu_end_staging(void)
> +{
> + struct fwu_end_staging_args *args = g_fwu_buf;
> + struct fwu_end_staging_resp *resp = g_fwu_buf;
> + char *svc_name = "FWU_END_STAGING";
> +
> + /* Filling the arguments in the shared buffer */
> + args->function_id = FWU_END_STAGING;
> +
> + /* Executing the FWU ABI through the FF-A bus */
> + return fwu_invoke_svc(args->function_id, svc_name,
> + sizeof(*args), sizeof(*resp), NULL);
> +}
> +
> +/**
> + * fwu_cancel_staging() - fwu_cancel_staging ABI
> + *
> + * Description: The Client cancels the staging procedure and the system
> + * transitions back to the Regular state.
> + *
> + * Return: 0 on success. Otherwise, failure.
> + */
> +static int fwu_cancel_staging(void)
> +{
> + struct fwu_cancel_staging_args *args = g_fwu_buf;
> + struct fwu_cancel_staging_resp *resp = g_fwu_buf;
> + char *svc_name = "FWU_CANCEL_STAGING";
> +
> + /* Filling the arguments in the shared buffer */
> + args->function_id = FWU_CANCEL_STAGING;
> +
> + /* Executing the FWU ABI through the FF-A bus */
> + return fwu_invoke_svc(args->function_id, svc_name,
> + sizeof(*args), sizeof(*resp), NULL);
> +}
> +
> /**
> * fwu_commit() - fwu_commit ABI
> * @handle: The handle of the context being closed
> @@ -402,6 +621,137 @@ static int fwu_commit(u32 handle, u32 acceptance_req, u32 max_atomic_len)
> return 0;
> }
>
> +/**
> + * fwu_write_stream() - fwu_write_stream ABI
> + * @handle: The handle of the context being writen to
> + * @payload: The data to be transferred
> + * @payload_size: Size of the data present in the payload
> + *
> + * Description: The call writes at most max_payload_size bytes to the Update
> + * Agent context pointed to by handle.
> + *
> + * Return: 0 on success. Otherwise, failure
> + */
> +static int fwu_write_stream(u32 handle, const u8 *payload, u32 payload_size)
> +{
> + int ret;
> + u32 write_size, max_write_size, curr_write_offset = 0;
> + u32 payload_bytes_left = payload_size, fwu_buf_bytes_left;
> + struct fwu_write_stream_args *args = g_fwu_buf;
> + struct fwu_write_stream_resp *resp = g_fwu_buf;
> + char *svc_name = "FWU_WRITE_STREAM";
> +
> + if (!payload || !payload_size)
> + return -EINVAL;
> +
> + fwu_buf_bytes_left = FWU_BUFFER_SIZE - sizeof(*args);
> +
> + if (g_max_payload_size <= fwu_buf_bytes_left)
> + max_write_size = g_max_payload_size;
> + else
> + max_write_size = fwu_buf_bytes_left;
> +
> + while (curr_write_offset < payload_size) {
> + if (payload_bytes_left <= max_write_size)
> + write_size = payload_bytes_left;
> + else
> + write_size = max_write_size;
> +
> + /* Filling the arguments in the shared buffer */
> + args->function_id = FWU_WRITE_STREAM;
> + args->handle = handle;
> + args->data_len = write_size;
> + memcpy(args->payload, payload + curr_write_offset, write_size);
> +
> + /* 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;
> +
> + curr_write_offset += write_size;
> + payload_bytes_left -= write_size;
> +
> + log_debug("%s: %d bytes written, remaining %d bytes\n",
> + svc_name, write_size, payload_bytes_left);
> + }
> +
> + return ret;
> +}
> +
> +/**
> + * fwu_update_image() - Update an image
> + *
> + * @image: Pointer to the payload to write
> + * @image_index: The payload index
> + * @image_size: The payload size
> + *
> + * Description: Perform staging with multiple payloads support.
> + * The capsule is expected to:
> + * - Start with a dummy payload to mark the start of the payloads sequence
> + * - One or more payloads to be written to the storage device
> + * - End with a dummy payload to mark the end of the payloads sequence
> + *
> + * The possible payloads in the capsule are described in the board file
> + * through struct efi_fw_image. This includes the dummy payloads.
> + * The dummy payloads image indexes must be >= CONFIG_FWU_NUM_IMAGES_PER_BANK
> + * The dummy payloads are not sent to the Secure world and are not written to
> + * the storage device.
> + *
> + * Return: 0 on success. Otherwise, failure.
> + */
> +int fwu_update_image(const void *image, u8 image_index, u32 image_size)
> +{
> + int ret;
> + u32 handle;
> +
> + if (!image)
> + return -EINVAL;
> +
> + /* Only image indexes starting from 1 are supported */
> + if (!image_index || image_index > update_info.num_images)
> + return -EINVAL;
> +
> + if (fwu_get_payload_type(image_index) ==
> + FWU_PAYLOAD_TYPE_DUMMY_START) {
> + return fwu_begin_staging();
> + }
> +
> + if (fwu_get_payload_type(image_index) ==
> + FWU_PAYLOAD_TYPE_DUMMY_END) {
> + ret = fwu_end_staging();
> + if (ret)
> + goto cancel_staging;
> + return 0;
> + }
> +
> + ret = fwu_open(&g_fwu_cached_directory.entries[image_index - 1].image_guid,
> + FWU_OP_TYPE_WRITE, &handle);
> + if (ret)
> + goto cancel_staging;
> +
> + ret = fwu_write_stream(handle, image, image_size);
> + if (ret)
> + goto cancel_staging;
> +
> + /*
> + * The Update Agent can execute for an unbounded time.
> + * The image should be tried before being accepted.
> + * So, we put the acceptance request as 'not accepted'.
> + */
> + ret = fwu_commit(handle, FWU_IMG_NOT_ACCEPTED, 0);
> + if (ret)
> + goto cancel_staging;
> +
> + log_debug("FWU: Image at index %d updated\n", image_index);
> +
> + return 0;
> +
> +cancel_staging:
> +
> + return fwu_cancel_staging();
> +}
> +
> /**
> * fwu_read_directory() - Read FWU directory information
> *
> --
> 2.43.0
>
More information about the U-Boot
mailing list