From: Abdellatif El Khlifi <[email protected]>

Read the active bank index directly from FWU metadata when setting the
kernel address and size during board_late_init().

Arm PSA FWU does not enable the multi-bank FWU implementation, so its
cached metadata and fwu_plat_get_bootidx() hook are unavailable. Read
and validate the metadata header and CRC through the FWU metadata uclass,
falling back from the primary copy to the secondary, then use the active
index to select the kernel partition.

This keeps Corstone-1000 kernel selection working with the Arm PSA FWU
configuration.

Signed-off-by: Abdellatif El Khlifi <[email protected]>
Signed-off-by: Alex Chapman <[email protected]>
Cc: Tom Rini <[email protected]>
Cc: Hugues Kamba Mpiana <[email protected]>
---
 board/armltd/corstone1000/corstone1000.c | 209 +++++++++++++++++++----
 include/fwu_arm_psa.h                    |  12 ++
 lib/efi_loader/Kconfig                   |   2 +
 3 files changed, 189 insertions(+), 34 deletions(-)

diff --git a/board/armltd/corstone1000/corstone1000.c 
b/board/armltd/corstone1000/corstone1000.c
index b255a0d78ad..084c9bfff63 100644
--- a/board/armltd/corstone1000/corstone1000.c
+++ b/board/armltd/corstone1000/corstone1000.c
@@ -11,14 +11,16 @@
 #include <generated/dt.h>
 #include <env.h>
 #include <efi_loader.h>
-#include <fwu.h>
 #include <fwu_arm_psa.h>
+#include <fwu_mdata.h>
+#include <u-boot/crc.h>
 #include <netdev.h>
 #include <nvmxip.h>
 #include <part.h>
 #include <dm/platform_data/serial_pl01x.h>
 #include <asm/armv8/mmu.h>
 #include <asm/global_data.h>
+#include <stdlib.h>
 
 #define CORSTONE1000_KERNEL_PARTS 2
 #define CORSTONE1000_KERNEL_PRIMARY "kernel_primary"
@@ -29,6 +31,9 @@
 /* The total number of upgradable images including the start and end dummy 
payloads */
 #define CAPSULE_PAYLOADS_MAX_COUNT (CONFIG_FWU_NUM_IMAGES_PER_BANK + 2)
 
+#define FWU_MDATA_VERSION      0x2U
+#define FWU_MDATA_MAX_SIZE     720
+
 /*
  * GUIDs for capsule updatable firmware images
  *
@@ -151,8 +156,6 @@ struct efi_capsule_update_info update_info = {
 
 #endif /* EFI_HAVE_CAPSULE_SUPPORT */
 
