]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
boot: Split out read_gpt_entries()
authorDaan De Meyer <daan@amutable.com>
Mon, 30 Mar 2026 19:20:46 +0000 (21:20 +0200)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Sat, 4 Apr 2026 18:03:44 +0000 (20:03 +0200)
src/boot/part-discovery.c

index 60959d4f78453eb5e2162f24dc2b6faa28c22426..cafc3aa3e71527068b48f5b4d0cf4d06ef2ac672 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "device-path-util.h"
+#include "efi-log.h"
 #include "part-discovery.h"
 #include "proto/block-io.h"
 #include "proto/device-path.h"
@@ -71,14 +72,14 @@ static bool verify_gpt(/* const */ GptHeader *h, EFI_LBA lba_expected) {
         return true;
 }
 
-static EFI_STATUS try_gpt(
-                const EFI_GUID *type,
+static EFI_STATUS read_gpt_entries(
                 EFI_DISK_IO_PROTOCOL *disk_io,
                 uint32_t media_id,
                 uint32_t block_size,
                 EFI_LBA lba,
-                EFI_LBA *ret_backup_lba, /* May be changed even on error! */
-                HARDDRIVE_DEVICE_PATH *ret_hd) {
+                EFI_LBA *reterr_backup_lba, /* May be changed even on error! */
+                GptHeader *ret_gpt,
+                void **ret_entries) {
 
         GptHeader gpt;
         EFI_STATUS err;
@@ -86,44 +87,80 @@ static EFI_STATUS try_gpt(
         size_t size;
 
         assert(disk_io);
-        assert(ret_hd);
+        assert(ret_gpt);
+        assert(ret_entries);
 
-        /* Read the GPT header */
         uint64_t offset;
         if (!MUL_SAFE(&offset, lba, block_size))
-                return EFI_INVALID_PARAMETER;
+                return log_debug_status(
+                                EFI_INVALID_PARAMETER,
+                                "LBA %" PRIu64 " * block size %" PRIu32 " overflow: %m",
+                                lba,
+                                block_size);
 
         err = disk_io->ReadDisk(disk_io, media_id, offset, sizeof(gpt), &gpt);
         if (err != EFI_SUCCESS)
-                return err;
+                return log_debug_status(err, "Failed to read GPT header at LBA %" PRIu64 ": %m", lba);
 
-        /* Indicate the location of backup LBA even if the rest of the header is corrupt. */
-        if (ret_backup_lba)
-                *ret_backup_lba = gpt.AlternateLBA;
+        /* Expose backup LBA even if the rest of the header is corrupt, so the caller can
+         * try the backup GPT. */
+        if (reterr_backup_lba)
+                *reterr_backup_lba = gpt.AlternateLBA;
 
         if (!verify_gpt(&gpt, lba))
-                return EFI_NOT_FOUND;
+                return log_debug_status(EFI_NOT_FOUND, "GPT header at LBA %" PRIu64 " is not valid: %m", lba);
 
-        /* Now load the GPT entry table */
         size = (size_t) gpt.SizeOfPartitionEntry * (size_t) gpt.NumberOfPartitionEntries;
         if (size == SIZE_MAX) /* overflow check */
-                return EFI_OUT_OF_RESOURCES;
+                return log_debug_status(EFI_OUT_OF_RESOURCES, "GPT partition entries size overflow: %m");
 
         _cleanup_free_ void *entries = xmalloc(size);
 
         if (!MUL_SAFE(&offset, gpt.PartitionEntryLBA, block_size))
-                return EFI_INVALID_PARAMETER;
+                return log_debug_status(
+                                EFI_INVALID_PARAMETER,
+                                "Partition entry LBA %" PRIu64 " * block size %" PRIu32 " overflow: %m",
+                                gpt.PartitionEntryLBA,
+                                block_size);
 
         err = disk_io->ReadDisk(disk_io, media_id, offset, size, entries);
         if (err != EFI_SUCCESS)
-                return err;
+                return log_debug_status(err, "Failed to read GPT partition entries at LBA %" PRIu64 ": %m", gpt.PartitionEntryLBA);
 
-        /* Calculate CRC of entries array, too */
         err = BS->CalculateCrc32(entries, size, &crc32);
-        if (err != EFI_SUCCESS || crc32 != gpt.PartitionEntryArrayCRC32)
-                return EFI_CRC_ERROR;
+        if (err != EFI_SUCCESS)
+                return log_debug_status(err, "Failed to calculate CRC32 of GPT partition entries: %m");
+        if (crc32 != gpt.PartitionEntryArrayCRC32)
+                return log_debug_status(
+                                EFI_CRC_ERROR,
+                                "GPT partition entries CRC32 mismatch (got 0x%08" PRIx32 ", expected 0x%08" PRIx32 "): %m",
+                                crc32,
+                                gpt.PartitionEntryArrayCRC32);
+
+        *ret_gpt = gpt;
+        *ret_entries = TAKE_PTR(entries);
+        return EFI_SUCCESS;
+}
+
+static EFI_STATUS try_gpt(
+                const EFI_GUID *type,
+                EFI_DISK_IO_PROTOCOL *disk_io,
+                uint32_t media_id,
+                uint32_t block_size,
+                EFI_LBA lba,
+                EFI_LBA *reterr_backup_lba, /* May be changed even on error! */
+                HARDDRIVE_DEVICE_PATH *ret_hd) {
+
+        GptHeader gpt;
+        _cleanup_free_ void *entries = NULL;
+        EFI_STATUS err;
+
+        assert(ret_hd);
+
+        err = read_gpt_entries(disk_io, media_id, block_size, lba, reterr_backup_lba, &gpt, &entries);
+        if (err != EFI_SUCCESS)
+                return err;
 
-        /* Now we can finally look for xbootloader partitions. */
         for (size_t i = 0; i < gpt.NumberOfPartitionEntries; i++) {
                 EFI_PARTITION_ENTRY *entry =
                                 (EFI_PARTITION_ENTRY *) ((uint8_t *) entries + gpt.SizeOfPartitionEntry * i);