[haiku-commits] haiku: hrev50829 - src/system/boot/platform/efi

  • From: fredrik.holmqvist@xxxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Fri, 6 Jan 2017 19:55:48 +0100 (CET)

hrev50829 adds 2 changesets to branch 'master'
old head: c337460525c39e870d31221d205a299d9cd79c6a
new head: 1d8306654a786a74cd83bc96db97e2b433ee86b2
overview: 
http://cgit.haiku-os.org/haiku/log/?qt=range&q=1d8306654a78+%5Ec337460525c3

----------------------------------------------------------------------------

57b59d47c57e: memset was done twice

1d8306654a78: Rewrote device handling in EFI boot-loader
  
  This allows me to find and boot disks and cds(*)
  platform_add_boot_device tries to find the disk of the EFI partition
  As on other platforms if boot disk isn't found platform_add_block_devices
  will be called.
  platform_add_block_devices will find all block devices that arn't partitions 
as
  they are handled by Haiku already.
  Currently first found suitable partition will be selected.
  
  TODO:
   * pass in partition UUID's as boot-loader arg to setup boot for
  any partition.
   * Better cd detection
   * Better disk_identifier
  
  *) vfs_boot.cpp is very restrictive when it comes to booting cds.
  It either do very Anyboot check where boot partition should be at offset 0,
  which isn't true for EFI. In my case it's not even on that disk.
  Or it only allow data session partition types.
  This is currently failing as the Anyboot partition type is BFS.

                         [ Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> ]

----------------------------------------------------------------------------

3 files changed, 101 insertions(+), 113 deletions(-)
src/system/boot/platform/efi/devices.cpp    | 210 +++++++++++-------------
src/system/boot/platform/efi/efi_platform.h |   2 +-
src/system/boot/platform/efi/start.cpp      |   2 -

############################################################################

Commit:      57b59d47c57ef1382d4be55792f5bf036c26c88a
URL:         http://cgit.haiku-os.org/haiku/commit/?id=57b59d47c57e
Author:      Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx>
Date:        Fri Jan  6 18:39:58 2017 UTC

memset was done twice

----------------------------------------------------------------------------

diff --git a/src/system/boot/platform/efi/start.cpp 
b/src/system/boot/platform/efi/start.cpp
index 16fa962..a8cc4bc 100644
--- a/src/system/boot/platform/efi/start.cpp
+++ b/src/system/boot/platform/efi/start.cpp
@@ -277,8 +277,6 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systemTable)
        kBootServices = systemTable->BootServices;
        kRuntimeServices = systemTable->RuntimeServices;
 
-       memset(&args, 0, sizeof(stage2_args));
-
        call_ctors();
 
        console_init();

############################################################################

Revision:    hrev50829
Commit:      1d8306654a786a74cd83bc96db97e2b433ee86b2
URL:         http://cgit.haiku-os.org/haiku/commit/?id=1d8306654a78
Author:      Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx>
Date:        Fri Jan  6 18:43:08 2017 UTC

Rewrote device handling in EFI boot-loader

This allows me to find and boot disks and cds(*)
platform_add_boot_device tries to find the disk of the EFI partition
As on other platforms if boot disk isn't found platform_add_block_devices
will be called.
platform_add_block_devices will find all block devices that arn't partitions as
they are handled by Haiku already.
Currently first found suitable partition will be selected.

TODO:
 * pass in partition UUID's as boot-loader arg to setup boot for
any partition.
 * Better cd detection
 * Better disk_identifier

*) vfs_boot.cpp is very restrictive when it comes to booting cds.
It either do very Anyboot check where boot partition should be at offset 0,
which isn't true for EFI. In my case it's not even on that disk.
Or it only allow data session partition types.
This is currently failing as the Anyboot partition type is BFS.

----------------------------------------------------------------------------

diff --git a/src/system/boot/platform/efi/devices.cpp 
b/src/system/boot/platform/efi/devices.cpp
index 8538ddd..b0488e9 100644
--- a/src/system/boot/platform/efi/devices.cpp
+++ b/src/system/boot/platform/efi/devices.cpp
@@ -11,6 +11,11 @@
 #include "efi_platform.h"
 
 
+static EFI_GUID BlockIoGUID = BLOCK_IO_PROTOCOL;
+static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL;
+static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL;
+
+
 class EfiDevice : public Node
 {
        public:
@@ -21,15 +26,15 @@ class EfiDevice : public Node
                        size_t bufferSize);
                virtual ssize_t WriteAt(void *cookie, off_t pos, const void 
*buffer,
                        size_t bufferSize) { return B_UNSUPPORTED; }
-               virtual off_t Size() const { return fSize; }
+               virtual off_t Size() const {
+                       return (fBlockIo->Media->LastBlock + 1) * BlockSize(); }
 
