[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