aboutsummaryrefslogtreecommitdiff
path: root/drivers/fwu-mdata/fwu-mdata-uclass.c
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2022-11-01 09:32:21 -0400
committerTom Rini <trini@konsulko.com>2022-11-01 09:32:21 -0400
commitc8d9ff634fc429db5acf2f5386ea937f0fef1ae7 (patch)
tree5ee0a5efa73f325b172a16db7551af87725fdb1f /drivers/fwu-mdata/fwu-mdata-uclass.c
parenta90afc6730e6c67ad37f4c98a02891a93b4ff971 (diff)
parent75f11c3bfdcfbadad0265eda74c372e52423ae4c (diff)
Merge branch '2022-10-31-FWU-add-FWU-multi-bank-update-feature-support'
To quote the author: The patchset adds support for the FWU Multi Bank Update[1] feature. Certain aspects of the Dependable Boot[2] specification have also been implemented. The FWU multi bank update feature is used for supporting multiple sets(also called banks) of firmware image(s), allowing the platform to boot from a different bank, in case it fails to boot from the active bank. This functionality is supported by keeping the relevant information in a structure called metadata, which provides information on the images. Among other parameters, the metadata structure contains information on the currect active bank that is being used to boot image(s). Functionality is being added to work with the UEFI capsule driver in u-boot. The metadata is read to gather information on the update bank, which is the bank to which the firmware images would be flashed to. On a successful completion of the update of all components, the active bank field in the metadata is updated, to reflect the bank from which the platform will boot on the subsequent boots. Currently, the feature is being enabled on the STM32MP157C-DK2 and Synquacer boards. The DK2 board boots a FIP image from a uSD card partitioned with the GPT partioning scheme, while the Synquacer board boots a FIP image from a MTD partitioned SPI NOR flash device. This feature also requires changes in a previous stage of bootloader, which parses the metadata and selects the bank to boot the image(s) from. Support has being added in tf-a(BL2 stage) for the STM32MP157C-DK2 board to boot the active bank images. These changes have been merged to the upstream tf-a repository. The patch for adding a python test for the feature has been developed, and was sent in the version 5 of the patches[3]. However, the test script depends on adding support for the feature on MTD SPI NOR devices, and that is being done as part of the Synquacer patches. Hence these set of patches do not have the test script for the feature. That will be added through the patches for adding support for the feauture on Synquacer platform. [1] - https://developer.arm.com/documentation/den0118/a [2] - https://git.codelinaro.org/linaro/dependable-boot/mbfw/uploads/6f7ddfe3be24e18d4319e108a758d02e/mbfw.pdf [3] - https://lists.denx.de/pipermail/u-boot/2022-June/485992.html
Diffstat (limited to 'drivers/fwu-mdata/fwu-mdata-uclass.c')
-rw-r--r--drivers/fwu-mdata/fwu-mdata-uclass.c186
1 files changed, 186 insertions, 0 deletions
diff --git a/drivers/fwu-mdata/fwu-mdata-uclass.c b/drivers/fwu-mdata/fwu-mdata-uclass.c
new file mode 100644
index 0000000000..b477e9603f
--- /dev/null
+++ b/drivers/fwu-mdata/fwu-mdata-uclass.c
@@ -0,0 +1,186 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2022, Linaro Limited
+ */
+
+#define LOG_CATEGORY UCLASS_FWU_MDATA
+
+#include <common.h>
+#include <dm.h>
+#include <efi_loader.h>
+#include <fwu.h>
+#include <fwu_mdata.h>
+#include <log.h>
+
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <u-boot/crc.h>
+
+/**
+ * fwu_get_mdata_part_num() - Get the FWU metadata partition numbers
+ * @dev: FWU metadata device
+ * @mdata_parts: array for storing the metadata partition numbers
+ *
+ * Get the partition numbers on the storage device on which the
+ * FWU metadata is stored. Two partition numbers will be returned.
+ *
+ * Return: 0 if OK, -ve on error
+ *
+ */
+int fwu_get_mdata_part_num(struct udevice *dev, uint *mdata_parts)
+{
+ const struct fwu_mdata_ops *ops = device_get_ops(dev);
+
+ if (!ops->get_mdata_part_num) {
+ log_debug("get_mdata_part_num() method not defined\n");
+ return -ENOSYS;
+ }
+
+ return ops->get_mdata_part_num(dev, mdata_parts);
+}
+
+/**
+ * fwu_read_mdata_partition() - Read the FWU metadata from a partition
+ * @dev: FWU metadata device
+ * @mdata: Copy of the FWU metadata
+ * @part_num: Partition number from which FWU metadata is to be read
+ *
+ * Read the FWU metadata from the specified partition number
+ *
+ * Return: 0 if OK, -ve on error
+ *
+ */
+int fwu_read_mdata_partition(struct udevice *dev, struct fwu_mdata *mdata,
+ uint part_num)
+{
+ const struct fwu_mdata_ops *ops = device_get_ops(dev);
+
+ if (!ops->read_mdata_partition) {
+ log_debug("read_mdata_partition() method not defined\n");
+ return -ENOSYS;
+ }
+
+ return ops->read_mdata_partition(dev, mdata, part_num);
+}
+
+/**
+ * fwu_write_mdata_partition() - Write the FWU metadata to a partition
+ * @dev: FWU metadata device
+ * @mdata: Copy of the FWU metadata
+ * @part_num: Partition number to which FWU metadata is to be written
+ *
+ * Write the FWU metadata to the specified partition number
+ *
+ * Return: 0 if OK, -ve on error
+ *
+ */
+int fwu_write_mdata_partition(struct udevice *dev, struct fwu_mdata *mdata,
+ uint part_num)
+{
+ const struct fwu_mdata_ops *ops = device_get_ops(dev);
+
+ if (!ops->write_mdata_partition) {
+ log_debug("write_mdata_partition() method not defined\n");
+ return -ENOSYS;
+ }
+
+ return ops->write_mdata_partition(dev, mdata, part_num);
+}
+
+/**
+ * fwu_mdata_check() - Check if the FWU metadata is valid
+ * @dev: FWU metadata device
+ *
+ * Validate both copies of the FWU metadata. If one of the copies
+ * has gone bad, restore it from the other copy.
+ *
+ * Return: 0 if OK, -ve on error
+ *
+ */
+int fwu_mdata_check(struct udevice *dev)
+{
+ const struct fwu_mdata_ops *ops = device_get_ops(dev);
+
+ if (!ops->check_mdata) {
+ log_debug("check_mdata() method not defined\n");
+ return -ENOSYS;
+ }
+
+ return ops->check_mdata(dev);
+}
+
+/**
+ * fwu_get_mdata() - Get a FWU metadata copy
+ * @dev: FWU metadata device
+ * @mdata: Copy of the FWU metadata
+ *
+ * Get a valid copy of the FWU metadata.
+ *
+ * Note: This function is to be called first when modifying any fields
+ * in the metadata. The sequence of calls to modify any field in the
+ * metadata would be 1) fwu_get_mdata 2) Modify metadata, followed by
+ * 3) fwu_update_mdata
+ *
+ * Return: 0 if OK, -ve on error
+ *
+ */
+int fwu_get_mdata(struct udevice *dev, struct fwu_mdata *mdata)
+{
+ const struct fwu_mdata_ops *ops = device_get_ops(dev);
+
+ if (!ops->get_mdata) {
+ log_debug("get_mdata() method not defined\n");
+ return -ENOSYS;
+ }
+
+ return ops->get_mdata(dev, mdata);
+}
+
+/**
+ * fwu_update_mdata() - Update the FWU metadata
+ * @dev: FWU metadata device
+ * @mdata: Copy of the FWU metadata
+ *
+ * Update the FWU metadata structure by writing to the
+ * FWU metadata partitions.
+ *
+ * Note: This function is not to be called directly to update the
+ * metadata fields. The sequence of function calls should be
+ * 1) fwu_get_mdata() 2) Modify the medata fields 3) fwu_update_mdata()
+ *
+ * The sequence of updating the partitions should be, update the
+ * primary metadata partition (first partition encountered), followed
+ * by updating the secondary partition. With this update sequence, in
+ * the rare scenario that the two metadata partitions are valid but do
+ * not match, maybe due to power outage at the time of updating the
+ * metadata copies, the secondary partition can be updated from the
+ * primary.
+ *
+ * Return: 0 if OK, -ve on error
+ *
+ */
+int fwu_update_mdata(struct udevice *dev, struct fwu_mdata *mdata)
+{
+ void *buf;
+ const struct fwu_mdata_ops *ops = device_get_ops(dev);
+
+ if (!ops->update_mdata) {
+ log_debug("get_mdata() method not defined\n");
+ return -ENOSYS;
+ }
+
+ /*
+ * Calculate the crc32 for the updated FWU metadata
+ * and put the updated value in the FWU metadata crc32
+ * field
+ */
+ buf = &mdata->version;
+ mdata->crc32 = crc32(0, buf, sizeof(*mdata) - sizeof(u32));
+
+ return ops->update_mdata(dev, mdata);
+}
+
+UCLASS_DRIVER(fwu_mdata) = {
+ .id = UCLASS_FWU_MDATA,
+ .name = "fwu-mdata",
+};