]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
boot: respect minimal I/O alignment when doing block i/o 40465/head
authorArtur Kowalski <arturkow2000@gmail.com>
Thu, 29 Jan 2026 19:55:42 +0000 (20:55 +0100)
committerArtur Kowalski <arturkow2000@gmail.com>
Sun, 15 Feb 2026 14:54:45 +0000 (15:54 +0100)
Fixes XBOOTLDR partition detection and bitlocker support when using
U-Boot as UEFI.

src/boot/boot.c
src/boot/part-discovery.c

index d88f99459a2c9c4061a2e6246803b40ae423f00b..d46c98da31435dffbde5111deafcd6f7e672c903 100644 (file)
@@ -2064,8 +2064,18 @@ static EFI_STATUS call_boot_windows_bitlocker(const BootEntry *entry, EFI_FILE *
                 if (err != EFI_SUCCESS || block_io->Media->BlockSize < 512 || block_io->Media->BlockSize > 4096)
                         continue;
 
-                char buf[4096];
-                err = block_io->ReadBlocks(block_io, block_io->Media->MediaId, 0, sizeof(buf), buf);
+                #define BLOCK_IO_BUFFER_SIZE 4096
+                _cleanup_pages_ Pages buf_pages = xmalloc_aligned_pages(
+                        AllocateMaxAddress,
+                        EfiLoaderData,
+                        EFI_SIZE_TO_PAGES(BLOCK_IO_BUFFER_SIZE),
+                        block_io->Media->IoAlign,
+                        /* On 32-bit allocate below 4G boundary as we can't easily access anything above that.
+                         * 64-bit platforms don't suffer this limitation, so we can allocate from anywhere.
+                         * addr= */ UINTPTR_MAX);
+                char *buf = PHYSICAL_ADDRESS_TO_POINTER(buf_pages.addr);
+
+                err = block_io->ReadBlocks(block_io, block_io->Media->MediaId, /* LBA= */ 0, BLOCK_IO_BUFFER_SIZE, buf);
                 if (err != EFI_SUCCESS)
                         continue;
 
index 0c8e7fde04ba9d64fa2658ad344977e6252d30aa..dc1aed0514b1d2b3f03898dd2a9dce6aa70c3689 100644 (file)
@@ -77,52 +77,73 @@ static EFI_STATUS try_gpt(
                 EFI_LBA *ret_backup_lba, /* May be changed even on error! */
                 HARDDRIVE_DEVICE_PATH *ret_hd) {
 
-        _cleanup_free_ EFI_PARTITION_ENTRY *entries = NULL;
-        GptHeader gpt;
+        EFI_PARTITION_ENTRY *entries;
+        _cleanup_pages_ Pages gpt_pages = {};
+        _cleanup_pages_ Pages entries_pages = {};
+        GptHeader *gpt;
         EFI_STATUS err;
         uint32_t crc32;
         size_t size;
 
         assert(block_io);
+        assert(block_io->Media);
         assert(ret_hd);
 
+        gpt_pages = xmalloc_aligned_pages(
+                AllocateMaxAddress,
+                EfiLoaderData,
+                EFI_SIZE_TO_PAGES(sizeof(GptHeader)),
+                block_io->Media->IoAlign,
+                /* On 32-bit allocate below 4G boundary as we can't easily access anything above that.
+                 * 64-bit platforms don't suffer this limitation, so we can allocate from anywhere.
+                 * addr= */ UINTPTR_MAX);
+        gpt = PHYSICAL_ADDRESS_TO_POINTER(gpt_pages.addr);
+
         /* Read the GPT header */
         err = block_io->ReadBlocks(
                         block_io,
                         block_io->Media->MediaId,
                         lba,
-                        sizeof(gpt), &gpt);
+                        sizeof(*gpt), gpt);
         if (err != EFI_SUCCESS)
                 return err;
 
         /* Indicate the location of backup LBA even if the rest of the header is corrupt. */
         if (ret_backup_lba)
-                *ret_backup_lba = gpt.AlternateLBA;
+                *ret_backup_lba = gpt->AlternateLBA;
 
-        if (!verify_gpt(&gpt, lba))
+        if (!verify_gpt(gpt, lba))
                 return EFI_NOT_FOUND;
 
         /* Now load the GPT entry table */
-        size = ALIGN_TO((size_t) gpt.SizeOfPartitionEntry * (size_t) gpt.NumberOfPartitionEntries, 512);
-        entries = xmalloc(size);
+        size = ALIGN_TO((size_t) gpt->SizeOfPartitionEntry * (size_t) gpt->NumberOfPartitionEntries, 512);
+        entries_pages = xmalloc_aligned_pages(
+                AllocateMaxAddress,
+                EfiLoaderData,
+                EFI_SIZE_TO_PAGES(size),
+                block_io->Media->IoAlign,
+                /* On 32-bit allocate below 4G boundary as we can't easily access anything above that.
+                 * 64-bit platforms don't suffer this limitation, so we can allocate from anywhere.
+                 * addr= */ UINTPTR_MAX);
+        entries = PHYSICAL_ADDRESS_TO_POINTER(entries_pages.addr);
 
         err = block_io->ReadBlocks(
                         block_io,
                         block_io->Media->MediaId,
-                        gpt.PartitionEntryLBA,
+                        gpt->PartitionEntryLBA,
                         size, entries);
         if (err != EFI_SUCCESS)
                 return err;
 
         /* Calculate CRC of entries array, too */
         err = BS->CalculateCrc32(entries, size, &crc32);
-        if (err != EFI_SUCCESS || crc32 != gpt.PartitionEntryArrayCRC32)
+        if (err != EFI_SUCCESS || crc32 != gpt->PartitionEntryArrayCRC32)
                 return EFI_CRC_ERROR;
 
         /* Now we can finally look for xbootloader partitions. */
-        for (size_t i = 0; i < gpt.NumberOfPartitionEntries; i++) {
+        for (size_t i = 0; i < gpt->NumberOfPartitionEntries; i++) {
                 EFI_PARTITION_ENTRY *entry =
-                                (EFI_PARTITION_ENTRY *) ((uint8_t *) entries + gpt.SizeOfPartitionEntry * i);
+                                (EFI_PARTITION_ENTRY *) ((uint8_t *) entries + gpt->SizeOfPartitionEntry * i);
 
                 if (!efi_guid_equal(&entry->PartitionTypeGUID, type))
                         continue;