UEFI: identify the boot partition to check that it's valid.

* Also modified EFI::Header to return the efi_table_header so
  that we can compare it to boot device partition table.
This commit is contained in:
Jessica Hamilton 2017-01-07 17:25:34 +13:00
parent 42e718f041
commit 6b4cbec040
3 changed files with 57 additions and 5 deletions

View File

@ -30,6 +30,8 @@ public:
{ return fHeader.FirstUsableBlock(); } { return fHeader.FirstUsableBlock(); }
uint64 LastUsableBlock() const uint64 LastUsableBlock() const
{ return fHeader.LastUsableBlock(); } { return fHeader.LastUsableBlock(); }
const efi_table_header& TableHeader() const
{ return fHeader; }
uint32 EntryCount() const uint32 EntryCount() const
{ return fHeader.EntryCount(); } { return fHeader.EntryCount(); }

View File

@ -6,6 +6,7 @@ UsePrivateHeaders [ FDirName kernel boot ] ;
UseBuildFeatureHeaders gnuefi ; UseBuildFeatureHeaders gnuefi ;
UseBuildFeatureHeaders gnuefi : headersProtocol ; UseBuildFeatureHeaders gnuefi : headersProtocol ;
UseBuildFeatureHeaders gnuefi : headersArch ; UseBuildFeatureHeaders gnuefi : headersArch ;
SubDirHdrs $(HAIKU_TOP) src add-ons kernel partitioning_systems gpt ;
{ {
local defines = _BOOT_MODE GNU_EFI_USE_MS_ABI _BOOT_PLATFORM_EFI ; local defines = _BOOT_MODE GNU_EFI_USE_MS_ABI _BOOT_PLATFORM_EFI ;

View File

@ -12,7 +12,11 @@
#include <boot/stdio.h> #include <boot/stdio.h>
#include <util/list.h> #include <util/list.h>
#include "Header.h"
#include "efi_platform.h" #include "efi_platform.h"
#include "efigpt.h"
#include "gpt_known_guids.h"
struct device_handle { struct device_handle {
@ -395,6 +399,53 @@ add_remaining_devices(NodeList *devicesList)
} }
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();
EFI_PARTITION_TABLE_HEADER *deviceHeader =
(EFI_PARTITION_TABLE_HEADER*)malloc(blockSize);
ssize_t bytesRead = device->ReadAt(NULL, blockSize, deviceHeader,
blockSize);
if (bytesRead != blockSize)
return false;
if (memcmp(deviceHeader, &header->TableHeader(),
sizeof(efi_table_header)) != 0)
return false;
// partition->cookie == int partition entry index
uint32 index = (uint32)(addr_t)partition->cookie;
uint32 size = sizeof(EFI_PARTITION_ENTRY) * (index + 1);
EFI_PARTITION_ENTRY *entries = (EFI_PARTITION_ENTRY*)malloc(size);
bytesRead = device->ReadAt(NULL,
deviceHeader->PartitionEntryLBA * blockSize, entries, size);
if (bytesRead != size)
return false;
if (memcmp(&entries[index], &header->EntryAt(index),
sizeof(efi_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 status_t
platform_add_boot_device(struct stage2_args *args, NodeList *devicesList) platform_add_boot_device(struct stage2_args *args, NodeList *devicesList)
{ {
@ -437,12 +488,10 @@ platform_get_boot_partition(struct stage2_args *args, Node *bootDevice,
NodeIterator iterator = partitions->GetIterator(); NodeIterator iterator = partitions->GetIterator();
boot::Partition *partition = NULL; boot::Partition *partition = NULL;
while ((partition = (boot::Partition *)iterator.Next()) != NULL) { while ((partition = (boot::Partition *)iterator.Next()) != NULL) {
// Currently we pick last partition; seems to work enough for now if (device_contains_partition((EfiDevice*)bootDevice, partition)) {
// until we can actually identify the partition we want to boot *_partition = partition;
// from
*_partition = partition;
if (!iterator.HasNext())
return B_OK; return B_OK;
}
} }
return B_ENTRY_NOT_FOUND; return B_ENTRY_NOT_FOUND;