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:
parent
3ca5eec002
commit
62f80a2a71
@ -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();
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user