* [PATCH v3 0/6] Add support for fwumdata
@ 2026-02-16 13:35 Kory Maincent
2026-02-16 13:35 ` [PATCH v3 1/6] tools: gitignore: Add mkfwumdata to the git ignore file Kory Maincent
` (5 more replies)
0 siblings, 6 replies; 18+ messages in thread
From: Kory Maincent @ 2026-02-16 13:35 UTC (permalink / raw)
To: u-boot
Cc: Thomas Petazzoni, Tom Rini, Patrice Chotard, Paul HENRYS,
Sughosh Ganu, Greg Malysa, Arturs Artamonovs, Vasileios Bimpikas,
Utsav Agarwal, Nathan Barrett-Morrison, Peng Fan, Simon Glass,
Duje Mihanović, Stefan Roese, Mattijs Korpershoek,
Sumit Garg, Heiko Schocher, Alif Zakuan Yuslaimi, E Shattow,
Raymond Mao, Jan Kiszka, Shiji Yang, Daniel Golle,
Heinrich Schuchardt, Ilias Apalodimas, Leonard Anderweit,
Kory Maincent, Yao Zi
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.
Made a few change to mkfwumdata tool along the way.
Here is an output example
$ ./fwumdata -l
FWU Metadata:
Version: 2
Active Index: 0
Previous Index: 1
CRC32: 0x1f21ff7b
Metadata Size: 120 bytes
Descriptor Offset: 32
Bank States:
Bank 0: accepted (0xfc)
Bank 1: accepted (0xfc)
Firmware Store Descriptor:
Number of Banks: 2
Number of Images: 1
Image Entry Size: 80
Bank Info Entry Size: 24
Images:
Image 0:
Image Type GUID: 65ae85ad-1fb3-0b46-8c5d-285543aa6eab
Location GUID: 51513491-da07-2a4f-9bea-375ea53b1b5c
Banks:
Bank 0:
Image GUID: cb2df442-f929-6a44-a374-672d92eb2aa7
Accepted: yes (1)
Bank 1:
Image GUID: a839a18f-395c-484f-83b8-0354077c8f9f
Accepted: yes (1)
Changes in v3:
- Rebase on master.
- Link to v2: https://lore.kernel.org/r/20251212-feature_fwumdata-v2-0-ad51572fbe79@bootlin.com
Changes in v2:
- Fix a small offset mistake in last patch
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
Kory Maincent (6):
tools: gitignore: Add mkfwumdata to the git ignore file
tools: Reorganize mkfwumdata tool into fwumdata_src directory
tools: mkfwumdata: Improve error message specificity
tools: mkfwumdata: Add bank count validation for FWU metadata v2
tools: Add support for fwumdata tool
tools: mkfwumdata: Remove dependency on fwu_mdata.h header
MAINTAINERS | 7 +-
doc/develop/uefi/fwu_updates.rst | 4 +-
doc/fwumdata.1 | 222 +++++++++
tools/.gitignore | 2 +
tools/Kconfig | 9 +-
tools/Makefile | 4 +-
tools/fwumdata_src/Kconfig | 19 +
tools/fwumdata_src/fwumdata.c | 854 ++++++++++++++++++++++++++++++++++
tools/fwumdata_src/fwumdata.config | 33 ++
tools/fwumdata_src/fwumdata.h | 138 ++++++
tools/fwumdata_src/fwumdata.mk | 10 +
tools/{ => fwumdata_src}/mkfwumdata.c | 106 ++---
12 files changed, 1315 insertions(+), 93 deletions(-)
---
base-commit: f9ffeec4bdcf1da655a0ffea482062adde78fee8
change-id: 20251107-feature_fwumdata-58508d61e1d3
Best regards,
--
Köry Maincent, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 18+ messages in thread* [PATCH v3 1/6] tools: gitignore: Add mkfwumdata to the git ignore file 2026-02-16 13:35 [PATCH v3 0/6] Add support for fwumdata Kory Maincent @ 2026-02-16 13:35 ` Kory Maincent 2026-02-16 13:35 ` [PATCH v3 2/6] tools: Reorganize mkfwumdata tool into fwumdata_src directory Kory Maincent ` (4 subsequent siblings) 5 siblings, 0 replies; 18+ messages in thread From: Kory Maincent @ 2026-02-16 13:35 UTC (permalink / raw) To: u-boot Cc: Thomas Petazzoni, Tom Rini, Patrice Chotard, Paul HENRYS, Sughosh Ganu, Greg Malysa, Arturs Artamonovs, Vasileios Bimpikas, Utsav Agarwal, Nathan Barrett-Morrison, Peng Fan, Simon Glass, Duje Mihanović, Stefan Roese, Mattijs Korpershoek, Sumit Garg, Heiko Schocher, Alif Zakuan Yuslaimi, E Shattow, Raymond Mao, Jan Kiszka, Shiji Yang, Daniel Golle, Heinrich Schuchardt, Ilias Apalodimas, Leonard Anderweit, Kory Maincent, Yao Zi mkfwumdata is a built image. Add it to .gitignore. Signed-off-by: Kory Maincent <kory.maincent@bootlin.com> --- tools/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/.gitignore b/tools/.gitignore index 6a5c613f772..e8daa24a52d 100644 --- a/tools/.gitignore +++ b/tools/.gitignore @@ -24,6 +24,7 @@ /mkeficapsule /mkenvimage /mkexynosspl +/mkfwumdata /mkimage /mksunxiboot /mxsboot -- 2.43.0 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v3 2/6] tools: Reorganize mkfwumdata tool into fwumdata_src directory 2026-02-16 13:35 [PATCH v3 0/6] Add support for fwumdata Kory Maincent 2026-02-16 13:35 ` [PATCH v3 1/6] tools: gitignore: Add mkfwumdata to the git ignore file Kory Maincent @ 2026-02-16 13:35 ` Kory Maincent 2026-02-16 13:35 ` [PATCH v3 3/6] tools: mkfwumdata: Improve error message specificity Kory Maincent ` (3 subsequent siblings) 5 siblings, 0 replies; 18+ messages in thread From: Kory Maincent @ 2026-02-16 13:35 UTC (permalink / raw) To: u-boot Cc: Thomas Petazzoni, Tom Rini, Patrice Chotard, Paul HENRYS, Sughosh Ganu, Greg Malysa, Arturs Artamonovs, Vasileios Bimpikas, Utsav Agarwal, Nathan Barrett-Morrison, Peng Fan, Simon Glass, Duje Mihanović, Stefan Roese, Mattijs Korpershoek, Sumit Garg, Heiko Schocher, Alif Zakuan Yuslaimi, E Shattow, Raymond Mao, Jan Kiszka, Shiji Yang, Daniel Golle, Heinrich Schuchardt, Ilias Apalodimas, Leonard Anderweit, Kory Maincent, Yao Zi Update FWU metadata-related tools by moving mkfwumdata.c into a new tools/fwumdata_src/ directory structure. This refactoring prepares for the addition of the fwumdata runtime tool, which will allow editing FWU metadata directly from the target. The Kconfig and Makefile entries are also moved into separate files within the new directory (Kconfig and fwumdata.mk respectively) to keep all FWU metadata tool configurations together and improve maintainability. Signed-off-by: Kory Maincent <kory.maincent@bootlin.com> --- MAINTAINERS | 3 ++- tools/Kconfig | 9 +-------- tools/Makefile | 4 +--- tools/fwumdata_src/Kconfig | 8 ++++++++ tools/fwumdata_src/fwumdata.mk | 7 +++++++ tools/{ => fwumdata_src}/mkfwumdata.c | 0 6 files changed, 19 insertions(+), 12 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 288b892f19b..9d954be4a9d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1244,9 +1244,10 @@ FWU Multi Bank Update M: Sughosh Ganu <sughosh.ganu@arm.com> S: Maintained T: git https://source.denx.de/u-boot/custodians/u-boot-efi.git +F: doc/mkfwumdata.1 F: lib/fwu_updates/* F: drivers/fwu-mdata/* -F: tools/mkfwumdata.c +F: tools/fwumdata_src/mkfwumdata.c GATEWORKS_SC M: Tim Harvey <tharvey@gateworks.com> diff --git a/tools/Kconfig b/tools/Kconfig index a1b4d701ac7..ef33295b8ec 100644 --- a/tools/Kconfig +++ b/tools/Kconfig @@ -194,13 +194,6 @@ config LUT_SEQUENCE help Look Up Table Sequence -config TOOLS_MKFWUMDATA - bool "Build mkfwumdata command" - default y if FWU_MULTI_BANK_UPDATE - help - This command allows users to create a raw image of the FWU - metadata for initial installation of the FWU multi bank - update on the board. The installation method depends on - the platform. +source tools/fwumdata_src/Kconfig endmenu diff --git a/tools/Makefile b/tools/Makefile index 0ac683ac3ec..1908a63b42c 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -272,9 +272,7 @@ mkeficapsule-objs := generated/lib/uuid.o \ mkeficapsule.o hostprogs-always-$(CONFIG_TOOLS_MKEFICAPSULE) += mkeficapsule -mkfwumdata-objs := mkfwumdata.o generated/lib/crc32.o -HOSTLDLIBS_mkfwumdata += -luuid -hostprogs-always-$(CONFIG_TOOLS_MKFWUMDATA) += mkfwumdata +include tools/fwumdata_src/fwumdata.mk # We build some files with extra pedantic flags to try to minimize things # that won't build on some weird host compiler -- though there are lots of diff --git a/tools/fwumdata_src/Kconfig b/tools/fwumdata_src/Kconfig new file mode 100644 index 00000000000..c033c560e8d --- /dev/null +++ b/tools/fwumdata_src/Kconfig @@ -0,0 +1,8 @@ +config TOOLS_MKFWUMDATA + bool "Build mkfwumdata command" + default y if FWU_MULTI_BANK_UPDATE + help + This command allows users to create a raw image of the FWU + metadata for initial installation of the FWU multi bank + update on the board. The installation method depends on + the platform. diff --git a/tools/fwumdata_src/fwumdata.mk b/tools/fwumdata_src/fwumdata.mk new file mode 100644 index 00000000000..00f4ae50dbb --- /dev/null +++ b/tools/fwumdata_src/fwumdata.mk @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# (C) Copyright 2025, Kory Maincent <kory.maincent@bootlin.com> + +mkfwumdata-objs := fwumdata_src/mkfwumdata.o generated/lib/crc32.o +HOSTLDLIBS_mkfwumdata += -luuid +hostprogs-always-$(CONFIG_TOOLS_MKFWUMDATA) += mkfwumdata diff --git a/tools/mkfwumdata.c b/tools/fwumdata_src/mkfwumdata.c similarity index 100% rename from tools/mkfwumdata.c rename to tools/fwumdata_src/mkfwumdata.c -- 2.43.0 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v3 3/6] tools: mkfwumdata: Improve error message specificity 2026-02-16 13:35 [PATCH v3 0/6] Add support for fwumdata Kory Maincent 2026-02-16 13:35 ` [PATCH v3 1/6] tools: gitignore: Add mkfwumdata to the git ignore file Kory Maincent 2026-02-16 13:35 ` [PATCH v3 2/6] tools: Reorganize mkfwumdata tool into fwumdata_src directory Kory Maincent @ 2026-02-16 13:35 ` Kory Maincent 2026-02-16 13:35 ` [PATCH v3 4/6] tools: mkfwumdata: Add bank count validation for FWU metadata v2 Kory Maincent ` (2 subsequent siblings) 5 siblings, 0 replies; 18+ messages in thread From: Kory Maincent @ 2026-02-16 13:35 UTC (permalink / raw) To: u-boot Cc: Thomas Petazzoni, Tom Rini, Patrice Chotard, Paul HENRYS, Sughosh Ganu, Greg Malysa, Arturs Artamonovs, Vasileios Bimpikas, Utsav Agarwal, Nathan Barrett-Morrison, Peng Fan, Simon Glass, Duje Mihanović, Stefan Roese, Mattijs Korpershoek, Sumit Garg, Heiko Schocher, Alif Zakuan Yuslaimi, E Shattow, Raymond Mao, Jan Kiszka, Shiji Yang, Daniel Golle, Heinrich Schuchardt, Ilias Apalodimas, Leonard Anderweit, Kory Maincent, Yao Zi Replace the generic error message with a more informative one. This helps users quickly understand the correct command-line argument format when the tool reports an error. Signed-off-by: Kory Maincent <kory.maincent@bootlin.com> --- tools/fwumdata_src/mkfwumdata.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/fwumdata_src/mkfwumdata.c b/tools/fwumdata_src/mkfwumdata.c index fbc2067bc12..5ceec7a2980 100644 --- a/tools/fwumdata_src/mkfwumdata.c +++ b/tools/fwumdata_src/mkfwumdata.c @@ -473,7 +473,9 @@ int main(int argc, char *argv[]) /* This command takes UUIDs * images and output file. */ if (optind + images + 1 != argc) { - fprintf(stderr, "Error: UUID list or output file is not specified or too much.\n"); + fprintf(stderr, + "Error: Expected %ld UUID string(s) and 1 output file, got %d argument(s).\n", + images, argc - optind); print_usage(); return -ERANGE; } -- 2.43.0 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v3 4/6] tools: mkfwumdata: Add bank count validation for FWU metadata v2 2026-02-16 13:35 [PATCH v3 0/6] Add support for fwumdata Kory Maincent ` (2 preceding siblings ...) 2026-02-16 13:35 ` [PATCH v3 3/6] tools: mkfwumdata: Improve error message specificity Kory Maincent @ 2026-02-16 13:35 ` Kory Maincent 2026-02-16 13:35 ` [PATCH v3 5/6] tools: Add support for fwumdata tool Kory Maincent 2026-02-16 13:35 ` [PATCH v3 6/6] tools: mkfwumdata: Remove dependency on fwu_mdata.h header Kory Maincent 5 siblings, 0 replies; 18+ messages in thread From: Kory Maincent @ 2026-02-16 13:35 UTC (permalink / raw) To: u-boot Cc: Thomas Petazzoni, Tom Rini, Patrice Chotard, Paul HENRYS, Sughosh Ganu, Greg Malysa, Arturs Artamonovs, Vasileios Bimpikas, Utsav Agarwal, Nathan Barrett-Morrison, Peng Fan, Simon Glass, Duje Mihanović, Stefan Roese, Mattijs Korpershoek, Sumit Garg, Heiko Schocher, Alif Zakuan Yuslaimi, E Shattow, Raymond Mao, Jan Kiszka, Shiji Yang, Daniel Golle, Heinrich Schuchardt, Ilias Apalodimas, Leonard Anderweit, Kory Maincent, Yao Zi The FWU metadata specification version 2 supports a maximum of 4 banks. Add validation to enforce this limit and prevent creation of non-compliant metadata structures when using version 2. Without this check, users could inadvertently create invalid metadata by specifying more than 4 banks, leading to potential compatibility issues with FWU-compliant firmware update implementations. Signed-off-by: Kory Maincent <kory.maincent@bootlin.com> --- tools/fwumdata_src/mkfwumdata.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/fwumdata_src/mkfwumdata.c b/tools/fwumdata_src/mkfwumdata.c index 5ceec7a2980..8b25539fd57 100644 --- a/tools/fwumdata_src/mkfwumdata.c +++ b/tools/fwumdata_src/mkfwumdata.c @@ -471,6 +471,12 @@ int main(int argc, char *argv[]) return -EINVAL; } + if (version == 2 && banks > MAX_BANKS_V2) { + fprintf(stderr, "Error: Version 2 supports maximum %d banks, %ld requested.\n", + MAX_BANKS_V2, banks); + return -EINVAL; + } + /* This command takes UUIDs * images and output file. */ if (optind + images + 1 != argc) { fprintf(stderr, -- 2.43.0 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v3 5/6] tools: Add support for fwumdata tool 2026-02-16 13:35 [PATCH v3 0/6] Add support for fwumdata Kory Maincent ` (3 preceding siblings ...) 2026-02-16 13:35 ` [PATCH v3 4/6] tools: mkfwumdata: Add bank count validation for FWU metadata v2 Kory Maincent @ 2026-02-16 13:35 ` Kory Maincent 2026-02-18 9:47 ` Sughosh Ganu 2026-02-18 9:53 ` Sughosh Ganu 2026-02-16 13:35 ` [PATCH v3 6/6] tools: mkfwumdata: Remove dependency on fwu_mdata.h header Kory Maincent 5 siblings, 2 replies; 18+ messages in thread From: Kory Maincent @ 2026-02-16 13:35 UTC (permalink / raw) To: u-boot Cc: Thomas Petazzoni, Tom Rini, Patrice Chotard, Paul HENRYS, Sughosh Ganu, Greg Malysa, Arturs Artamonovs, Vasileios Bimpikas, Utsav Agarwal, Nathan Barrett-Morrison, Peng Fan, Simon Glass, Duje Mihanović, Stefan Roese, Mattijs Korpershoek, Sumit Garg, Heiko Schocher, Alif Zakuan Yuslaimi, E Shattow, Raymond Mao, Jan Kiszka, Shiji Yang, Daniel Golle, Heinrich Schuchardt, Ilias Apalodimas, Leonard Anderweit, Kory Maincent, Yao Zi 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 <kory.maincent@bootlin.com> --- 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 <sughosh.ganu@arm.com> +M: Kory Maincent <kory.maincent@bootlin.com> 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 <kory.maincent@bootlin.com> +.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 <kory.maincent@bootlin.com> + * + * 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 <kory.maincent@bootlin.com> + */ + +#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 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH v3 5/6] tools: Add support for fwumdata tool 2026-02-16 13:35 ` [PATCH v3 5/6] tools: Add support for fwumdata tool Kory Maincent @ 2026-02-18 9:47 ` Sughosh Ganu 2026-02-18 9:56 ` Sughosh Ganu 2026-02-18 9:53 ` Sughosh Ganu 1 sibling, 1 reply; 18+ messages in thread From: Sughosh Ganu @ 2026-02-18 9:47 UTC (permalink / raw) To: Kory Maincent Cc: u-boot, Thomas Petazzoni, Tom Rini, Patrice Chotard, Paul HENRYS, Greg Malysa, Arturs Artamonovs, Vasileios Bimpikas, Utsav Agarwal, Nathan Barrett-Morrison, Peng Fan, Simon Glass, Duje Mihanović, Stefan Roese, Mattijs Korpershoek, Sumit Garg, Heiko Schocher, Alif Zakuan Yuslaimi, E Shattow, Raymond Mao, Jan Kiszka, Shiji Yang, Daniel Golle, Heinrich Schuchardt, Ilias Apalodimas, Leonard Anderweit, Yao Zi 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 <kory.maincent@bootlin.com> > --- 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. -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 <sughosh.ganu@arm.com> > +M: Kory Maincent <kory.maincent@bootlin.com> > 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 <kory.maincent@bootlin.com> > +.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 <kory.maincent@bootlin.com> > + * > + * 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 <kory.maincent@bootlin.com> > + */ > + > +#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 ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v3 5/6] tools: Add support for fwumdata tool 2026-02-18 9:47 ` Sughosh Ganu @ 2026-02-18 9:56 ` Sughosh Ganu 2026-02-18 10:31 ` Kory Maincent 0 siblings, 1 reply; 18+ messages in thread From: Sughosh Ganu @ 2026-02-18 9:56 UTC (permalink / raw) To: Kory Maincent; +Cc: u-boot, jose.marinho 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 <kory.maincent@bootlin.com> > > --- > > 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 <sughosh.ganu@arm.com> > > +M: Kory Maincent <kory.maincent@bootlin.com> > > 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 <kory.maincent@bootlin.com> > > +.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 <kory.maincent@bootlin.com> > > + * > > + * 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 <kory.maincent@bootlin.com> > > + */ > > + > > +#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 ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v3 5/6] tools: Add support for fwumdata tool 2026-02-18 9:56 ` Sughosh Ganu @ 2026-02-18 10:31 ` Kory Maincent 2026-02-18 10:45 ` Sughosh Ganu 2026-02-18 13:55 ` Ilias Apalodimas 0 siblings, 2 replies; 18+ messages in thread From: Kory Maincent @ 2026-02-18 10:31 UTC (permalink / raw) To: Sughosh Ganu Cc: u-boot, jose.marinho, Thomas Petazzoni, Tom Rini, Patrice Chotard, Paul HENRYS, Greg Malysa, Arturs Artamonovs, Vasileios Bimpikas, Utsav Agarwal, Nathan Barrett-Morrison, Peng Fan, Simon Glass, Duje Mihanović, Stefan Roese, Mattijs Korpershoek, Sumit Garg, Heiko Schocher, Alif Zakuan Yuslaimi, E Shattow, Raymond Mao, Jan Kiszka, Shiji Yang, Daniel Golle, Heinrich Schuchardt, Ilias Apalodimas, Leonard Anderweit, Yao Zi Hello Sughosh, On Wed, 18 Feb 2026 15:26:35 +0530 Sughosh Ganu <sughosh.ganu@arm.com> wrote: > 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 <kory.maincent@bootlin.com> > > > --- > > > > 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. We indeed already had some discussion about it with Ilias. https://lists.denx.de/pipermail/u-boot/2025-December/605924.html It seems ST deviate from the original idea behind the standard. It does not use EFI neither update capsule. TF-A is managing the selection of the boot partition (FIP image: OPTEE + bootloader) according to the FWU metadata content and is dealingwith the rollback mechanism. Linux through this tools is the update agent to select the boot image. The final goal is to have RAUC updating the boot A/B partition and switching to it calling this new tool. Regards, -- Köry Maincent, Bootlin Embedded Linux and kernel engineering https://bootlin.com ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v3 5/6] tools: Add support for fwumdata tool 2026-02-18 10:31 ` Kory Maincent @ 2026-02-18 10:45 ` Sughosh Ganu 2026-02-18 11:08 ` Kory Maincent 2026-02-18 13:55 ` Ilias Apalodimas 1 sibling, 1 reply; 18+ messages in thread From: Sughosh Ganu @ 2026-02-18 10:45 UTC (permalink / raw) To: Kory Maincent Cc: u-boot, jose.marinho, Thomas Petazzoni, Tom Rini, Patrice Chotard, Paul HENRYS, Greg Malysa, Arturs Artamonovs, Vasileios Bimpikas, Utsav Agarwal, Nathan Barrett-Morrison, Peng Fan, Simon Glass, Duje Mihanović, Stefan Roese, Mattijs Korpershoek, Sumit Garg, Heiko Schocher, Alif Zakuan Yuslaimi, E Shattow, Raymond Mao, Jan Kiszka, Shiji Yang, Daniel Golle, Heinrich Schuchardt, Ilias Apalodimas, Leonard Anderweit, Yao Zi On Wed, Feb 18, 2026 at 11:31:16AM +0100, Kory Maincent wrote: > Hello Sughosh, > > On Wed, 18 Feb 2026 15:26:35 +0530 > Sughosh Ganu <sughosh.ganu@arm.com> wrote: > > > 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 <kory.maincent@bootlin.com> > > > > --- > > > > > > 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. > > We indeed already had some discussion about it with Ilias. > https://lists.denx.de/pipermail/u-boot/2025-December/605924.html > > It seems ST deviate from the original idea behind the standard. It does not use > EFI neither update capsule. > TF-A is managing the selection of the boot partition (FIP image: OPTEE + > bootloader) according to the FWU metadata content and is dealingwith the > rollback mechanism. Linux through this tools is the update agent to select the > boot image. Okay. I guess that is fine then -- with the Update Agent residing in Linux, this is not an issue. My next question then would be, why are you adding this to U-Boot then :). Can this not be bundled with a related package of RAUC maybe(if one such exists)? -sughosh > The final goal is to have RAUC updating the boot A/B partition and switching to > it calling this new tool. > > Regards, > -- > Köry Maincent, Bootlin > Embedded Linux and kernel engineering > https://bootlin.com -sughosh ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v3 5/6] tools: Add support for fwumdata tool 2026-02-18 10:45 ` Sughosh Ganu @ 2026-02-18 11:08 ` Kory Maincent 2026-02-18 11:23 ` Sughosh Ganu 0 siblings, 1 reply; 18+ messages in thread From: Kory Maincent @ 2026-02-18 11:08 UTC (permalink / raw) To: Sughosh Ganu Cc: u-boot, jose.marinho, Thomas Petazzoni, Tom Rini, Patrice Chotard, Paul HENRYS, Greg Malysa, Arturs Artamonovs, Vasileios Bimpikas, Utsav Agarwal, Nathan Barrett-Morrison, Peng Fan, Simon Glass, Duje Mihanović, Stefan Roese, Mattijs Korpershoek, Sumit Garg, Heiko Schocher, Alif Zakuan Yuslaimi, E Shattow, Raymond Mao, Jan Kiszka, Shiji Yang, Daniel Golle, Heinrich Schuchardt, Ilias Apalodimas, Leonard Anderweit, Yao Zi On Wed, 18 Feb 2026 16:15:14 +0530 Sughosh Ganu <sughosh.ganu@arm.com> wrote: > On Wed, Feb 18, 2026 at 11:31:16AM +0100, Kory Maincent wrote: > > Hello Sughosh, > > > > On Wed, 18 Feb 2026 15:26:35 +0530 > > Sughosh Ganu <sughosh.ganu@arm.com> wrote: > > > > > 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 <kory.maincent@bootlin.com> > > > > > --- > > > > > > > > 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. > > > > We indeed already had some discussion about it with Ilias. > > https://lists.denx.de/pipermail/u-boot/2025-December/605924.html > > > > It seems ST deviate from the original idea behind the standard. It does not > > use EFI neither update capsule. > > TF-A is managing the selection of the boot partition (FIP image: OPTEE + > > bootloader) according to the FWU metadata content and is dealingwith the > > rollback mechanism. Linux through this tools is the update agent to select > > the boot image. > > Okay. I guess that is fine then -- with the Update Agent residing in > Linux, this is not an issue. My next question then would be, why are > you adding this to U-Boot then :). Can this not be bundled with a > related package of RAUC maybe(if one such exists)? There was also a discussion about this topic: https://lists.denx.de/pipermail/u-boot/2025-December/604901.html The final conclusion is: - for the short/medium term we add it alongside the mkfwumdata tool. - for the long term it would be nice to extract all generic tools to a different repo than U-boot to make life easier for other projects. Regards, -- Köry Maincent, Bootlin Embedded Linux and kernel engineering https://bootlin.com ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v3 5/6] tools: Add support for fwumdata tool 2026-02-18 11:08 ` Kory Maincent @ 2026-02-18 11:23 ` Sughosh Ganu 0 siblings, 0 replies; 18+ messages in thread From: Sughosh Ganu @ 2026-02-18 11:23 UTC (permalink / raw) To: Kory Maincent Cc: u-boot, jose.marinho, Thomas Petazzoni, Tom Rini, Patrice Chotard, Paul HENRYS, Greg Malysa, Arturs Artamonovs, Vasileios Bimpikas, Utsav Agarwal, Nathan Barrett-Morrison, Peng Fan, Simon Glass, Duje Mihanović, Stefan Roese, Mattijs Korpershoek, Sumit Garg, Heiko Schocher, Alif Zakuan Yuslaimi, E Shattow, Raymond Mao, Jan Kiszka, Shiji Yang, Daniel Golle, Heinrich Schuchardt, Ilias Apalodimas, Leonard Anderweit, Yao Zi On Wed, Feb 18, 2026 at 12:08:16PM +0100, Kory Maincent wrote: > On Wed, 18 Feb 2026 16:15:14 +0530 > Sughosh Ganu <sughosh.ganu@arm.com> wrote: > > > On Wed, Feb 18, 2026 at 11:31:16AM +0100, Kory Maincent wrote: > > > Hello Sughosh, > > > > > > On Wed, 18 Feb 2026 15:26:35 +0530 > > > Sughosh Ganu <sughosh.ganu@arm.com> wrote: > > > > > > > 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 <kory.maincent@bootlin.com> > > > > > > --- > > > > > > > > > > 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. > > > > > > We indeed already had some discussion about it with Ilias. > > > https://lists.denx.de/pipermail/u-boot/2025-December/605924.html > > > > > > It seems ST deviate from the original idea behind the standard. It does not > > > use EFI neither update capsule. > > > TF-A is managing the selection of the boot partition (FIP image: OPTEE + > > > bootloader) according to the FWU metadata content and is dealingwith the > > > rollback mechanism. Linux through this tools is the update agent to select > > > the boot image. > > > > Okay. I guess that is fine then -- with the Update Agent residing in > > Linux, this is not an issue. My next question then would be, why are > > you adding this to U-Boot then :). Can this not be bundled with a > > related package of RAUC maybe(if one such exists)? > > There was also a discussion about this topic: > https://lists.denx.de/pipermail/u-boot/2025-December/604901.html > > The final conclusion is: > - for the short/medium term we add it alongside the mkfwumdata tool. > - for the long term it would be nice to extract all generic tools to a different repo > than U-boot to make life easier for other projects. Okay. In that case, please post a v4 which fixes the building of the tools. Thanks. -sughosh ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v3 5/6] tools: Add support for fwumdata tool 2026-02-18 10:31 ` Kory Maincent 2026-02-18 10:45 ` Sughosh Ganu @ 2026-02-18 13:55 ` Ilias Apalodimas 2026-02-18 15:17 ` Kory Maincent 1 sibling, 1 reply; 18+ messages in thread From: Ilias Apalodimas @ 2026-02-18 13:55 UTC (permalink / raw) To: Kory Maincent, Sughosh Ganu Cc: u-boot, jose.marinho, Thomas Petazzoni, Tom Rini, Patrice Chotard, Paul HENRYS, Greg Malysa, Arturs Artamonovs, Vasileios Bimpikas, Utsav Agarwal, Nathan Barrett-Morrison, Peng Fan, Simon Glass, Duje Mihanović, Stefan Roese, Mattijs Korpershoek, Sumit Garg, Heiko Schocher, Alif Zakuan Yuslaimi, E Shattow, Raymond Mao, Jan Kiszka, Shiji Yang, Daniel Golle, Heinrich Schuchardt, Ilias Apalodimas, Leonard Anderweit, Yao Zi On Wed Feb 18, 2026 at 12:31 PM EET, Kory Maincent wrote: > Hello Sughosh, > > On Wed, 18 Feb 2026 15:26:35 +0530 > Sughosh Ganu <sughosh.ganu@arm.com> wrote: > >> 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 <kory.maincent@bootlin.com> >> > > --- >> > >> > 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. > > We indeed already had some discussion about it with Ilias. > https://lists.denx.de/pipermail/u-boot/2025-December/605924.html > > It seems ST deviate from the original idea behind the standard. It does not use > EFI neither update capsule. > TF-A is managing the selection of the boot partition (FIP image: OPTEE + > bootloader) according to the FWU metadata content and is dealingwith the > rollback mechanism. Linux through this tools is the update agent to select the > boot image. > The final goal is to have RAUC updating the boot A/B partition and switching to > it calling this new tool. The whole point of adding this via EFI, is that we had an existing mechanism for reporting. e.g when an update is in trial state and an acceptance must be explicitly approved by the OS. I assume RAUC etc will implement that ad-hoc? Thanks /Ilias > > Regards, ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v3 5/6] tools: Add support for fwumdata tool 2026-02-18 13:55 ` Ilias Apalodimas @ 2026-02-18 15:17 ` Kory Maincent 0 siblings, 0 replies; 18+ messages in thread From: Kory Maincent @ 2026-02-18 15:17 UTC (permalink / raw) To: Ilias Apalodimas Cc: Sughosh Ganu, u-boot, jose.marinho, Thomas Petazzoni, Tom Rini, Patrice Chotard, Paul HENRYS, Greg Malysa, Arturs Artamonovs, Vasileios Bimpikas, Utsav Agarwal, Nathan Barrett-Morrison, Peng Fan, Simon Glass, Duje Mihanović, Stefan Roese, Mattijs Korpershoek, Sumit Garg, Heiko Schocher, Alif Zakuan Yuslaimi, E Shattow, Raymond Mao, Jan Kiszka, Shiji Yang, Daniel Golle, Heinrich Schuchardt, Leonard Anderweit, Yao Zi On Wed, 18 Feb 2026 15:55:54 +0200 "Ilias Apalodimas" <ilias.apalodimas@linaro.org> wrote: > On Wed Feb 18, 2026 at 12:31 PM EET, Kory Maincent wrote: > > Hello Sughosh, > > > > On Wed, 18 Feb 2026 15:26:35 +0530 > > Sughosh Ganu <sughosh.ganu@arm.com> wrote: > > > >> 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 <kory.maincent@bootlin.com> > >> > > --- > >> > > >> > 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. > > > > We indeed already had some discussion about it with Ilias. > > https://lists.denx.de/pipermail/u-boot/2025-December/605924.html > > > > It seems ST deviate from the original idea behind the standard. It does not > > use EFI neither update capsule. > > TF-A is managing the selection of the boot partition (FIP image: OPTEE + > > bootloader) according to the FWU metadata content and is dealingwith the > > rollback mechanism. Linux through this tools is the update agent to select > > the boot image. > > The final goal is to have RAUC updating the boot A/B partition and > > switching to it calling this new tool. > > The whole point of adding this via EFI, is that we had an existing mechanism > for reporting. e.g when an update is in trial state and an acceptance must be > explicitly approved by the OS. I assume RAUC etc will implement that ad-hoc? Yes it can report the current status of the update process. Regards, -- Köry Maincent, Bootlin Embedded Linux and kernel engineering https://bootlin.com ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v3 5/6] tools: Add support for fwumdata tool 2026-02-16 13:35 ` [PATCH v3 5/6] tools: Add support for fwumdata tool Kory Maincent 2026-02-18 9:47 ` Sughosh Ganu @ 2026-02-18 9:53 ` Sughosh Ganu 2026-02-18 10:36 ` Kory Maincent 1 sibling, 1 reply; 18+ messages in thread From: Sughosh Ganu @ 2026-02-18 9:53 UTC (permalink / raw) To: Kory Maincent Cc: u-boot, Thomas Petazzoni, Tom Rini, Patrice Chotard, Paul HENRYS, Greg Malysa, Arturs Artamonovs, Vasileios Bimpikas, Utsav Agarwal, Nathan Barrett-Morrison, Peng Fan, Simon Glass, Duje Mihanović, Stefan Roese, Mattijs Korpershoek, Sumit Garg, Heiko Schocher, Alif Zakuan Yuslaimi, E Shattow, Raymond Mao, Jan Kiszka, Shiji Yang, Daniel Golle, Heinrich Schuchardt, Ilias Apalodimas, Leonard Anderweit, Yao Zi 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 <kory.maincent@bootlin.com> > --- > 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(-) > <snip> > 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 This is correct the first way around. > + > +fwumdata-objs := fwumdata_src/fwumdata.o generated/lib/crc32.o > +hostprogs-$(CONFIG_TOOLS_FWUMDATA) += fwumdata This needs to be hostprogs-always-$(...) -sughosh ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v3 5/6] tools: Add support for fwumdata tool 2026-02-18 9:53 ` Sughosh Ganu @ 2026-02-18 10:36 ` Kory Maincent 0 siblings, 0 replies; 18+ messages in thread From: Kory Maincent @ 2026-02-18 10:36 UTC (permalink / raw) To: Sughosh Ganu Cc: u-boot, Thomas Petazzoni, Tom Rini, Patrice Chotard, Paul HENRYS, Greg Malysa, Arturs Artamonovs, Vasileios Bimpikas, Utsav Agarwal, Nathan Barrett-Morrison, Peng Fan, Simon Glass, Duje Mihanović, Stefan Roese, Mattijs Korpershoek, Sumit Garg, Heiko Schocher, Alif Zakuan Yuslaimi, E Shattow, Raymond Mao, Jan Kiszka, Shiji Yang, Daniel Golle, Heinrich Schuchardt, Ilias Apalodimas, Leonard Anderweit, Yao Zi On Wed, 18 Feb 2026 15:23:07 +0530 Sughosh Ganu <sughosh.ganu@arm.com> 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 <kory.maincent@bootlin.com> > > --- > > 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(-) > > > > <snip> > > > 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 > > This is correct the first way around. > > > + > > +fwumdata-objs := fwumdata_src/fwumdata.o generated/lib/crc32.o > > +hostprogs-$(CONFIG_TOOLS_FWUMDATA) += fwumdata > > This needs to be hostprogs-always-$(...) Oh thanks spotting this, I don't know how I lost the always suffix. Regards, -- Köry Maincent, Bootlin Embedded Linux and kernel engineering https://bootlin.com ^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v3 6/6] tools: mkfwumdata: Remove dependency on fwu_mdata.h header 2026-02-16 13:35 [PATCH v3 0/6] Add support for fwumdata Kory Maincent ` (4 preceding siblings ...) 2026-02-16 13:35 ` [PATCH v3 5/6] tools: Add support for fwumdata tool Kory Maincent @ 2026-02-16 13:35 ` Kory Maincent 2026-02-18 9:48 ` Sughosh Ganu 5 siblings, 1 reply; 18+ messages in thread From: Kory Maincent @ 2026-02-16 13:35 UTC (permalink / raw) To: u-boot Cc: Thomas Petazzoni, Tom Rini, Patrice Chotard, Paul HENRYS, Sughosh Ganu, Greg Malysa, Arturs Artamonovs, Vasileios Bimpikas, Utsav Agarwal, Nathan Barrett-Morrison, Peng Fan, Simon Glass, Duje Mihanović, Stefan Roese, Mattijs Korpershoek, Sumit Garg, Heiko Schocher, Alif Zakuan Yuslaimi, E Shattow, Raymond Mao, Jan Kiszka, Shiji Yang, Daniel Golle, Heinrich Schuchardt, Ilias Apalodimas, Leonard Anderweit, Kory Maincent, Yao Zi The dependency on fwu_mdata.h creates unnecessary configuration requirements. To generate metadata V1, CONFIG_FWU_MDATA_V1 must be enabled, which in turn requires enabling FWU_MULTI_BANK_UPDATE, EFI_CAPSULE_ON_DISK, PARTITION_TYPE_GUID, and other unrelated configs. This is not suitable for a simple standalone tool. Additionally, even with the "-v 1" option to generate V1 metadata, the tool will still include the firmware store description if CONFIG_FWU_MDATA_V1 is not enabled. This structure should only be present in metadata V2. Replace the fwu_mdata.h dependency with the new fwumdata header to make the tool compatible with both V1 and V2 without requiring any defconfig changes. This also uses the access helper functions from the header to eliminate code duplication. Signed-off-by: Kory Maincent <kory.maincent@bootlin.com> --- Change in v2: - Fix mdata->desc_offset value. --- tools/fwumdata_src/mkfwumdata.c | 96 ++++++++--------------------------------- 1 file changed, 17 insertions(+), 79 deletions(-) diff --git a/tools/fwumdata_src/mkfwumdata.c b/tools/fwumdata_src/mkfwumdata.c index 8b25539fd57..b8b60473b91 100644 --- a/tools/fwumdata_src/mkfwumdata.c +++ b/tools/fwumdata_src/mkfwumdata.c @@ -17,26 +17,7 @@ #include <u-boot/crc.h> #include <uuid/uuid.h> -typedef uint8_t u8; -typedef int16_t s16; -typedef uint16_t u16; -typedef uint32_t u32; -typedef uint64_t u64; - -#undef CONFIG_FWU_NUM_BANKS -#undef CONFIG_FWU_NUM_IMAGES_PER_BANK - -/* This will dynamically allocate the fwu_mdata */ -#define CONFIG_FWU_NUM_BANKS 0 -#define CONFIG_FWU_NUM_IMAGES_PER_BANK 0 - -/* version 2 supports maximum of 4 banks */ -#define MAX_BANKS_V2 4 - -#define BANK_INVALID (u8)0xFF -#define BANK_ACCEPTED (u8)0xFC - -#include <fwu_mdata.h> +#include "fwumdata.h" static const char *opts_short = "b:i:a:p:v:V:gh"; @@ -116,6 +97,7 @@ static struct fwu_mdata_object *fwu_alloc_mdata(size_t images, size_t banks, sizeof(struct fwu_image_bank_info) * banks) * images; } else { mobj->size = 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) * banks) * images; @@ -146,50 +128,6 @@ alloc_err: return NULL; } -static struct fwu_image_entry * -fwu_get_image(struct fwu_mdata_object *mobj, size_t idx) -{ - size_t offset; - - if (mobj->version == 1) { - offset = sizeof(struct fwu_mdata) + - (sizeof(struct fwu_image_entry) + - sizeof(struct fwu_image_bank_info) * mobj->banks) * - idx; - } else { - offset = sizeof(struct fwu_mdata) + - sizeof(struct fwu_fw_store_desc) + - (sizeof(struct fwu_image_entry) + - sizeof(struct fwu_image_bank_info) * mobj->banks) * - idx; - } - - return (struct fwu_image_entry *)((char *)mobj->mdata + offset); -} - -static struct fwu_image_bank_info * -fwu_get_bank(struct fwu_mdata_object *mobj, size_t img_idx, size_t bnk_idx) -{ - size_t offset; - - if (mobj->version == 1) { - offset = sizeof(struct fwu_mdata) + - (sizeof(struct fwu_image_entry) + - sizeof(struct fwu_image_bank_info) * mobj->banks) * - img_idx + sizeof(struct fwu_image_entry) + - sizeof(struct fwu_image_bank_info) * bnk_idx; - } else { - offset = sizeof(struct fwu_mdata) + - sizeof(struct fwu_fw_store_desc) + - (sizeof(struct fwu_image_entry) + - sizeof(struct fwu_image_bank_info) * mobj->banks) * - img_idx + sizeof(struct fwu_image_entry) + - sizeof(struct fwu_image_bank_info) * bnk_idx; - } - - return (struct fwu_image_bank_info *)((char *)mobj->mdata + offset); -} - /** * convert_uuid_to_guid() - convert UUID to GUID * @buf: UUID binary @@ -239,11 +177,13 @@ static int fwu_parse_fill_image_uuid(struct fwu_mdata_object *mobj, size_t idx, char *uuids) { - struct fwu_image_entry *image = fwu_get_image(mobj, idx); struct fwu_image_bank_info *bank; + struct fwu_image_entry *image; char *p = uuids, *uuid; int i; + image = fwu_get_image_entry(mobj->mdata, mobj->version, + mobj->banks, idx); if (!image) return -ENOENT; @@ -266,7 +206,8 @@ fwu_parse_fill_image_uuid(struct fwu_mdata_object *mobj, /* Fill bank image-UUID */ for (i = 0; i < mobj->banks; i++) { - bank = fwu_get_bank(mobj, idx, i); + bank = fwu_get_bank_info(mobj->mdata, mobj->version, + mobj->banks, idx, i); if (!bank) return -ENOENT; bank->accepted = 1; @@ -281,25 +222,22 @@ fwu_parse_fill_image_uuid(struct fwu_mdata_object *mobj, return 0; } -#if defined(CONFIG_FWU_MDATA_V1) -static void fwu_fill_version_specific_mdata(struct fwu_mdata_object *mobj) -{ -} -#else static void fwu_fill_version_specific_mdata(struct fwu_mdata_object *mobj) { int i; struct fwu_fw_store_desc *fw_desc; - struct fwu_mdata *mdata = mobj->mdata; + struct fwu_mdata_ext *mdata_ext; - mdata->metadata_size = mobj->size; - mdata->desc_offset = sizeof(struct fwu_mdata); + mdata_ext = fwu_get_fw_mdata_ext(mobj->mdata); + mdata_ext->metadata_size = mobj->size; + mdata_ext->desc_offset = sizeof(struct fwu_mdata) + + sizeof(struct fwu_mdata_ext); for (i = 0; i < MAX_BANKS_V2; i++) - mdata->bank_state[i] = i < mobj->banks ? - BANK_ACCEPTED : BANK_INVALID; + mdata_ext->bank_state[i] = i < mobj->banks ? + FWU_BANK_ACCEPTED : FWU_BANK_INVALID; - fw_desc = (struct fwu_fw_store_desc *)((u8 *)mdata + sizeof(*mdata)); + fw_desc = fwu_get_fw_desc(mobj->mdata); fw_desc->num_banks = mobj->banks; fw_desc->num_images = mobj->images; fw_desc->img_entry_size = sizeof(struct fwu_image_entry) + @@ -307,7 +245,6 @@ static void fwu_fill_version_specific_mdata(struct fwu_mdata_object *mobj) fw_desc->bank_info_entry_size = sizeof(struct fwu_image_bank_info); } -#endif /* CONFIG_FWU_MDATA_V1 */ /* Caller must ensure that @uuids[] has @mobj->images entries. */ static int fwu_parse_fill_uuids(struct fwu_mdata_object *mobj, char *uuids[]) @@ -320,7 +257,8 @@ static int fwu_parse_fill_uuids(struct fwu_mdata_object *mobj, char *uuids[]) mdata->active_index = active_bank; mdata->previous_active_index = previous_bank; - fwu_fill_version_specific_mdata(mobj); + if (mdata->version == 2) + fwu_fill_version_specific_mdata(mobj); for (i = 0; i < mobj->images; i++) { ret = fwu_parse_fill_image_uuid(mobj, i, uuids[i]); -- 2.43.0 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH v3 6/6] tools: mkfwumdata: Remove dependency on fwu_mdata.h header 2026-02-16 13:35 ` [PATCH v3 6/6] tools: mkfwumdata: Remove dependency on fwu_mdata.h header Kory Maincent @ 2026-02-18 9:48 ` Sughosh Ganu 0 siblings, 0 replies; 18+ messages in thread From: Sughosh Ganu @ 2026-02-18 9:48 UTC (permalink / raw) To: Kory Maincent Cc: u-boot, Thomas Petazzoni, Tom Rini, Patrice Chotard, Paul HENRYS, Greg Malysa, Arturs Artamonovs, Vasileios Bimpikas, Utsav Agarwal, Nathan Barrett-Morrison, Peng Fan, Simon Glass, Duje Mihanović, Stefan Roese, Mattijs Korpershoek, Sumit Garg, Heiko Schocher, Alif Zakuan Yuslaimi, E Shattow, Raymond Mao, Jan Kiszka, Shiji Yang, Daniel Golle, Heinrich Schuchardt, Ilias Apalodimas, Leonard Anderweit, Yao Zi On Mon, Feb 16, 2026 at 02:35:36PM +0100, Kory Maincent wrote: > The dependency on fwu_mdata.h creates unnecessary configuration > requirements. To generate metadata V1, CONFIG_FWU_MDATA_V1 must be > enabled, which in turn requires enabling FWU_MULTI_BANK_UPDATE, > EFI_CAPSULE_ON_DISK, PARTITION_TYPE_GUID, and other unrelated configs. > This is not suitable for a simple standalone tool. > > Additionally, even with the "-v 1" option to generate V1 metadata, the > tool will still include the firmware store description if > CONFIG_FWU_MDATA_V1 is not enabled. This structure should only be > present in metadata V2. > > Replace the fwu_mdata.h dependency with the new fwumdata header to make > the tool compatible with both V1 and V2 without requiring any defconfig > changes. This also uses the access helper functions from the header to > eliminate code duplication. > > Signed-off-by: Kory Maincent <kory.maincent@bootlin.com> > --- Acked-by: Sughosh Ganu <sughosh.ganu@arm.com> Tested-by: Sughosh Ganu <sughosh.ganu@arm.com> -sughosh > > Change in v2: > - Fix mdata->desc_offset value. > --- > tools/fwumdata_src/mkfwumdata.c | 96 ++++++++--------------------------------- > 1 file changed, 17 insertions(+), 79 deletions(-) > > diff --git a/tools/fwumdata_src/mkfwumdata.c b/tools/fwumdata_src/mkfwumdata.c > index 8b25539fd57..b8b60473b91 100644 > --- a/tools/fwumdata_src/mkfwumdata.c > +++ b/tools/fwumdata_src/mkfwumdata.c > @@ -17,26 +17,7 @@ > #include <u-boot/crc.h> > #include <uuid/uuid.h> > > -typedef uint8_t u8; > -typedef int16_t s16; > -typedef uint16_t u16; > -typedef uint32_t u32; > -typedef uint64_t u64; > - > -#undef CONFIG_FWU_NUM_BANKS > -#undef CONFIG_FWU_NUM_IMAGES_PER_BANK > - > -/* This will dynamically allocate the fwu_mdata */ > -#define CONFIG_FWU_NUM_BANKS 0 > -#define CONFIG_FWU_NUM_IMAGES_PER_BANK 0 > - > -/* version 2 supports maximum of 4 banks */ > -#define MAX_BANKS_V2 4 > - > -#define BANK_INVALID (u8)0xFF > -#define BANK_ACCEPTED (u8)0xFC > - > -#include <fwu_mdata.h> > +#include "fwumdata.h" > > static const char *opts_short = "b:i:a:p:v:V:gh"; > > @@ -116,6 +97,7 @@ static struct fwu_mdata_object *fwu_alloc_mdata(size_t images, size_t banks, > sizeof(struct fwu_image_bank_info) * banks) * images; > } else { > mobj->size = 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) * banks) * images; > @@ -146,50 +128,6 @@ alloc_err: > return NULL; > } > > -static struct fwu_image_entry * > -fwu_get_image(struct fwu_mdata_object *mobj, size_t idx) > -{ > - size_t offset; > - > - if (mobj->version == 1) { > - offset = sizeof(struct fwu_mdata) + > - (sizeof(struct fwu_image_entry) + > - sizeof(struct fwu_image_bank_info) * mobj->banks) * > - idx; > - } else { > - offset = sizeof(struct fwu_mdata) + > - sizeof(struct fwu_fw_store_desc) + > - (sizeof(struct fwu_image_entry) + > - sizeof(struct fwu_image_bank_info) * mobj->banks) * > - idx; > - } > - > - return (struct fwu_image_entry *)((char *)mobj->mdata + offset); > -} > - > -static struct fwu_image_bank_info * > -fwu_get_bank(struct fwu_mdata_object *mobj, size_t img_idx, size_t bnk_idx) > -{ > - size_t offset; > - > - if (mobj->version == 1) { > - offset = sizeof(struct fwu_mdata) + > - (sizeof(struct fwu_image_entry) + > - sizeof(struct fwu_image_bank_info) * mobj->banks) * > - img_idx + sizeof(struct fwu_image_entry) + > - sizeof(struct fwu_image_bank_info) * bnk_idx; > - } else { > - offset = sizeof(struct fwu_mdata) + > - sizeof(struct fwu_fw_store_desc) + > - (sizeof(struct fwu_image_entry) + > - sizeof(struct fwu_image_bank_info) * mobj->banks) * > - img_idx + sizeof(struct fwu_image_entry) + > - sizeof(struct fwu_image_bank_info) * bnk_idx; > - } > - > - return (struct fwu_image_bank_info *)((char *)mobj->mdata + offset); > -} > - > /** > * convert_uuid_to_guid() - convert UUID to GUID > * @buf: UUID binary > @@ -239,11 +177,13 @@ static int > fwu_parse_fill_image_uuid(struct fwu_mdata_object *mobj, > size_t idx, char *uuids) > { > - struct fwu_image_entry *image = fwu_get_image(mobj, idx); > struct fwu_image_bank_info *bank; > + struct fwu_image_entry *image; > char *p = uuids, *uuid; > int i; > > + image = fwu_get_image_entry(mobj->mdata, mobj->version, > + mobj->banks, idx); > if (!image) > return -ENOENT; > > @@ -266,7 +206,8 @@ fwu_parse_fill_image_uuid(struct fwu_mdata_object *mobj, > > /* Fill bank image-UUID */ > for (i = 0; i < mobj->banks; i++) { > - bank = fwu_get_bank(mobj, idx, i); > + bank = fwu_get_bank_info(mobj->mdata, mobj->version, > + mobj->banks, idx, i); > if (!bank) > return -ENOENT; > bank->accepted = 1; > @@ -281,25 +222,22 @@ fwu_parse_fill_image_uuid(struct fwu_mdata_object *mobj, > return 0; > } > > -#if defined(CONFIG_FWU_MDATA_V1) > -static void fwu_fill_version_specific_mdata(struct fwu_mdata_object *mobj) > -{ > -} > -#else > static void fwu_fill_version_specific_mdata(struct fwu_mdata_object *mobj) > { > int i; > struct fwu_fw_store_desc *fw_desc; > - struct fwu_mdata *mdata = mobj->mdata; > + struct fwu_mdata_ext *mdata_ext; > > - mdata->metadata_size = mobj->size; > - mdata->desc_offset = sizeof(struct fwu_mdata); > + mdata_ext = fwu_get_fw_mdata_ext(mobj->mdata); > + mdata_ext->metadata_size = mobj->size; > + mdata_ext->desc_offset = sizeof(struct fwu_mdata) + > + sizeof(struct fwu_mdata_ext); > > for (i = 0; i < MAX_BANKS_V2; i++) > - mdata->bank_state[i] = i < mobj->banks ? > - BANK_ACCEPTED : BANK_INVALID; > + mdata_ext->bank_state[i] = i < mobj->banks ? > + FWU_BANK_ACCEPTED : FWU_BANK_INVALID; > > - fw_desc = (struct fwu_fw_store_desc *)((u8 *)mdata + sizeof(*mdata)); > + fw_desc = fwu_get_fw_desc(mobj->mdata); > fw_desc->num_banks = mobj->banks; > fw_desc->num_images = mobj->images; > fw_desc->img_entry_size = sizeof(struct fwu_image_entry) + > @@ -307,7 +245,6 @@ static void fwu_fill_version_specific_mdata(struct fwu_mdata_object *mobj) > fw_desc->bank_info_entry_size = > sizeof(struct fwu_image_bank_info); > } > -#endif /* CONFIG_FWU_MDATA_V1 */ > > /* Caller must ensure that @uuids[] has @mobj->images entries. */ > static int fwu_parse_fill_uuids(struct fwu_mdata_object *mobj, char *uuids[]) > @@ -320,7 +257,8 @@ static int fwu_parse_fill_uuids(struct fwu_mdata_object *mobj, char *uuids[]) > mdata->active_index = active_bank; > mdata->previous_active_index = previous_bank; > > - fwu_fill_version_specific_mdata(mobj); > + if (mdata->version == 2) > + fwu_fill_version_specific_mdata(mobj); > > for (i = 0; i < mobj->images; i++) { > ret = fwu_parse_fill_image_uuid(mobj, i, uuids[i]); > > -- > 2.43.0 > -sughosh ^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2026-02-18 15:17 UTC | newest] Thread overview: 18+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-02-16 13:35 [PATCH v3 0/6] Add support for fwumdata Kory Maincent 2026-02-16 13:35 ` [PATCH v3 1/6] tools: gitignore: Add mkfwumdata to the git ignore file Kory Maincent 2026-02-16 13:35 ` [PATCH v3 2/6] tools: Reorganize mkfwumdata tool into fwumdata_src directory Kory Maincent 2026-02-16 13:35 ` [PATCH v3 3/6] tools: mkfwumdata: Improve error message specificity Kory Maincent 2026-02-16 13:35 ` [PATCH v3 4/6] tools: mkfwumdata: Add bank count validation for FWU metadata v2 Kory Maincent 2026-02-16 13:35 ` [PATCH v3 5/6] tools: Add support for fwumdata tool Kory Maincent 2026-02-18 9:47 ` Sughosh Ganu 2026-02-18 9:56 ` Sughosh Ganu 2026-02-18 10:31 ` Kory Maincent 2026-02-18 10:45 ` Sughosh Ganu 2026-02-18 11:08 ` Kory Maincent 2026-02-18 11:23 ` Sughosh Ganu 2026-02-18 13:55 ` Ilias Apalodimas 2026-02-18 15:17 ` Kory Maincent 2026-02-18 9:53 ` Sughosh Ganu 2026-02-18 10:36 ` Kory Maincent 2026-02-16 13:35 ` [PATCH v3 6/6] tools: mkfwumdata: Remove dependency on fwu_mdata.h header Kory Maincent 2026-02-18 9:48 ` Sughosh Ganu
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox