Kory Maincent 02673659e8 tools: Add support for fwumdata tool
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>
Tested-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
Signed-off-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
2026-03-26 08:20:00 +02:00

139 lines
3.3 KiB
C

/* 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_ */