On Wed, Feb 18, 2026 at 03:17:58PM +0530, Sughosh Ganu wrote:
> On Mon, Feb 16, 2026 at 02:35:35PM +0100, Kory Maincent wrote:
> > Add a new fwumdata tool to allows users to read, display, and modify FWU
> > (Firmware Update) metadata from Linux userspace. It provides functionality
> > similar to fw_printenv/fw_setenv but for FWU metadata. Users can view
> > metadata, change active/previous bank indices, modify bank states, and set
> > image acceptance flags. Configuration is done via fwumdata.config file.
> > 
> > Signed-off-by: Kory Maincent <[email protected]>
> > ---
> 
> I am not sure if this has been discussed with Ilias earlier, and
> apologies if it has been, but I do think that this patch is not
> adhering to the DEN0118 specification, specifically the part mentioned
> in section A3.2.1, which says that the metadata is to be maintained by
> the Update Agent. I would like to hear from Jose Marinho, who is the
> author of the spec, on what he thinks about this approach.
> 
> I do think that the other patches in series look fine, and can be
> applied. There is just an issue of inclusion of the tool for
> building. I will comment on that patch separately.


Adding Jose to the discussion.

-sughosh

> 
> 
> >  MAINTAINERS                        |   4 +
> >  doc/develop/uefi/fwu_updates.rst   |   4 +-
> >  doc/fwumdata.1                     | 222 ++++++++++
> >  tools/.gitignore                   |   1 +
> >  tools/fwumdata_src/Kconfig         |  11 +
> >  tools/fwumdata_src/fwumdata.c      | 854 
> > +++++++++++++++++++++++++++++++++++++
> >  tools/fwumdata_src/fwumdata.config |  33 ++
> >  tools/fwumdata_src/fwumdata.h      | 138 ++++++
> >  tools/fwumdata_src/fwumdata.mk     |   5 +-
> >  9 files changed, 1270 insertions(+), 2 deletions(-)
> > 
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 9d954be4a9d..d680b193033 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -1242,11 +1242,15 @@ F:  drivers/watchdog/sbsa_gwdt.c
> >  
> >  FWU Multi Bank Update
> >  M: Sughosh Ganu <[email protected]>
> > +M: Kory Maincent <[email protected]>
> >  S: Maintained
> >  T: git https://source.denx.de/u-boot/custodians/u-boot-efi.git
> > +F: doc/fwumdata.1
> >  F: doc/mkfwumdata.1
> >  F: lib/fwu_updates/*
> >  F: drivers/fwu-mdata/*
> > +F: tools/fwumdata_src/fwumdata.c
> > +F: tools/fwumdata_src/fwumdata.h
> >  F: tools/fwumdata_src/mkfwumdata.c
> >  
> >  GATEWORKS_SC
> > diff --git a/doc/develop/uefi/fwu_updates.rst 
> > b/doc/develop/uefi/fwu_updates.rst
> > index 84713581459..c592106f8a8 100644
> > --- a/doc/develop/uefi/fwu_updates.rst
> > +++ b/doc/develop/uefi/fwu_updates.rst
> > @@ -66,7 +66,9 @@ FWU Metadata
> >  U-Boot supports both versions(1 and 2) of the FWU metadata defined in
> >  the two revisions of the specification. Support can be enabled for
> >  either of the two versions through a config flag. The mkfwumdata tool
> > -can generate metadata for both the supported versions.
> > +can generate metadata for both the supported versions. On the target side,
> > +the fwumdata tool can read and update FWU metadata located in memory,
> > +similarly to how fw_printenv/fw_setenv works.
> >  
> >  Setting up the device for GPT partitioned storage
> >  -------------------------------------------------
> > diff --git a/doc/fwumdata.1 b/doc/fwumdata.1
> > new file mode 100644
> > index 00000000000..66a53fc9403
> > --- /dev/null
> > +++ b/doc/fwumdata.1
> > @@ -0,0 +1,222 @@
> > +.\" SPDX-License-Identifier: GPL-2.0-or-later
> > +.\" Copyright (C) 2025 Kory Maincent <[email protected]>
> > +.TH FWUMDATA 1 2025 U-Boot
> > +.SH NAME
> > +fwumdata \- read, display, and modify FWU metadata
> > +.
> > +.SH SYNOPSIS
> > +.SY fwumdata
> > +.OP \-c config
> > +.OP \-l
> > +.OP \-u
> > +.OP \-a bankid
> > +.OP \-p bankid
> > +.RB [ \-s
> > +.IR bankid " " state ]
> > +.OP \-i imageid
> > +.OP \-b bankid
> > +.OP \-A
> > +.OP \-C
> > +.OP \-B num_banks
> > +.OP \-I num_images
> > +.YS
> > +.SY fwumdata
> > +.B \-h
> > +.YS
> > +.
> > +.SH DESCRIPTION
> > +.B fwumdata
> > +reads, displays, and modifies FWU (Firmware Update) metadata from Linux
> > +userspace.
> > +.PP
> > +The tool operates on FWU metadata stored on block or MTD devices, allowing
> > +userspace manipulation of firmware update state including active bank
> > +selection, image acceptance, and bank state management.
> > +.
> > +.SH OPTIONS
> > +.TP
> > +.BR \-c ", " \-\-config " \fIfile\fR"
> > +Use custom configuration file. By default, the tool searches for
> > +.I ./fwumdata.config
> > +then
> > +.IR /etc/fwumdata.config .
> > +.
> > +.TP
> > +.BR \-l ", " \-\-list
> > +Display detailed metadata information including all GUIDs, image entries,
> > +and bank information. Without this option, only a summary is shown.
> > +.
> > +.TP
> > +.BR \-u ", " \-\-update
> > +Update metadata if CRC validation fails. Useful for recovering from 
> > corrupted
> > +metadata.
> > +.
> > +.TP
> > +.BR \-a ", " \-\-active " \fIbankid\fR"
> > +Set the active bank index to
> > +.IR bank .
> > +.
> > +.TP
> > +.BR \-p ", " \-\-previous " \fIbankid\fR"
> > +Set the previous active bank index to
> > +.IR bank .
> > +.
> > +.TP
> > +.BR \-s ", " \-\-state " \fIbankid state\fR"
> > +Set bank index
> > +.I bankid
> > +to the specified
> > +.IR state .
> > +Valid states are:
> > +.BR accepted ,
> > +.BR valid ,
> > +or
> > +.BR invalid .
> > +Supported only with version 2 metadata. When setting a bank to accepted 
> > state,
> > +all firmware images in that bank are automatically marked as accepted.
> > +.
> > +.TP
> > +.BR \-i ", " \-\-image " \fIimageid\fR"
> > +Specify image number (used with
> > +.B \-A
> > +or
> > +.BR \-C ).
> > +.
> > +.TP
> > +.BR \-b ", " \-\-bank " \fIbankid\fR"
> > +Specify bank number (used with
> > +.B \-A
> > +or
> > +.BR \-C ).
> > +.
> > +.TP
> > +.BR \-A ", " \-\-accept
> > +Accept the image specified by
> > +.B \-i
> > +in the bank specified by
> > +.BR \-b .
> > +Sets the FWU_IMAGE_ACCEPTED flag for the image.
> > +.
> > +.TP
> > +.BR \-C ", " \-\-clear
> > +Clear the acceptance flag for the image specified by
> > +.B \-i
> > +in the bank specified by
> > +.BR \-b .
> > +According to the FWU specification, the bank state is automatically set to
> > +invalid before clearing the acceptance flag.
> > +.
> > +.TP
> > +.BR \-B ", " \-\-nbanks " \fInum_banks\fR"
> > +Specify total number of banks (required for V1 metadata).
> > +.
> > +.TP
> > +.BR \-I ", " \-\-nimages " \fInum_images\fR"
> > +Specify total number of images (required for V1 metadata).
> > +.
> > +.TP
> > +.BR \-h ", " \-\-help
> > +Print usage information and exit.
> > +.
> > +.SH CONFIGURATION FILE
> > +The configuration file specifies the location of FWU metadata on storage
> > +devices. The format is:
> > +.PP
> > +.EX
> > +.in +4
> > +# Device Name      Device Offset    Metadata Size    Erase Size
> > +/dev/mtd0          0x0              0x78             0x1000
> > +/dev/mtd1          0x0              0x78             0x1000
> > +.in
> > +.EE
> > +.PP
> > +Lines starting with
> > +.B #
> > +are comments.
> > +.I Erase Size
> > +is optional and only applies to MTD devices; if omitted, it defaults to the
> > +metadata size.
> > +.PP
> > +Specifying two devices enables redundant metadata support.
> > +.
> > +.SH BUGS
> > +Please report bugs to the
> > +.UR https://\:source\:.denx\:.de/\:u-boot/\:u-boot/\:issues
> > +U-Boot bug tracker
> > +.UE .
> > +.
> > +.SH EXAMPLES
> > +Display FWU metadata summary:
> > +.PP
> > +.EX
> > +.in +4
> > +$ \c
> > +.B fwumdata
> > +.in
> > +.EE
> > +.PP
> > +Display detailed metadata with all GUIDs:
> > +.PP
> > +.EX
> > +.in +4
> > +$ \c
> > +.B fwumdata \-l
> > +.in
> > +.EE
> > +.PP
> > +Set active bank to 1:
> > +.PP
> > +.EX
> > +.in +4
> > +$ \c
> > +.B fwumdata \-a 1
> > +.in
> > +.EE
> > +.PP
> > +Set bank 1 to accepted state (automatically accepts all images in that 
> > bank):
> > +.PP
> > +.EX
> > +.in +4
> > +$ \c
> > +.B fwumdata \-s 1 accepted
> > +.in
> > +.EE
> > +.PP
> > +Accept image 0 in bank 0:
> > +.PP
> > +.EX
> > +.in +4
> > +$ \c
> > +.B fwumdata \-i 0 \-b 0 \-A \-l
> > +.in
> > +.EE
> > +.PP
> > +Clear acceptance for image 0 in bank 1:
> > +.PP
> > +.EX
> > +.in +4
> > +$ \c
> > +.B fwumdata \-i 0 \-b 1 \-C \-l
> > +.in
> > +.EE
> > +.PP
> > +Clear acceptance for image 1 in bank 1 with metadata V1:
> > +.PP
> > +.EX
> > +.in +4
> > +$ \c
> > +.B fwumdata \-B 2 \-I 2 \-i 1 \-b 1 \-C \-l
> > +.in
> > +.EE
> > +.PP
> > +Use custom configuration file:
> > +.PP
> > +.EX
> > +.in +4
> > +$ \c
> > +.B fwumdata \-c /path/to/custom.config
> > +.in
> > +.EE
> > +.
> > +.SH SEE ALSO
> > +.BR mkfwumdata (1)
> > diff --git a/tools/.gitignore b/tools/.gitignore
> > index e8daa24a52d..49943d2cf3a 100644
> > --- a/tools/.gitignore
> > +++ b/tools/.gitignore
> > @@ -11,6 +11,7 @@
> >  /file2include
> >  /fit_check_sign
> >  /fit_info
> > +/fwumdata
> >  /gdb/gdbcont
> >  /gdb/gdbsend
> >  /gen_eth_addr
> > diff --git a/tools/fwumdata_src/Kconfig b/tools/fwumdata_src/Kconfig
> > index c033c560e8d..af1f3bb3f57 100644
> > --- a/tools/fwumdata_src/Kconfig
> > +++ b/tools/fwumdata_src/Kconfig
> > @@ -6,3 +6,14 @@ config TOOLS_MKFWUMDATA
> >       metadata for initial installation of the FWU multi bank
> >       update on the board. The installation method depends on
> >       the platform.
> > +
> > +config TOOLS_FWUMDATA
> > +   bool "Build fwumdata command"
> > +   default y if FWU_MULTI_BANK_UPDATE
> > +   help
> > +     This command allows users to read, display, and modify FWU
> > +     (Firmware Update) metadata from Linux userspace. It provides
> > +     functionality similar to fw_printenv/fw_setenv but for FWU
> > +     metadata. Users can view metadata, change active/previous
> > +     bank indices, modify bank states, and set image acceptance
> > +     flags. Configuration is done via fwumdata.config file.
> > diff --git a/tools/fwumdata_src/fwumdata.c b/tools/fwumdata_src/fwumdata.c
> > new file mode 100644
> > index 00000000000..c5b0f56842d
> > --- /dev/null
> > +++ b/tools/fwumdata_src/fwumdata.c
> > @@ -0,0 +1,854 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * FWU Metadata Read/Write Tool
> > + * Copyright (c) 2025, Kory Maincent <[email protected]>
> > + *
> > + * Tool to read, display, and modify FWU (Firmware Update) metadata
> > + * from Linux userspace. Similar to fw_printenv/fw_setenv for U-Boot
> > + * environment, but for FWU metadata.
> > + *
> > + * Usage:
> > + *   fwumdata                          - Print all metadata
> > + *   fwumdata -u                       - Print metadata and update it if 
> > CRC corrupted
> > + *   fwumdata -c <config>              - Use custom config file
> > + *   fwumdata -a <bank>                - Set active bank
> > + *   fwumdata -p <bank>                - Set previous bank
> > + *   fwumdata -s <bank> <state>        - Set bank state (V2 only)
> > + *   fwumdata -i <id> -b <bank> -A     - Accept image
> > + *   fwumdata -i <id> -b <bank> -C     - Clear image acceptance
> > + *   fwumdata -i <id> -b <bank>
> > + *            -B <num_banks>
> > + *            -I <num_images> -C       - Clear image acceptance (V1 only)
> > + *   fwumdata -l                       - List detailed info with GUIDs
> > + */
> > +
> > +#include <errno.h>
> > +#include <getopt.h>
> > +#include <stdio.h>
> > +#include <unistd.h>
> > +#include <mtd/mtd-user.h>
> > +#include <sys/ioctl.h>
> > +#include <u-boot/crc.h>
> > +#include "fwumdata.h"
> > +
> > +/* Device configuration */
> > +struct fwumdata_device {
> > +   const char *devname;
> > +   long long devoff;
> > +   unsigned long mdata_size;
> > +   unsigned long erase_size;
> > +   int fd;
> > +   bool is_mtd;
> > +};
> > +
> > +/* Global state */
> > +static struct fwumdata_device devices[2];  /* Primary and secondary */
> > +static struct fwu_mdata *mdata;
> > +static int have_redundant;
> > +static struct fwu_mdata *valid_mdata;
> > +static bool mdata_mod;
> > +static const char *config_file;
> > +static int nbanks, nimages; /* For V1 only */
> > +static const char * const default_config_files[] = {
> > +   "./fwumdata.config",
> > +   "/etc/fwumdata.config",
> > +   NULL
> > +};
> > +
> > +/* GUID/UUID utilities */
> > +static void guid_to_string(const struct efi_guid *guid, char *str)
> > +{
> > +   sprintf(str, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
> > +           guid->time_high, guid->time_low, guid->reserved,
> > +           guid->family, guid->node[0],
> > +           guid->node[1], guid->node[2], guid->node[3],
> > +           guid->node[4], guid->node[5], guid->node[6]);
> > +}
> > +
> > +/* Config file parsing */
> > +static int parse_config(const char *fname)
> > +{
> > +   size_t linesize = 0;
> > +   char *line = NULL;
> > +   char *devname;
> > +   int i = 0;
> > +   FILE *fp;
> > +   int rc;
> > +
> > +   fp = fopen(fname, "r");
> > +   if (!fp)
> > +           return -ENOENT;
> > +
> > +   while (i < 2 && getline(&line, &linesize, fp) != -1) {
> > +           /* Skip comments and empty lines */
> > +           if (line[0] == '#' || line[0] == '\n')
> > +                   continue;
> > +
> > +           rc = sscanf(line, "%ms %lli %lx %lx",
> > +                       &devname,
> > +                       &devices[i].devoff,
> > +                       &devices[i].mdata_size,
> > +                       &devices[i].erase_size);
> > +
> > +           if (rc < 3) {
> > +                   free(devname);
> > +                   continue;
> > +           }
> > +
> > +           if (rc < 4)
> > +                   devices[i].erase_size = devices[i].mdata_size;
> > +
> > +           devices[i].devname = devname;
> > +           i++;
> > +   }
> > +
> > +   free(line);
> > +   fclose(fp);
> > +
> > +   if (i == 2) {
> > +           have_redundant = true;
> > +           if (devices[0].mdata_size != devices[1].mdata_size) {
> > +                   fprintf(stderr,
> > +                           "Size mismatch between the two metadata\n");
> > +                   return -EINVAL;
> > +           }
> > +   }
> > +
> > +   if (!i) {
> > +           fprintf(stderr,
> > +                   "Can't read config %s content\n", fname);
> > +           return -EINVAL;
> > +   }
> > +
> > +   return 0;
> > +}
> > +
> > +static int find_parse_config(void)
> > +{
> > +   int i;
> > +
> > +   if (config_file)
> > +           return parse_config(config_file);
> > +
> > +   for (i = 0; default_config_files[i]; i++) {
> > +           int ret;
> > +
> > +           ret = parse_config(default_config_files[i]);
> > +           if (ret == -ENOENT)
> > +                   continue;
> > +           if (ret)
> > +                   return ret;
> > +
> > +           config_file = default_config_files[i];
> > +           return 0;
> > +   }
> > +
> > +   fprintf(stderr, "Error: Cannot find config file\n");
> > +   return -ENOENT;
> > +}
> > +
> > +static int open_device(struct fwumdata_device *dev)
> > +{
> > +   if (strstr(dev->devname, "/dev/mtd"))
> > +           dev->is_mtd = true;
> > +
> > +   dev->fd = open(dev->devname, O_RDWR | O_SYNC);
> > +   if (dev->fd < 0) {
> > +           fprintf(stderr, "Cannot open %s: %s\n", dev->devname,
> > +                   strerror(errno));
> > +           return -ENODEV;
> > +   }
> > +
> > +   return 0;
> > +}
> > +
> > +static int mtd_erase(int fd, unsigned long offset, unsigned long size)
> > +{
> > +   struct erase_info_user erase;
> > +   int ret;
> > +
> > +   erase.start = offset;
> > +   erase.length = size;
> > +
> > +   ret = ioctl(fd, MEMERASE, &erase);
> > +   if (ret < 0) {
> > +           fprintf(stderr, "MTD erase failed: %s\n", strerror(errno));
> > +           return -errno;
> > +   }
> > +
> > +   return 0;
> > +}
> > +
> > +static int read_device(struct fwumdata_device *dev, void *buf, size_t 
> > count)
> > +{
> > +   if (lseek(dev->fd, dev->devoff, SEEK_SET) < 0) {
> > +           fprintf(stderr, "Seek failed: %s\n", strerror(errno));
> > +           return -errno;
> > +   }
> > +
> > +   if (read(dev->fd, buf, count) < 0) {
> > +           fprintf(stderr, "Read failed: %s\n", strerror(errno));
> > +           return -errno;
> > +   }
> > +
> > +   return 0;
> > +}
> > +
> > +static int write_device(struct fwumdata_device *dev, const void *buf,
> > +                   size_t count)
> > +{
> > +   int ret;
> > +
> > +   /* Erase if MTD device */
> > +   if (dev->is_mtd) {
> > +           ret = mtd_erase(dev->fd, dev->devoff, dev->erase_size);
> > +           if (ret)
> > +                   return ret;
> > +   }
> > +
> > +   if (lseek(dev->fd, dev->devoff, SEEK_SET) < 0) {
> > +           fprintf(stderr, "Seek failed: %s\n", strerror(errno));
> > +           return -errno;
> > +   }
> > +
> > +   if (write(dev->fd, buf, count) < 0) {
> > +           fprintf(stderr, "Write failed: %s\n", strerror(errno));
> > +           return -errno;
> > +   }
> > +
> > +   return 0;
> > +}
> > +
> > +/* Metadata operations */
> > +static int validate_crc(struct fwu_mdata *mdata, size_t size)
> > +{
> > +   u32 calc_crc, stored_crc;
> > +
> > +   stored_crc = mdata->crc32;
> > +   calc_crc = crc32(0, (const u8 *)&mdata->version, size - sizeof(u32));
> > +
> > +   if (calc_crc != stored_crc) {
> > +           fprintf(stderr,
> > +                   "CRC mismatch: calculated 0x%08x, stored 0x%08x\n",
> > +                   calc_crc, stored_crc);
> > +           if (mdata->version == 1)
> > +                   fprintf(stderr,
> > +                           "Metadata is V1, this may be size description 
> > issue\n");
> > +           return -1;
> > +   }
> > +
> > +   return 0;
> > +}
> > +
> > +static void update_crc(struct fwu_mdata *mdata, size_t size)
> > +{
> > +   mdata->crc32 = crc32(0, (const u8 *)&mdata->version, size - 
> > sizeof(u32));
> > +}
> > +
> > +static int read_one_metadata(int mdata_id, size_t size)
> > +{
> > +   int ret;
> > +
> > +   ret = open_device(&devices[mdata_id]);
> > +   if (ret)
> > +           return ret;
> > +
> > +   ret = read_device(&devices[mdata_id], &mdata[mdata_id], size);
> > +   if (ret)
> > +           return ret;
> > +
> > +   if (mdata[mdata_id].version != 1 && mdata[mdata_id].version != 2) {
> > +           fprintf(stderr, "Invalid metadata %d version: %u\n",
> > +                   mdata_id, mdata[mdata_id].version);
> > +   }
> > +
> > +   return 0;
> > +}
> > +
> > +static int read_metadata(bool update)
> > +{
> > +   size_t alloc_size;
> > +   int ret;
> > +
> > +   /* Allocate initial buffer */
> > +   alloc_size = devices[0].mdata_size;
> > +   mdata = calloc(have_redundant ? 2 : 1, alloc_size);
> > +   if (!mdata) {
> > +           fprintf(stderr, "Memory allocation failed\n");
> > +           return -ENOMEM;
> > +   }
> > +
> > +   ret = read_one_metadata(0, alloc_size);
> > +   if (ret)
> > +           return ret;
> > +
> > +   if (validate_crc(&mdata[0], alloc_size) < 0) {
> > +           fprintf(stderr,
> > +                   "Warning: Primary metadata CRC validation failed\n");
> > +           mdata_mod = update;
> > +   } else {
> > +           valid_mdata = &mdata[0];
> > +   }
> > +
> > +   if (have_redundant) {
> > +           ret = read_one_metadata(1, alloc_size);
> > +           if (ret)
> > +                   return ret;
> > +
> > +           if (validate_crc(&mdata[1], alloc_size) < 0) {
> > +                   fprintf(stderr,
> > +                           "Warning: Secondary metadata CRC validation 
> > failed\n");
> > +                   mdata_mod = update;
> > +           } else if (valid_mdata && mdata[0].crc32 != mdata[1].crc32) {
> > +                   fprintf(stderr,
> > +                           "Metadatas valid but not equal, use first one 
> > as default\n");
> > +                   mdata_mod = update;
> > +           } else {
> > +                   valid_mdata = &mdata[1];
> > +           }
> > +   }
> > +
> > +   if (!valid_mdata) {
> > +           fprintf(stderr,
> > +                   "No metadata valid, use first one as default\n");
> > +           mdata_mod = update;
> > +           valid_mdata = &mdata[0];
> > +   }
> > +
> > +   if (valid_mdata->version == 2) {
> > +           struct fwu_mdata_ext *mdata_ext;
> > +
> > +           mdata_ext = fwu_get_fw_mdata_ext(valid_mdata);
> > +           if (mdata_ext->metadata_size != alloc_size) {
> > +                   fprintf(stderr,
> > +                           "Metadata real size 0x%x mismatch with the 
> > config 0x%zx\n",
> > +                           mdata_ext->metadata_size, alloc_size);
> > +                           return -EINVAL;
> > +           }
> > +   }
> > +
> > +   return 0;
> > +}
> > +
> > +static int write_metadata(void)
> > +{
> > +   size_t write_size = devices[0].mdata_size;
> > +   int ret;
> > +
> > +   if (!mdata_mod)
> > +           return 0;
> > +
> > +   /* Update CRC */
> > +   update_crc(valid_mdata, write_size);
> > +
> > +   /* Write primary */
> > +   ret = write_device(&devices[0], valid_mdata, write_size);
> > +   if (ret < 0) {
> > +           fprintf(stderr, "Failed to write primary metadata\n");
> > +           return ret;
> > +   }
> > +
> > +   /* Write secondary if redundant */
> > +   if (have_redundant) {
> > +           ret = write_device(&devices[1], valid_mdata, write_size);
> > +           if (ret < 0) {
> > +                   fprintf(stderr, "Failed to write secondary metadata\n");
> > +                   return -1;
> > +           }
> > +   }
> > +
> > +   printf("FWU metadata updated successfully\n");
> > +   mdata_mod = 0;
> > +
> > +   return 0;
> > +}
> > +
> > +/* Display functions */
> > +static const char *bank_state_to_string(u8 state)
> > +{
> > +   switch (state) {
> > +   case FWU_BANK_ACCEPTED:
> > +           return "accepted";
> > +   case FWU_BANK_VALID:
> > +           return "valid";
> > +   case FWU_BANK_INVALID:
> > +           return "invalid";
> > +   default:
> > +           return "unknown";
> > +   }
> > +}
> > +
> > +static void print_metadata_summary(void)
> > +{
> > +   int i;
> > +
> > +   printf("FWU Metadata:\n");
> > +   printf("\tVersion:            %u\n", valid_mdata->version);
> > +   printf("\tActive Index:       %u\n", valid_mdata->active_index);
> > +   printf("\tPrevious Index:     %u\n", 
> > valid_mdata->previous_active_index);
> > +   printf("\tCRC32:              0x%08x\n", valid_mdata->crc32);
> > +
> > +   if (valid_mdata->version == 2) {
> > +           struct fwu_fw_store_desc *fw_desc;
> > +           struct fwu_mdata_ext *mdata_ext;
> > +
> > +           mdata_ext = fwu_get_fw_mdata_ext(valid_mdata);
> > +           printf("\tMetadata Size:      %u bytes\n", 
> > mdata_ext->metadata_size);
> > +           printf("\tDescriptor Offset:  %u\n", mdata_ext->desc_offset);
> > +           printf("\tBank States:\n");
> > +
> > +           fw_desc = fwu_get_fw_desc(valid_mdata);
> > +           for (i = 0; i < fw_desc->num_banks && i < MAX_BANKS_V2; i++) {
> > +                   printf("\t\tBank %d: %s (0x%02x)\n", i,
> > +                          bank_state_to_string(mdata_ext->bank_state[i]),
> > +                          mdata_ext->bank_state[i]);
> > +           }
> > +   }
> > +}
> > +
> > +static void print_metadata_detailed(void)
> > +{
> > +   struct fwu_fw_store_desc *fw_desc = NULL;
> > +   struct fwu_image_bank_info *bank_info;
> > +   struct fwu_image_entry *img_entry;
> > +   int num_images, num_banks;
> > +   char guid_str[64];
> > +   int i, j;
> > +
> > +   print_metadata_summary();
> > +
> > +   if (valid_mdata->version == 1) {
> > +           num_images = nimages;
> > +           num_banks = nbanks;
> > +   } else {
> > +           fw_desc = fwu_get_fw_desc(valid_mdata);
> > +           num_images = fw_desc->num_images;
> > +           num_banks = fw_desc->num_banks;
> > +   }
> > +
> > +   if (fw_desc) {
> > +           printf("\n\tFirmware Store Descriptor:\n");
> > +           printf("\t\tNumber of Banks:       %u\n", num_banks);
> > +           printf("\t\tNumber of Images:      %u\n", num_images);
> > +           printf("\t\tImage Entry Size:      %u\n", 
> > fw_desc->img_entry_size);
> > +           printf("\t\tBank Info Entry Size:  %u\n", 
> > fw_desc->bank_info_entry_size);
> > +   }
> > +
> > +   printf("\n\tImages:\n");
> > +   for (i = 0; i < num_images; i++) {
> > +           img_entry = fwu_get_image_entry(valid_mdata, 
> > valid_mdata->version,
> > +                                           num_banks, i);
> > +
> > +           printf("\t\tImage %d:\n", i);
> > +
> > +           guid_to_string(&img_entry->image_type_guid, guid_str);
> > +           printf("\t\t\tImage Type GUID:  %s\n", guid_str);
> > +
> > +           guid_to_string(&img_entry->location_guid, guid_str);
> > +           printf("\t\t\tLocation GUID:    %s\n", guid_str);
> > +
> > +           printf("\t\t\tBanks:\n");
> > +           for (j = 0; j < num_banks; j++) {
> > +                   bank_info = fwu_get_bank_info(valid_mdata,
> > +                                                 valid_mdata->version,
> > +                                                 num_banks, i, j);
> > +
> > +                   guid_to_string(&bank_info->image_guid, guid_str);
> > +                   printf("\t\t\t\tBank %d:\n", j);
> > +                   printf("\t\t\t\t\tImage GUID:  %s\n", guid_str);
> > +                   printf("\t\t\t\t\tAccepted:    %s (%u)\n",
> > +                          (bank_info->accepted & FWU_IMAGE_ACCEPTED) ? 
> > "yes" : "no",
> > +                          bank_info->accepted);
> > +           }
> > +   }
> > +}
> > +
> > +/* Modification functions */
> > +static int set_active_index(int bank)
> > +{
> > +   struct fwu_fw_store_desc *fw_desc;
> > +   int num_banks;
> > +
> > +   if (valid_mdata->version == 2) {
> > +           fw_desc = fwu_get_fw_desc(valid_mdata);
> > +           num_banks = fw_desc->num_banks;
> > +   } else {
> > +           num_banks = nbanks;
> > +   }
> > +
> > +   if (bank < 0 || bank >= num_banks) {
> > +           fprintf(stderr, "Error: Invalid bank %d (must be 0-%d)\n",
> > +                   bank, num_banks - 1);
> > +           return -EINVAL;
> > +   }
> > +
> > +   if (valid_mdata->active_index == bank)
> > +           return 0;
> > +
> > +   valid_mdata->active_index = bank;
> > +   mdata_mod = 1;
> > +
> > +   printf("Active bank set to %d\n", bank);
> > +   return 0;
> > +}
> > +
> > +static int set_previous_index(int bank)
> > +{
> > +   struct fwu_fw_store_desc *fw_desc;
> > +   int num_banks;
> > +
> > +   if (valid_mdata->version == 2) {
> > +           fw_desc = fwu_get_fw_desc(valid_mdata);
> > +           num_banks = fw_desc->num_banks;
> > +   } else {
> > +           num_banks = nbanks;
> > +   }
> > +
> > +   if (bank < 0 || bank >= num_banks) {
> > +           fprintf(stderr, "Error: Invalid bank %d (must be 0-%d)\n",
> > +                   bank, num_banks - 1);
> > +           return -EINVAL;
> > +   }
> > +
> > +   if (valid_mdata->previous_active_index == bank)
> > +           return 0;
> > +
> > +   valid_mdata->previous_active_index = bank;
> > +   mdata_mod = 1;
> > +
> > +   printf("Previous bank set to %d\n", bank);
> > +   return 0;
> > +}
> > +
> > +static int set_image_accepted(int image, int bank, int accept)
> > +{
> > +   struct fwu_image_bank_info *bank_info;
> > +   int num_images, num_banks;
> > +
> > +   if (valid_mdata->version == 1) {
> > +           num_images = nimages;
> > +           num_banks = nbanks;
> > +   } else {
> > +           struct fwu_fw_store_desc *fw_desc;
> > +
> > +           fw_desc = fwu_get_fw_desc(valid_mdata);
> > +           num_images = fw_desc->num_images;
> > +           num_banks = fw_desc->num_banks;
> > +   }
> > +
> > +   if (bank < 0 || bank >= num_banks) {
> > +           fprintf(stderr, "Error: Invalid bank %d (must be 0-%d)\n",
> > +                   bank, num_banks - 1);
> > +           return -EINVAL;
> > +   }
> > +
> > +   if (image < 0 || image >= num_images) {
> > +           fprintf(stderr, "Error: Invalid image %d (must be 0-%d)\n",
> > +                   image, num_images - 1);
> > +           return -EINVAL;
> > +   }
> > +
> > +   bank_info = fwu_get_bank_info(valid_mdata, valid_mdata->version,
> > +                                 num_banks, image, bank);
> > +   if (accept == bank_info->accepted)
> > +           return 0;
> > +
> > +   if (accept) {
> > +           bank_info->accepted = FWU_IMAGE_ACCEPTED;
> > +   } else {
> > +           bank_info->accepted = 0;
> > +
> > +           /* According to the spec: bank_state[index] have to be set
> > +            * to invalid before any content in the img_bank_info[index]
> > +            * is overwritten.
> > +            */
> > +           if (valid_mdata->version == 2) {
> > +                   struct fwu_mdata_ext *mdata_ext;
> > +
> > +                   mdata_ext = fwu_get_fw_mdata_ext(valid_mdata);
> > +                   mdata_ext->bank_state[bank] = FWU_BANK_INVALID;
> > +           }
> > +   }
> > +
> > +   mdata_mod = 1;
> > +   printf("Image %d in bank %d: acceptance %s\n",
> > +          image, bank, accept ? "set" : "cleared");
> > +
> > +   return 0;
> > +}
> > +
> > +static int set_bank_state(int bank, const char *state_str)
> > +{
> > +   struct fwu_fw_store_desc *fw_desc;
> > +   struct fwu_mdata_ext *mdata_ext;
> > +   u8 state;
> > +   int i;
> > +
> > +   if (valid_mdata->version != 2) {
> > +           fprintf(stderr,
> > +                   "Error: Bank state is only supported in V2 metadata\n");
> > +           return -EINVAL;
> > +   }
> > +
> > +   fw_desc = fwu_get_fw_desc(valid_mdata);
> > +   mdata_ext = fwu_get_fw_mdata_ext(valid_mdata);
> > +
> > +   if (bank < 0 || bank >= fw_desc->num_banks || bank >= MAX_BANKS_V2) {
> > +           fprintf(stderr, "Error: Invalid bank %d (must be 0-%d)\n",
> > +                   bank, fw_desc->num_banks - 1);
> > +           return -EINVAL;
> > +   }
> > +
> > +   /* Parse state string */
> > +   if (!strcmp(state_str, "accepted")) {
> > +           state = FWU_BANK_ACCEPTED;
> > +   } else if (!strcmp(state_str, "valid")) {
> > +           state = FWU_BANK_VALID;
> > +   } else if (!strcmp(state_str, "invalid")) {
> > +           state = FWU_BANK_INVALID;
> > +   } else {
> > +           fprintf(stderr,
> > +                   "Error: Invalid state '%s' (must be 
> > accepted/valid/invalid)\n",
> > +                   state_str);
> > +           return -EINVAL;
> > +   }
> > +
> > +   if (mdata_ext->bank_state[bank] == state)
> > +           return 0;
> > +
> > +   /* If a bank is set in a accepted state all firmware images in
> > +    * that bank must be marked as accepted as described in the spec.
> > +    */
> > +   if (state == FWU_BANK_ACCEPTED) {
> > +           for (i = 0; i < fw_desc->num_images; i++) {
> > +                   int ret;
> > +
> > +                   ret = set_image_accepted(i, bank, true);
> > +                   if (ret)
> > +                           return ret;
> > +           }
> > +   }
> > +   mdata_ext->bank_state[bank] = state;
> > +   mdata_mod = 1;
> > +
> > +   printf("Bank %d state set to %s (0x%02x)\n", bank, state_str, state);
> > +   return 0;
> > +}
> > +
> > +static int metadata_v1_validate_size(void)
> > +{
> > +   int calc_size;
> > +
> > +   calc_size = sizeof(struct fwu_mdata) +
> > +               (sizeof(struct fwu_image_entry) +
> > +                sizeof(struct fwu_image_bank_info) * nbanks) * nimages;
> > +
> > +   if (devices[0].mdata_size != calc_size) {
> > +           fprintf(stderr,
> > +                   "Metadata calculate size (-B and -I options) 0x%x 
> > mismatch with the config 0x%zx\n",
> > +                   calc_size, devices[0].mdata_size);
> > +           return -EINVAL;
> > +   }
> > +
> > +   return 0;
> > +}
> > +
> > +/* Command-line interface */
> > +static void print_usage(void)
> > +{
> > +   fprintf(stderr, "Usage: fwumdata [options]\n\n");
> > +   fprintf(stderr, "Options:\n"
> > +           "\t-c, --config <file>         Use custom config file, 
> > defaults:\n"
> > +           "\t                              ./fwumdata.config or 
> > /etc/fwumdata.config\n"
> > +           "\t-l, --list                  List detailed metadata with 
> > GUIDs\n"
> > +           "\t-a, --active <bank>         Set active bank index\n"
> > +           "\t-p, --previous <bank>       Set previous bank index\n"
> > +           "\t-s, --state <bank> <state>  Set bank state (V2 only)\n"
> > +           "\t                              state: 
> > accepted|valid|invalid\n"
> > +           "\t-i, --image <id>            Image number (for -A/-C)\n"
> > +           "\t-b, --bank <bank>           Bank number (for -A/-C)\n"
> > +           "\t-A, --accept                Accept image (requires -i and 
> > -b)\n"
> > +           "\t-C, --clear                 Clear image acceptance (requires 
> > -i and -b)\n"
> > +           "\t-u, --update                Update metadata if there is a 
> > checksum issue\n"
> > +           "\t-B, --nbanks <num_banks>    Number of banks (required for V1 
> > metadata)\n"
> > +           "\t-I, --nimages <num_images>  Number of images (required for 
> > V1 metadata)\n"
> > +           "\t-h, --help                  Print this help\n\n");
> > +   fprintf(stderr, "Config file format (fwumdata.config):\n"
> > +           "\t# Device Name      Device Offset    Metadata Size    Erase 
> > Size\n"
> > +           "\t/dev/mtd0          0x0              0x78             
> > 0x1000\n"
> > +           "\t/dev/mtd1          0x0              0x78             
> > 0x1000\n\n");
> > +   fprintf(stderr, "Examples:\n"
> > +           "\tfwumdata                              # Print metadata 
> > summary\n"
> > +           "\tfwumdata -l                           # Print detailed 
> > metadata\n"
> > +           "\tfwumdata -a 1                         # Set active bank to 
> > 1\n"
> > +           "\tfwumdata -s 1 accepted                # Set bank 1 to 
> > accepted state\n"
> > +           "\tfwumdata -i 0 -b 0 -A                 # Accept image in bank 
> > 0\n"
> > +           "\tfwumdata -B 2 -I 2 -i 1 -b 1 -A -l    # Accept image 1 in 
> > bank 1 with metadata V1\n");
> > +}
> > +
> > +int main(int argc, char *argv[])
> > +{
> > +   char *bank_state_str = NULL;
> > +   bool list_detailed = false;
> > +   int bank_state_num = -1;
> > +   int active_index = -1;
> > +   int bank_id = -1;
> > +   int prev_index = -1;
> > +   bool do_accept = 0;
> > +   bool do_clear = 0;
> > +   bool do_update = 0;
> > +   int image_id = -1;
> > +   int ret = 0;
> > +   int opt;
> > +
> > +   static struct option long_options[] = {
> > +           {"config", required_argument, 0, 'c'},
> > +           {"list", no_argument, 0, 'l'},
> > +           {"active", required_argument, 0, 'a'},
> > +           {"previous", required_argument, 0, 'p'},
> > +           {"state", required_argument, 0, 's'},
> > +           {"image", required_argument, 0, 'i'},
> > +           {"bank", required_argument, 0, 'b'},
> > +           {"accept", no_argument, 0, 'A'},
> > +           {"clear", no_argument, 0, 'C'},
> > +           {"update", no_argument, 0, 'u'},
> > +           {"nbanks", required_argument, 0, 'B'},
> > +           {"nimages", required_argument, 0, 'I'},
> > +           {"help", no_argument, 0, 'h'},
> > +           {0, 0, 0, 0}
> > +   };
> > +
> > +   /* Parse arguments */
> > +   while ((opt = getopt_long(argc, argv, "c:la:p:s:i:b:ACuB:I:h", 
> > long_options, NULL)) != -1) {
> > +           switch (opt) {
> > +           case 'c':
> > +                   config_file = optarg;
> > +                   break;
> > +           case 'l':
> > +                   list_detailed = 1;
> > +                   break;
> > +           case 'a':
> > +                   active_index = atoi(optarg);
> > +                   break;
> > +           case 'p':
> > +                   prev_index = atoi(optarg);
> > +                   break;
> > +           case 's':
> > +                   bank_state_num = atoi(optarg);
> > +                   if (optind < argc && argv[optind][0] != '-') {
> > +                           bank_state_str = argv[optind++];
> > +                   } else {
> > +                           fprintf(stderr,
> > +                                   "Error: -s requires bank number and 
> > state\n");
> > +                           return 1;
> > +                   }
> > +                   break;
> > +           case 'i':
> > +                   image_id = atoi(optarg);
> > +                   break;
> > +           case 'b':
> > +                   bank_id = atoi(optarg);
> > +                   break;
> > +           case 'A':
> > +                   do_accept = 1;
> > +                   break;
> > +           case 'C':
> > +                   do_clear = 1;
> > +                   break;
> > +           case 'u':
> > +                   do_update = 1;
> > +                   break;
> > +           case 'B':
> > +                   nbanks = atoi(optarg);
> > +                   break;
> > +           case 'I':
> > +                   nimages = atoi(optarg);
> > +                   break;
> > +           case 'h':
> > +                   print_usage();
> > +                   return 0;
> > +           default:
> > +                   print_usage();
> > +                   return 1;
> > +           }
> > +   }
> > +
> > +   ret = find_parse_config();
> > +   if (ret < 0) {
> > +           fprintf(stderr, "Error: Cannot read configuration\n");
> > +           return ret;
> > +   }
> > +
> > +   ret = read_metadata(do_update);
> > +   if (ret < 0) {
> > +           fprintf(stderr, "Error: Cannot read metadata\n");
> > +           goto cleanup;
> > +   }
> > +
> > +   if (valid_mdata->version == 1) {
> > +           ret = metadata_v1_validate_size();
> > +           if (ret)
> > +                   goto cleanup;
> > +   }
> > +
> > +   /* Perform operations */
> > +   if (active_index >= 0) {
> > +           ret = set_active_index(active_index);
> > +           if (ret < 0)
> > +                   goto cleanup;
> > +   }
> > +
> > +   if (prev_index >= 0) {
> > +           ret = set_previous_index(prev_index);
> > +           if (ret < 0)
> > +                   goto cleanup;
> > +   }
> > +
> > +   if (do_accept || do_clear) {
> > +           if (image_id < 0 || bank_id < 0) {
> > +                   fprintf(stderr,
> > +                           "Error: -A/-C requires both -i <guid> and -b 
> > <bank>\n");
> > +                   ret = -EINVAL;
> > +                   goto cleanup;
> > +           }
> > +
> > +           ret = set_image_accepted(image_id, bank_id, do_accept);
> > +           if (ret < 0)
> > +                   goto cleanup;
> > +   }
> > +
> > +   if (bank_state_num >= 0 && bank_state_str) {
> > +           ret = set_bank_state(bank_state_num, bank_state_str);
> > +           if (ret < 0)
> > +                   goto cleanup;
> > +   }
> > +
> > +   /* Write back if modified */
> > +   if (mdata_mod) {
> > +           ret = write_metadata();
> > +           if (ret)
> > +                   goto cleanup;
> > +   }
> > +
> > +   /* Display metadata if no modifications or list requested */
> > +   if (list_detailed)
> > +           print_metadata_detailed();
> > +   else
> > +           print_metadata_summary();
> > +
> > +cleanup:
> > +   /* Close devices and free memory */
> > +   if (devices[0].fd)
> > +           close(devices[0].fd);
> > +   if (devices[1].fd)
> > +           close(devices[1].fd);
> > +
> > +   free(mdata);
> > +
> > +   for (int i = 0; i < 2; i++) {
> > +           if (devices[i].devname)
> > +                   free((void *)devices[i].devname);
> > +   }
> > +
> > +   return ret;
> > +}
> > diff --git a/tools/fwumdata_src/fwumdata.config 
> > b/tools/fwumdata_src/fwumdata.config
> > new file mode 100644
> > index 00000000000..7e83f7a5909
> > --- /dev/null
> > +++ b/tools/fwumdata_src/fwumdata.config
> > @@ -0,0 +1,33 @@
> > +# FWU Metadata Configuration File
> > +#
> > +# Format: <device> <offset> <metadata_size> <erase_size>
> > +#
> > +# This file describes where the FWU metadata is stored. You can specify
> > +# up to two entries for redundant metadata copies.
> > +#
> > +# Device: MTD device (/dev/mtdX), block device (/dev/mmcblkX), or file path
> > +# Offset: Byte offset from start of device (hex with 0x prefix)
> > +# Metadata Size: Size of metadata structure in bytes (hex with 0x prefix)
> > +# Erase Size: Sector/erase block size (hex with 0x prefix, defaults to
> > +#        metadata_size, required only for MTD device)
> > +#
> > +# Examples:
> > +#
> > +# MTD devices (NOR/NAND flash):
> > +# /dev/mtd0  0x0       0x1000  0x1000
> > +# /dev/mtd1  0x0       0x1000  0x1000
> > +#
> > +# Block device (eMMC/SD):
> > +# /dev/mmcblk0  0x100000  0x78
> > +# /dev/mmcblk0  0x101000  0x78
> > +#
> > +# or:
> > +# /dev/disk/by-partlabel/metadata1  0  0x78
> > +# /dev/disk/by-partlabel/metadata2  0  0x78
> > +#
> > +# Regular file:
> > +# /boot/fwu-mdata.bin  0x0  0x78
> > +#
> > +# Default configuration (update for your platform):
> > +/dev/mtd0  0x0  0x78  0x1000
> > +/dev/mtd1  0x0  0x78  0x1000
> > diff --git a/tools/fwumdata_src/fwumdata.h b/tools/fwumdata_src/fwumdata.h
> > new file mode 100644
> > index 00000000000..5e2c45d0fb0
> > --- /dev/null
> > +++ b/tools/fwumdata_src/fwumdata.h
> > @@ -0,0 +1,138 @@
> > +/* SPDX-License-Identifier: GPL-2.0-or-later */
> > +/*
> > + * Copyright (c) 2025, Kory Maincent <[email protected]>
> > + */
> > +
> > +#ifndef _FWUMDATA_H_
> > +#define _FWUMDATA_H_
> > +
> > +#include <linux/compiler_attributes.h>
> > +
> > +/* Type definitions for U-Boot compatibility */
> > +typedef uint8_t u8;
> > +typedef uint16_t u16;
> > +typedef uint32_t u32;
> > +typedef uint64_t u64;
> > +
> > +/* FWU Constants */
> > +#define FWU_IMAGE_ACCEPTED 0x1
> > +#define FWU_BANK_INVALID   (uint8_t)0xFF
> > +#define FWU_BANK_VALID             (uint8_t)0xFE
> > +#define FWU_BANK_ACCEPTED  (uint8_t)0xFC
> > +#define MAX_BANKS_V2               4
> > +
> > +/* EFI GUID structure */
> > +struct efi_guid {
> > +   u32 time_high;
> > +   u16 time_low;
> > +   u16 reserved;
> > +   u8  family;
> > +   u8  node[7];
> > +} __packed;
> > +
> > +/* FWU Metadata structures */
> > +struct fwu_image_bank_info {
> > +   struct efi_guid  image_guid;
> > +   u32 accepted;
> > +   u32 reserved;
> > +} __packed;
> > +
> > +struct fwu_image_entry {
> > +   struct efi_guid image_type_guid;
> > +   struct efi_guid location_guid;
> > +   struct fwu_image_bank_info img_bank_info[0]; /* Variable length */
> > +} __packed;
> > +
> > +struct fwu_fw_store_desc {
> > +   u8  num_banks;
> > +   u8  reserved;
> > +   u16 num_images;
> > +   u16 img_entry_size;
> > +   u16 bank_info_entry_size;
> > +   struct fwu_image_entry img_entry[0]; /* Variable length */
> > +} __packed;
> > +
> > +struct fwu_mdata {
> > +   u32 crc32;
> > +   u32 version;
> > +   u32 active_index;
> > +   u32 previous_active_index;
> > +   /* Followed by image entries or fwu_mdata_ext */
> > +} __packed;
> > +
> > +struct fwu_mdata_ext { /* V2 only */
> > +   u32 metadata_size;
> > +   u16 desc_offset;
> > +   u16 reserved1;
> > +   u8  bank_state[4];
> > +   u32 reserved2;
> > +} __packed;
> > +
> > +/* Metadata access helpers */
> > +struct fwu_image_entry *fwu_get_image_entry(struct fwu_mdata *mdata,
> > +                                       int version, int num_banks,
> > +                                       int img_id)
> > +{
> > +   size_t offset;
> > +
> > +   if (version == 1) {
> > +           offset = sizeof(struct fwu_mdata) +
> > +                   (sizeof(struct fwu_image_entry) +
> > +                    sizeof(struct fwu_image_bank_info) * num_banks) * 
> > img_id;
> > +   } else {
> > +           /* V2: skip fwu_fw_store_desc header */
> > +           offset = sizeof(struct fwu_mdata) +
> > +                    sizeof(struct fwu_mdata_ext) +
> > +                    sizeof(struct fwu_fw_store_desc) +
> > +                    (sizeof(struct fwu_image_entry) +
> > +                     sizeof(struct fwu_image_bank_info) * num_banks) * 
> > img_id;
> > +   }
> > +
> > +   return (struct fwu_image_entry *)((char *)mdata + offset);
> > +}
> > +
> > +struct fwu_image_bank_info *fwu_get_bank_info(struct fwu_mdata *mdata,
> > +                                         int version, int num_banks,
> > +                                         int img_id, int bank_id)
> > +{
> > +   size_t offset;
> > +
> > +   if (version == 1) {
> > +           offset = sizeof(struct fwu_mdata) +
> > +                    (sizeof(struct fwu_image_entry) +
> > +                     sizeof(struct fwu_image_bank_info) * num_banks) * 
> > img_id +
> > +                    sizeof(struct fwu_image_entry) +
> > +                    sizeof(struct fwu_image_bank_info) * bank_id;
> > +   } else {
> > +           offset = sizeof(struct fwu_mdata) +
> > +                    sizeof(struct fwu_mdata_ext) +
> > +                    sizeof(struct fwu_fw_store_desc) +
> > +                    (sizeof(struct fwu_image_entry) +
> > +                     sizeof(struct fwu_image_bank_info) * num_banks) * 
> > img_id +
> > +                    sizeof(struct fwu_image_entry) +
> > +                    sizeof(struct fwu_image_bank_info) * bank_id;
> > +   }
> > +
> > +   return (struct fwu_image_bank_info *)((char *)mdata + offset);
> > +}
> > +
> > +struct fwu_fw_store_desc *fwu_get_fw_desc(struct fwu_mdata *mdata)
> > +{
> > +   size_t offset;
> > +
> > +   offset = sizeof(struct fwu_mdata) +
> > +            sizeof(struct fwu_mdata_ext);
> > +
> > +   return (struct fwu_fw_store_desc *)((char *)mdata + offset);
> > +}
> > +
> > +struct fwu_mdata_ext *fwu_get_fw_mdata_ext(struct fwu_mdata *mdata)
> > +{
> > +   size_t offset;
> > +
> > +   offset = sizeof(struct fwu_mdata);
> > +
> > +   return (struct fwu_mdata_ext *)((char *)mdata + offset);
> > +}
> > +
> > +#endif /* _FWUMDATA_H_ */
> > diff --git a/tools/fwumdata_src/fwumdata.mk b/tools/fwumdata_src/fwumdata.mk
> > index 00f4ae50dbb..2199e43b372 100644
> > --- a/tools/fwumdata_src/fwumdata.mk
> > +++ b/tools/fwumdata_src/fwumdata.mk
> > @@ -4,4 +4,7 @@
> >  
> >  mkfwumdata-objs := fwumdata_src/mkfwumdata.o generated/lib/crc32.o
> >  HOSTLDLIBS_mkfwumdata += -luuid
> > -hostprogs-always-$(CONFIG_TOOLS_MKFWUMDATA) += mkfwumdata
> > +hostprogs-$(CONFIG_TOOLS_MKFWUMDATA) += mkfwumdata
> > +
> > +fwumdata-objs := fwumdata_src/fwumdata.o generated/lib/crc32.o
> > +hostprogs-$(CONFIG_TOOLS_FWUMDATA) += fwumdata
> > 
> > -- 
> > 2.43.0
> > 
> 
> -sughosh

-sughosh

Reply via email to