added 3 changesets to branch 'refs/remotes/jessicah-github/uefi-devices'
old head: 0000000000000000000000000000000000000000
new head: 6a569b28b184438a41da4d3407c2e8472a1a8e74
overview: https://github.com/jessicah/haiku/compare/6a569b28b184
----------------------------------------------------------------------------
445b080ea3e7: UEFI: support selecting video resolution & vesa settings file.
be13524235f3: loader: get_boot_file_system() iterate over all devices found.
* This is useful for UEFI, as we can then add the device that
contains the UEFI loader, as well as all CD devices. As a
result, if the device with the UEFI loader doesn't contain
a bootable BFS partition, it will then attempt the same for
CD devices.
6a569b28b184: UEFI: improve boot support in devices.cpp
[ Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx> ]
----------------------------------------------------------------------------
6 files changed, 623 insertions(+), 85 deletions(-)
src/system/boot/Jamfile | 1 +
src/system/boot/loader/vfs.cpp | 55 ++--
src/system/boot/platform/efi/devices.cpp | 410 +++++++++++++++++++++++----
src/system/boot/platform/efi/menu.cpp | 17 +-
src/system/boot/platform/efi/video.cpp | 208 +++++++++++++-
src/system/boot/platform/efi/video.h | 17 ++
############################################################################
Commit: 445b080ea3e749d732ffb2d00cdfd16d36a8a1d2
Author: Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx>
Date: Sun Dec 25 03:13:57 2016 UTC
UEFI: support selecting video resolution & vesa settings file.
----------------------------------------------------------------------------
diff --git a/src/system/boot/Jamfile b/src/system/boot/Jamfile
index d005d35..30fc891 100644
--- a/src/system/boot/Jamfile
+++ b/src/system/boot/Jamfile
@@ -48,6 +48,7 @@ BootMergeObject boot_libroot.o :
strchr.c
strrchr.c
strtol.c
+ strtoul.c
$(extraSources)
;
diff --git a/src/system/boot/platform/efi/menu.cpp
b/src/system/boot/platform/efi/menu.cpp
index 0b13b2d..b4f6e6a 100644
--- a/src/system/boot/platform/efi/menu.cpp
+++ b/src/system/boot/platform/efi/menu.cpp
@@ -8,12 +8,27 @@
#include <boot/platform/generic/text_menu.h>
#include "efi_platform.h"
+#include "video.h"
void
platform_add_menus(Menu *menu)
{
- // No platform specific menus
+ MenuItem *item;
+
+ switch (menu->Type()) {
+ case MAIN_MENU:
+ item = new(std::nothrow)MenuItem("Select video mode",
video_mode_menu());
+ if (item != NULL) {
+ menu->AddItem(item);
+ item->SetTarget(video_mode_hook);
+ item->SetShortcut('v');
+ }
+
+ break;
+ default:
+ break;
+ }
}
diff --git a/src/system/boot/platform/efi/video.cpp
b/src/system/boot/platform/efi/video.cpp
index e292b4d..aa96c96 100644
--- a/src/system/boot/platform/efi/video.cpp
+++ b/src/system/boot/platform/efi/video.cpp
@@ -4,23 +4,154 @@
*/
+#include "video.h"
+
+#include <stdlib.h>
+
#include <boot/kernel_args.h>
+#include <boot/menu.h>
#include <boot/platform.h>
#include <boot/platform/generic/video.h>
#include <boot/stage2.h>
#include <boot/stdio.h>
+#include <drivers/driver_settings.h>
+#include <util/list.h>
#include "efi_platform.h"
+//#define TRACE_VIDEO
+#ifdef TRACE_VIDEO
+# define TRACE(x) dprintf x
+#else
+# define TRACE(x) ;
+#endif
+
+
+struct video_mode {
+ list_link link;
+ UINTN mode;
+ UINTN width, height, bits_per_pixel, bytes_per_row;
+};
+
+
static EFI_GUID sGraphicsOutputGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
static EFI_GRAPHICS_OUTPUT_PROTOCOL *sGraphicsOutput;
static UINTN sGraphicsMode;
+static struct list sModeList;
+static uint32 sModeCount;
+static bool sModeChosen;
+static bool sSettingsLoaded;
+
+
+static int
+compare_video_modes(video_mode *a, video_mode *b)
+{
+ int compare = a->width - b->width;
+ if (compare != 0)
+ return compare;
+
+ compare = a->height - b->height;
+ if (compare != 0)
+ return compare;
+
+ return a->bits_per_pixel - b->bits_per_pixel;
+}
+
+
+static void
+add_video_mode(video_mode *videoMode)
+{
+ video_mode *mode = NULL;
+ while ((mode = (video_mode*)list_get_next_item(&sModeList, mode))
+ != NULL) {
+ int compare = compare_video_modes(videoMode, mode);
+ if (compare == 0) {
+ // mode already exists
+ return;
+ }
+
+ if (compare > 0)
+ break;
+ }
+
+ list_insert_item_before(&sModeList, mode, videoMode);
+ sModeCount++;
+}
+
+
+static video_mode*
+closest_video_mode(uint32 width, uint32 height, uint32 depth)
+{
+ video_mode *bestMode = NULL;
+ uint32 bestDiff = 0;
+
+ video_mode *mode = NULL;
+ while ((mode = (video_mode*)list_get_next_item(&sModeList, mode)) !=
NULL) {
+ if (mode->width > width) {
+ // Only choose modes with a width less or equal than
the searched
+ // one; or else it might well be that the monitor
cannot keep up.
+ continue;
+ }
+
+ uint32 diff = 2 * abs(mode->width - width) + abs(mode->height -
height)
+ + abs(mode->bits_per_pixel - depth);
+
+ if (bestMode == NULL || bestDiff > diff) {
+ bestMode = mode;
+ bestDiff = diff;
+ }
+ }
+
+ return bestMode;
+}
+
+
+static void
+get_mode_from_settings(void)
+{
+ if (sSettingsLoaded)
+ return;
+
+ void *handle = load_driver_settings("vesa");
+ if (handle == NULL)
+ return;
+
+ bool found = false;
+
+ const driver_settings *settings = get_driver_settings(handle);
+ if (settings == NULL)
+ goto out;
+
+ sSettingsLoaded = true;
+
+ for (int32 i = 0; i < settings->parameter_count; i++) {
+ driver_parameter ¶meter = settings->parameters[i];
+
+ if (strcmp(parameter.name, "mode") == 0 &&
parameter.value_count > 2) {
+ uint32 width = strtoul(parameter.values[0], NULL, 0);
+ uint32 height = strtoul(parameter.values[1], NULL, 0);
+ uint32 depth = strtoul(parameter.values[2], NULL, 0);
+
+ // search mode that fits
+ video_mode *mode = closest_video_mode(width, height,
depth);
+ if (mode != NULL) {
+ found = true;
+ sGraphicsMode = mode->mode;
+ }
+ }
+ }
+
+out:
+ unload_driver_settings(handle);
+}
extern "C" status_t
platform_init_video(void)
{
+ list_init(&sModeList);
+
// we don't support VESA modes or EDID
gKernelArgs.vesa_modes = NULL;
gKernelArgs.vesa_modes_size = 0;
@@ -39,17 +170,17 @@ platform_init_video(void)
UINTN bestArea = 0;
UINTN bestDepth = 0;
- dprintf("looking for best graphics mode...\n");
+ TRACE(("looking for best graphics mode...\n"));
for (UINTN mode = 0; mode < sGraphicsOutput->Mode->MaxMode; ++mode) {
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info;
UINTN size, depth;
sGraphicsOutput->QueryMode(sGraphicsOutput, mode, &size, &info);
UINTN area = info->HorizontalResolution *
info->VerticalResolution;
- dprintf(" mode: %lu\n", mode);
- dprintf(" width: %u\n", info->HorizontalResolution);
- dprintf(" height: %u\n", info->VerticalResolution);
- dprintf(" area: %lu\n", area);
+ TRACE((" mode: %lu\n", mode));
+ TRACE((" width: %u\n", info->HorizontalResolution));
+ TRACE((" height: %u\n", info->VerticalResolution));
+ TRACE((" area: %lu\n", area));
if (info->PixelFormat == PixelRedGreenBlueReserved8BitPerColor)
{
depth = 32;
} else if (info->PixelFormat ==
PixelBlueGreenRedReserved8BitPerColor) {
@@ -62,16 +193,26 @@ platform_init_video(void)
&& info->PixelInformation.ReservedMask == 0) {
depth = 24;
} else {
- dprintf(" pixel format: %x unsupported\n",
- info->PixelFormat);
+ TRACE((" pixel format: %x unsupported\n",
+ info->PixelFormat));
continue;
}
- dprintf(" depth: %lu\n", depth);
+ TRACE((" depth: %lu\n", depth));
+
+ video_mode *videoMode = (video_mode*)malloc(sizeof(struct
video_mode));
+ if (videoMode != NULL) {
+ videoMode->mode = mode;
+ videoMode->width = info->HorizontalResolution;
+ videoMode->height = info->VerticalResolution;
+ videoMode->bits_per_pixel = info->PixelFormat ==
PixelBitMask ? 24 : 32;
+ videoMode->bytes_per_row = info->PixelsPerScanLine *
depth / 8;
+ add_video_mode(videoMode);
+ }
area *= depth;
- dprintf(" area (w/depth): %lu\n", area);
+ TRACE((" area (w/depth): %lu\n", area));
if (area >= bestArea) {
- dprintf("selected new best mode: %lu\n", mode);
+ TRACE(("selected new best mode: %lu\n", mode));
bestArea = area;
bestDepth = depth;
sGraphicsMode = mode;
@@ -85,6 +226,8 @@ platform_init_video(void)
}
gKernelArgs.frame_buffer.enabled = true;
+ sModeChosen = false;
+ sSettingsLoaded = false;
return B_OK;
}
@@ -95,6 +238,9 @@ platform_switch_to_logo(void)
if (sGraphicsOutput == NULL || !gKernelArgs.frame_buffer.enabled)
return;
+ if (!sModeChosen)
+ get_mode_from_settings();
+
sGraphicsOutput->SetMode(sGraphicsOutput, sGraphicsMode);
gKernelArgs.frame_buffer.physical_buffer.start =
sGraphicsOutput->Mode->FrameBufferBase;
@@ -114,6 +260,48 @@ platform_switch_to_logo(void)
}
+bool
+video_mode_hook(Menu *menu, MenuItem *item)
+{
+ menu = item->Submenu();
+ item = menu->FindMarked();
+ if (item != NULL) {
+ sGraphicsMode = (UINTN)item->Data();
+ sModeChosen = true;
+ }
+
+ return true;
+}
+
+
+Menu*
+video_mode_menu()
+{
+ Menu *menu = new(std::nothrow)Menu(CHOICE_MENU, "Select Video Mode");
+ MenuItem *item;
+
+ video_mode *mode = NULL;
+ while ((mode = (video_mode*)list_get_next_item(&sModeList, mode)) !=
NULL) {
+ char label[64];
+ snprintf(label, sizeof(label), "%lux%lu %lu bit", mode->width,
+ mode->height, mode->bits_per_pixel);
+
+ menu->AddItem(item = new (std::nothrow)MenuItem(label));
+ item->SetData((const void*)mode->mode);
+ if (mode->mode == sGraphicsMode) {
+ item->SetMarked(true);
+ item->Select(true);
+ }
+ }
+
+ menu->AddSeparatorItem();
+ menu->AddItem(item = new(std::nothrow)MenuItem("Return to main menu"));
+ item->SetType(MENU_ITEM_NO_CHOICE);
+
+ return menu;
+}
+
+
extern "C" void
platform_blit4(addr_t frameBuffer, const uint8 *data,
uint16 width, uint16 height, uint16 imageWidth,
diff --git a/src/system/boot/platform/efi/video.h
b/src/system/boot/platform/efi/video.h
new file mode 100644
index 0000000..bc7ce85
--- /dev/null
+++ b/src/system/boot/platform/efi/video.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2004, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx. All rights reserved.
+ * Copyright 2011, Rene Gollent, rene@xxxxxxxxxxx. All rights reserved.
+ *
+ * Distributed under the terms of the Haiku License.
+ */
+#ifndef VIDEO_H
+#define VIDEO_H
+
+
+class Menu;
+class MenuItem;
+
+bool video_mode_hook(Menu *menu, MenuItem *item);
+Menu *video_mode_menu();
+
+#endif /* VIDEO_H */
############################################################################
Commit: be13524235f351054ff8cb238e76670c43692054
Author: Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx>
Date: Sat Jan 7 02:11:54 2017 UTC
loader: get_boot_file_system() iterate over all devices found.
* This is useful for UEFI, as we can then add the device that
contains the UEFI loader, as well as all CD devices. As a
result, if the device with the UEFI loader doesn't contain
a bootable BFS partition, it will then attempt the same for
CD devices.
----------------------------------------------------------------------------
diff --git a/src/system/boot/loader/vfs.cpp b/src/system/boot/loader/vfs.cpp
index 73344cc..3dc9b0d 100644
--- a/src/system/boot/loader/vfs.cpp
+++ b/src/system/boot/loader/vfs.cpp
@@ -527,7 +527,7 @@ BootVolume::_SetTo(Directory* rootDirectory,
fSystemDirectory = static_cast<Directory*>(systemNode);
if (packageVolumeInfo == NULL) {
- // get a package volume info
+ // get a package volume info
BReference<PackageVolumeInfo> packageVolumeInfoReference(
new(std::nothrow) PackageVolumeInfo);
status_t error =
packageVolumeInfoReference->SetTo(fSystemDirectory,
@@ -646,40 +646,43 @@ register_boot_file_system(BootVolume& bootVolume)
status_t
get_boot_file_system(stage2_args* args, BootVolume& _bootVolume)
{
- Node *device;
status_t error = platform_add_boot_device(args, &gBootDevices);
if (error != B_OK)
return error;
- // the boot device must be the first device in the list
- device = gBootDevices.First();
+ NodeIterator iterator = gBootDevices.GetIterator();
+ while (iterator.HasNext()) {
+ Node *device = iterator.Next();
- error = add_partitions_for(device, false, true);
- if (error != B_OK)
- return error;
+ error = add_partitions_for(device, false, true);
+ if (error != B_OK)
+ continue;
- Partition *partition;
- error = platform_get_boot_partition(args, device, &gPartitions,
&partition);
- if (error != B_OK)
- return error;
+ Partition *partition;
+ error = platform_get_boot_partition(args, device, &gPartitions,
&partition);
+ 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;
- return error;
- }
+ 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)
- return error;
+ // init the BootVolume
+ error = _bootVolume.SetTo(fileSystem);
+ if (error != B_OK)
+ continue;
- sBootDevice = device;
- return B_OK;
+ sBootDevice = device;
+ return B_OK;
+ }
+
+ return B_ERROR;
}
############################################################################
Commit: 6a569b28b184438a41da4d3407c2e8472a1a8e74
Author: Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx>
Date: Sat Jan 7 02:15:20 2017 UTC
UEFI: improve boot support in devices.cpp
----------------------------------------------------------------------------
diff --git a/src/system/boot/platform/efi/devices.cpp
b/src/system/boot/platform/efi/devices.cpp
index b0488e9..0bb873a 100644
--- a/src/system/boot/platform/efi/devices.cpp
+++ b/src/system/boot/platform/efi/devices.cpp
@@ -4,18 +4,107 @@
*/
+#include <string.h>
+
#include <boot/partitions.h>
#include <boot/platform.h>
#include <boot/stage2.h>
+#include <boot/stdio.h>
+#include <util/list.h>
#include "efi_platform.h"
+struct device_handle {
+ list_link link;
+ EFI_DEVICE_PATH* device_path;
+ EFI_HANDLE handle;
+};
+
+
+static struct list sMessagingDevices;
+static struct list sMediaDevices;
+
static EFI_GUID BlockIoGUID = BLOCK_IO_PROTOCOL;
static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL;
static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL;
+static void
+dump_device_path(EFI_DEVICE_PATH* path)
+{
+ while (!IsDevicePathEnd(path)) {
+ dprintf("%x:%x => ", path->Type, path->SubType);
+ path = NextDevicePathNode(path);
+ }
+ dprintf("end\n");
+}
+
+
+static UINTN
+device_path_length(EFI_DEVICE_PATH* path)
+{
+ EFI_DEVICE_PATH *node = path;
+ UINTN length = 0;
+ while (!IsDevicePathEnd(node)) {
+ length += DevicePathNodeLength(node);
+ node = NextDevicePathNode(node);
+ }
+
+ // node now points to the device path end node; add its length as well
+ return length + DevicePathNodeLength(node);
+}
+
+
+// If matchSubPath is true, then the second device path can be a sub-path
+// of the first device path
+static bool
+compare_device_paths(EFI_DEVICE_PATH* first, EFI_DEVICE_PATH* second, bool
matchSubPath = false)
+{
+ EFI_DEVICE_PATH *firstNode = first;
+ EFI_DEVICE_PATH *secondNode = second;
+ while (!IsDevicePathEnd(firstNode) && !IsDevicePathEnd(secondNode)) {
+ UINTN firstLength = DevicePathNodeLength(firstNode);
+ UINTN secondLength = DevicePathNodeLength(secondNode);
+ if (firstLength != secondLength || memcmp(firstNode,
secondNode, firstLength) != 0) {
+ return false;
+ }
+ firstNode = NextDevicePathNode(firstNode);
+ secondNode = NextDevicePathNode(secondNode);
+ }
+
+ if (matchSubPath)
+ return IsDevicePathEnd(secondNode);
+
+ return IsDevicePathEnd(firstNode) && IsDevicePathEnd(secondNode);
+}
+
+
+static bool
+add_device_path(struct list *list, EFI_DEVICE_PATH* path, EFI_HANDLE handle)
+{
+ device_handle *node = NULL;
+ while ((node = (device_handle*)list_get_next_item(list, node)) != NULL)
{
+ if (compare_device_paths(node->device_path, path)) {
+ dprintf(" device path already exists\n");
+ return false;
+ }
+ }
+
+ dprintf(" adding a new device path!\n");
+ dump_device_path(path);
+ UINTN length = device_path_length(path);
+ node = (device_handle*)malloc(sizeof(struct device_handle));
+ node->device_path = (EFI_DEVICE_PATH*)malloc(length);
+ node->handle = handle;
+ memcpy(node->device_path, path, length);
+
+ list_add_item(list, node);
+
+ return true;
+}
+
+
class EfiDevice : public Node
{
public:
@@ -30,8 +119,20 @@ class EfiDevice : public Node
return (fBlockIo->Media->LastBlock + 1) * BlockSize(); }
uint32 BlockSize() const { return fBlockIo->Media->BlockSize; }
- //TODO: Check for ATAPI messaging in device path?
- bool IsCD() { return fBlockIo->Media->ReadOnly;}
+ bool ReadOnly() const { return fBlockIo->Media->ReadOnly; }
+ int32 BootMethod() const {
+ if (fDevicePath->Type == MEDIA_DEVICE_PATH) {
+ if (fDevicePath->SubType == MEDIA_CDROM_DP)
+ return BOOT_METHOD_CD;
+ if (fDevicePath->SubType == MEDIA_HARDDRIVE_DP)
+ return BOOT_METHOD_HARD_DISK;
+ }
+
+ return BOOT_METHOD_DEFAULT;
+ }
+
+ EFI_DEVICE_PATH* DevicePath() { return fDevicePath; }
+
private:
EFI_BLOCK_IO* fBlockIo;
EFI_DEVICE_PATH* fDevicePath;
@@ -69,6 +170,74 @@ EfiDevice::ReadAt(void *cookie, off_t pos, void *buffer,
size_t bufferSize)
return bufferSize;
}
+#if 0
+static EFI_DEVICE_PATH*
+find_device_path(EFI_DEVICE_PATH *devicePath, uint16 type, uint16 subType)
+{
+ EFI_DEVICE_PATH *node = devicePath;
+ while (!IsDevicePathEnd(node)) {
+ if (DevicePathType(node) == type
+ && (subType == 0xFFFF || DevicePathSubType(node) ==
subType))
+ return node;
+
+ node = NextDevicePathNode(node);
+ }
+
+ return NULL;
+}
+#endif
+
+static status_t
+build_device_handles()
+{
+ EFI_GUID blockIoGuid = BLOCK_IO_PROTOCOL;
+ EFI_GUID devicePathGuid = DEVICE_PATH_PROTOCOL;
+
+ //EFI_BLOCK_IO *blockIo;
+ EFI_DEVICE_PATH *devicePath, *node;
+ EFI_HANDLE *handles = NULL;
+ EFI_STATUS status;
+ UINTN size = 0;
+
+ status = kBootServices->LocateHandle(ByProtocol, &blockIoGuid, 0,
&size, 0);
+ if (status != EFI_BUFFER_TOO_SMALL)
+ return B_ENTRY_NOT_FOUND;
+
+ handles = (EFI_HANDLE*)malloc(size);
+ status = kBootServices->LocateHandle(ByProtocol, &blockIoGuid, 0, &size,
+ handles);
+ if (status != EFI_SUCCESS) {
+ free(handles);
+ return B_ENTRY_NOT_FOUND;
+ }
+
+ for (UINTN n = 0; n < (size / sizeof(EFI_HANDLE)); n++) {
+ dprintf(" processing handle %lu\n", n);
+ status = kBootServices->HandleProtocol(handles[n],
&devicePathGuid,
+ (void**)&devicePath);
+ if (status != EFI_SUCCESS)
+ continue;
+
+ node = devicePath;
+ while (!IsDevicePathEnd(NextDevicePathNode(node)))
+ node = NextDevicePathNode(node);
+
+ if (DevicePathType(node) == MEDIA_DEVICE_PATH) {
+ // Add to our media devices list
+ dprintf(" adding a media device path instance\n");
+ add_device_path(&sMediaDevices, devicePath, handles[n]);
+ } else if (DevicePathType(node) == MESSAGING_DEVICE_PATH) {
+ // Add to our messaging devices list
+ dprintf(" adding a messaging device path
instance\n");
+ add_device_path(&sMessagingDevices, devicePath,
handles[n]);
+ }
+ dprintf(" finished pass...\n");
+ }
+ dprintf("finished processing handles\n");
+
+ return B_OK;
+}
+
static off_t
get_next_check_sum_offset(int32 index, off_t maxSize)
@@ -80,7 +249,6 @@ get_next_check_sum_offset(int32 index, off_t maxSize)
return (maxSize >> 10) + index * 2048;
return ((system_time() + index) % (maxSize >> 9)) * 512;
- //return 42 * 512;
}
@@ -105,91 +273,234 @@ compute_check_sum(Node *device, off_t offset)
}
-status_t
-platform_add_boot_device(struct stage2_args *args, NodeList *devicesList)
+static status_t
+add_boot_device(NodeList *devicesList)
+{
+ return B_ENTRY_NOT_FOUND;
+}
+
+
+static device_handle*
+get_messaging_device_for_media_device(device_handle *media_device)
+{
+ device_handle *messaging_device = NULL;
+ while ((messaging_device =
(device_handle*)list_get_next_item(&sMessagingDevices, messaging_device)) !=
NULL) {
+ if (compare_device_paths(media_device->device_path,
+ messaging_device->device_path, true)) {
+ dprintf("found messaging device for media device\n");
+ return messaging_device;
+ }
+ }
+
+ return NULL;
+}
+
+
+static status_t
+add_boot_device_for_image(NodeList *devicesList)
{
EFI_LOADED_IMAGE *loadedImage;
- if (kBootServices->HandleProtocol(kImage, &LoadedImageGUID,
+ if (kBootServices->HandleProtocol(kImage, &LoadedImageGUID,
(void**)&loadedImage) != EFI_SUCCESS)
return B_ERROR;
EFI_DEVICE_PATH *devicePath, *node;
if (kBootServices->HandleProtocol(loadedImage->DeviceHandle,
- &DevicePathGUID, (void **)&devicePath) != EFI_SUCCESS)
- panic("Failed to lookup boot device path!");
+ &DevicePathGUID, (void**)&devicePath) != EFI_SUCCESS)
+ return B_ERROR;
- for (node = devicePath;DevicePathType(node) != MESSAGING_DEVICE_PATH;
+ dprintf("got device path for image handle\n");
+ dump_device_path(devicePath);
+ for (node = devicePath; DevicePathType(node) != MESSAGING_DEVICE_PATH;
node = NextDevicePathNode(node)) {
+ dprintf("finding messaging device path node\n");
+ dump_device_path(node);
if (IsDevicePathEnd(node))
- panic("Could not find disk of EFI partition!");
+ return B_ERROR;
}
SetDevicePathEndNode(NextDevicePathNode(node));
+ dprintf("updating device path end\n");
+ dump_device_path(devicePath);
+ dump_device_path(node);
+
+ UINTN length = device_path_length(devicePath);
+ EFI_DEVICE_PATH *savedDevicePath = (EFI_DEVICE_PATH*)malloc(length);
+ memcpy(savedDevicePath, devicePath, length);
+
EFI_HANDLE handle;
if (kBootServices->LocateDevicePath(&BlockIoGUID, &devicePath, &handle)
!= EFI_SUCCESS)
- panic("Cannot get boot device handle!");
+ return B_ERROR;
+
+ if (!IsDevicePathEnd(devicePath))
+ return B_ERROR;
+
+ dprintf("LocateDevicePath(BlockIoGUID, devicePath, handle)\n");
+ dump_device_path(savedDevicePath);
EFI_BLOCK_IO *blockIo;
if (kBootServices->HandleProtocol(handle, &BlockIoGUID,
(void**)&blockIo)
!= EFI_SUCCESS)
- panic("Cannot get boot block io protocol!");
+ return B_ERROR;
if (!blockIo->Media->MediaPresent)
- panic("Boot disk has no media present!");
-
+ return B_ERROR;
- EfiDevice *device = new(std::nothrow)EfiDevice(blockIo, devicePath);
+ EfiDevice *device = new(std::nothrow)EfiDevice(blockIo,
savedDevicePath);
if (device == NULL)
- panic("Can't allocate memory for boot device!");
+ return B_ERROR;
+
+ dprintf("checking whether to add boot device to messaging devices
list...\n");
+ if (add_device_path(&sMessagingDevices, savedDevicePath, handle)) {
+ dprintf("adding the boot device to the list\n");
+ } else {
+ dprintf("device already present in messaging devices\n");
+ }
+ dprintf(" => adding the boot device based on image handle\n");
devicesList->Insert(device);
return B_OK;
}
-status_t
-platform_add_block_devices(struct stage2_args *args, NodeList *devicesList)
+static status_t
+add_cd_devices(NodeList *devicesList)
{
- EFI_BLOCK_IO *blockIo;
- UINTN memSize = 0;
-
- // Read to zero sized buffer to get memory needed for handles
- if (kBootServices->LocateHandle(ByProtocol, &BlockIoGUID, 0, &memSize,
0)
- != EFI_BUFFER_TOO_SMALL)
- panic("Cannot read size of block device handles!");
+ device_handle *handle = NULL;
+ while ((handle = (device_handle*)list_get_next_item(&sMediaDevices,
handle)) != NULL) {
+ EFI_DEVICE_PATH *node = handle->device_path;
+ while (!IsDevicePathEnd(NextDevicePathNode(node)))
+ node = NextDevicePathNode(node);
- uint32 noOfHandles = memSize / sizeof(EFI_HANDLE);
-
- EFI_HANDLE handles[noOfHandles];
- if (kBootServices->LocateHandle(ByProtocol, &BlockIoGUID, 0, &memSize,
- handles) != EFI_SUCCESS)
- panic("Failed to locate block devices!");
+ if (DevicePathType(node) != MEDIA_DEVICE_PATH)
+ continue;
- for (uint32 n = 0; n < noOfHandles; n++) {
- if (kBootServices->HandleProtocol(handles[n], &BlockIoGUID,
- (void**)&blockIo) != EFI_SUCCESS)
- panic("Cannot get block device handle!");
+ if (DevicePathSubType(node) != MEDIA_CDROM_DP)
+ continue;
- // Skip partition block devices, Haiku does partition scan
- if (!blockIo->Media->MediaPresent ||
blockIo->Media->LogicalPartition)
+ device_handle *messaging_device =
get_messaging_device_for_media_device(handle);
+ if (messaging_device == NULL) {
+ dprintf("couldn't find messaging device for media
device\n");
+ continue;
+ }
+
+ EFI_BLOCK_IO *blockIo;
+ EFI_GUID blockIoGuid = BLOCK_IO_PROTOCOL;
+ EFI_STATUS status =
kBootServices->HandleProtocol(messaging_device->handle,
+ &blockIoGuid, (void**)&blockIo);
+ if (status != EFI_SUCCESS) {
+ dprintf("unable to get block IO for device path\n");
continue;
+ }
+ if (!blockIo->Media->MediaPresent) {
+ dprintf("media not present for device path\n");
+ continue;
+ }
- EFI_DEVICE_PATH *devicePath;
- // Atm devicePath isn't necessary so result isn't checked
- kBootServices->HandleProtocol(handles[n], &DevicePathGUID,
- (void**)&devicePath);
+ if (blockIo->Media->ReadOnly) {
+ dprintf("note: media is readonly\n");
+ }
- EfiDevice *device = new(std::nothrow)EfiDevice(blockIo,
devicePath);
+ EfiDevice *device = new(std::nothrow)EfiDevice(blockIo,
handle->device_path);
if (device == NULL)
- panic("Can't allocate memory for block devices!");
+ continue;
+
+ dprintf(" => adding a CD device\n");
devicesList->Insert(device);
}
+
return devicesList->Count() > 0 ? B_OK : B_ENTRY_NOT_FOUND;
}
+static status_t
+add_remaining_devices(NodeList *devicesList)
+{
+ device_handle *node = NULL;
+ while ((node = (device_handle*)list_get_next_item(&sMessagingDevices,
node)) != NULL) {
+ NodeIterator it = devicesList->GetIterator();
+ bool found = false;
+ while (it.HasNext()) {
+ EfiDevice *device = (EfiDevice*)it.Next();
+ // device->DevicePath() is a Media Device Path instance
+ if (compare_device_paths(device->DevicePath(),
node->device_path, true)) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ EFI_BLOCK_IO *blockIo;
+ EFI_GUID blockIoGuid = BLOCK_IO_PROTOCOL;
+ EFI_STATUS status =
kBootServices->HandleProtocol(node->handle,
+ &blockIoGuid, (void**)&blockIo);
+ if (status != EFI_SUCCESS) {
+ dprintf("unable to get block IO for device
path\n");
+ continue;
+ }
+ if (!blockIo->Media->MediaPresent) {
+ dprintf("media not present for device path\n");
+ continue;
+ }
+
+ EfiDevice *device = new(std::nothrow)EfiDevice(blockIo,
node->device_path);
+ if (device == NULL)
+ continue;
+
+ devicesList->Insert(device);
+ dprintf(" => added a new messaging device to devices
list\n");
+ } else {
+ dprintf(" => skipping existing messaging device
path\n");
+ }
+ }
+
+ return B_OK;
+}
+
+
+static bool
+get_boot_uuid(void)
+{
+ return false;
+}
+
+
+status_t
+platform_add_boot_device(struct stage2_args *args, NodeList *devicesList)
+{
+ // This is the first entry point, so init the lists here
+ list_init(&sMessagingDevices);
+ list_init(&sMediaDevices);
+
+ build_device_handles();
+
+ if (get_boot_uuid()) {
+ // If we have the UUID, add the boot device containing that
partition
+ return add_boot_device(devicesList);
+ } else {
+ // If we don't have a UUID, add all CD devices with media, and
the
+ // device that haiku_loader.efi is located on
+ add_boot_device_for_image(devicesList);
+ // We do this first, so that booting from CD is the
fallback
+ add_cd_devices(devicesList);
+ if (devicesList->Count() > 0)
+ return B_OK;
+ }
+
+ // Otherwise, we don't know what the boot device is; defer to
+ // platform_add_block_devices() to add the rest
+ return B_ENTRY_NOT_FOUND;
+}
+
+
+status_t
+platform_add_block_devices(struct stage2_args *args, NodeList *devicesList)
+{
+ return add_remaining_devices(devicesList);
+}
+
+
status_t
platform_get_boot_partition(struct stage2_args *args, Node *bootDevice,
NodeList *partitions, boot::Partition **_partition)
@@ -197,10 +508,14 @@ platform_get_boot_partition(struct stage2_args *args,
Node *bootDevice,
NodeIterator iterator = partitions->GetIterator();
boot::Partition *partition = NULL;
while ((partition = (boot::Partition *)iterator.Next()) != NULL) {
- //Currently we pick first partition. If not found menu lets
user select.
+ // Currently we pick last partition; seems to work enough for
now
+ // until we can actually identify the partition we want to boot
+ // from
*_partition = partition;
- return B_OK;
+ if (!iterator.HasNext())
+ return B_OK;
}
+
return B_ENTRY_NOT_FOUND;
}
@@ -222,9 +537,8 @@ platform_register_boot_device(Node *device)
identifier.device.unknown.check_sums[i].sum =
compute_check_sum(device, offset);
}
- gBootVolume.SetInt32(BOOT_METHOD, efiDevice->IsCD() ? BOOT_METHOD_CD:
- BOOT_METHOD_HARD_DISK);
- gBootVolume.SetBool(BOOT_VOLUME_BOOTED_FROM_IMAGE, true);
+ gBootVolume.SetInt32(BOOT_METHOD, efiDevice->BootMethod());
+ gBootVolume.SetBool(BOOT_VOLUME_BOOTED_FROM_IMAGE,
efiDevice->ReadOnly());
gBootVolume.SetData(BOOT_VOLUME_DISK_IDENTIFIER, B_RAW_TYPE,
&identifier, sizeof(disk_identifier));