From ccbd324a3a522362de0863e8d06cdd06a58d2fca Mon Sep 17 00:00:00 2001 From: Artur Kowalski Date: Thu, 29 Jan 2026 20:55:42 +0100 Subject: [PATCH] boot: respect minimal I/O alignment when doing block i/o Fixes XBOOTLDR partition detection and bitlocker support when using U-Boot as UEFI. --- src/boot/boot.c | 14 +++++++++++-- src/boot/part-discovery.c | 43 +++++++++++++++++++++++++++++---------- 2 files changed, 44 insertions(+), 13 deletions(-) diff --git a/src/boot/boot.c b/src/boot/boot.c index d88f99459a2..d46c98da314 100644 --- a/src/boot/boot.c +++ b/src/boot/boot.c @@ -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; diff --git a/src/boot/part-discovery.c b/src/boot/part-discovery.c index 0c8e7fde04b..dc1aed0514b 100644 --- a/src/boot/part-discovery.c +++ b/src/boot/part-discovery.c @@ -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; -- 2.47.3