boot: respect minimal I/O alignment when doing block i/o

Fixes XBOOTLDR partition detection and bitlocker support when using
U-Boot as UEFI.
This commit is contained in:
Artur Kowalski
2026-01-29 20:55:42 +01:00
parent fd7c6d1ac1
commit ccbd324a3a
2 changed files with 44 additions and 13 deletions

View 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;

View 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;