Merge changes from topic "gpt_updates" into integration

* changes:
  refactor(arm): use gpt_partition_init
  feat(partition): add interface to init gpt
  refactor(partition): convert warn to verbose
  feat(partition): add support to use backup GPT header
  refactor(partition): get GPT header location from MBR
  feat(arm): add IO policy to use backup gpt header
  feat(tbbr): add image id for backup GPT
diff --git a/drivers/partition/partition.c b/drivers/partition/partition.c
index 1881c91..c60820d 100644
--- a/drivers/partition/partition.c
+++ b/drivers/partition/partition.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2023, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -49,30 +49,43 @@
 static int load_mbr_header(uintptr_t image_handle, mbr_entry_t *mbr_entry)
 {
 	size_t bytes_read;
-	uintptr_t offset;
 	int result;
+	mbr_entry_t *tmp;
 
 	assert(mbr_entry != NULL);
 	/* MBR partition table is in LBA0. */
 	result = io_seek(image_handle, IO_SEEK_SET, MBR_OFFSET);
 	if (result != 0) {
-		WARN("Failed to seek (%i)\n", result);
+		VERBOSE("Failed to seek (%i)\n", result);
 		return result;
 	}
 	result = io_read(image_handle, (uintptr_t)&mbr_sector,
 			 PLAT_PARTITION_BLOCK_SIZE, &bytes_read);
-	if (result != 0) {
-		WARN("Failed to read data (%i)\n", result);
+	if ((result != 0) || (bytes_read != PLAT_PARTITION_BLOCK_SIZE)) {
+		VERBOSE("Failed to read data (%i)\n", result);
 		return result;
 	}
 
 	/* Check MBR boot signature. */
 	if ((mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) ||
 	    (mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) {
+		VERBOSE("MBR boot signature failure\n");
 		return -ENOENT;
 	}
-	offset = (uintptr_t)&mbr_sector + MBR_PRIMARY_ENTRY_OFFSET;
-	memcpy(mbr_entry, (void *)offset, sizeof(mbr_entry_t));
+
+	tmp = (mbr_entry_t *)(&mbr_sector[MBR_PRIMARY_ENTRY_OFFSET]);
+
+	if (tmp->first_lba != 1) {
+		VERBOSE("MBR header may have an invalid first LBA\n");
+		return -EINVAL;
+	}
+
+	if ((tmp->sector_nums == 0) || (tmp->sector_nums == UINT32_MAX)) {
+		VERBOSE("MBR header entry has an invalid number of sectors\n");
+		return -EINVAL;
+	}
+
+	memcpy(mbr_entry, tmp, sizeof(mbr_entry_t));
 	return 0;
 }
 
@@ -80,24 +93,31 @@
  * Load GPT header and check the GPT signature and header CRC.
  * If partition numbers could be found, check & update it.
  */
-static int load_gpt_header(uintptr_t image_handle)
+static int load_gpt_header(uintptr_t image_handle, size_t header_offset,
+			   unsigned long long *part_lba)
 {
 	gpt_header_t header;
 	size_t bytes_read;
 	int result;
 	uint32_t header_crc, calc_crc;
 
-	result = io_seek(image_handle, IO_SEEK_SET, GPT_HEADER_OFFSET);
+	result = io_seek(image_handle, IO_SEEK_SET, header_offset);
 	if (result != 0) {
+		VERBOSE("Failed to seek into the GPT image at offset (%zu)\n",
+			header_offset);
 		return result;
 	}
 	result = io_read(image_handle, (uintptr_t)&header,
 			 sizeof(gpt_header_t), &bytes_read);
 	if ((result != 0) || (sizeof(gpt_header_t) != bytes_read)) {
+		VERBOSE("GPT header read error(%i) or read mismatch occurred,"
+			"expected(%zu) and actual(%zu)\n", result,
+			sizeof(gpt_header_t), bytes_read);
 		return result;
 	}
 	if (memcmp(header.signature, GPT_SIGNATURE,
-		   sizeof(header.signature)) != 0) {
+			   sizeof(header.signature)) != 0) {
+		VERBOSE("GPT header signature failure\n");
 		return -EINVAL;
 	}
 
@@ -109,7 +129,7 @@
 	header_crc = header.header_crc;
 	header.header_crc = 0U;
 
-	calc_crc = tf_crc32(0U, (uint8_t *)&header, DEFAULT_GPT_HEADER_SIZE);
+	calc_crc = tf_crc32(0U, (uint8_t *)&header, sizeof(gpt_header_t));
 	if (header_crc != calc_crc) {
 		ERROR("Invalid GPT Header CRC: Expected 0x%x but got 0x%x.\n",
 		      header_crc, calc_crc);
@@ -123,11 +143,16 @@
 	if (list.entry_count > PLAT_PARTITION_MAX_ENTRIES) {
 		list.entry_count = PLAT_PARTITION_MAX_ENTRIES;
 	}
+
+	*part_lba = header.part_lba;
 	return 0;
 }
 
+/*
+ * Load a single MBR entry based on details from MBR header.
+ */
 static int load_mbr_entry(uintptr_t image_handle, mbr_entry_t *mbr_entry,
-			int part_number)
+			  int part_number)
 {
 	size_t bytes_read;
 	uintptr_t offset;
@@ -137,19 +162,20 @@
 	/* MBR partition table is in LBA0. */
 	result = io_seek(image_handle, IO_SEEK_SET, MBR_OFFSET);
 	if (result != 0) {
-		WARN("Failed to seek (%i)\n", result);
+		VERBOSE("Failed to seek (%i)\n", result);
 		return result;
 	}
 	result = io_read(image_handle, (uintptr_t)&mbr_sector,
 			 PLAT_PARTITION_BLOCK_SIZE, &bytes_read);
 	if (result != 0) {
-		WARN("Failed to read data (%i)\n", result);
+		VERBOSE("Failed to read data (%i)\n", result);
 		return result;
 	}
 
 	/* Check MBR boot signature. */
 	if ((mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) ||
 	    (mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) {
+		VERBOSE("MBR Entry boot signature failure\n");
 		return -ENOENT;
 	}
 	offset = (uintptr_t)&mbr_sector +
@@ -160,6 +186,9 @@
 	return 0;
 }
 
+/*
+ * Load MBR entries based on max number of partition entries.
+ */
 static int load_mbr_entries(uintptr_t image_handle)
 {
 	mbr_entry_t mbr_entry;
@@ -177,33 +206,60 @@
 	return 0;
 }
 
+/*
+ * Try to read and load a single GPT entry.
+ */
 static int load_gpt_entry(uintptr_t image_handle, gpt_entry_t *entry)
 {
-	size_t bytes_read;
+	size_t bytes_read = 0U;
 	int result;
 
 	assert(entry != NULL);
 	result = io_read(image_handle, (uintptr_t)entry, sizeof(gpt_entry_t),
-			 &bytes_read);
-	if (sizeof(gpt_entry_t) != bytes_read)
+			&bytes_read);
+	if ((result != 0) || (sizeof(gpt_entry_t) != bytes_read)) {
+		VERBOSE("GPT Entry read error(%i) or read mismatch occurred,"
+			"expected(%zu) and actual(%zu)\n", result,
+			sizeof(gpt_entry_t), bytes_read);
 		return -EINVAL;
+	}
+
 	return result;
 }
 
-static int verify_partition_gpt(uintptr_t image_handle)
+/*
+ * Retrieve each entry in the partition table, parse the data from each
+ * entry and store them in the list of partition table entries.
+ */
+static int load_partition_gpt(uintptr_t image_handle,
+			      unsigned long long part_lba)
 {
+	const signed long long gpt_entry_offset = LBA(part_lba);
 	gpt_entry_t entry;
 	int result, i;
 
+	result = io_seek(image_handle, IO_SEEK_SET, gpt_entry_offset);
+	if (result != 0) {
+		VERBOSE("Failed to seek (%i), Failed loading GPT partition"
+			"table entries\n", result);
+		return result;
+	}
+
 	for (i = 0; i < list.entry_count; i++) {
 		result = load_gpt_entry(image_handle, &entry);
-		assert(result == 0);
+		if (result != 0) {
+			VERBOSE("Failed to load gpt entry data(%i) error is (%i)\n",
+				i, result);
+			return result;
+		}
+
 		result = parse_gpt_entry(&entry, &list.list[i]);
 		if (result != 0) {
 			break;
 		}
 	}
 	if (i == 0) {
+		VERBOSE("No Valid GPT Entries found\n");
 		return -EINVAL;
 	}
 	/*
@@ -216,6 +272,94 @@
 	return 0;
 }
 
+/*
+ * Try retrieving and parsing the backup-GPT header and backup GPT entries.
+ * Last 33 blocks contains the backup-GPT entries and header.
+ */
+static int load_backup_gpt(unsigned int image_id, unsigned int sector_nums)
+{
+	int result;
+	unsigned long long part_lba = 0;
+	size_t gpt_header_offset;
+	uintptr_t dev_handle, image_spec, image_handle;
+	io_block_spec_t *block_spec;
+	int part_num_entries;
+
+	result = plat_get_image_source(image_id, &dev_handle, &image_spec);
+	if (result != 0) {
+		VERBOSE("Failed to obtain reference to image id=%u (%i)\n",
+			image_id, result);
+		return result;
+	}
+
+	block_spec = (io_block_spec_t *)image_spec;
+	/*
+	 * We need to read 32 blocks of GPT entries and one block of GPT header
+	 * try mapping only last 33 last blocks from the image to read the
+	 * Backup-GPT header and its entries.
+	 */
+	part_num_entries = (PLAT_PARTITION_MAX_ENTRIES / 4);
+	/* Move the offset base to LBA-33 */
+	block_spec->offset += LBA(sector_nums - part_num_entries);
+	/*
+	 * Set length as LBA-33, 32 blocks of backup-GPT entries and one
+	 * block of backup-GPT header.
+	 */
+	block_spec->length = LBA(part_num_entries + 1);
+
+	result = io_open(dev_handle, image_spec, &image_handle);
+	if (result != 0) {
+		VERBOSE("Failed to access image id (%i)\n", result);
+		return result;
+	}
+
+	INFO("Trying to retrieve back-up GPT header\n");
+	/* Last block is backup-GPT header, after the end of GPT entries */
+	gpt_header_offset = LBA(part_num_entries);
+	result = load_gpt_header(image_handle, gpt_header_offset, &part_lba);
+	if ((result != 0) || (part_lba == 0)) {
+		ERROR("Failed to retrieve Backup GPT header,"
+		      "Partition maybe corrupted\n");
+		goto out;
+	}
+
+	/*
+	 * Note we mapped last 33 blocks(LBA-33), first block here starts with
+	 * entries while last block was header.
+	 */
+	result = load_partition_gpt(image_handle, 0);
+
+out:
+	io_close(image_handle);
+	return result;
+}
+
+/*
+ * Load a GPT partition, Try retrieving and parsing the primary GPT header,
+ * if its corrupted try loading backup GPT header and then retrieve list
+ * of partition table entries found from the GPT.
+ */
+static int load_primary_gpt(uintptr_t image_handle, unsigned int first_lba)
+{
+	int result;
+	unsigned long long part_lba;
+	size_t gpt_header_offset;
+
+	/* Try to load Primary GPT header from LBA1 */
+	gpt_header_offset = LBA(first_lba);
+	result = load_gpt_header(image_handle, gpt_header_offset, &part_lba);
+	if ((result != 0) || (part_lba == 0)) {
+		VERBOSE("Failed to retrieve Primary GPT header,"
+			"trying to retrieve back-up GPT header\n");
+		return result;
+	}
+
+	return load_partition_gpt(image_handle, part_lba);
+}
+
+/*
+ * Load the partition table info based on the image id provided.
+ */
 int load_partition_table(unsigned int image_id)
 {
 	uintptr_t dev_handle, image_handle, image_spec = 0;
@@ -224,36 +368,41 @@
 
 	result = plat_get_image_source(image_id, &dev_handle, &image_spec);
 	if (result != 0) {
-		WARN("Failed to obtain reference to image id=%u (%i)\n",
+		VERBOSE("Failed to obtain reference to image id=%u (%i)\n",
 			image_id, result);
 		return result;
 	}
 
 	result = io_open(dev_handle, image_spec, &image_handle);
 	if (result != 0) {
-		WARN("Failed to access image id=%u (%i)\n", image_id, result);
+		VERBOSE("Failed to access image id=%u (%i)\n", image_id, result);
 		return result;
 	}
 
 	result = load_mbr_header(image_handle, &mbr_entry);
 	if (result != 0) {
-		WARN("Failed to access image id=%u (%i)\n", image_id, result);
-		return result;
+		VERBOSE("Failed to access image id=%u (%i)\n", image_id, result);
+		goto out;
 	}
 	if (mbr_entry.type == PARTITION_TYPE_GPT) {
-		result = load_gpt_header(image_handle);
-		assert(result == 0);
-		result = io_seek(image_handle, IO_SEEK_SET, GPT_ENTRY_OFFSET);
-		assert(result == 0);
-		result = verify_partition_gpt(image_handle);
+		result = load_primary_gpt(image_handle, mbr_entry.first_lba);
+		if (result != 0) {
+			io_close(image_handle);
+			return load_backup_gpt(BKUP_GPT_IMAGE_ID,
+					       mbr_entry.sector_nums);
+		}
 	} else {
 		result = load_mbr_entries(image_handle);
 	}
 
+out:
 	io_close(image_handle);
 	return result;
 }
 
+/*
+ * Try retrieving a partition table entry based on the name of the partition.
+ */
 const partition_entry_t *get_partition_entry(const char *name)
 {
 	int i;
@@ -266,6 +415,9 @@
 	return NULL;
 }
 
+/*
+ * Try retrieving a partition table entry based on the GUID.
+ */
 const partition_entry_t *get_partition_entry_by_type(const uuid_t *type_uuid)
 {
 	int i;
@@ -279,6 +431,9 @@
 	return NULL;
 }
 
+/*
+ * Try retrieving a partition table entry based on the UUID.
+ */
 const partition_entry_t *get_partition_entry_by_uuid(const uuid_t *part_uuid)
 {
 	int i;
@@ -292,12 +447,32 @@
 	return NULL;
 }
 
+/*
+ * Return entry to the list of partition table entries.
+ */
 const partition_entry_list_t *get_partition_entry_list(void)
 {
 	return &list;
 }
 
+/*
+ * Try loading partition table info for the given image ID.
+ */
 void partition_init(unsigned int image_id)
 {
+	int ret;
+
+	ret = load_partition_table(image_id);
+	if (ret != 0) {
+		ERROR("Failed to parse partition with image id = %u\n",
+		      image_id);
+	}
+}
+
+/*
+ * Load a GPT based image.
+ */
+int gpt_partition_init(void)
+{
-	load_partition_table(image_id);
+	return load_partition_table(GPT_IMAGE_ID);
 }
diff --git a/include/drivers/partition/gpt.h b/include/drivers/partition/gpt.h
index c2a229e..383c17d 100644
--- a/include/drivers/partition/gpt.h
+++ b/include/drivers/partition/gpt.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2023, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -12,10 +12,6 @@
 #include <tools_share/uuid.h>
 
 #define PARTITION_TYPE_GPT		0xee
-#define GPT_HEADER_OFFSET		PLAT_PARTITION_BLOCK_SIZE
-#define GPT_ENTRY_OFFSET		(GPT_HEADER_OFFSET +		\
-					 PLAT_PARTITION_BLOCK_SIZE)
-
 #define GPT_SIGNATURE			"EFI PART"
 
 typedef struct gpt_entry {
@@ -45,7 +41,7 @@
 	/* size of a single partition entry (usually 128) */
 	unsigned int		part_size;
 	unsigned int		part_crc;
-} gpt_header_t;
+} __packed gpt_header_t;
 
 int parse_gpt_entry(gpt_entry_t *gpt_entry, partition_entry_t *entry);
 
diff --git a/include/drivers/partition/partition.h b/include/drivers/partition/partition.h
index 6cb59c3..d567d4c 100644
--- a/include/drivers/partition/partition.h
+++ b/include/drivers/partition/partition.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2023, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -29,7 +29,7 @@
 
 #define LEGACY_PARTITION_BLOCK_SIZE	512
 
-#define DEFAULT_GPT_HEADER_SIZE 	92
+#define LBA(n) ((unsigned long long)(n) * PLAT_PARTITION_BLOCK_SIZE)
 
 typedef struct partition_entry {
 	uint64_t		start;
@@ -50,5 +50,6 @@
 const partition_entry_t *get_partition_entry_by_uuid(const uuid_t *part_uuid);
 const partition_entry_list_t *get_partition_entry_list(void);
 void partition_init(unsigned int image_id);
+int gpt_partition_init(void);
 
 #endif /* PARTITION_H */
diff --git a/include/export/common/tbbr/tbbr_img_def_exp.h b/include/export/common/tbbr/tbbr_img_def_exp.h
index 98a0099..ce17b4a 100644
--- a/include/export/common/tbbr/tbbr_img_def_exp.h
+++ b/include/export/common/tbbr/tbbr_img_def_exp.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019-2023, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -79,41 +79,44 @@
 /* NT_FW_CONFIG */
 #define NT_FW_CONFIG_ID			U(27)
 
-/* GPT Partition */
+/* GPT primary header and entries */
 #define GPT_IMAGE_ID			U(28)
 
+/* GPT backup header and entries */
+#define BKUP_GPT_IMAGE_ID		U(29)
+
 /* Binary with STM32 header */
-#define STM32_IMAGE_ID			U(29)
+#define STM32_IMAGE_ID			U(30)
 
 /* Encrypted image identifier */
-#define ENC_IMAGE_ID			U(30)
+#define ENC_IMAGE_ID			U(31)
 
 /* FW_CONFIG */
-#define FW_CONFIG_ID			U(31)
+#define FW_CONFIG_ID			U(32)
 
 /*
  * Primary FWU metadata image ID
  */
-#define FWU_METADATA_IMAGE_ID		U(32)
+#define FWU_METADATA_IMAGE_ID		U(33)
 
 /*
  * Backup FWU metadata image ID
  */
-#define BKUP_FWU_METADATA_IMAGE_ID	U(33)
+#define BKUP_FWU_METADATA_IMAGE_ID	U(34)
 
 /* Realm Monitor Manager (RMM) */
-#define RMM_IMAGE_ID			U(34)
+#define RMM_IMAGE_ID			U(35)
 
 /* CCA Content Certificate ID */
-#define CCA_CONTENT_CERT_ID		U(35)
+#define CCA_CONTENT_CERT_ID		U(36)
 
 /* Core SWD Key Certificate ID */
-#define CORE_SWD_KEY_CERT_ID		U(36)
+#define CORE_SWD_KEY_CERT_ID		U(37)
 
 /* Platform Key Certificate ID */
-#define PLAT_KEY_CERT_ID		U(37)
+#define PLAT_KEY_CERT_ID		U(38)
 
 /* Max Images */
-#define MAX_IMAGE_IDS			U(38)
+#define MAX_IMAGE_IDS			U(39)
 
 #endif /* ARM_TRUSTED_FIRMWARE_EXPORT_COMMON_TBBR_TBBR_IMG_DEF_EXP_H */
diff --git a/plat/arm/common/arm_bl2_setup.c b/plat/arm/common/arm_bl2_setup.c
index b142b62..6f3d0e9 100644
--- a/plat/arm/common/arm_bl2_setup.c
+++ b/plat/arm/common/arm_bl2_setup.c
@@ -69,6 +69,8 @@
 void arm_bl2_early_platform_setup(uintptr_t fw_config,
 				  struct meminfo *mem_layout)
 {
+	int __maybe_unused ret;
+
 	/* Initialize the console to provide early debug support */
 	arm_console_boot_init();
 
@@ -82,9 +84,13 @@
 
 	/* Load partition table */
 #if ARM_GPT_SUPPORT
-	partition_init(GPT_IMAGE_ID);
-#endif /* ARM_GPT_SUPPORT */
+	ret = gpt_partition_init();
+	if (ret != 0) {
+		ERROR("GPT partition initialisation failed!\n");
+		panic();
+	}
 
+#endif /* ARM_GPT_SUPPORT */
 }
 
 void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3)
diff --git a/plat/arm/common/fconf/arm_fconf_io.c b/plat/arm/common/fconf/arm_fconf_io.c
index 27acc3a..07f6a82 100644
--- a/plat/arm/common/fconf/arm_fconf_io.c
+++ b/plat/arm/common/fconf/arm_fconf_io.c
@@ -45,10 +45,21 @@
 	 * each sector has 4 partition entries, and there are
 	 * 2 reserved sectors i.e. protective MBR and primary
 	 * GPT header hence length gets calculated as,
-	 * length = 512 * (128/4 + 2)
+	 * length = PLAT_PARTITION_BLOCK_SIZE * (128/4 + 2)
 	 */
-	.length         = PLAT_PARTITION_BLOCK_SIZE *
-			  (PLAT_PARTITION_MAX_ENTRIES / 4 + 2),
+	.length         = LBA(PLAT_PARTITION_MAX_ENTRIES / 4 + 2),
+};
+
+/*
+ * length will be assigned at runtime based on MBR header data.
+ * Backup GPT Header is present in Last LBA-1 and its entries
+ * are last 32 blocks starts at LBA-33, On runtime update these
+ * before device usage. Update offset to beginning LBA-33 and
+ * length to LBA-33.
+ */
+static io_block_spec_t bkup_gpt_spec = {
+	.offset         = PLAT_ARM_FLASH_IMAGE_BASE,
+	.length         = 0,
 };
 #endif /* ARM_GPT_SUPPORT */
 
@@ -107,6 +118,11 @@
 		(uintptr_t)&gpt_spec,
 		open_memmap
 	},
+	[BKUP_GPT_IMAGE_ID] = {
+		&memmap_dev_handle,
+		(uintptr_t)&bkup_gpt_spec,
+		open_memmap
+	},
 #endif /* ARM_GPT_SUPPORT */
 #if PSA_FWU_SUPPORT
 	[FWU_METADATA_IMAGE_ID] = {