-static int corstone1000_boot_idx;
-
 static struct mm_region corstone1000_mem_map[] = {
        {
                /* CVM */
@@ -232,46 +235,38 @@ int dram_init_banksize(void)
        return 0;
 }
 
-void fwu_plat_get_bootidx(uint *boot_idx)
-{
-       int ret;
-
-       /*
-        * in our platform, the Secure Enclave is the one who controls
-        * all the boot tries and status, so, every time we get here
-        * we know that the we are booting from the active index
-        */
-       ret = fwu_get_active_index(boot_idx);
-       if (ret < 0) {
-               *boot_idx = CONFIG_FWU_NUM_BANKS;
-               log_err("corstone1000: failed to read active index\n");
-       }
-}
-
-int board_late_init(void)
+static void corstone1000_setup_kernel_env(void)
 {
        struct disk_partition part_info;
        struct udevice *dev, *bdev;
        struct nvmxip_plat *plat;
        struct blk_desc *desc;
+       u32 active_idx;
        int ret;
+       bool kernel_addr_set, kernel_size_set;
 
        ret = uclass_first_device_err(UCLASS_NVMXIP, &dev);
        if (ret < 0) {
-               log_err("Cannot find kernel device\n");
-               return ret;
+               log_err("Cannot find kernel device, err (%d)\n", ret);
+               return;
        }
 
        plat = dev_get_plat(dev);
        device_find_first_child(dev, &bdev);
        desc = dev_get_uclass_plat(bdev);
-       ret = fwu_get_active_index(&corstone1000_boot_idx);
+       ret = fwu_plat_get_active_index(&active_idx);
        if (ret < 0) {
-               log_err("corstone1000: failed to read boot index\n");
-               return ret;
+               log_err("corstone1000: failed to read boot index, err (%d)\n", 
ret);
+               return;
        }
 
-       if (!corstone1000_boot_idx)
+       kernel_addr_set = env_get_hex("kernel_addr", 0) ? true : false;
+       kernel_size_set = env_get_hex("kernel_size", 0) ? true : false;
+
+       if (kernel_addr_set && kernel_size_set)
+               return;
+
+       if (!active_idx)
                ret = part_get_info_by_name(desc, CORSTONE1000_KERNEL_PRIMARY,
                                            &part_info);
        else
@@ -280,18 +275,164 @@ int board_late_init(void)
 
        if (ret < 0) {
                log_err("failed to fetch kernel partition index: %d\n",
-                       corstone1000_boot_idx);
-               return ret;
+                       active_idx);
+               return;
+       }
+
+       if (!kernel_addr_set) {
+               ret = env_set_hex("kernel_addr", plat->phys_base +
+                               (part_info.start * part_info.blksz));
+               if (ret)
+                       log_err("cannot set kernel_addr variable, err (%d)\n",
+                               ret);
+       }
+
+       if (!kernel_size_set) {
+               ret = env_set_hex("kernel_size",
+                                 part_info.size * part_info.blksz);
+               if (ret)
+                       log_err("cannot set kernel_size variable, err (%d)\n",
+                               ret);
+       }
+}
+
+/**
+ * fwu_read_mdata() - Wrapper around fwu_mdata_ops.read_mdata()
+ *
+ * @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 fwu_read_mdata(struct udevice *dev, struct fwu_mdata *mdata,
+                  bool primary, uint32_t size);
+
+/**
+ * corstone1000_mdata_crc_check() - Verify CRC32 of FWU metadata
+ *
+ * @mdata: FWU metadata information
+ *
+ * Calculate the crc32 of the metadata and compare it to the FWU
+ * metadata crc32 field.
+ *
+ * Return: EFI_SUCCESS on success. Otherwise, failure.
+ */
+static int corstone1000_mdata_crc_check(struct fwu_mdata *mdata)
+{
+       u32 calc_crc32;
+       void *buf = &mdata->version;
+       u32 mdata_size = mdata->metadata_size;
+
+       calc_crc32 = crc32(0, buf, mdata_size - sizeof(u32));
+
+       return calc_crc32 == mdata->crc32 ? EFI_SUCCESS : -EINVAL;
+}
+
+/**
+ * corstone1000_read_active_index() - Read active index from metadata storage 
media
+ *
+ * @primary:   Primary or secondary metadata partition
+ * @active_idx:        Active index value
+ *
+ * Read the selected metadata partition, perform basic verification, and return
+ * the active index.
+ *
+ * Return: EFI_SUCCESS on success. Otherwise, failure.
+ */
+static int corstone1000_read_active_index(bool primary,
+                                                  uint *active_idx)
+{
+       struct fwu_mdata *mdata_full = NULL;
+       struct fwu_mdata mdata;
+       struct udevice *dev;
+       int ret;
+
+       ret = uclass_first_device_err(UCLASS_FWU_MDATA, &dev);
+       if (ret)
+               goto fail;
+
+       // Read metadata header, get length
+       ret = fwu_read_mdata(dev, &mdata, primary, sizeof(struct fwu_mdata));
+       if (ret)
+               goto fail;
+
+       if (mdata.version != FWU_MDATA_VERSION) {
+               log_err("FWU partition %s has metadata version %u. Expected 
value of %u\n",
+                       primary ? "Primary" : "Secondary", mdata.version, 
FWU_MDATA_VERSION);
+               ret = -EINVAL;
+               goto fail;
        }
 
-       ret = 0;
+       if (mdata.metadata_size > FWU_MDATA_MAX_SIZE) {
+               log_err("FWU partition %s has metadata size too large %u. Max 
size %u\n",
+                       primary ? "Primary" : "Secondary", mdata.metadata_size, 
FWU_MDATA_MAX_SIZE);
+               ret = -EINVAL;
+               goto fail;
+       }
 
-       ret |= env_set_hex("kernel_addr", plat->phys_base +
-                          (part_info.start * part_info.blksz));
-       ret |= env_set_hex("kernel_size", part_info.size * part_info.blksz);
+       // Read full metadata
+       mdata_full = calloc(1, mdata.metadata_size);
+       if (!mdata_full) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       ret = fwu_read_mdata(dev, mdata_full, primary, mdata.metadata_size);
+       if (ret)
+               goto fail;
+
+       ret = corstone1000_mdata_crc_check(mdata_full);
+       if (ret)
+               goto fail;
+
+       if (mdata_full->active_index >= CONFIG_FWU_NUM_BANKS) {
+               log_err("Active Index(%u) in the FWU partition %s is larger 
than the number of configured banks\n",
+                       mdata_full->active_index,
+                       primary ? "Primary" : "Secondary");
+               ret = -EINVAL;
+               goto fail;
+       }
+
+       *active_idx = mdata_full->active_index;
+       ret = EFI_SUCCESS;
 
-       if (ret < 0)
-               log_err("failed to setup kernel addr and size\n");
+fail:
+       if (mdata_full)
+               free(mdata_full);
 
        return ret;
 }
+
+/**
+ * fwu_plat_get_active_index() - Get the value of the active index
+ *
+ * @active_idx:        Active index value
+ *
+ * Read the active index from the primary metadata copy, falling back to the
+ * secondary on read failure.
+ *
+ * Return: EFI_SUCCESS on success. Otherwise, failure.
+ */
+int fwu_plat_get_active_index(uint *active_idx)
+{
+       int ret;
+
+       if (!active_idx) {
+               log_err("!active_idx\n");
+               return -EINVAL;
+       }
+
+       ret = corstone1000_read_active_index(true, active_idx);
+       if (ret != EFI_SUCCESS)
+               ret = corstone1000_read_active_index(false, active_idx);
+
+       return ret;
+}
+
+int board_late_init(void)
+{
+       corstone1000_setup_kernel_env();
+       return 0;
+}
diff --git a/include/fwu_arm_psa.h b/include/fwu_arm_psa.h
index 9fb5f87ac6c..2b0501f39fe 100644
--- a/include/fwu_arm_psa.h
+++ b/include/fwu_arm_psa.h
@@ -397,6 +397,18 @@ int fwu_agent_init(void);
  */
 int fwu_update_image(const void *image, u8 image_index, u32 image_size);
 
+/**
+ * fwu_plat_get_active_index() - Get the value of the active index
+ *
+ * @active_idx:        Active index value
+ *
+ * Read the active index from the primary metadata copy, falling back to the
+ * secondary on read failure.
+ *
+ * Return: EFI_SUCCESS on success. Otherwise, failure.
+ */
+int fwu_plat_get_active_index(u32 *active_idx);
+
 /**
  * fwu_get_payload_type() - Identifies the payload type
  * @image_index:       The payload index
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index f01889fd6d3..273b135553e 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -376,6 +376,8 @@ config FWU_ARM_PSA
                !FWU_MULTI_BANK_UPDATE
        select EFI_CAPSULE_FIRMWARE
        select EFI_PARTITION
+       select FWU_MDATA
+       select PARTITION_TYPE_GUID
        imply EFI_CAPSULE_ON_DISK_EARLY
        help
          Select this option if you want to enable firmware management protocol
-- 
2.43.0

Reply via email to