summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS8
-rw-r--r--cmd/fwu_mdata.c39
-rw-r--r--configs/corstone1000_defconfig1
-rw-r--r--configs/synquacer_developerbox_defconfig2
-rw-r--r--doc/board/socionext/developerbox.rst7
-rw-r--r--doc/develop/uefi/fwu_updates.rst20
-rw-r--r--doc/mkfwumdata.116
-rw-r--r--drivers/fwu-mdata/fwu-mdata-uclass.c10
-rw-r--r--drivers/fwu-mdata/gpt_blk.c23
-rw-r--r--drivers/fwu-mdata/raw_mtd.c78
-rw-r--r--include/fwu.h147
-rw-r--r--include/fwu_mdata.h71
-rw-r--r--lib/efi_loader/efi_capsule.c14
-rw-r--r--lib/fwu_updates/Kconfig14
-rw-r--r--lib/fwu_updates/Makefile2
-rw-r--r--lib/fwu_updates/fwu.c204
-rw-r--r--lib/fwu_updates/fwu_mtd.c34
-rw-r--r--lib/fwu_updates/fwu_v1.c167
-rw-r--r--lib/fwu_updates/fwu_v2.c260
-rw-r--r--test/dm/fwu_mdata.c16
-rw-r--r--tools/mkfwumdata.c235
21 files changed, 1152 insertions, 216 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 8e7a8ddaddf..6c861b529df 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1168,6 +1168,14 @@ T: git https://source.denx.de/u-boot/custodians/u-boot-fsl-qoriq.git
F: drivers/watchdog/sp805_wdt.c
F: drivers/watchdog/sbsa_gwdt.c
+FWU Multi Bank Update
+M: Sughosh Ganu <sughosh.ganu@linaro.org>
+S: Maintained
+T: git https://source.denx.de/u-boot/custodians/u-boot-efi.git
+F: lib/fwu_updates/*
+F: drivers/fwu-mdata/*
+F: tools/mkfwumdata.c
+
GATEWORKS_SC
M: Tim Harvey <tharvey@gateworks.com>
S: Maintained
diff --git a/cmd/fwu_mdata.c b/cmd/fwu_mdata.c
index 5ecda455df6..3c8be576ac7 100644
--- a/cmd/fwu_mdata.c
+++ b/cmd/fwu_mdata.c
@@ -13,27 +13,33 @@
#include <linux/types.h>
-static void print_mdata(struct fwu_mdata *mdata)
+static void print_mdata(struct fwu_data *data)
{
int i, j;
struct fwu_image_entry *img_entry;
struct fwu_image_bank_info *img_info;
printf("\tFWU Metadata\n");
- printf("crc32: %#x\n", mdata->crc32);
- printf("version: %#x\n", mdata->version);
- printf("active_index: %#x\n", mdata->active_index);
- printf("previous_active_index: %#x\n", mdata->previous_active_index);
+ printf("crc32: %#x\n", data->crc32);
+ printf("version: %#x\n", data->version);
+ printf("active_index: %#x\n", data->active_index);
+ printf("previous_active_index: %#x\n", data->previous_active_index);
+
+ if (data->version == 2) {
+ for (i = 0; i < 4; i++)
+ printf("bank_state[%d]: %#x\n",
+ i, data->bank_state[i]);
+ }
printf("\tImage Info\n");
for (i = 0; i < CONFIG_FWU_NUM_IMAGES_PER_BANK; i++) {
- img_entry = &mdata->img_entry[i];
+ img_entry = &data->fwu_images[i];
printf("\nImage Type Guid: %pUL\n",
- &img_entry->image_type_uuid);
- printf("Location Guid: %pUL\n", &img_entry->location_uuid);
+ &img_entry->image_type_guid);
+ printf("Location Guid: %pUL\n", &img_entry->location_guid);
for (j = 0; j < CONFIG_FWU_NUM_BANKS; j++) {
img_info = &img_entry->img_bank_info[j];
- printf("Image Guid: %pUL\n", &img_info->image_uuid);
+ printf("Image Guid: %pUL\n", &img_info->image_guid);
printf("Image Acceptance: %s\n",
img_info->accepted == 0x1 ? "yes" : "no");
}
@@ -43,20 +49,11 @@ static void print_mdata(struct fwu_mdata *mdata)
int do_fwu_mdata_read(struct cmd_tbl *cmdtp, int flag,
int argc, char * const argv[])
{
- int ret = CMD_RET_SUCCESS, res;
- struct fwu_mdata mdata;
-
- res = fwu_get_mdata(&mdata);
- if (res < 0) {
- log_err("Unable to get valid FWU metadata\n");
- ret = CMD_RET_FAILURE;
- goto out;
- }
+ struct fwu_data *data = fwu_get_data();
- print_mdata(&mdata);
+ print_mdata(data);
-out:
- return ret;
+ return CMD_RET_SUCCESS;
}
U_BOOT_CMD(
diff --git a/configs/corstone1000_defconfig b/configs/corstone1000_defconfig
index 8b2f77f6485..ab4e0fefc90 100644
--- a/configs/corstone1000_defconfig
+++ b/configs/corstone1000_defconfig
@@ -68,3 +68,4 @@ CONFIG_FFA_SHARED_MM_BUF_ADDR=0x02000000
CONFIG_EFI_CAPSULE_ON_DISK=y
CONFIG_EFI_IGNORE_OSINDICATIONS=y
CONFIG_FWU_MULTI_BANK_UPDATE=y
+CONFIG_FWU_MDATA_V1=y
diff --git a/configs/synquacer_developerbox_defconfig b/configs/synquacer_developerbox_defconfig
index 2a0407de407..7e1aeac217c 100644
--- a/configs/synquacer_developerbox_defconfig
+++ b/configs/synquacer_developerbox_defconfig
@@ -11,7 +11,6 @@ CONFIG_DM_GPIO=y
CONFIG_DEFAULT_DEVICE_TREE="synquacer-sc2a11-developerbox"
CONFIG_SYS_LOAD_ADDR=0x80000000
CONFIG_TARGET_DEVELOPERBOX=y
-CONFIG_FWU_NUM_IMAGES_PER_BANK=1
CONFIG_AHCI=y
CONFIG_FIT=y
CONFIG_SYS_BOOTM_LEN=0x800000
@@ -97,3 +96,4 @@ CONFIG_EFI_CAPSULE_ON_DISK=y
CONFIG_EFI_IGNORE_OSINDICATIONS=y
CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y
CONFIG_FWU_MULTI_BANK_UPDATE=y
+CONFIG_FWU_MDATA_V2=y
diff --git a/doc/board/socionext/developerbox.rst b/doc/board/socionext/developerbox.rst
index 46712c379b6..863761c6e27 100644
--- a/doc/board/socionext/developerbox.rst
+++ b/doc/board/socionext/developerbox.rst
@@ -116,6 +116,7 @@ configs/synquacer_developerbox_defconfig enables default FWU configuration ::
CONFIG_FWU_NUM_BANKS=2
CONFIG_FWU_NUM_IMAGES_PER_BANK=1
CONFIG_CMD_FWU_METADATA=y
+ CONFIG_FWU_MDATA_V2=y
And build it::
@@ -129,7 +130,9 @@ And build it::
By default, the CONFIG_FWU_NUM_BANKS and CONFIG_FWU_NUM_IMAGES_PER_BANKS are
set to 2 and 1 respectively. This uses FIP (Firmware Image Package) type image
which contains TF-A, U-Boot and OP-TEE (the OP-TEE is optional).
-You can use fiptool to compose the FIP image from those firmware images.
+You can use fiptool to compose the FIP image from those firmware
+images. There are two versions of the FWU metadata, of which the
+platform enables version 2 by default.
Rebuild SCP firmware
--------------------
@@ -194,7 +197,7 @@ following UUIDs.
These UUIDs are used for making a FWU metadata image.
-u-boot$ ./tools/mkfwumdata -i 1 -b 2 \
+u-boot$ ./tools/mkfwumdata -v 2 -i 1 -b 2 \
17e86d77-41f9-4fd7-87ec-a55df9842de5,10c36d7d-ca52-b843-b7b9-f9d6c501d108,5a66a702-99fd-4fef-a392-c26e261a2828,a8f868a1-6e5c-4757-878d-ce63375ef2c0 \
../devbox-fwu-mdata.img
diff --git a/doc/develop/uefi/fwu_updates.rst b/doc/develop/uefi/fwu_updates.rst
index e4709d82b41..51e8a28efe1 100644
--- a/doc/develop/uefi/fwu_updates.rst
+++ b/doc/develop/uefi/fwu_updates.rst
@@ -46,6 +46,8 @@ The feature can be enabled by specifying the following configs::
CONFIG_FWU_NUM_BANKS=<val>
CONFIG_FWU_NUM_IMAGES_PER_BANK=<val>
+ CONFIG_FWU_MDATA_V1=y or CONFIG_FWU_MDATA_V2=y
+
in the .config file
By enabling the CONFIG_CMD_FWU_METADATA config option, the
@@ -58,6 +60,14 @@ enable the FWU Multi Bank Update functionality. Please refer to the
section :ref:`uefi_capsule_update_ref` for more details on generation
of the UEFI capsule.
+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.
+
Setting up the device for GPT partitioned storage
-------------------------------------------------
@@ -94,12 +104,12 @@ of. Each GPT partition entry in the GPT header has two GUIDs::
* UniquePartitionGUID
The PartitionTypeGUID value should correspond to the
-``image_type_uuid`` field of the FWU metadata. This field is used to
+``image_type_guid`` field of the FWU metadata. This field is used to
identify a given type of updatable firmware image, e.g. U-Boot,
OP-TEE, FIP etc. This GUID should also be used for specifying the
`--guid` parameter when generating the capsule.
-The UniquePartitionGUID value should correspond to the ``image_uuid``
+The UniquePartitionGUID value should correspond to the ``image_guid``
field in the FWU metadata. This GUID is used to identify images of a
given image type in different banks.
@@ -108,8 +118,8 @@ metadata partitions. This would be the PartitionTypeGUID for the
metadata partitions. Similarly, the UEFI specification defines the ESP
GUID to be be used.
-When generating the metadata, the ``image_type_uuid`` and the
-``image_uuid`` values should match the *PartitionTypeGUID* and the
+When generating the metadata, the ``image_type_guid`` and the
+``image_guid`` values should match the *PartitionTypeGUID* and the
*UniquePartitionGUID* values respectively.
Performing the Update
@@ -181,5 +191,5 @@ empty capsule would be::
Links
-----
-* [1] https://developer.arm.com/documentation/den0118/a/ - FWU Specification
+* [1] https://developer.arm.com/documentation/den0118/ - FWU Specification
* [2] https://git.codelinaro.org/linaro/dependable-boot/mbfw/uploads/6f7ddfe3be24e18d4319e108a758d02e/mbfw.pdf - Dependable Boot Specification
diff --git a/doc/mkfwumdata.1 b/doc/mkfwumdata.1
index 7dd718b26e2..2ed0fb100b8 100644
--- a/doc/mkfwumdata.1
+++ b/doc/mkfwumdata.1
@@ -6,9 +6,11 @@ mkfwumdata \- create FWU metadata image
.
.SH SYNOPSIS
.SY mkfwumdata
+.OP \-v version
.OP \-a activeidx
.OP \-p previousidx
.OP \-g
+.OP \-V vendor-file
.BI \-i\~ imagecount
.BI \-b\~ bankcount
.I UUIDs
@@ -28,6 +30,12 @@ creates metadata info to be used with FWU.
Print usage information and exit.
.
.TP
+.B \-v
+Set
+.IR version
+as the metadata version to generate. Valid values 1 or 2.
+.
+.TP
.B \-a
Set
.IR activeidx
@@ -50,6 +58,12 @@ Convert the
as GUIDs before use.
.
.TP
+.B \-V
+Pass
+.IR vendor-file
+for appending vendor data to the metadata. Supported only with version 2.
+.
+.TP
.B \-i
Specify there are
.IR imagecount
@@ -81,7 +95,7 @@ Create a metadata image with 2 banks and 1 image/bank, BankAct=0, BankPrev=1:
.EX
.in +4
$ \c
-.B mkfwumdata \-a 0 \-p 1 \-b 2 \-i 1 \\\\\&
+.B mkfwumdata \-v 2 \-a 0 \-p 1 \-b 2 \-i 1 \\\\\&
.in +6
.B 17e86d77-41f9-4fd7-87ec-a55df9842de5,\\\\\&
.B 10c36d7d-ca52-b843-b7b9-f9d6c501d108,\\\\\&
diff --git a/drivers/fwu-mdata/fwu-mdata-uclass.c b/drivers/fwu-mdata/fwu-mdata-uclass.c
index bab7a7e80d1..92abb94dcc9 100644
--- a/drivers/fwu-mdata/fwu-mdata-uclass.c
+++ b/drivers/fwu-mdata/fwu-mdata-uclass.c
@@ -19,7 +19,8 @@
*
* Return: 0 if OK, -ve on error
*/
-int fwu_read_mdata(struct udevice *dev, struct fwu_mdata *mdata, bool primary)
+int fwu_read_mdata(struct udevice *dev, struct fwu_mdata *mdata, bool primary,
+ uint32_t size)
{
const struct fwu_mdata_ops *ops = device_get_ops(dev);
@@ -28,7 +29,7 @@ int fwu_read_mdata(struct udevice *dev, struct fwu_mdata *mdata, bool primary)
return -ENOSYS;
}
- return ops->read_mdata(dev, mdata, primary);
+ return ops->read_mdata(dev, mdata, primary, size);
}
/**
@@ -36,7 +37,8 @@ int fwu_read_mdata(struct udevice *dev, struct fwu_mdata *mdata, bool primary)
*
* Return: 0 if OK, -ve on error
*/
-int fwu_write_mdata(struct udevice *dev, struct fwu_mdata *mdata, bool primary)
+int fwu_write_mdata(struct udevice *dev, struct fwu_mdata *mdata, bool primary,
+ uint32_t size)
{
const struct fwu_mdata_ops *ops = device_get_ops(dev);
@@ -45,7 +47,7 @@ int fwu_write_mdata(struct udevice *dev, struct fwu_mdata *mdata, bool primary)
return -ENOSYS;
}
- return ops->write_mdata(dev, mdata, primary);
+ return ops->write_mdata(dev, mdata, primary, size);
}
UCLASS_DRIVER(fwu_mdata) = {
diff --git a/drivers/fwu-mdata/gpt_blk.c b/drivers/fwu-mdata/gpt_blk.c
index c7284916c4e..97eac3611f7 100644
--- a/drivers/fwu-mdata/gpt_blk.c
+++ b/drivers/fwu-mdata/gpt_blk.c
@@ -81,15 +81,14 @@ static int gpt_get_mdata_disk_part(struct blk_desc *desc,
return -ENOENT;
}
-static int gpt_read_write_mdata(struct blk_desc *desc,
- struct fwu_mdata *mdata,
- u8 access, u32 part_num)
+static int gpt_read_write_mdata(struct blk_desc *desc, struct fwu_mdata *mdata,
+ u8 access, u32 part_num, u32 size)
{
int ret;
u32 len, blk_start, blkcnt;
struct disk_partition info;
- ALLOC_CACHE_ALIGN_BUFFER_PAD(struct fwu_mdata, mdata_aligned, 1,
+ ALLOC_CACHE_ALIGN_BUFFER_PAD(u8, mdata_aligned, size,
desc->blksz);
if (!mdata)
@@ -101,7 +100,7 @@ static int gpt_read_write_mdata(struct blk_desc *desc,
return -ENOENT;
}
- len = sizeof(*mdata);
+ len = size;
blkcnt = BLOCK_CNT(len, desc);
if (blkcnt > info.size) {
log_debug("Block count exceeds FWU metadata partition size\n");
@@ -114,7 +113,7 @@ static int gpt_read_write_mdata(struct blk_desc *desc,
log_debug("Error reading FWU metadata from the device\n");
return -EIO;
}
- memcpy(mdata, mdata_aligned, sizeof(struct fwu_mdata));
+ memcpy(mdata, mdata_aligned, size);
} else {
if (blk_dwrite(desc, blk_start, blkcnt, mdata) != blkcnt) {
log_debug("Error writing FWU metadata to the device\n");
@@ -164,7 +163,7 @@ static int fwu_mdata_gpt_blk_probe(struct udevice *dev)
}
static int fwu_gpt_read_mdata(struct udevice *dev, struct fwu_mdata *mdata,
- bool primary)
+ bool primary, u32 size)
{
struct fwu_mdata_gpt_blk_priv *priv = dev_get_priv(dev);
struct blk_desc *desc = dev_get_uclass_plat(priv->blk_dev);
@@ -177,11 +176,13 @@ static int fwu_gpt_read_mdata(struct udevice *dev, struct fwu_mdata *mdata,
}
return gpt_read_write_mdata(desc, mdata, MDATA_READ,
- primary ? g_mdata_part[0] : g_mdata_part[1]);
+ primary ?
+ g_mdata_part[0] : g_mdata_part[1],
+ size);
}
static int fwu_gpt_write_mdata(struct udevice *dev, struct fwu_mdata *mdata,
- bool primary)
+ bool primary, u32 size)
{
struct fwu_mdata_gpt_blk_priv *priv = dev_get_priv(dev);
struct blk_desc *desc = dev_get_uclass_plat(priv->blk_dev);
@@ -194,7 +195,9 @@ static int fwu_gpt_write_mdata(struct udevice *dev, struct fwu_mdata *mdata,
}
return gpt_read_write_mdata(desc, mdata, MDATA_WRITE,
- primary ? g_mdata_part[0] : g_mdata_part[1]);
+ primary ?
+ g_mdata_part[0] : g_mdata_part[1],
+ size);
}
static const struct fwu_mdata_ops fwu_gpt_blk_ops = {
diff --git a/drivers/fwu-mdata/raw_mtd.c b/drivers/fwu-mdata/raw_mtd.c
index 17e45179738..78a709f766c 100644
--- a/drivers/fwu-mdata/raw_mtd.c
+++ b/drivers/fwu-mdata/raw_mtd.c
@@ -12,22 +12,11 @@
#include <linux/errno.h>
#include <linux/types.h>
-/* Internal helper structure to move data around */
-struct fwu_mdata_mtd_priv {
- struct mtd_info *mtd;
- char pri_label[50];
- char sec_label[50];
- u32 pri_offset;
- u32 sec_offset;
-};
-
enum fwu_mtd_op {
FWU_MTD_READ,
FWU_MTD_WRITE,
};
-extern struct fwu_mtd_image_info fwu_mtd_images[];
-
static bool mtd_is_aligned_with_block_size(struct mtd_info *mtd, u64 size)
{
return !do_div(size, mtd->erasesize);
@@ -97,22 +86,24 @@ lock:
return ret;
}
-static int fwu_mtd_read_mdata(struct udevice *dev, struct fwu_mdata *mdata, bool primary)
+static int fwu_mtd_read_mdata(struct udevice *dev, struct fwu_mdata *mdata,
+ bool primary, u32 size)
{
struct fwu_mdata_mtd_priv *mtd_priv = dev_get_priv(dev);
struct mtd_info *mtd = mtd_priv->mtd;
u32 offs = primary ? mtd_priv->pri_offset : mtd_priv->sec_offset;
- return mtd_io_data(mtd, offs, sizeof(struct fwu_mdata), mdata, FWU_MTD_READ);
+ return mtd_io_data(mtd, offs, size, mdata, FWU_MTD_READ);
}
-static int fwu_mtd_write_mdata(struct udevice *dev, struct fwu_mdata *mdata, bool primary)
+static int fwu_mtd_write_mdata(struct udevice *dev, struct fwu_mdata *mdata,
+ bool primary, u32 size)
{
struct fwu_mdata_mtd_priv *mtd_priv = dev_get_priv(dev);
struct mtd_info *mtd = mtd_priv->mtd;
u32 offs = primary ? mtd_priv->pri_offset : mtd_priv->sec_offset;
- return mtd_io_data(mtd, offs, sizeof(struct fwu_mdata), mdata, FWU_MTD_WRITE);
+ return mtd_io_data(mtd, offs, size, mdata, FWU_MTD_WRITE);
}
static int flash_partition_offset(struct udevice *dev, const char *part_name, fdt_addr_t *offset)
@@ -132,7 +123,7 @@ static int flash_partition_offset(struct udevice *dev, const char *part_name, fd
return (int)size;
}
-static int fwu_mdata_mtd_of_to_plat(struct udevice *dev)
+static int get_fwu_mdata_dev(struct udevice *dev)
{
struct fwu_mdata_mtd_priv *mtd_priv = dev_get_priv(dev);
const fdt32_t *phandle_p = NULL;
@@ -142,8 +133,6 @@ static int fwu_mdata_mtd_of_to_plat(struct udevice *dev)
fdt_addr_t offset;
int ret, size;
u32 phandle;
- ofnode bank;
- int off_img;
/* Find the FWU mdata storage device */
phandle_p = ofnode_get_property(dev_ofnode(dev),
@@ -197,8 +186,28 @@ static int fwu_mdata_mtd_of_to_plat(struct udevice *dev)
return ret;
mtd_priv->sec_offset = offset;
- off_img = 0;
+ return 0;
+}
+
+static int fwu_mtd_image_info_populate(struct udevice *dev, u8 nbanks,
+ u16 nimages)
+{
+ struct fwu_mtd_image_info *mtd_images;
+ struct fwu_mdata_mtd_priv *mtd_priv = dev_get_priv(dev);
+ struct udevice *mtd_dev = mtd_priv->mtd->dev;
+ fdt_addr_t offset;
+ ofnode bank;
+ int off_img;
+ u32 total_images;
+ total_images = nbanks * nimages;
+ mtd_priv->fwu_mtd_images = malloc(sizeof(struct fwu_mtd_image_info) *
+ total_images);
+ if (!mtd_priv->fwu_mtd_images)
+ return -ENOMEM;
+
+ off_img = 0;
+ mtd_images = mtd_priv->fwu_mtd_images;
ofnode_for_each_subnode(bank, dev_ofnode(dev)) {
int bank_num, bank_offset, bank_size;
const char *bank_name;
@@ -217,8 +226,7 @@ static int fwu_mdata_mtd_of_to_plat(struct udevice *dev)
int image_num, image_offset, image_size;
const char *uuid;
- if (off_img == CONFIG_FWU_NUM_BANKS *
- CONFIG_FWU_NUM_IMAGES_PER_BANK) {
+ if (off_img == total_images) {
log_err("DT provides more images than configured!\n");
break;
}
@@ -228,11 +236,11 @@ static int fwu_mdata_mtd_of_to_plat(struct udevice *dev)
ofnode_read_u32(image, "offset", &image_offset);
ofnode_read_u32(image, "size", &image_size);
- fwu_mtd_images[off_img].start = bank_offset + image_offset;
- fwu_mtd_images[off_img].size = image_size;
- fwu_mtd_images[off_img].bank_num = bank_num;
- fwu_mtd_images[off_img].image_num = image_num;
- strcpy(fwu_mtd_images[off_img].uuidbuf, uuid);
+ mtd_images[off_img].start = bank_offset + image_offset;
+ mtd_images[off_img].size = image_size;
+ mtd_images[off_img].bank_num = bank_num;
+ mtd_images[off_img].image_num = image_num;
+ strcpy(mtd_images[off_img].uuidbuf, uuid);
log_debug("\tImage%d: %s @0x%x\n\n",
image_num, uuid, bank_offset + image_offset);
off_img++;
@@ -244,8 +252,21 @@ static int fwu_mdata_mtd_of_to_plat(struct udevice *dev)
static int fwu_mdata_mtd_probe(struct udevice *dev)
{
- /* Ensure the metadata can be read. */
- return fwu_get_mdata(NULL);
+ u8 nbanks;
+ u16 nimages;
+ int ret;
+
+ ret = get_fwu_mdata_dev(dev);
+ if (ret)
+ return ret;
+
+ nbanks = CONFIG_FWU_NUM_BANKS;
+ nimages = CONFIG_FWU_NUM_IMAGES_PER_BANK;
+ ret = fwu_mtd_image_info_populate(dev, nbanks, nimages);
+ if (ret)
+ return ret;
+
+ return 0;
}
static struct fwu_mdata_ops fwu_mtd_ops = {
@@ -264,6 +285,5 @@ U_BOOT_DRIVER(fwu_mdata_mtd) = {
.of_match = fwu_mdata_ids,
.ops = &fwu_mtd_ops,
.probe = fwu_mdata_mtd_probe,
- .of_to_plat = fwu_mdata_mtd_of_to_plat,
.priv_auto = sizeof(struct fwu_mdata_mtd_priv),
};
diff --git a/include/fwu.h b/include/fwu.h
index eb5638f4f3a..77ec65e6180 100644
--- a/include/fwu.h
+++ b/include/fwu.h
@@ -8,6 +8,7 @@
#include <blk.h>
#include <efi.h>
+#include <fwu_mdata.h>
#include <mtd.h>
#include <uuid.h>
@@ -26,31 +27,70 @@ struct fwu_mtd_image_info {
char uuidbuf[UUID_STR_LEN + 1];
};
+struct fwu_mdata_mtd_priv {
+ struct mtd_info *mtd;
+ char pri_label[50];
+ char sec_label[50];
+ u32 pri_offset;
+ u32 sec_offset;
+ struct fwu_mtd_image_info *fwu_mtd_images;
+};
+
+struct fwu_data {
+ uint32_t crc32;
+ uint32_t version;
+ uint32_t active_index;
+ uint32_t previous_active_index;
+ uint32_t metadata_size;
+ uint32_t boot_index;
+ uint32_t num_banks;
+ uint32_t num_images;
+ uint8_t bank_state[4];
+ bool trial_state;
+
+ struct fwu_mdata *fwu_mdata;
+
+ struct fwu_image_entry fwu_images[CONFIG_FWU_NUM_IMAGES_PER_BANK];
+};
+
struct fwu_mdata_ops {
/**
* read_mdata() - Populate the asked FWU metadata copy
* @dev: FWU metadata device
* @mdata: Output FWU mdata read
* @primary: If primary or secondary copy of metadata is to be read
+ * @size: Size in bytes of the metadata to be read
*
* Return: 0 if OK, -ve on error
*/
- int (*read_mdata)(struct udevice *dev, struct fwu_mdata *mdata, bool primary);
+ int (*read_mdata)(struct udevice *dev, struct fwu_mdata *mdata,
+ bool primary, uint32_t size);
/**
* write_mdata() - Write the given FWU metadata copy
* @dev: FWU metadata device
* @mdata: Copy of the FWU metadata to write
* @primary: If primary or secondary copy of metadata is to be written
+ * @size: Size in bytes of the metadata to be written
*
* Return: 0 if OK, -ve on error
*/
- int (*write_mdata)(struct udevice *dev, struct fwu_mdata *mdata, bool primary);
+ int (*write_mdata)(struct udevice *dev, struct fwu_mdata *mdata,
+ bool primary, uint32_t size);
};
-#define FWU_MDATA_VERSION 0x1
#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
+
+enum {
+ PRIMARY_PART = 1,
+ SECONDARY_PART,
+ BOTH_PARTS,
+};
+
/*
* GUID value defined in the FWU specification for identification
* of the FWU metadata partition.
@@ -80,12 +120,14 @@ struct fwu_mdata_ops {
/**
* fwu_read_mdata() - Wrapper around fwu_mdata_ops.read_mdata()
*/
-int fwu_read_mdata(struct udevice *dev, struct fwu_mdata *mdata, bool primary);
+int fwu_read_mdata(struct udevice *dev, struct fwu_mdata *mdata,
+ bool primary, uint32_t size);
/**
* fwu_write_mdata() - Wrapper around fwu_mdata_ops.write_mdata()
*/
-int fwu_write_mdata(struct udevice *dev, struct fwu_mdata *mdata, bool primary);
+int fwu_write_mdata(struct udevice *dev, struct fwu_mdata *mdata,
+ bool primary, uint32_t size);
/**
* fwu_get_mdata() - Read, verify and return the FWU metadata
@@ -280,4 +322,99 @@ int fwu_gen_alt_info_from_mtd(char *buf, size_t len, struct mtd_info *mtd);
*/
int fwu_mtd_get_alt_num(efi_guid_t *image_guid, u8 *alt_num, const char *mtd_dev);
+/**
+ * fwu_mdata_copies_allocate() - Allocate memory for metadata
+ * @mdata_size: Size of the metadata structure
+ *
+ * Allocate memory for storing both the copies of the FWU metadata. The
+ * copies are then used as a cache for storing FWU metadata contents.
+ *
+ * Return: 0 if OK, -ve on error
+ */
+int fwu_mdata_copies_allocate(u32 mdata_size);
+
+/**
+ * fwu_get_dev() - Return the FWU metadata device
+ *
+ * Return the pointer to the FWU metadata device.
+ *
+ * Return: Pointer to the FWU metadata dev
+ */
+struct udevice *fwu_get_dev(void);
+
+/**
+ * fwu_get_data() - Return the version agnostic FWU structure
+ *
+ * Return the pointer to the version agnostic FWU structure.
+ *
+ * Return: Pointer to the FWU data structure
+ */
+struct fwu_data *fwu_get_data(void);
+
+/**
+ * fwu_sync_mdata() - Update given meta-data partition(s) with the copy provided
+ * @data: FWU Data structure
+ * @part: Bitmask of FWU metadata partitions to be written to
+ *
+ * Return: 0 if OK, -ve on error
+ */
+int fwu_sync_mdata(struct fwu_mdata *mdata, int part);
+
+/**
+ * fwu_populate_mdata_image_info() - Populate the image information
+ * of the metadata
+ * @data: Version agnostic FWU metadata information
+ *
+ * Populate the image information in the FWU metadata by copying it
+ * from the version agnostic structure. This is done before the
+ * metadata gets written to the storage media.
+ *
+ * Return: None
+ */
+void fwu_populate_mdata_image_info(struct fwu_data *data);
+
+/**
+ * fwu_get_mdata_size() - Get the FWU metadata size
+ * @mdata_size: Size of the metadata structure
+ *
+ * Get the size of the FWU metadata from the structure. This is later used
+ * to allocate memory for the structure.
+ *
+ * Return: 0 if OK, -ve on error
+ */
+int fwu_get_mdata_size(uint32_t *mdata_size);
+
+/**
+ * fwu_state_machine_updates() - Update FWU state of the platform
+ * @trial_state: Is platform transitioning into Trial State
+ * @update_index: Bank number to which images have been updated
+ *
+ * On successful completion of updates, transition the platform to
+ * either Trial State or Regular State.
+ *
+ * To transition the platform to Trial State, start the
+ * TrialStateCtr counter, followed by setting the value of bank_state
+ * field of the metadata to Valid state(applicable only in version 2
+ * of metadata).
+ *
+ * In case, the platform is to transition directly to Regular State,
+ * update the bank_state field of the metadata to Accepted
+ * state(applicable only in version 2 of metadata).
+ *
+ * Return: 0 if OK, -ve on error
+ */
+int fwu_state_machine_updates(bool trial_state, uint32_t update_index);
+
+/**
+ * fwu_init() - FWU specific initialisations
+ *
+ * Carry out some FWU specific initialisations including allocation
+ * of memory for the metadata copies, and reading the FWU metadata
+ * copies into the allocated memory. The metadata fields are then
+ * copied into a version agnostic structure.
+ *
+ * Return: 0 if OK, -ve on error
+ */
+int fwu_init(void);
+
#endif /* _FWU_H_ */
diff --git a/include/fwu_mdata.h b/include/fwu_mdata.h
index 56189e2f40a..d2521f39b42 100644
--- a/include/fwu_mdata.h
+++ b/include/fwu_mdata.h
@@ -11,7 +11,7 @@
/**
* struct fwu_image_bank_info - firmware image information
- * @image_uuid: Guid value of the image in this bank
+ * @image_guid: Guid value of the image in this bank
* @accepted: Acceptance status of the image
* @reserved: Reserved
*
@@ -20,15 +20,15 @@
* acceptance status
*/
struct fwu_image_bank_info {
- efi_guid_t image_uuid;
+ efi_guid_t image_guid;
uint32_t accepted;
uint32_t reserved;
} __packed;
/**
* struct fwu_image_entry - information for a particular type of image
- * @image_type_uuid: Guid value for identifying the image type
- * @location_uuid: Guid of the storage volume where the image is located
+ * @image_type_guid: Guid value for identifying the image type
+ * @location_guid: Guid of the storage volume where the image is located
* @img_bank_info: Array containing properties of images
*
* This structure contains information on various types of updatable
@@ -36,12 +36,36 @@ struct fwu_image_bank_info {
* information per bank.
*/
struct fwu_image_entry {
- efi_guid_t image_type_uuid;
- efi_guid_t location_uuid;
+ efi_guid_t image_type_guid;
+ efi_guid_t location_guid;
struct fwu_image_bank_info img_bank_info[CONFIG_FWU_NUM_BANKS];
} __packed;
/**
+ * struct fwu_fw_store_desc - FWU updatable image information
+ * @num_banks: Number of firmware banks
+ * @num_images: Number of images per bank
+ * @img_entry_size: The size of the img_entry array
+ * @bank_info_entry_size: The size of the img_bank_info array
+ * @img_entry: Array of image entries each giving information on a image
+ *
+ * This image descriptor structure contains information on the number of
+ * updatable banks and images per bank. It also gives the total sizes of
+ * the fwu_image_entry and fwu_image_bank_info arrays. This structure is
+ * only present in version 2 of the metadata structure.
+ */
+struct fwu_fw_store_desc {
+ uint8_t num_banks;
+ uint8_t reserved;
+ uint16_t num_images;
+ uint16_t img_entry_size;
+ uint16_t bank_info_entry_size;
+
+ struct fwu_image_entry img_entry[CONFIG_FWU_NUM_IMAGES_PER_BANK];
+} __packed;
+
+#if defined(CONFIG_FWU_MDATA_V1)
+/**
* struct fwu_mdata - FWU metadata structure for multi-bank updates
* @crc32: crc32 value for the FWU metadata
* @version: FWU metadata version
@@ -65,4 +89,39 @@ struct fwu_mdata {
struct fwu_image_entry img_entry[CONFIG_FWU_NUM_IMAGES_PER_BANK];
} __packed;
+#else /* CONFIG_FWU_MDATA_V1 */
+/**
+ * struct fwu_mdata - FWU metadata structure for multi-bank updates
+ * @crc32: crc32 value for the FWU metadata
+ * @version: FWU metadata version
+ * @active_index: Index of the bank currently used for booting images
+ * @previous_active_inde: Index of the bank used before the current bank
+ * being used for booting
+ * @metadata_size: Size of the entire metadata structure, including the
+ * image descriptors
+ * @desc_offset: The offset from the start of this structure where the
+ * image descriptor structure starts. 0 if absent
+ * @bank_state: State of each bank, valid, invalid or accepted
+ * @fw_desc: The structure describing the FWU updatable images
+ *
+ * This is the top level structure used to store all information for performing
+ * multi bank updates on the platform. This contains info on the bank being
+ * used to boot along with the information on state of individual banks.
+ */
+struct fwu_mdata {
+ uint32_t crc32;
+ uint32_t version;
+ uint32_t active_index;
+ uint32_t previous_active_index;
+ uint32_t metadata_size;
+ uint16_t desc_offset;
+ uint16_t reserved1;
+ uint8_t bank_state[4];
+ uint32_t reserved2;
+
+ // struct fwu_fw_store_desc fw_desc;
+} __packed;
+
+#endif /* CONFIG_FWU_MDATA_V1 */
+
#endif /* _FWU_MDATA_H_ */
diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c
index de0d49ebebd..0937800e588 100644
--- a/lib/efi_loader/efi_capsule.c
+++ b/lib/efi_loader/efi_capsule.c
@@ -480,6 +480,11 @@ static __maybe_unused efi_status_t fwu_empty_capsule_process(
if (ret != EFI_SUCCESS)
log_err("Unable to set the Accept bit for the image %pUs\n",
image_guid);
+
+ status = fwu_state_machine_updates(0, active_idx);
+ if (status < 0)
+ ret = EFI_DEVICE_ERROR;
+
}
return ret;
@@ -521,11 +526,10 @@ static __maybe_unused efi_status_t fwu_post_update_process(bool fw_accept_os)
log_err("Failed to update FWU metadata index values\n");
} else {
log_debug("Successfully updated the active_index\n");
- if (fw_accept_os) {
- status = fwu_trial_state_ctr_start();
- if (status < 0)
- ret = EFI_DEVICE_ERROR;
- }
+ status = fwu_state_machine_updates(fw_accept_os ? 1 : 0,
+ update_index);
+ if (status < 0)
+ ret = EFI_DEVICE_ERROR;
}
return ret;
diff --git a/lib/fwu_updates/Kconfig b/lib/fwu_updates/Kconfig
index d35247d0e5d..51b7fbbefd3 100644
--- a/lib/fwu_updates/Kconfig
+++ b/lib/fwu_updates/Kconfig
@@ -31,4 +31,18 @@ config FWU_TRIAL_STATE_CNT
the platform is allowed to boot in Trial State after an
update.
+config FWU_MDATA_V1
+ bool "Enable support FWU Metadata version 1"
+ help
+ The FWU specification supports two versions of the
+ metadata structure. This option enables support for FWU
+ Metadata version 1 access.
+
+config FWU_MDATA_V2
+ bool "Enable support FWU Metadata version 2"
+ help
+ The FWU specification supports two versions of the
+ metadata structure. This option enables support for FWU
+ Metadata version 2 access.
+
endif
diff --git a/lib/fwu_updates/Makefile b/lib/fwu_updates/Makefile
index c9e3c06b489..3681bef46cd 100644
--- a/lib/fwu_updates/Makefile
+++ b/lib/fwu_updates/Makefile
@@ -6,3 +6,5 @@
obj-$(CONFIG_FWU_MULTI_BANK_UPDATE) += fwu.o
obj-$(CONFIG_FWU_MDATA_GPT_BLK) += fwu_gpt.o
obj-$(CONFIG_FWU_MDATA_MTD) += fwu_mtd.o
+obj-$(CONFIG_FWU_MDATA_V1) += fwu_v1.o
+obj-$(CONFIG_FWU_MDATA_V2) += fwu_v2.o
diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c
index 86518108c2d..5dfea2a4d8d 100644
--- a/lib/fwu_updates/fwu.c
+++ b/lib/fwu_updates/fwu.c
@@ -10,6 +10,7 @@
#include <event.h>
#include <fwu.h>
#include <fwu_mdata.h>
+#include <log.h>
#include <malloc.h>
#include <linux/errno.h>
@@ -17,7 +18,7 @@
#include <u-boot/crc.h>
-static struct fwu_mdata g_mdata; /* = {0} makes uninit crc32 always invalid */
+struct fwu_data g_fwu_data;
static struct udevice *g_dev;
static u8 in_trial;
static u8 boottime_check;
@@ -27,12 +28,6 @@ enum {
IMAGE_ACCEPT_CLEAR,
};
-enum {
- PRIMARY_PART = 1,
- SECONDARY_PART,
- BOTH_PARTS,
-};
-
static int trial_counter_update(u16 *trial_state_ctr)
{
bool delete;
@@ -106,23 +101,9 @@ out:
return ret;
}
-static int in_trial_state(struct fwu_mdata *mdata)
+static u32 in_trial_state(void)
{
- u32 i, active_bank;
- struct fwu_image_entry *img_entry;
- struct fwu_image_bank_info *img_bank_info;
-
- active_bank = mdata->active_index;
- img_entry = &mdata->img_entry[0];
- for (i = 0; i < CONFIG_FWU_NUM_IMAGES_PER_BANK; i++) {
- img_bank_info = &img_entry[i].img_bank_info[active_bank];
- if (!img_bank_info->accepted) {
- log_info("System booting in Trial State\n");
- return 1;
- }
- }
-
- return 0;
+ return g_fwu_data.trial_state;
}
static int fwu_get_image_type_id(u8 image_index, efi_guid_t *image_type_id)
@@ -141,17 +122,70 @@ static int fwu_get_image_type_id(u8 image_index, efi_guid_t *image_type_id)
return -ENOENT;
}
+static int mdata_crc_check(struct fwu_mdata *mdata)
+{
+ int ret;
+ u32 calc_crc32;
+ uint32_t mdata_size;
+ void *buf = &mdata->version;
+
+ ret = fwu_get_mdata_size(&mdata_size);
+ if (ret)
+ return ret;
+
+ calc_crc32 = crc32(0, buf, mdata_size - sizeof(u32));
+ return calc_crc32 == mdata->crc32 ? 0 : -EINVAL;
+}
+
+static void fwu_data_crc_update(uint32_t crc32)
+{
+ g_fwu_data.crc32 = crc32;
+}
+
+/**
+ * fwu_get_data() - Return the version agnostic FWU structure
+ *
+ * Return the pointer to the version agnostic FWU structure.
+ *
+ * Return: Pointer to the FWU data structure
+ */
+struct fwu_data *fwu_get_data(void)
+{
+ return &g_fwu_data;
+}
+
+static void fwu_populate_mdata_bank_index(struct fwu_data *fwu_data)
+{
+ struct fwu_mdata *mdata = fwu_data->fwu_mdata;
+
+ mdata->active_index = fwu_data->active_index;
+ mdata->previous_active_index = fwu_data->previous_active_index;
+}
+
+/**
+ * fwu_get_dev() - Return the FWU metadata device
+ *
+ * Return the pointer to the FWU metadata device.
+ *
+ * Return: Pointer to the FWU metadata dev
+ */
+struct udevice *fwu_get_dev(void)
+{
+ return g_dev;
+}
+
/**
* fwu_sync_mdata() - Update given meta-data partition(s) with the copy provided
- * @mdata: FWU metadata structure
+ * @data: FWU Data structure
* @part: Bitmask of FWU metadata partitions to be written to
*
* Return: 0 if OK, -ve on error
*/
-static int fwu_sync_mdata(struct fwu_mdata *mdata, int part)
+int fwu_sync_mdata(struct fwu_mdata *mdata, int part)
{
- void *buf = &mdata->version;
int err;
+ uint mdata_size;
+ void *buf = &mdata->version;
if (part == BOTH_PARTS) {
err = fwu_sync_mdata(mdata, SECONDARY_PART);
@@ -160,32 +194,53 @@ static int fwu_sync_mdata(struct fwu_mdata *mdata, int part)
part = PRIMARY_PART;
}
+ err = fwu_get_mdata_size(&mdata_size);
+ if (err)
+ return err;
+
/*
* Calculate the crc32 for the updated FWU metadata
* and put the updated value in the FWU metadata crc32
* field
*/
- mdata->crc32 = crc32(0, buf, sizeof(*mdata) - sizeof(u32));
+ mdata->crc32 = crc32(0, buf, mdata_size - sizeof(u32));
+ fwu_data_crc_update(mdata->crc32);
- err = fwu_write_mdata(g_dev, mdata, part == PRIMARY_PART);
+ err = fwu_write_mdata(g_dev, mdata, part == PRIMARY_PART, mdata_size);
if (err) {
log_err("Unable to write %s mdata\n",
part == PRIMARY_PART ? "primary" : "secondary");
return err;
}
- /* update the cached copy of meta-data */
- memcpy(&g_mdata, mdata, sizeof(struct fwu_mdata));
-
return 0;
}
-static inline int mdata_crc_check(struct fwu_mdata *mdata)
+/**
+ * fwu_mdata_copies_allocate() - Allocate memory for metadata
+ * @mdata_size: Size of the metadata structure
+ *
+ * Allocate memory for storing both the copies of the FWU metadata. The
+ * copies are then used as a cache for storing FWU metadata contents.
+ *
+ * Return: 0 if OK, -ve on error
+ */
+int fwu_mdata_copies_allocate(u32 mdata_size)
{
- void *buf = &mdata->version;
- u32 calc_crc32 = crc32(0, buf, sizeof(*mdata) - sizeof(u32));
+ if (g_fwu_data.fwu_mdata)
+ return 0;
- return calc_crc32 == mdata->crc32 ? 0 : -EINVAL;
+ /*
+ * Allocate the total memory that would be needed for both
+ * the copies.
+ */
+ g_fwu_data.fwu_mdata = calloc(2, mdata_size);
+ if (!g_fwu_data.fwu_mdata) {
+ log_err("Unable to allocate space for FWU metadata\n");
+ return -ENOMEM;
+ }
+
+ return 0;
}
/**
@@ -201,21 +256,33 @@ static inline int mdata_crc_check(struct fwu_mdata *mdata)
int fwu_get_mdata(struct fwu_mdata *mdata)
{
int err;
+ uint32_t mdata_size;
bool parts_ok[2] = { false };
- struct fwu_mdata s, *parts_mdata[2];
+ struct fwu_mdata *parts_mdata[2];
- parts_mdata[0] = &g_mdata;
- parts_mdata[1] = &s;
+ err = fwu_get_mdata_size(&mdata_size);
+ if (err)
+ return err;
+
+ parts_mdata[0] = g_fwu_data.fwu_mdata;
+ if (!parts_mdata[0]) {
+ log_err("Memory not allocated for the FWU Metadata copies\n");
+ return -ENOMEM;
+ }
+
+ parts_mdata[1] = (struct fwu_mdata *)((char *)parts_mdata[0] +
+ mdata_size);
/* if mdata already read and ready */
err = mdata_crc_check(parts_mdata[0]);
if (!err)
goto ret_mdata;
- /* else read, verify and, if needed, fix mdata */
+
+ /* else read, verify and, if needed, fix mdata */
for (int i = 0; i < 2; i++) {
parts_ok[i] = false;
- err = fwu_read_mdata(g_dev, parts_mdata[i], !i);
+ err = fwu_read_mdata(g_dev, parts_mdata[i], !i, mdata_size);
if (!err) {
err = mdata_crc_check(parts_mdata[i]);
if (!err)
@@ -230,7 +297,7 @@ int fwu_get_mdata(struct fwu_mdata *mdata)
* Before returning, check that both the
* FWU metadata copies are the same.
*/
- err = memcmp(parts_mdata[0], parts_mdata[1], sizeof(struct fwu_mdata));
+ err = memcmp(parts_mdata[0], parts_mdata[1], mdata_size);
if (!err)
goto ret_mdata;
@@ -247,7 +314,7 @@ int fwu_get_mdata(struct fwu_mdata *mdata)
if (parts_ok[i])
continue;
- memcpy(parts_mdata[i], parts_mdata[1 - i], sizeof(struct fwu_mdata));
+ memcpy(parts_mdata[i], parts_mdata[1 - i], mdata_size);
err = fwu_sync_mdata(parts_mdata[i], i ? SECONDARY_PART : PRIMARY_PART);
if (err) {
log_debug("mdata : %s write failed\n", i ? "secondary" : "primary");
@@ -257,7 +324,7 @@ int fwu_get_mdata(struct fwu_mdata *mdata)
ret_mdata:
if (!err && mdata)
- memcpy(mdata, parts_mdata[0], sizeof(struct fwu_mdata));
+ memcpy(mdata, parts_mdata[0], mdata_size);
return err;
}
@@ -275,13 +342,13 @@ ret_mdata:
int fwu_get_active_index(uint *active_idx)
{
int ret = 0;
- struct fwu_mdata *mdata = &g_mdata;
+ struct fwu_data *data = &g_fwu_data;
/*
* Found the FWU metadata partition, now read the active_index
* value
*/
- *active_idx = mdata->active_index;
+ *active_idx = data->active_index;
if (*active_idx >= CONFIG_FWU_NUM_BANKS) {
log_debug("Active index value read is incorrect\n");
ret = -EINVAL;
@@ -302,7 +369,7 @@ int fwu_get_active_index(uint *active_idx)
int fwu_set_active_index(uint active_idx)
{
int ret;
- struct fwu_mdata *mdata = &g_mdata;
+ struct fwu_data *data = &g_fwu_data;
if (active_idx >= CONFIG_FWU_NUM_BANKS) {
log_debug("Invalid active index value\n");
@@ -313,14 +380,16 @@ int fwu_set_active_index(uint active_idx)
* Update the active index and previous_active_index fields
* in the FWU metadata
*/
- mdata->previous_active_index = mdata->active_index;
- mdata->active_index = active_idx;
+ data->previous_active_index = data->active_index;
+ data->active_index = active_idx;
+
+ fwu_populate_mdata_bank_index(data);
/*
* Now write this updated FWU metadata to both the
* FWU metadata partitions
*/
- ret = fwu_sync_mdata(mdata, BOTH_PARTS);
+ ret = fwu_sync_mdata(data->fwu_mdata, BOTH_PARTS);
if (ret) {
log_debug("Failed to update FWU metadata partitions\n");
ret = -EIO;
@@ -346,7 +415,7 @@ int fwu_get_dfu_alt_num(u8 image_index, u8 *alt_num)
int ret, i;
uint update_bank;
efi_guid_t *image_guid, image_type_id;
- struct fwu_mdata *mdata = &g_mdata;
+ struct fwu_data *data = &g_fwu_data;
struct fwu_image_entry *img_entry;
struct fwu_image_bank_info *img_bank_info;
@@ -365,15 +434,15 @@ int fwu_get_dfu_alt_num(u8 image_index, u8 *alt_num)
ret = -EINVAL;
/*
- * The FWU metadata has been read. Now get the image_uuid for the
+ * The FWU metadata has been read. Now get the image_guid for the
* image with the update_bank.
*/
for (i = 0; i < CONFIG_FWU_NUM_IMAGES_PER_BANK; i++) {
if (!guidcmp(&image_type_id,
- &mdata->img_entry[i].image_type_uuid)) {
- img_entry = &mdata->img_entry[i];
+ &data->fwu_images[i].image_type_guid)) {
+ img_entry = &data->fwu_images[i];
img_bank_info = &img_entry->img_bank_info[update_bank];
- image_guid = &img_bank_info->image_uuid;
+ image_guid = &img_bank_info->image_guid;
ret = fwu_plat_get_alt_num(g_dev, image_guid, alt_num);
if (ret)
log_debug("alt_num not found for partition with GUID %pUs\n",
@@ -407,21 +476,23 @@ int fwu_revert_boot_index(void)
{
int ret;
u32 cur_active_index;
- struct fwu_mdata *mdata = &g_mdata;
+ struct fwu_data *data = &g_fwu_data;
/*
* Swap the active index and previous_active_index fields
* in the FWU metadata
*/
- cur_active_index = mdata->active_index;
- mdata->active_index = mdata->previous_active_index;
- mdata->previous_active_index = cur_active_index;
+ cur_active_index = data->active_index;
+ data->active_index = data->previous_active_index;
+ data->previous_active_index = cur_active_index;
+
+ fwu_populate_mdata_bank_index(data);
/*
* Now write this updated FWU metadata to both the
* FWU metadata partitions
*/
- ret = fwu_sync_mdata(mdata, BOTH_PARTS);
+ ret = fwu_sync_mdata(data->fwu_mdata, BOTH_PARTS);
if (ret) {
log_debug("Failed to update FWU metadata partitions\n");
ret = -EIO;
@@ -448,20 +519,21 @@ int fwu_revert_boot_index(void)
static int fwu_clrset_image_accept(efi_guid_t *img_type_id, u32 bank, u8 action)
{
int ret, i;
- struct fwu_mdata *mdata = &g_mdata;
+ struct fwu_data *data = &g_fwu_data;
struct fwu_image_entry *img_entry;
struct fwu_image_bank_info *img_bank_info;
- img_entry = &mdata->img_entry[0];
+ img_entry = &data->fwu_images[0];
for (i = 0; i < CONFIG_FWU_NUM_IMAGES_PER_BANK; i++) {
- if (!guidcmp(&img_entry[i].image_type_uuid, img_type_id)) {
+ if (!guidcmp(&img_entry[i].image_type_guid, img_type_id)) {
img_bank_info = &img_entry[i].img_bank_info[bank];
if (action == IMAGE_ACCEPT_SET)
img_bank_info->accepted |= FWU_IMAGE_ACCEPTED;
else
img_bank_info->accepted = 0;
- ret = fwu_sync_mdata(mdata, BOTH_PARTS);
+ fwu_populate_mdata_image_info(data);
+ ret = fwu_sync_mdata(data->fwu_mdata, BOTH_PARTS);
goto out;
}
}
@@ -627,9 +699,9 @@ static int fwu_boottime_checks(void)
return 0;
}
- ret = fwu_get_mdata(NULL);
+ ret = fwu_init();
if (ret) {
- log_debug("Unable to read meta-data\n");
+ log_debug("fwu_init() failed\n");
return ret;
}
@@ -665,7 +737,7 @@ static int fwu_boottime_checks(void)
if (efi_init_obj_list() != EFI_SUCCESS)
return 0;
- in_trial = in_trial_state(&g_mdata);
+ in_trial = in_trial_state();
if (!in_trial || (ret = fwu_trial_count_update()) > 0)
ret = trial_counter_update(NULL);
diff --git a/lib/fwu_updates/fwu_mtd.c b/lib/fwu_updates/fwu_mtd.c
index 4a52834b61a..ccaba3f3115 100644
--- a/lib/fwu_updates/fwu_mtd.c
+++ b/lib/fwu_updates/fwu_mtd.c
@@ -15,16 +15,21 @@
#include <dm/ofnode.h>
-struct fwu_mtd_image_info
-fwu_mtd_images[CONFIG_FWU_NUM_BANKS * CONFIG_FWU_NUM_IMAGES_PER_BANK];
-
static struct fwu_mtd_image_info *mtd_img_by_uuid(const char *uuidbuf)
{
- int num_images = ARRAY_SIZE(fwu_mtd_images);
+ int num_images;
+ struct fwu_mdata_mtd_priv *mtd_priv = dev_get_priv(fwu_get_dev());
+ struct fwu_mtd_image_info *image_info = mtd_priv->fwu_mtd_images;
+
+ if (!image_info)
+ return NULL;
+
+ num_images = CONFIG_FWU_NUM_BANKS *
+ CONFIG_FWU_NUM_IMAGES_PER_BANK;
for (int i = 0; i < num_images; i++)
- if (!strcmp(uuidbuf, fwu_mtd_images[i].uuidbuf))
- return &fwu_mtd_images[i];
+ if (!strcmp(uuidbuf, image_info[i].uuidbuf))
+ return &image_info[i];
return NULL;
}
@@ -107,7 +112,7 @@ __weak int fwu_plat_get_alt_num(struct udevice *dev, efi_guid_t *image_id,
return fwu_mtd_get_alt_num(image_id, alt_num, "nor1");
}
-static int gen_image_alt_info(char *buf, size_t len, int sidx,
+static int gen_image_alt_info(char *buf, size_t len,
struct fwu_image_entry *img, struct mtd_info *mtd)
{
char *p = buf, *end = buf + len;
@@ -131,7 +136,7 @@ static int gen_image_alt_info(char *buf, size_t len, int sidx,
/* Query a partition by image UUID */
bank = &img->img_bank_info[i];
- uuid_bin_to_str(bank->image_uuid.b, uuidbuf, UUID_STR_FORMAT_STD);
+ uuid_bin_to_str(bank->image_guid.b, uuidbuf, UUID_STR_FORMAT_STD);
mtd_img_info = mtd_img_by_uuid(uuidbuf);
if (!mtd_img_info) {
@@ -158,18 +163,13 @@ static int gen_image_alt_info(char *buf, size_t len, int sidx,
int fwu_gen_alt_info_from_mtd(char *buf, size_t len, struct mtd_info *mtd)
{
- struct fwu_mdata mdata;
int i, l, ret;
-
- ret = fwu_get_mdata(&mdata);
- if (ret < 0) {
- log_err("Failed to get the FWU mdata.\n");
- return ret;
- }
+ struct fwu_data *data = fwu_get_data();
+ struct fwu_image_entry *img_entry;
for (i = 0; i < CONFIG_FWU_NUM_IMAGES_PER_BANK; i++) {
- ret = gen_image_alt_info(buf, len, i * CONFIG_FWU_NUM_BANKS,
- &mdata.img_entry[i], mtd);
+ img_entry = &data->fwu_images[i];
+ ret = gen_image_alt_info(buf, len, img_entry, mtd);
if (ret)
break;
diff --git a/lib/fwu_updates/fwu_v1.c b/lib/fwu_updates/fwu_v1.c
new file mode 100644
index 00000000000..efb8d515008
--- /dev/null
+++ b/lib/fwu_updates/fwu_v1.c
@@ -0,0 +1,167 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2024, Linaro Limited
+ */
+
+#include <fwu.h>
+#include <fwu_mdata.h>
+
+#include <linux/types.h>
+
+#define FWU_MDATA_VERSION 0x1U
+
+static uint32_t fwu_check_trial_state(struct fwu_mdata *mdata, uint32_t bank)
+{
+ u32 i;
+ struct fwu_image_entry *img_entry;
+ struct fwu_image_bank_info *img_bank_info;
+
+ img_entry = &mdata->img_entry[0];
+ for (i = 0; i < CONFIG_FWU_NUM_IMAGES_PER_BANK; i++) {
+ img_bank_info = &img_entry[i].img_bank_info[bank];
+ if (!img_bank_info->accepted) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static void fwu_data_init(void)
+{
+ size_t image_info_size;
+ void *dst_img_info, *src_img_info;
+ struct fwu_data *data = fwu_get_data();
+ struct fwu_mdata *mdata = data->fwu_mdata;
+
+ data->crc32 = mdata->crc32;
+ data->version = mdata->version;
+ data->active_index = mdata->active_index;
+ data->previous_active_index = mdata->previous_active_index;
+
+ data->metadata_size = sizeof(struct fwu_mdata);
+ data->num_banks = CONFIG_FWU_NUM_BANKS;
+ data->num_images = CONFIG_FWU_NUM_IMAGES_PER_BANK;
+ fwu_plat_get_bootidx(&data->boot_index);
+ data->trial_state = fwu_check_trial_state(mdata, data->boot_index);
+
+ src_img_info = &mdata->img_entry[0];
+ dst_img_info = &data->fwu_images[0];
+ image_info_size = sizeof(data->fwu_images);
+
+ memcpy(dst_img_info, src_img_info, image_info_size);
+}
+
+static int fwu_trial_state_update(bool trial_state)
+{
+ int ret;
+ struct fwu_data *data = fwu_get_data();
+
+ if (trial_state) {
+ ret = fwu_trial_state_ctr_start();
+ if (ret)
+ return ret;
+ }
+
+ data->trial_state = trial_state;
+
+ return 0;
+}
+
+/**
+ * fwu_populate_mdata_image_info() - Populate the image information
+ * of the metadata
+ * @data: Version agnostic FWU metadata information
+ *
+ * Populate the image information in the FWU metadata by copying it
+ * from the version agnostic structure. This is done before the
+ * metadata gets written to the storage media.
+ *
+ * Return: None
+ */
+void fwu_populate_mdata_image_info(struct fwu_data *data)
+{
+ size_t image_info_size;
+ void *dst_img_info, *src_img_info;
+ struct fwu_mdata *mdata = data->fwu_mdata;
+
+ image_info_size = sizeof(data->fwu_images);
+ dst_img_info = &mdata->img_entry[0];
+ src_img_info = &data->fwu_images[0];
+
+ memcpy(dst_img_info, src_img_info, image_info_size);
+}
+
+/**
+ * fwu_state_machine_updates() - Update FWU state of the platform
+ * @trial_state: Is platform transitioning into Trial State
+ * @update_index: Bank number to which images have been updated
+ *
+ * On successful completion of updates, transition the platform to
+ * either Trial State or Regular State.
+ *
+ * To transition the platform to Trial State, start the
+ * TrialStateCtr counter, followed by setting the value of bank_state
+ * field of the metadata to Valid state(applicable only in version 2
+ * of metadata).
+ *
+ * In case, the platform is to transition directly to Regular State,
+ * update the bank_state field of the metadata to Accepted
+ * state(applicable only in version 2 of metadata).
+ *
+ * Return: 0 if OK, -ve on error
+ */
+int fwu_state_machine_updates(bool trial_state,
+ __maybe_unused uint32_t update_index)
+{
+ return fwu_trial_state_update(trial_state);
+}
+
+/**
+ * fwu_get_mdata_size() - Get the FWU metadata size
+ * @mdata_size: Size of the metadata structure
+ *
+ * Get the size of the FWU metadata.
+ *
+ * Return: 0 if OK, -ve on error
+ */
+int fwu_get_mdata_size(uint32_t *mdata_size)
+{
+ *mdata_size = sizeof(struct fwu_mdata);
+
+ return 0;
+}
+
+/**
+ * fwu_init() - FWU specific initialisations
+ *
+ * Carry out some FWU specific initialisations including allocation
+ * of memory for the metadata copies, and reading the FWU metadata
+ * copies into the allocated memory. The metadata fields are then
+ * copied into a version agnostic structure.
+ *
+ * Return: 0 if OK, -ve on error
+ */
+int fwu_init(void)
+{
+ int ret;
+ uint32_t mdata_size;
+
+ fwu_get_mdata_size(&mdata_size);
+
+ ret = fwu_mdata_copies_allocate(mdata_size);
+ if (ret)
+ return ret;
+
+ /*
+ * Now read the entire structure, both copies, and
+ * validate that the copies.
+ */
+ ret = fwu_get_mdata(NULL);
+ if (ret)
+ return ret;
+
+ fwu_data_init();
+
+ return 0;
+}
diff --git a/lib/fwu_updates/fwu_v2.c b/lib/fwu_updates/fwu_v2.c
new file mode 100644
index 00000000000..108bc9bb4ac
--- /dev/null
+++ b/lib/fwu_updates/fwu_v2.c
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2024, Linaro Limited
+ */
+
+#include <fwu.h>
+#include <fwu_mdata.h>
+#include <log.h>
+
+#include <linux/types.h>
+
+#define FWU_MDATA_VERSION 0x2U
+
+static inline struct fwu_fw_store_desc *fwu_get_fw_desc(struct fwu_mdata *mdata)
+{
+ return (struct fwu_fw_store_desc *)((u8 *)mdata + sizeof(*mdata));
+}
+
+static uint32_t fwu_check_trial_state(struct fwu_mdata *mdata, uint32_t bank)
+{
+ return mdata->bank_state[bank] == FWU_BANK_VALID ? 1 : 0;
+}
+
+static void fwu_data_init(void)
+{
+ int i;
+ size_t image_info_size;
+ void *dst_img_info, *src_img_info;
+ struct fwu_data *data = fwu_get_data();
+ struct fwu_mdata *mdata = data->fwu_mdata;
+
+ data->crc32 = mdata->crc32;
+ data->version = mdata->version;
+ data->active_index = mdata->active_index;
+ data->previous_active_index = mdata->previous_active_index;
+ data->metadata_size = mdata->metadata_size;
+ fwu_plat_get_bootidx(&data->boot_index);
+ data->trial_state = fwu_check_trial_state(mdata, data->boot_index);
+
+ data->num_banks = fwu_get_fw_desc(mdata)->num_banks;
+ data->num_images = fwu_get_fw_desc(mdata)->num_images;
+
+ for (i = 0; i < 4; i++) {
+ data->bank_state[i] = mdata->bank_state[i];
+ }
+
+ image_info_size = sizeof(data->fwu_images);
+ src_img_info = &fwu_get_fw_desc(mdata)->img_entry[0];
+ dst_img_info = &data->fwu_images[0];
+
+ memcpy(dst_img_info, src_img_info, image_info_size);
+}
+
+static int fwu_mdata_sanity_checks(void)
+{
+ uint8_t num_banks;
+ uint16_t num_images;
+ struct fwu_data *data = fwu_get_data();
+ struct fwu_mdata *mdata = data->fwu_mdata;
+
+ if (mdata->version != FWU_MDATA_VERSION) {
+ log_err("FWU metadata version %u. Expected value of %u\n",
+ mdata->version, FWU_MDATA_VERSION);
+ return -EINVAL;
+ }
+
+ if (!mdata->desc_offset) {
+ log_err("No image information provided with the Metadata. ");
+ log_err("Image information expected in the metadata\n");
+ return -EINVAL;
+ }
+
+ if (mdata->desc_offset != 0x20) {
+ log_err("Descriptor Offset(0x%x) in the FWU Metadata not equal to 0x20\n",
+ mdata->desc_offset);
+ return -EINVAL;
+ }
+
+ num_banks = fwu_get_fw_desc(mdata)->num_banks;
+ num_images = fwu_get_fw_desc(mdata)->num_images;
+
+ if (num_banks != CONFIG_FWU_NUM_BANKS) {
+ log_err("Number of Banks(%u) in FWU Metadata different from the configured value(%d)",
+ num_banks, CONFIG_FWU_NUM_BANKS);
+ return -EINVAL;
+ }
+
+ if (num_images != CONFIG_FWU_NUM_IMAGES_PER_BANK) {
+ log_err("Number of Images(%u) in FWU Metadata different from the configured value(%d)",
+ num_images, CONFIG_FWU_NUM_IMAGES_PER_BANK);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int fwu_bank_state_update(bool trial_state, uint32_t bank)
+{
+ int ret;
+ struct fwu_data *data = fwu_get_data();
+ struct fwu_mdata *mdata = data->fwu_mdata;
+
+ mdata->bank_state[bank] = data->bank_state[bank] = trial_state ?
+ FWU_BANK_VALID : FWU_BANK_ACCEPTED;
+
+ ret = fwu_sync_mdata(mdata, BOTH_PARTS);
+ if (ret)
+ log_err("Unable to set bank_state for bank %u\n", bank);
+ else
+ data->trial_state = trial_state;
+
+ return ret;
+}
+
+static int fwu_trial_state_start(uint update_index)
+{
+ int ret;
+
+ ret = fwu_trial_state_ctr_start();
+ if (ret)
+ return ret;
+
+ ret = fwu_bank_state_update(1, update_index);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+/**
+ * fwu_populate_mdata_image_info() - Populate the image information
+ * of the metadata
+ * @data: Version agnostic FWU metadata information
+ *
+ * Populate the image information in the FWU metadata by copying it
+ * from the version agnostic structure. This is done before the
+ * metadata gets written to the storage media.
+ *
+ * Return: None
+ */
+void fwu_populate_mdata_image_info(struct fwu_data *data)
+{
+ size_t image_info_size;
+ struct fwu_mdata *mdata = data->fwu_mdata;
+ void *dst_img_info, *src_img_info;
+
+ image_info_size = sizeof(data->fwu_images);
+ dst_img_info = &fwu_get_fw_desc(mdata)->img_entry[0];
+ src_img_info = &data->fwu_images[0];
+
+ memcpy(dst_img_info, src_img_info, image_info_size);
+}
+
+/**
+ * fwu_state_machine_updates() - Update FWU state of the platform
+ * @trial_state: Is platform transitioning into Trial State
+ * @update_index: Bank number to which images have been updated
+ *
+ * On successful completion of updates, transition the platform to
+ * either Trial State or Regular State.
+ *
+ * To transition the platform to Trial State, start the
+ * TrialStateCtr counter, followed by setting the value of bank_state
+ * field of the metadata to Valid state(applicable only in version 2
+ * of metadata).
+ *
+ * In case, the platform is to transition directly to Regular State,
+ * update the bank_state field of the metadata to Accepted
+ * state(applicable only in version 2 of metadata).
+ *
+ * Return: 0 if OK, -ve on error
+ */
+int fwu_state_machine_updates(bool trial_state, uint32_t update_index)
+{
+ return trial_state ? fwu_trial_state_start(update_index) :
+ fwu_bank_state_update(0, update_index);
+}
+
+/**
+ * fwu_get_mdata_size() - Get the FWU metadata size
+ * @mdata_size: Size of the metadata structure
+ *
+ * Get the size of the FWU metadata from the structure. This is later used
+ * to allocate memory for the structure.
+ *
+ * Return: 0 if OK, -ve on error
+ */
+int fwu_get_mdata_size(uint32_t *mdata_size)
+{
+ int ret = 0;
+ struct fwu_mdata mdata = { 0 };
+ struct fwu_data *data = fwu_get_data();
+ struct udevice *fwu_dev = fwu_get_dev();
+
+ if (data->metadata_size) {
+ *mdata_size = data->metadata_size;
+ return 0;
+ }
+
+ ret = fwu_read_mdata(fwu_dev, &mdata, 1,
+ sizeof(struct fwu_mdata));
+ if (ret) {
+ log_err("FWU metadata read failed\n");
+ return ret;
+ }
+
+ *mdata_size = mdata.metadata_size;
+ if (!*mdata_size)
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
+ * fwu_init() - FWU specific initialisations
+ *
+ * Carry out some FWU specific initialisations including allocation
+ * of memory for the metadata copies, and reading the FWU metadata
+ * copies into the allocated memory. The metadata fields are then
+ * copied into a version agnostic structure.
+ *
+ * Return: 0 if OK, -ve on error
+ */
+int fwu_init(void)
+{
+ int ret;
+ struct fwu_mdata mdata = { 0 };
+ struct udevice *fwu_dev = fwu_get_dev();
+
+ /*
+ * First we read only the top level structure
+ * and get the size of the complete structure.
+ */
+ ret = fwu_read_mdata(fwu_dev, &mdata, 1,
+ sizeof(struct fwu_mdata));
+ if (ret) {
+ log_err("FWU metadata read failed\n");
+ return ret;
+ }
+
+ ret = fwu_mdata_copies_allocate(mdata.metadata_size);
+ if (ret)
+ return ret;
+
+ /*
+ * Now read the entire structure, both copies, and
+ * validate that the copies.
+ */
+ ret = fwu_get_mdata(NULL);
+ if (ret)
+ return ret;
+
+ ret = fwu_mdata_sanity_checks();
+ if (ret)
+ return ret;
+
+ fwu_data_init();
+
+ return 0;
+}
diff --git a/test/dm/fwu_mdata.c b/test/dm/fwu_mdata.c
index 43ce3d0a9d8..0be7f4519e2 100644
--- a/test/dm/fwu_mdata.c
+++ b/test/dm/fwu_mdata.c
@@ -92,6 +92,10 @@ static int dm_test_fwu_mdata_read(struct unit_test_state *uts)
struct udevice *dev;
struct fwu_mdata mdata = { 0 };
+ ut_assertok(setup_blk_device(uts));
+ ut_assertok(populate_mmc_disk_image(uts));
+ ut_assertok(write_mmc_blk_device(uts));
+
/*
* Trigger lib/fwu_updates/fwu.c fwu_boottime_checks()
* to populate g_dev global pointer in that library.
@@ -99,9 +103,7 @@ static int dm_test_fwu_mdata_read(struct unit_test_state *uts)
event_notify_null(EVT_MAIN_LOOP);
ut_assertok(uclass_first_device_err(UCLASS_FWU_MDATA, &dev));
- ut_assertok(setup_blk_device(uts));
- ut_assertok(populate_mmc_disk_image(uts));
- ut_assertok(write_mmc_blk_device(uts));
+ ut_assertok(fwu_init());
ut_assertok(fwu_get_mdata(&mdata));
@@ -117,18 +119,20 @@ static int dm_test_fwu_mdata_write(struct unit_test_state *uts)
struct udevice *dev;
struct fwu_mdata mdata = { 0 };
+ ut_assertok(setup_blk_device(uts));
+ ut_assertok(populate_mmc_disk_image(uts));
+ ut_assertok(write_mmc_blk_device(uts));
+
/*
* Trigger lib/fwu_updates/fwu.c fwu_boottime_checks()
* to populate g_dev global pointer in that library.
*/
event_notify_null(EVT_MAIN_LOOP);
- ut_assertok(setup_blk_device(uts));
- ut_assertok(populate_mmc_disk_image(uts));
- ut_assertok(write_mmc_blk_device(uts));
ut_assertok(uclass_first_device_err(UCLASS_FWU_MDATA, &dev));
+ ut_assertok(fwu_init());
ut_assertok(fwu_get_mdata(&mdata));
active_idx = (mdata.active_index + 1) % CONFIG_FWU_NUM_BANKS;
diff --git a/tools/mkfwumdata.c b/tools/mkfwumdata.c
index 9732a8ddc5a..fbc2067bc12 100644
--- a/tools/mkfwumdata.c
+++ b/tools/mkfwumdata.c
@@ -10,28 +10,35 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
-#include <u-boot/crc.h>
#include <unistd.h>
+#include <generated/autoconf.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <u-boot/crc.h>
#include <uuid/uuid.h>
-/* This will dynamically allocate the fwu_mdata */
-#define CONFIG_FWU_NUM_BANKS 0
-#define CONFIG_FWU_NUM_IMAGES_PER_BANK 0
-
-/* Since we can not include fwu.h, redefine version here. */
-#define FWU_MDATA_VERSION 1
-
typedef uint8_t u8;
typedef int16_t s16;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
-#include <fwu_mdata.h>
+#undef CONFIG_FWU_NUM_BANKS
+#undef CONFIG_FWU_NUM_IMAGES_PER_BANK
-/* TODO: Endianness conversion may be required for some arch. */
+/* 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
-static const char *opts_short = "b:i:a:p:gh";
+#include <fwu_mdata.h>
+
+static const char *opts_short = "b:i:a:p:v:V:gh";
static struct option options[] = {
{"banks", required_argument, NULL, 'b'},
@@ -39,6 +46,8 @@ static struct option options[] = {
{"guid", required_argument, NULL, 'g'},
{"active-bank", required_argument, NULL, 'a'},
{"previous-bank", required_argument, NULL, 'p'},
+ {"version", required_argument, NULL, 'v'},
+ {"vendor-file", required_argument, NULL, 'V'},
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0},
};
@@ -49,9 +58,11 @@ static void print_usage(void)
fprintf(stderr, "Options:\n"
"\t-i, --images <num> Number of images (mandatory)\n"
"\t-b, --banks <num> Number of banks (mandatory)\n"
+ "\t-v, --version Metadata version (mandatory)\n"
"\t-a, --active-bank <num> Active bank (default=0)\n"
"\t-p, --previous-bank <num> Previous active bank (default=active_bank - 1)\n"
"\t-g, --guid Use GUID instead of UUID\n"
+ "\t-V, --vendor-file Vendor data file to append to the metadata\n"
"\t-h, --help print a help message\n"
);
fprintf(stderr, " UUIDs list syntax:\n"
@@ -70,13 +81,28 @@ struct fwu_mdata_object {
size_t images;
size_t banks;
size_t size;
+ u8 version;
+ size_t vsize;
+ void *vbuf;
struct fwu_mdata *mdata;
};
static int previous_bank, active_bank;
static bool __use_guid;
-static struct fwu_mdata_object *fwu_alloc_mdata(size_t images, size_t banks)
+static bool supported_mdata_version(unsigned long version)
+{
+ switch (version) {
+ case 1:
+ case 2:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static struct fwu_mdata_object *fwu_alloc_mdata(size_t images, size_t banks,
+ u8 version, size_t vendor_size)
{
struct fwu_mdata_object *mobj;
@@ -84,19 +110,40 @@ static struct fwu_mdata_object *fwu_alloc_mdata(size_t images, size_t banks)
if (!mobj)
return NULL;
- mobj->size = sizeof(struct fwu_mdata) +
- (sizeof(struct fwu_image_entry) +
- sizeof(struct fwu_image_bank_info) * banks) * images;
+ if (version == 1) {
+ mobj->size = sizeof(struct fwu_mdata) +
+ (sizeof(struct fwu_image_entry) +
+ sizeof(struct fwu_image_bank_info) * banks) * images;
+ } else {
+ mobj->size = sizeof(struct fwu_mdata) +
+ sizeof(struct fwu_fw_store_desc) +
+ (sizeof(struct fwu_image_entry) +
+ sizeof(struct fwu_image_bank_info) * banks) * images;
+
+ mobj->size += vendor_size;
+ mobj->vsize = vendor_size;
+ }
+
mobj->images = images;
mobj->banks = banks;
+ mobj->version = version;
mobj->mdata = calloc(1, mobj->size);
- if (!mobj->mdata) {
- free(mobj);
- return NULL;
+ if (!mobj->mdata)
+ goto alloc_err;
+
+ if (vendor_size) {
+ mobj->vbuf = calloc(1, mobj->vsize);
+ if (!mobj->vbuf)
+ goto alloc_err;
}
return mobj;
+
+alloc_err:
+ free(mobj->mdata);
+ free(mobj);
+ return NULL;
}
static struct fwu_image_entry *
@@ -104,9 +151,18 @@ fwu_get_image(struct fwu_mdata_object *mobj, size_t idx)
{
size_t offset;
- offset = sizeof(struct fwu_mdata) +
- (sizeof(struct fwu_image_entry) +
- sizeof(struct fwu_image_bank_info) * mobj->banks) * idx;
+ 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);
}
@@ -116,11 +172,20 @@ fwu_get_bank(struct fwu_mdata_object *mobj, size_t img_idx, size_t bnk_idx)
{
size_t offset;
- 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;
+ 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);
}
@@ -188,7 +253,7 @@ fwu_parse_fill_image_uuid(struct fwu_mdata_object *mobj,
return -EINVAL;
if (strcmp(uuid, "0") &&
- uuid_guid_parse(uuid, (unsigned char *)&image->location_uuid) < 0)
+ uuid_guid_parse(uuid, (unsigned char *)&image->location_guid) < 0)
return -EINVAL;
/* Image type UUID */
@@ -196,7 +261,7 @@ fwu_parse_fill_image_uuid(struct fwu_mdata_object *mobj,
if (!uuid)
return -EINVAL;
- if (uuid_guid_parse(uuid, (unsigned char *)&image->image_type_uuid) < 0)
+ if (uuid_guid_parse(uuid, (unsigned char *)&image->image_type_guid) < 0)
return -EINVAL;
/* Fill bank image-UUID */
@@ -210,45 +275,118 @@ fwu_parse_fill_image_uuid(struct fwu_mdata_object *mobj,
return -EINVAL;
if (strcmp(uuid, "0") &&
- uuid_guid_parse(uuid, (unsigned char *)&bank->image_uuid) < 0)
+ uuid_guid_parse(uuid, (unsigned char *)&bank->image_guid) < 0)
return -EINVAL;
}
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;
+
+ mdata->metadata_size = mobj->size;
+ mdata->desc_offset = sizeof(struct fwu_mdata);
+
+ for (i = 0; i < MAX_BANKS_V2; i++)
+ mdata->bank_state[i] = i < mobj->banks ?
+ BANK_ACCEPTED : BANK_INVALID;
+
+ fw_desc = (struct fwu_fw_store_desc *)((u8 *)mdata + sizeof(*mdata));
+ fw_desc->num_banks = mobj->banks;
+ fw_desc->num_images = mobj->images;
+ fw_desc->img_entry_size = sizeof(struct fwu_image_entry) +
+ (sizeof(struct fwu_image_bank_info) * mobj->banks);
+ 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[])
{
struct fwu_mdata *mdata = mobj->mdata;
+ char *vdata;
int i, ret;
- mdata->version = FWU_MDATA_VERSION;
+ mdata->version = mobj->version;
mdata->active_index = active_bank;
mdata->previous_active_index = previous_bank;
+ fwu_fill_version_specific_mdata(mobj);
+
for (i = 0; i < mobj->images; i++) {
ret = fwu_parse_fill_image_uuid(mobj, i, uuids[i]);
if (ret < 0)
return ret;
}
+ if (mobj->vsize) {
+ vdata = (char *)mobj->mdata + (mobj->size - mobj->vsize);
+ memcpy(vdata, mobj->vbuf, mobj->vsize);
+ }
+
mdata->crc32 = crc32(0, (const unsigned char *)&mdata->version,
mobj->size - sizeof(uint32_t));
return 0;
}
-static int
-fwu_make_mdata(size_t images, size_t banks, char *uuids[], char *output)
+static int fwu_read_vendor_data(struct fwu_mdata_object *mobj,
+ const char *vendor_file)
+{
+ int ret = 0;
+ FILE *vfile = NULL;
+
+ vfile = fopen(vendor_file, "r");
+ if (!vfile) {
+ ret = -1;
+ goto out;
+ }
+
+ if (fread(mobj->vbuf, 1, mobj->vsize, vfile) != mobj->vsize)
+ ret = -1;
+
+out:
+ fclose(vfile);
+ return ret;
+}
+
+static int fwu_make_mdata(size_t images, size_t banks, u8 version,
+ const char *vendor_file, char *uuids[],
+ char *output)
{
- struct fwu_mdata_object *mobj;
- FILE *file;
int ret;
+ FILE *file;
+ struct stat sbuf;
+ size_t vendor_size = 0;
+ struct fwu_mdata_object *mobj;
+
+ if (vendor_file) {
+ ret = stat(vendor_file, &sbuf);
+ if (ret)
+ return -errno;
- mobj = fwu_alloc_mdata(images, banks);
+ vendor_size = sbuf.st_size;
+ }
+
+ mobj = fwu_alloc_mdata(images, banks, version, vendor_size);
if (!mobj)
return -ENOMEM;
+ if (vendor_file) {
+ ret = fwu_read_vendor_data(mobj, vendor_file);
+ if (ret)
+ goto done_make;
+ }
+
ret = fwu_parse_fill_uuids(mobj, uuids);
if (ret < 0)
goto done_make;
@@ -259,7 +397,7 @@ fwu_make_mdata(size_t images, size_t banks, char *uuids[], char *output)
goto done_make;
}
- ret = fwrite(mobj->mdata, mobj->size, 1, file);
+ ret = fwrite(mobj->mdata, 1, mobj->size, file);
if (ret != mobj->size)
ret = -errno;
else
@@ -269,6 +407,7 @@ fwu_make_mdata(size_t images, size_t banks, char *uuids[], char *output)
done_make:
free(mobj->mdata);
+ free(mobj->vbuf);
free(mobj);
return ret;
@@ -276,13 +415,15 @@ done_make:
int main(int argc, char *argv[])
{
- unsigned long banks = 0, images = 0;
+ unsigned long banks = 0, images = 0, version = 0;
int c, ret;
+ const char *vendor_file;
/* Explicitly initialize defaults */
active_bank = 0;
__use_guid = false;
previous_bank = INT_MAX;
+ vendor_file = NULL;
do {
c = getopt_long(argc, argv, opts_short, options, NULL);
@@ -305,6 +446,12 @@ int main(int argc, char *argv[])
case 'a':
active_bank = strtoul(optarg, NULL, 0);
break;
+ case 'v':
+ version = strtoul(optarg, NULL, 0);
+ break;
+ case 'V':
+ vendor_file = optarg;
+ break;
}
} while (c != -1);
@@ -313,6 +460,17 @@ int main(int argc, char *argv[])
return -EINVAL;
}
+ if (!version || !supported_mdata_version(version)) {
+ fprintf(stderr, "Error: Version value can only be either 1 or 2, not %ld.\n",
+ version);
+ return -EINVAL;
+ }
+
+ if (version == 1 && vendor_file) {
+ fprintf(stderr, "Error: Vendor Data can only be appended in version 2 of FWU Metadata.\n");
+ return -EINVAL;
+ }
+
/* 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");
@@ -325,7 +483,8 @@ int main(int argc, char *argv[])
previous_bank = active_bank > 0 ? active_bank - 1 : banks - 1;
}
- ret = fwu_make_mdata(images, banks, argv + optind, argv[argc - 1]);
+ ret = fwu_make_mdata(images, banks, (u8)version, vendor_file,
+ argv + optind, argv[argc - 1]);
if (ret < 0)
fprintf(stderr, "Error: Failed to parse and write image: %s\n",
strerror(-ret));