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 0d932a49ad.

Change-Id: I5fac8608035d56b8bb4dc6c3d495ec6db42fa9b7
Reviewed-on: https://review.haiku-os.org/c/haiku/+/4149
Reviewed-by: Alex von Gluck IV <kallisti5@unixzen.com>
This commit is contained in:
Jessica Hamilton 2021-07-04 22:35:18 +00:00 committed by Alex von Gluck IV
parent 3ca5eec002
commit 62f80a2a71
9 changed files with 108 additions and 43 deletions

View File

@ -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();

View File

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

View File

@ -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

View File

@ -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<BlockHandle *>(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;
}
}

View File

@ -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<BIOSDrive *>(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;
}
}

View File

@ -8,9 +8,14 @@
#include <boot/platform.h>
#include <boot/stage2.h>
#include "Header.h"
#include "efi_platform.h"
#include <efi/protocol/block-io.h>
#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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}