-               uint32 BlockSize() const { return fBlockSize; }
+               uint32 BlockSize() const { return fBlockIo->Media->BlockSize; }
+               //TODO: Check for ATAPI messaging in device path?
+               bool IsCD() { return fBlockIo->Media->ReadOnly;}
        private:
                EFI_BLOCK_IO*           fBlockIo;
                EFI_DEVICE_PATH*        fDevicePath;
-
-               uint32                          fBlockSize;
-               uint64                          fSize;
 };
 
 
@@ -38,8 +43,6 @@ EfiDevice::EfiDevice(EFI_BLOCK_IO *blockIo, EFI_DEVICE_PATH 
*devicePath)
        fBlockIo(blockIo),
        fDevicePath(devicePath)
 {
-       fBlockSize = fBlockIo->Media->BlockSize;
-       fSize = (fBlockIo->Media->LastBlock + 1) * fBlockSize;
 }
 
 
@@ -51,16 +54,14 @@ EfiDevice::~EfiDevice()
 ssize_t
 EfiDevice::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize)
 {
-       uint32 offset = pos % fBlockSize;
-       pos /= fBlockSize;
+       uint32 offset = pos % BlockSize();
+       pos /= BlockSize();
 
-       uint32 numBlocks = (offset + bufferSize + fBlockSize) / fBlockSize;
-       char readBuffer[numBlocks * fBlockSize];
+       uint32 numBlocks = (offset + bufferSize + BlockSize()) / BlockSize();
+       char readBuffer[numBlocks * BlockSize()];
 
-       EFI_STATUS status = fBlockIo->ReadBlocks(fBlockIo, 
fBlockIo->Media->MediaId,
-               pos, sizeof(readBuffer), readBuffer);
-
-       if (status != EFI_SUCCESS)
+       if (fBlockIo->ReadBlocks(fBlockIo, fBlockIo->Media->MediaId,
+               pos, sizeof(readBuffer), readBuffer) != EFI_SUCCESS)
                return B_ERROR;
 
        memcpy(buffer, readBuffer + offset, bufferSize);
@@ -69,88 +70,6 @@ EfiDevice::ReadAt(void *cookie, off_t pos, void *buffer, 
size_t bufferSize)
 }
 
 
-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;
-}
-
-
-static status_t
-add_boot_devices(NodeList *devicesList)
-{
-       EFI_GUID blockIoGuid = BLOCK_IO_PROTOCOL;
-       EFI_GUID devicePathGuid = DEVICE_PATH_PROTOCOL;
-       EFI_BLOCK_IO *blockIo;
-       EFI_DEVICE_PATH *devicePath, *node, *targetDevicePath = NULL;
-       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) {
-               if (handles != NULL)
-                       free(handles);
-               return B_ENTRY_NOT_FOUND;
-       }
-
-       for (int n = (size / sizeof(EFI_HANDLE)) - 1; n >= 0; --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
-                       && DevicePathSubType(node) == MEDIA_CDROM_DP) {
-                       targetDevicePath = find_device_path(devicePath,
-                               MESSAGING_DEVICE_PATH, 0xFFFF);
-                       continue;
-               }
-
-               if (DevicePathType(node) != MESSAGING_DEVICE_PATH)
-                       continue;
-
-               status = kBootServices->HandleProtocol(handles[n], &blockIoGuid,
-                       (void**)&blockIo);
-               if (status != EFI_SUCCESS || !blockIo->Media->MediaPresent)
-                       continue;
-
-               EfiDevice *device = new(std::nothrow)EfiDevice(blockIo, 
devicePath);
-               if (device == NULL)
-                       continue;
-
-               if (targetDevicePath != NULL
-                       && memcmp(targetDevicePath, node, 
DevicePathNodeLength(node)) == 0)
-                       devicesList->InsertBefore(devicesList->Head(), device);
-               else
-                       devicesList->Insert(device);
-
-               targetDevicePath = NULL;
-       }
-
-       return devicesList->Count() > 0 ? B_OK : B_ENTRY_NOT_FOUND;
-}
-
-
 static off_t
 get_next_check_sum_offset(int32 index, off_t maxSize)
 {
@@ -160,8 +79,8 @@ get_next_check_sum_offset(int32 index, off_t maxSize)
        if (index < 4)
                return (maxSize >> 10) + index * 2048;
 
-       //return ((system_time() + index) % (maxSize >> 9)) * 512;
-       return 42 * 512;
+       return ((system_time() + index) % (maxSize >> 9)) * 512;
+       //return 42 * 512;
 }
 
 
