[PATCH v5 09/24] fwu_arm_psa: Initialize the update agent

Sughosh Ganu sughosh.ganu at linaro.org
Tue Nov 11 09:22:42 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>
>
> Add the initializations required for the update agent
>
> The aim is adding support for the Trusted Services (aka TS)
> Firmware Update API. This API allows the interaction with
> the FWU services provided by Secure world.
> At U-Boot level, we provide the PSA FWU ABI built on top of the
> FF-A bus to invoke the FWU services in Secure world.
>
> The design is based on the Platform Security Firmware Update
> for the A-profile Arm Architecture specification [1].
>
> In our design, the Secure world is the update agent. U-Boot
> is the update client.
>
> The update agent is initialized as follows:
>
> - Trusted Services FWU SP discovery
> - Setting up the shared buffer between the Normal world (U-Boot) and
>   Secure world (Trusted Services)
> - Notifying FWU SP about the shared buffer
>
> [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: 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:
>
> * Address kernel-doc warnings
>
> v4:
>
> * Update the function headers in fwu_arm_psa.c to pass kernel-doc tests
>
> v1:
>
> * Add the feature
>
>  MAINTAINERS                   |   7 +
>  include/fwu_arm_psa.h         |  55 +++++++
>  lib/fwu_updates/Kconfig       |  18 +++
>  lib/fwu_updates/Makefile      |   2 +
>  lib/fwu_updates/fwu_arm_psa.c | 263 ++++++++++++++++++++++++++++++++++
>  5 files changed, 345 insertions(+)
>  create mode 100644 include/fwu_arm_psa.h
>  create mode 100644 lib/fwu_updates/fwu_arm_psa.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 92119667618..fdf34c74049 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1227,6 +1227,13 @@ T:       git https://source.denx.de/u-boot/custodians/u-boot-fsl-qoriq.git
>  F:     drivers/watchdog/sp805_wdt.c
>  F:     drivers/watchdog/sbsa_gwdt.c
>
> +FWU ARM PSA
> +M:     Abdellatif El Khlifi <abdellatif.elkhlifi at arm.com>
> +M:     Davidson kumaresan <davidson.kumaresan at arm.com>
> +S:     Maintained
> +F:     include/fwu_arm_psa.h
> +F:     lib/fwu_updates/fwu_arm_psa.c
> +
>  FWU Multi Bank Update
>  M:     Sughosh Ganu <sughosh.ganu at linaro.org>
>  S:     Maintained
> diff --git a/include/fwu_arm_psa.h b/include/fwu_arm_psa.h
> new file mode 100644
> index 00000000000..5e1229f3bdb
> --- /dev/null
> +++ b/include/fwu_arm_psa.h
> @@ -0,0 +1,55 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Copyright 2025 Arm Limited and/or its affiliates <open-source-office at arm.com>
> + *
> + * Authors:
> + *   Abdellatif El Khlifi <abdellatif.elkhlifi at arm.com>
> + *   Davidson kumaresan <davidson.kumaresan at arm.com>
> + */
> +
> +#ifndef __FWU_ARM_PSA_H
> +#define __FWU_ARM_PSA_H
> +
> +#include <linux/bitfield.h>
> +#include <u-boot/uuid.h>
> +
> +#define FWU_BUFFER_PAGES               (1024)
> +
> +/* 4 MB buffer shared with secure world */
> +#define FWU_BUFFER_SIZE                        (FWU_BUFFER_PAGES * EFI_PAGE_SIZE)
> +
> +/* TS UUID string for detecting all SPs  (in big-endian format) */
> +#define ALL_TS_SP_UUID                 "d776cdbd-5e82-5147-3b96-ac4349f8d486"
> +/* In little-endian equivalent to: bdcd76d7-825e-4751-963b-86d4f84943ac */
> +
> +/* TS FWU service UUID string (in big-endian format) */
> +#define TS_FWU_SERVICE_UUID            "38a82368-061b-0e47-7497-fd53fb8bce0c"
> +/* In little-endian equivalent to:  6823a838-1b06-470e-9774-0cce8bfb53fd */
> +
> +#define TS_RPC_MEM_RETRIEVE            (0xff0001)
> +#define TS_RPC_SERVICE_INFO_GET                (0xff0003)
> +#define RPC_SUCCESS                    (0)
> +
> +#define SVC_IFACE_ID_GET_MASK          GENMASK(7, 0)
> +#define GET_SVC_IFACE_ID(x)            \
> +                        ((u8)(FIELD_GET(SVC_IFACE_ID_GET_MASK, (x))))
> +
> +#define HANDLE_MSW_MASK                        GENMASK(63, 32)
> +#define HANDLE_LSW_MASK                        GENMASK(31, 0)
> +#define GET_FWU_BUF_MSW(x)             \
> +                               ((u32)(FIELD_GET(HANDLE_MSW_MASK, (x))))
> +#define GET_FWU_BUF_LSW(x)             \
> +                               ((u32)(FIELD_GET(HANDLE_LSW_MASK, (x))))
> +
> +/**
> + * fwu_agent_init() - Setup the FWU agent
> + * Perform the initializations required to communicate
> + * and use the FWU agent in secure world.
> + * The frontend of the FWU agent is the Trusted Services (aka TS)
> + * FWU SP (aka Secure Partition).
> + *
> + * Return: 0 on success. Otherwise, failure
> + */
> +int fwu_agent_init(void);
> +
> +#endif
> diff --git a/lib/fwu_updates/Kconfig b/lib/fwu_updates/Kconfig
> index a722107c129..cdc96109f0a 100644
> --- a/lib/fwu_updates/Kconfig
> +++ b/lib/fwu_updates/Kconfig
> @@ -46,4 +46,22 @@ config FWU_MDATA_V2
>           metadata structure. This option enables support for FWU
>           Metadata version 2 access.
>
> +config FWU_ARM_PSA
> +       bool "FMP driver for Arm PSA FWU specification"
> +       depends on EFI_CAPSULE_FIRMWARE_MANAGEMENT && \
> +               EFI_CAPSULE_FIRMWARE_RAW && \
> +               ARM_FFA_TRANSPORT && (ARM64 || SANDBOX)
> +       select EFI_CAPSULE_FIRMWARE
> +       help
> +         Select this option if you want to enable firmware management protocol
> +         driver that supports the Arm PSA firmware update specification as
> +         mentioned in https://developer.arm.com/documentation/den0118/a/
> +
> +config FWU_BUFFER_PAGES
> +       int "Number of 4KB pages in the FWU shared buffer"
> +       depends on FWU_ARM_PSA
> +       default 1024
> +       help
> +         This defines the size of the FWU shared buffer used for communication.
> +
>  endif
> diff --git a/lib/fwu_updates/Makefile b/lib/fwu_updates/Makefile
> index 3681bef46cd..ae8e4b27793 100644
> --- a/lib/fwu_updates/Makefile
> +++ b/lib/fwu_updates/Makefile
> @@ -1,6 +1,7 @@
>  # SPDX-License-Identifier: GPL-2.0-or-later
>  #
>  # Copyright (c) 2022, Linaro Limited
> +# Copyright 2025 Arm Limited and/or its affiliates <open-source-office at arm.com>
>  #

I don't think adding a single line justifies adding a copyright.

>
>  obj-$(CONFIG_FWU_MULTI_BANK_UPDATE) += fwu.o
> @@ -8,3 +9,4 @@ obj-$(CONFIG_FWU_MDATA_GPT_BLK) += fwu_gpt.o
>  obj-$(CONFIG_FWU_MDATA_MTD) += fwu_mtd.o
>  obj-$(CONFIG_FWU_MDATA_V1) += fwu_v1.o
>  obj-$(CONFIG_FWU_MDATA_V2) += fwu_v2.o
> +obj-$(CONFIG_FWU_ARM_PSA) += fwu_arm_psa.o
> diff --git a/lib/fwu_updates/fwu_arm_psa.c b/lib/fwu_updates/fwu_arm_psa.c
> new file mode 100644
> index 00000000000..8ac53cc9152
> --- /dev/null
> +++ b/lib/fwu_updates/fwu_arm_psa.c
> @@ -0,0 +1,263 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright 2025 Arm Limited and/or its affiliates <open-source-office at arm.com>
> + *
> + * Authors:
> + *   Abdellatif El Khlifi <abdellatif.elkhlifi at arm.com>
> + *   Davidson kumaresan <davidson.kumaresan at arm.com>
> + */
> +#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>
> +#include <mapmem.h>
> +#include <linux/errno.h>
> +
> +static void *g_fwu_buf;
> +static u64 g_fwu_buf_handle;
> +static u16 g_fwu_sp_id;
> +static struct udevice *g_dev;
> +static u16 g_svc_interface_id;
> +static bool g_fwu_initialized;
> +
> +/**
> + * fwu_discover_ts_sp_id() - Query the FWU partition ID
> + *
> + * Description: Use the FF-A driver to get the FWU partition ID.
> + * If multiple partitions are found, use the first one.
> + *
> + * Return: 0 on success. Otherwise, failure.
> + */
> +static int fwu_discover_ts_sp_id(void)
> +{
> +       u32 count = 0;
> +       int ret;
> +       u32 i;
> +       struct ffa_partition_desc *descs = NULL;
> +       struct ffa_send_direct_data msg;
> +       struct ffa_partition_uuid fwu_service_uuid = {0};
> +
> +       /* Ask the driver to fill the buffer with the SPs info */
> +
> +       ret = ffa_partition_info_get(g_dev, ALL_TS_SP_UUID, &count, &descs);
> +       if (ret) {
> +               log_err("FWU: Failure in querying partitions (err: %d)\n", ret);
> +               return ret;
> +       }
> +
> +       if (!count) {
> +               log_err("FWU: No Trusted Service partition found\n");
> +               return -ENODATA;
> +       }
> +
> +       if (!descs) {
> +               log_err("FWU: No partitions descriptors filled\n");
> +               return -EINVAL;
> +       }
> +
> +       if (uuid_str_to_le_bin(TS_FWU_SERVICE_UUID,
> +                              (unsigned char *)&fwu_service_uuid)) {
> +               log_err("FWU: invalid FWU SP  UUID\n");
> +               return -EINVAL;
> +       }
> +
> +       for (i = 0; i < count ; i++) {
> +               log_debug("FWU: Enquiring service from SP 0x%x\n",
> +                         descs[i].info.id);
> +
> +               msg.data0 = TS_RPC_SERVICE_INFO_GET;
> +               msg.data1 = fwu_service_uuid.a1;
> +               msg.data2 = fwu_service_uuid.a2;
> +               msg.data3 = fwu_service_uuid.a3;
> +               msg.data4 = fwu_service_uuid.a4;
> +
> +               ret = ffa_sync_send_receive(g_dev, descs[i].info.id, &msg, 0);
> +               if (ret) {
> +                       log_err("FWU: FF-A error for SERVICE_INFO_GET (err: %d)\n",
> +                               ret);
> +                       return ret;
> +               }
> +
> +               if (msg.data0 != TS_RPC_SERVICE_INFO_GET) {
> +                       log_err("FWU: Wrong SERVICE_INFO_GET return: (%lx)\n",
> +                               msg.data0);
> +                       continue;
> +               }
> +
> +               if (msg.data1 == RPC_SUCCESS) {
> +                       g_svc_interface_id = GET_SVC_IFACE_ID(msg.data2);
> +                       g_fwu_sp_id = descs[i].info.id;
> +                       log_debug("FWU: Service interface ID 0x%x found\n",
> +                                 g_svc_interface_id);
> +                       return 0;
> +               }
> +
> +               log_debug("FWU: service not found\n");
> +       }
> +
> +       log_err("FWU: No SP provides the service\n");
> +
> +       return -ENOENT;
> +}
> +
> +/**
> + * fwu_shared_buf_reclaim() - Reclaim the shared communication buffer
> + *
> + * Description: In case of errors, this function can be called to retrieve
> + * the FWU shared buffer.
> + *
> + * Return: 0 on success. Otherwise, failure.
> + */
> +static int fwu_shared_buf_reclaim(void)
> +{
> +       int reclaim_ret;
> +
> +       reclaim_ret = ffa_memory_reclaim(g_dev, g_fwu_buf_handle, 0);
> +       if (reclaim_ret)
> +               log_err("FWU: FF-A memory reclaim failure (err: %d)\n",
> +                       reclaim_ret);
> +       else
> +               log_debug("FWU: Shared buffer reclaimed\n");
> +
> +       free(g_fwu_buf);
> +       g_fwu_buf = NULL;
> +
> +       return reclaim_ret;
> +}
> +
> +/**
> + * fwu_shared_buf_init() - Setup the FWU shared communication buffer
> + *
> + * Description: The communication with the TS FWU SP is based on a buffer shared
> + * between U-Boot and TS FWU SP allocated in normal world and accessed
> + * by both sides. The buffer contains the data exchanged between both sides
> + * such as the payloads data.
> + *
> + * Return: 0 on success. Otherwise, failure.
> + */
> +static int fwu_shared_buf_init(void)
> +{
> +       struct ffa_mem_ops_args args = {0};
> +       struct ffa_mem_region_attributes attrs = {0};
> +       struct ffa_send_direct_data msg;
> +       int ret;
> +
> +       g_fwu_buf = memalign(EFI_PAGE_SIZE, FWU_BUFFER_SIZE);
> +       if (!g_fwu_buf) {
> +               log_err("FWU: Failure to allocate the shared buffer\n");
> +               return -ENOMEM;
> +       }
> +
> +       /* Setting up user arguments */
> +       args.use_txbuf = true;
> +       args.address = g_fwu_buf;
> +       args.pg_cnt = FWU_BUFFER_PAGES;
> +       args.nattrs = 1;
> +       attrs.receiver = g_fwu_sp_id;
> +       attrs.attrs = FFA_MEM_RW;
> +       args.attrs = &attrs;
> +
> +       /* Registering the shared buffer with secure world (Trusted Services) */
> +       ret = ffa_memory_share(g_dev, &args);
> +       if (ret) {
> +               free(g_fwu_buf);
> +               g_fwu_buf = NULL;
> +               log_err("FWU: Failure setting up the shared buffer (err: %d)\n",
> +                       ret);
> +               return ret;
> +       }
> +
> +       g_fwu_buf_handle = args.g_handle;
> +
> +       log_debug("FWU: shared buffer handle 0x%llx\n", g_fwu_buf_handle);
> +
> +       /* Inform the FWU SP know about the shared buffer */
> +
> +       msg.data0 = TS_RPC_MEM_RETRIEVE;
> +       msg.data1 = GET_FWU_BUF_LSW(g_fwu_buf_handle);
> +       msg.data2 = GET_FWU_BUF_MSW(g_fwu_buf_handle);
> +
> +       ret = ffa_sync_send_receive(g_dev, g_fwu_sp_id, &msg, 0);
> +       if (ret) {
> +               log_err("FWU: FF-A message error for MEM_RETRIEVE (err: %d)\n",
> +                       ret);
> +               goto failure;
> +       }
> +
> +       if (msg.data0 != TS_RPC_MEM_RETRIEVE) {
> +               log_err("FWU: Unexpected MEM_RETRIEVE return: (%lx)\n",
> +                       msg.data0);
> +               ret = -EINVAL;
> +               goto failure;
> +       }
> +
> +       if (msg.data1 != RPC_SUCCESS) {
> +               log_err("FWU: MEM_RETRIEVE failed\n");
> +               ret = -EOPNOTSUPP;
> +               goto failure;
> +       }
> +
> +       log_debug("FWU: MEM_RETRIEVE success for SP 0x%x\n", g_fwu_sp_id);
> +
> +       return 0;
> +
> +failure:
> +       fwu_shared_buf_reclaim();
> +       return ret;
> +}
> +
> +/**
> + * fwu_agent_init() - Setup the FWU agent
> + *
> + * Description: Perform the initializations required to communicate
> + * and use the FWU agent in secure world.
> + * The frontend of the FWU agent is the Trusted Services (aka TS)
> + * FWU SP (aka Secure Partition).
> + *
> + * Return: 0 on success. Otherwise, failure.
> + */
> +int fwu_agent_init(void)
> +{
> +       int ret;
> +       struct fwu_data *fwu_data;
> +       u32 active_idx;
> +
> +       fwu_data = fwu_get_data();
> +       if (!fwu_data) {
> +               log_err("FWU: Cannot get FWU data\n");
> +               return -EINVAL;
> +       }

Why are you calling this function?

> +
> +       ret = fwu_get_active_index(&active_idx);
> +       if (ret) {
> +               log_err("FWU: Failed to read boot index, err (%d)\n",
> +                       ret);
> +               return ret;
> +       }

Same here. Why is this function being called when U-Boot is a update client?

-sughosh

> +
> +       if (fwu_data->trial_state)
> +               log_info("FWU: System booting in Trial State\n");
> +       else
> +               log_info("FWU: System booting in Regular State\n");
> +
> +       ret = uclass_first_device_err(UCLASS_FFA, &g_dev);
> +       if (ret) {
> +               log_err("FWU: Cannot find FF-A bus device, err (%d)\n", ret);
> +               return ret;
> +       }
> +
> +       ret = fwu_discover_ts_sp_id();
> +       if (ret)
> +               return ret;
> +
> +       ret = fwu_shared_buf_init();
> +       if (ret)
> +               return ret;
> +
> +       g_fwu_initialized = true;
> +
> +       return 0;
> +}
> --
> 2.43.0
>


More information about the U-Boot mailing list