From 62f80a2a71f25302936b713842a38e8bc293b073 Mon Sep 17 00:00:00 2001 From: Jessica Hamilton Date: Sun, 4 Jul 2021 22:35:18 +0000 Subject: [PATCH] loader: fetch all potential boot partitions for device This also keeps the functionality of hrev53848, which simplifies the list of disks searched for bootable partitions; however, it maintains the previous behaviour of platform_get_boot_partitions that continues to iterate over a list of possible boot partitions, which should allow finding a bootable BFS partition better in more circumstances. Particularly, there are numerous reports of the UEFI loader entering the boot menu despite it finding a bootable partition, which this should address. EFI's device_contains_partition is also structured such that it compares the disk GPT table of the partition the loader is querying of the EFI disk's GPT table, in the case that there are multiple disks, as the most reliable method of comparison, with a generic fallback for non-GPT disks, which will be less reliable. This reverts commit 0d932a49ada8af6314cd3f20c3f597143f1f555d. Change-Id: I5fac8608035d56b8bb4dc6c3d495ec6db42fa9b7 Reviewed-on: https://review.haiku-os.org/c/haiku/+/4149 Reviewed-by: Alex von Gluck IV --- headers/private/kernel/boot/platform.h | 4 +- src/system/boot/loader/vfs.cpp | 41 ++++++----- .../boot/platform/amiga_m68k/devices.cpp | 4 +- .../boot/platform/atari_m68k/devices.cpp | 6 +- .../boot/platform/bios_ia32/devices.cpp | 6 +- src/system/boot/platform/efi/devices.cpp | 72 +++++++++++++++++-- .../boot/platform/openfirmware/devices.cpp | 6 +- src/system/boot/platform/pxe_ia32/devices.cpp | 6 +- src/system/boot/platform/u-boot/devices.cpp | 6 +- 9 files changed, 108 insertions(+), 43 deletions(-) diff --git a/headers/private/kernel/boot/platform.h b/headers/private/kernel/boot/platform.h index c30fcff9c2..146edb3936 100644 --- a/headers/private/kernel/boot/platform.h +++ b/headers/private/kernel/boot/platform.h @@ -59,8 +59,8 @@ namespace boot { extern status_t platform_add_boot_device(struct stage2_args *args, NodeList *devicesList); extern status_t platform_add_block_devices(struct stage2_args *args, NodeList *devicesList); -extern status_t platform_get_boot_partition(struct stage2_args *args, Node *bootDevice, - NodeList *partitions, boot::Partition **_partition); +extern status_t platform_get_boot_partitions(struct stage2_args *args, Node *bootDevice, + NodeList *partitions, NodeList *bootPartitions); extern status_t platform_register_boot_device(Node *device); extern void platform_cleanup_devices(); diff --git a/src/system/boot/loader/vfs.cpp b/src/system/boot/loader/vfs.cpp index 403878b063..e724f123c3 100644 --- a/src/system/boot/loader/vfs.cpp +++ b/src/system/boot/loader/vfs.cpp @@ -659,28 +659,33 @@ get_boot_file_system(stage2_args* args, BootVolume& _bootVolume) if (error != B_OK) continue; - Partition *partition; - error = platform_get_boot_partition(args, device, &gPartitions, &partition); + NodeList bootPartitions; + error = platform_get_boot_partitions(args, device, &gPartitions, &bootPartitions); if (error != B_OK) continue; - Directory *fileSystem; - error = partition->Mount(&fileSystem, true); - if (error != B_OK) { - // this partition doesn't contain any known file system; we - // don't need it anymore - gPartitions.Remove(partition); - delete partition; - continue; + NodeIterator partitionIterator = bootPartitions.GetIterator(); + while (partitionIterator.HasNext()) { + Partition *partition = (Partition*)partitionIterator.Next(); + + Directory *fileSystem; + error = partition->Mount(&fileSystem, true); + if (error != B_OK) { + // this partition doesn't contain any known file system; we + // don't need it anymore + gPartitions.Remove(partition); + delete partition; + continue; + } + + // init the BootVolume + error = _bootVolume.SetTo(fileSystem); + if (error != B_OK) + continue; + + sBootDevice = device; + return B_OK; } - - // init the BootVolume - error = _bootVolume.SetTo(fileSystem); - if (error != B_OK) - continue; - - sBootDevice = device; - return B_OK; } return B_ERROR; diff --git a/src/system/boot/platform/amiga_m68k/devices.cpp b/src/system/boot/platform/amiga_m68k/devices.cpp index c6edd40590..ef33682aff 100644 --- a/src/system/boot/platform/amiga_m68k/devices.cpp +++ b/src/system/boot/platform/amiga_m68k/devices.cpp @@ -168,8 +168,8 @@ platform_add_boot_device(struct stage2_args *args, NodeList *devicesList) status_t -platform_get_boot_partition(struct stage2_args *args, Node *bootDevice, - NodeList *list, boot::Partition **_partition) +platform_get_boot_partitions(struct stage2_args *args, Node *bootDevice, + NodeList *list, NodeList *partitions) { //TODO diff --git a/src/system/boot/platform/atari_m68k/devices.cpp b/src/system/boot/platform/atari_m68k/devices.cpp index 6f9d95cc5d..5738e94369 100644 --- a/src/system/boot/platform/atari_m68k/devices.cpp +++ b/src/system/boot/platform/atari_m68k/devices.cpp @@ -1189,8 +1189,8 @@ platform_add_boot_device(struct stage2_args *args, NodeList *devicesList) status_t -platform_get_boot_partition(struct stage2_args *args, Node *bootDevice, - NodeList *list, boot::Partition **_partition) +platform_get_boot_partitions(struct stage2_args *args, Node *bootDevice, + NodeList *list, NodeList *partitionList) { BlockHandle *drive = static_cast(bootDevice); off_t offset = (off_t)gBootPartitionOffset * drive->BlockSize(); @@ -1205,7 +1205,7 @@ platform_get_boot_partition(struct stage2_args *args, Node *bootDevice, // offset as reported by the BFS boot block if (offset >= partition->offset && offset < partition->offset + partition->size) { - *_partition = partition; + partitionList->Insert(partition); return B_OK; } } diff --git a/src/system/boot/platform/bios_ia32/devices.cpp b/src/system/boot/platform/bios_ia32/devices.cpp index d06798226a..35a1b03d17 100644 --- a/src/system/boot/platform/bios_ia32/devices.cpp +++ b/src/system/boot/platform/bios_ia32/devices.cpp @@ -877,8 +877,8 @@ platform_add_boot_device(struct stage2_args *args, NodeList *devicesList) status_t -platform_get_boot_partition(struct stage2_args *args, Node *bootDevice, - NodeList *list, boot::Partition **_partition) +platform_get_boot_partitions(struct stage2_args *args, Node *bootDevice, + NodeList *list, NodeList *bootList) { BIOSDrive *drive = static_cast(bootDevice); off_t offset = (off_t)gBootPartitionOffset * drive->BlockSize(); @@ -893,7 +893,7 @@ platform_get_boot_partition(struct stage2_args *args, Node *bootDevice, // offset as reported by the BFS boot block if (offset >= partition->offset && offset < partition->offset + partition->size) { - *_partition = partition; + bootList->Insert(partition); return B_OK; } } diff --git a/src/system/boot/platform/efi/devices.cpp b/src/system/boot/platform/efi/devices.cpp index 348ec1437d..18c7180562 100644 --- a/src/system/boot/platform/efi/devices.cpp +++ b/src/system/boot/platform/efi/devices.cpp @@ -8,9 +8,14 @@ #include #include +#include "Header.h" + #include "efi_platform.h" #include +#include "gpt.h" +#include "gpt_known_guids.h" + //#define TRACE_DEVICES #ifdef TRACE_DEVICES @@ -121,6 +126,53 @@ compute_check_sum(Node *device, off_t offset) } +static bool +device_contains_partition(EfiDevice *device, boot::Partition *partition) +{ + EFI::Header *header = (EFI::Header*)partition->content_cookie; + if (header != NULL && header->InitCheck() == B_OK) { + // check if device is GPT, and contains partition entry + uint32 blockSize = device->BlockSize(); + gpt_table_header *deviceHeader = + (gpt_table_header*)malloc(blockSize); + ssize_t bytesRead = device->ReadAt(NULL, blockSize, deviceHeader, + blockSize); + if (bytesRead != blockSize) + return false; + + if (memcmp(deviceHeader, &header->TableHeader(), + sizeof(gpt_table_header)) != 0) + return false; + + // partition->cookie == int partition entry index + uint32 index = (uint32)(addr_t)partition->cookie; + uint32 size = sizeof(gpt_partition_entry) * (index + 1); + gpt_partition_entry *entries = (gpt_partition_entry*)malloc(size); + bytesRead = device->ReadAt(NULL, + deviceHeader->entries_block * blockSize, entries, size); + if (bytesRead != size) + return false; + + if (memcmp(&entries[index], &header->EntryAt(index), + sizeof(gpt_partition_entry)) != 0) + return false; + + for (size_t i = 0; i < sizeof(kTypeMap) / sizeof(struct type_map); ++i) + if (strcmp(kTypeMap[i].type, BFS_NAME) == 0) + if (kTypeMap[i].guid == header->EntryAt(index).partition_type) + return true; + + // Our partition has an EFI header, but we couldn't find one, so bail + return false; + } + + if ((partition->offset + partition->size) <= device->Size()) + return true; + + return false; +} + + status_t platform_add_boot_device(struct stage2_args *args, NodeList *devicesList) { @@ -176,6 +228,7 @@ platform_add_boot_device(struct stage2_args *args, NodeList *devicesList) return devicesList->Count() > 0 ? B_OK : B_ENTRY_NOT_FOUND; } + status_t platform_add_block_devices(struct stage2_args *args, NodeList *devicesList) { @@ -185,13 +238,21 @@ platform_add_block_devices(struct stage2_args *args, NodeList *devicesList) return B_ENTRY_NOT_FOUND; } + status_t -platform_get_boot_partition(struct stage2_args *args, Node *bootDevice, - NodeList *partitions, boot::Partition **_partition) +platform_get_boot_partitions(struct stage2_args *args, Node *bootDevice, + NodeList *partitions, NodeList *bootPartitions) { - TRACE("%s: called\n", __func__); - *_partition = (boot::Partition*)partitions->GetIterator().Next(); - return *_partition != NULL ? B_OK : B_ENTRY_NOT_FOUND; + NodeIterator iterator = partitions->GetIterator(); + boot::Partition *partition = NULL; + while ((partition = (boot::Partition*)iterator.Next()) != NULL) { + if (device_contains_partition((EfiDevice*)bootDevice, partition)) { + iterator.Remove(); + bootPartitions->Insert(partition); + } + } + + return bootPartitions->Count() > 0 ? B_OK : B_ENTRY_NOT_FOUND; } @@ -200,7 +261,6 @@ platform_register_boot_device(Node *device) { TRACE("%s: called\n", __func__); - EfiDevice *efiDevice = (EfiDevice *)device; disk_identifier identifier; identifier.bus_type = UNKNOWN_BUS; diff --git a/src/system/boot/platform/openfirmware/devices.cpp b/src/system/boot/platform/openfirmware/devices.cpp index e177f0e86b..c46267604d 100644 --- a/src/system/boot/platform/openfirmware/devices.cpp +++ b/src/system/boot/platform/openfirmware/devices.cpp @@ -117,14 +117,14 @@ platform_add_boot_device(struct stage2_args *args, NodeList *devicesList) status_t -platform_get_boot_partition(struct stage2_args *args, Node *device, - NodeList *list, boot::Partition **_partition) +platform_get_boot_partitions(struct stage2_args *args, Node *device, + NodeList *list, NodeList *partitionList) { NodeIterator iterator = list->GetIterator(); boot::Partition *partition = NULL; while ((partition = (boot::Partition *)iterator.Next()) != NULL) { // ToDo: just take the first partition for now - *_partition = partition; + partitionList->Insert(partition); return B_OK; } diff --git a/src/system/boot/platform/pxe_ia32/devices.cpp b/src/system/boot/platform/pxe_ia32/devices.cpp index 2ffbcff042..696bf77d2e 100644 --- a/src/system/boot/platform/pxe_ia32/devices.cpp +++ b/src/system/boot/platform/pxe_ia32/devices.cpp @@ -118,15 +118,15 @@ platform_add_boot_device(struct stage2_args *args, NodeList *devicesList) status_t -platform_get_boot_partition(struct stage2_args *args, Node *device, - NodeList *list, boot::Partition **_partition) +platform_get_boot_partitions(struct stage2_args *args, Node *device, + NodeList *list, NodeList *partitionList) { TRACE("platform_get_boot_partition\n"); NodeIterator iterator = list->GetIterator(); boot::Partition *partition = NULL; while ((partition = (boot::Partition *)iterator.Next()) != NULL) { // ToDo: just take the first partition for now - *_partition = partition; + partitionList->Insert(partition); return B_OK; } diff --git a/src/system/boot/platform/u-boot/devices.cpp b/src/system/boot/platform/u-boot/devices.cpp index 140ed1e70a..aaf5206d1b 100644 --- a/src/system/boot/platform/u-boot/devices.cpp +++ b/src/system/boot/platform/u-boot/devices.cpp @@ -48,8 +48,8 @@ platform_add_boot_device(struct stage2_args *args, NodeList *devicesList) status_t -platform_get_boot_partition(struct stage2_args *args, Node *device, - NodeList *list, boot::Partition **_partition) +platform_get_boot_partitions(struct stage2_args *args, Node *device, + NodeList *list, NodeList *partitionList) { TRACE("platform_get_boot_partition\n"); @@ -57,7 +57,7 @@ platform_get_boot_partition(struct stage2_args *args, Node *device, boot::Partition *partition = NULL; while ((partition = (boot::Partition *)iterator.Next()) != NULL) { // ToDo: just take the first partition for now - *_partition = partition; + partitionList->Insert(partition); return B_OK; }