@@ -189,16 +108,85 @@ compute_check_sum(Node *device, off_t offset)
 status_t
 platform_add_boot_device(struct stage2_args *args, NodeList *devicesList)
 {
-       // TODO: get GUID of partition to boot, and support for SATA/ATA devices
-       return add_boot_devices(devicesList);
+       EFI_LOADED_IMAGE *loadedImage;
+       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!");
+
+       for (node = devicePath;DevicePathType(node) != MESSAGING_DEVICE_PATH;
+                       node = NextDevicePathNode(node)) {
+               if (IsDevicePathEnd(node))
+                       panic("Could not find disk of EFI partition!");
+       }
+
+       SetDevicePathEndNode(NextDevicePathNode(node));
+
+       EFI_HANDLE handle;
+       if (kBootServices->LocateDevicePath(&BlockIoGUID, &devicePath, &handle)
+                       != EFI_SUCCESS)
+               panic("Cannot get boot device handle!");
+
+       EFI_BLOCK_IO *blockIo;
+       if (kBootServices->HandleProtocol(handle, &BlockIoGUID, 
(void**)&blockIo)
+                       != EFI_SUCCESS)
+               panic("Cannot get boot block io protocol!");
+
+       if (!blockIo->Media->MediaPresent)
+               panic("Boot disk has no media present!");
+
+
+       EfiDevice *device = new(std::nothrow)EfiDevice(blockIo, devicePath);
+       if (device == NULL)
+               panic("Can't allocate memory for boot device!");
+
+       devicesList->Insert(device);
+       return B_OK;
 }
 
 
 status_t
 platform_add_block_devices(struct stage2_args *args, NodeList *devicesList)
 {
-       // add_boot_devices will add all available devices, so nothing to do 
here
-       return B_OK;
+       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!");
+
+       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!");
+
+       for (uint32 n = 0; n < noOfHandles; n++) {
+               if (kBootServices->HandleProtocol(handles[n], &BlockIoGUID,
+                               (void**)&blockIo) != EFI_SUCCESS)
+                       panic("Cannot get block device handle!");
+
+               // Skip partition block devices, Haiku does partition scan
+               if (!blockIo->Media->MediaPresent || 
blockIo->Media->LogicalPartition)
+                       continue;
+
+               EFI_DEVICE_PATH *devicePath;
+               // Atm devicePath isn't necessary so result isn't checked
+               kBootServices->HandleProtocol(handles[n], &DevicePathGUID,
+                       (void**)&devicePath);
+
+               EfiDevice *device = new(std::nothrow)EfiDevice(blockIo, 
devicePath);
+               if (device == NULL)
+                       panic("Can't allocate memory for block devices!");
+               devicesList->Insert(device);
+       }
+       return devicesList->Count() > 0 ? B_OK : B_ENTRY_NOT_FOUND;
 }
 
 
@@ -206,23 +194,24 @@ status_t
 platform_get_boot_partition(struct stage2_args *args, Node *bootDevice,
                NodeList *partitions, boot::Partition **_partition)
 {
-       NodeIterator it = partitions->GetIterator();
-       while (it.HasNext()) {
-               boot::Partition *partition = (boot::Partition*)it.Next();
-               // we're only looking for CDs atm, so just return first found
+       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.
                *_partition = partition;
                return B_OK;
        }
-
-       return B_ERROR;
+       return B_ENTRY_NOT_FOUND;
 }
 
 
 status_t
 platform_register_boot_device(Node *device)
 {
+       EfiDevice *efiDevice = (EfiDevice *)device;
        disk_identifier identifier;
 
+       // TODO: Setup using device path
        identifier.bus_type = UNKNOWN_BUS;
        identifier.device_type = UNKNOWN_DEVICE;
        identifier.device.unknown.size = device->Size();
@@ -233,7 +222,8 @@ platform_register_boot_device(Node *device)
                identifier.device.unknown.check_sums[i].sum = 
compute_check_sum(device, offset);
        }
 
-       gBootVolume.SetInt32(BOOT_METHOD, BOOT_METHOD_CD);
+       gBootVolume.SetInt32(BOOT_METHOD, efiDevice->IsCD() ? BOOT_METHOD_CD:
+               BOOT_METHOD_HARD_DISK);
        gBootVolume.SetBool(BOOT_VOLUME_BOOTED_FROM_IMAGE, true);
        gBootVolume.SetData(BOOT_VOLUME_DISK_IDENTIFIER, B_RAW_TYPE,
                &identifier, sizeof(disk_identifier));
diff --git a/src/system/boot/platform/efi/efi_platform.h 
b/src/system/boot/platform/efi/efi_platform.h
index b9670e9..8067497 100644
--- a/src/system/boot/platform/efi/efi_platform.h
+++ b/src/system/boot/platform/efi/efi_platform.h
@@ -18,6 +18,6 @@
 extern const EFI_SYSTEM_TABLE          *kSystemTable;
 extern const EFI_BOOT_SERVICES         *kBootServices;
 extern const EFI_RUNTIME_SERVICES      *kRuntimeServices;
-
+extern EFI_HANDLE kImage;
 
 #endif /* EFI_PLATFORM_H */


Other related posts:

  • » [haiku-commits] haiku: hrev50829 - src/system/boot/platform/efi - fredrik . holmqvist