[PATCH 5/6] partitions: gpt: fix GPT restauration from alternate GPT

Sascha Hauer s.hauer at pengutronix.de
Wed Dec 3 07:19:09 PST 2025


We read GPT headers from the device and store it in epd->gpt. When
writing a partition table we assume that epd->gpt is read from
the primary GPT header: We only adjust the partition_entry_lba for
the alternate header. This assumption is wrong, in case the primary
GPT header is corrupted epd->gpt could also come from the alternate
GPT header. When this happens we have to set partition_entry_lba
correctly for the primary GPT header as well.

Unfortunately this is not trivial. While we could just use LBA2 for
the partition entries, this might overwrite a bootloader stored there (see
[1]). Instead the following logic is applied:

When the primary GPT header was good when reading it, keep the partition
table entries where they are. If not, take the first usable LBA and
substract the size we need for the partition entries.

[1] https://lore.barebox.org/20250602-createnv-v1-2-c3239ff875d5@pengutronix.de

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 common/partitions/efi.c | 31 ++++++++++++++++++++++++++++++-
 1 file changed, 30 insertions(+), 1 deletion(-)

diff --git a/common/partitions/efi.c b/common/partitions/efi.c
index 1766f0123353d502065673d02e983e6cdd51b9af..0fd60c9fd0442c3c571c685a5b0b41b8f33db7bd 100644
--- a/common/partitions/efi.c
+++ b/common/partitions/efi.c
@@ -762,7 +762,36 @@ static int __efi_partition_write(struct efi_partition_desc *epd, bool primary)
 
 	if (primary) {
 		my_lba = 1;
-		partition_entry_lba = le64_to_cpu(gpt->partition_entry_lba);
+
+		if (epd->good_pgpt) {
+			/*
+			 * The primary GPT was good, we can just leave the partition
+			 * entries where they are.
+			 */
+			partition_entry_lba = le64_to_cpu(gpt->partition_entry_lba);
+		} else {
+			/*
+			 * The primary GPT was bad. When this is not a new partition
+			 * table, but instead read from the disk, the header is from the
+			 * alternate GPT, meaning the partition_entry_lba also points
+			 * to the alternate partitions. We have to find a place for the
+			 * primary partition entries in this case. We could store them
+			 * right after the GPT header, but this might destroy a bootloader
+			 * stored there. Instead, substract the size we need from the
+			 * first usable LBA.
+			 */
+			uint64_t first_usable_lba;
+
+			first_usable_lba = le64_to_cpu(gpt->first_usable_lba);
+
+			if (first_usable_lba < 32 + 1 + 1) {
+				pr_err("First usable LBA is %llu which doesn't leave "
+				       "enough space for partition entries\n",
+					first_usable_lba);
+				return -EINVAL;
+			}
+			partition_entry_lba = first_usable_lba - 32;
+		}
 		gpt->alternate_lba = cpu_to_le64(last_lba(blk));
 	} else {
 		my_lba = last_lba(blk);

-- 
2.47.3




More information about the barebox mailing list