1e2e1558aSJessica Hamilton /* 242e718f0SJessica Hamilton * Copyright 2016-2017 Haiku, Inc. All rights reserved. 3e2e1558aSJessica Hamilton * Distributed under the terms of the MIT License. 4e2e1558aSJessica Hamilton */ 5e2e1558aSJessica Hamilton 6e2e1558aSJessica Hamilton 742e718f0SJessica Hamilton #include <string.h> 842e718f0SJessica Hamilton 92da1cb75SJessica Hamilton #include <boot/partitions.h> 10e2e1558aSJessica Hamilton #include <boot/platform.h> 11e2e1558aSJessica Hamilton #include <boot/stage2.h> 1242e718f0SJessica Hamilton #include <boot/stdio.h> 1342e718f0SJessica Hamilton #include <util/list.h> 14e2e1558aSJessica Hamilton 15*6b4cbec0SJessica Hamilton #include "Header.h" 16*6b4cbec0SJessica Hamilton 172da1cb75SJessica Hamilton #include "efi_platform.h" 18*6b4cbec0SJessica Hamilton #include "efigpt.h" 19*6b4cbec0SJessica Hamilton #include "gpt_known_guids.h" 202da1cb75SJessica Hamilton 212da1cb75SJessica Hamilton 2242e718f0SJessica Hamilton struct device_handle { 2342e718f0SJessica Hamilton list_link link; 2442e718f0SJessica Hamilton EFI_DEVICE_PATH* device_path; 2542e718f0SJessica Hamilton EFI_HANDLE handle; 2642e718f0SJessica Hamilton }; 2742e718f0SJessica Hamilton 2842e718f0SJessica Hamilton 2942e718f0SJessica Hamilton static struct list sMessagingDevices; 3042e718f0SJessica Hamilton static struct list sMediaDevices; 3142e718f0SJessica Hamilton 321d830665SFredrik Holmqvist static EFI_GUID BlockIoGUID = BLOCK_IO_PROTOCOL; 331d830665SFredrik Holmqvist static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; 341d830665SFredrik Holmqvist static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; 351d830665SFredrik Holmqvist 361d830665SFredrik Holmqvist 3742e718f0SJessica Hamilton static UINTN 3842e718f0SJessica Hamilton device_path_length(EFI_DEVICE_PATH* path) 3942e718f0SJessica Hamilton { 4042e718f0SJessica Hamilton EFI_DEVICE_PATH *node = path; 4142e718f0SJessica Hamilton UINTN length = 0; 4242e718f0SJessica Hamilton while (!IsDevicePathEnd(node)) { 4342e718f0SJessica Hamilton length += DevicePathNodeLength(node); 4442e718f0SJessica Hamilton node = NextDevicePathNode(node); 4542e718f0SJessica Hamilton } 4642e718f0SJessica Hamilton 4742e718f0SJessica Hamilton // node now points to the device path end node; add its length as well 4842e718f0SJessica Hamilton return length + DevicePathNodeLength(node); 4942e718f0SJessica Hamilton } 5042e718f0SJessica Hamilton 5142e718f0SJessica Hamilton 5242e718f0SJessica Hamilton // If matchSubPath is true, then the second device path can be a sub-path 5342e718f0SJessica Hamilton // of the first device path 5442e718f0SJessica Hamilton static bool 5542e718f0SJessica Hamilton compare_device_paths(EFI_DEVICE_PATH* first, EFI_DEVICE_PATH* second, bool matchSubPath = false) 5642e718f0SJessica Hamilton { 5742e718f0SJessica Hamilton EFI_DEVICE_PATH *firstNode = first; 5842e718f0SJessica Hamilton EFI_DEVICE_PATH *secondNode = second; 5942e718f0SJessica Hamilton while (!IsDevicePathEnd(firstNode) && !IsDevicePathEnd(secondNode)) { 6042e718f0SJessica Hamilton UINTN firstLength = DevicePathNodeLength(firstNode); 6142e718f0SJessica Hamilton UINTN secondLength = DevicePathNodeLength(secondNode); 6242e718f0SJessica Hamilton if (firstLength != secondLength || memcmp(firstNode, secondNode, firstLength) != 0) { 6342e718f0SJessica Hamilton return false; 6442e718f0SJessica Hamilton } 6542e718f0SJessica Hamilton firstNode = NextDevicePathNode(firstNode); 6642e718f0SJessica Hamilton secondNode = NextDevicePathNode(secondNode); 6742e718f0SJessica Hamilton } 6842e718f0SJessica Hamilton 6942e718f0SJessica Hamilton if (matchSubPath) 7042e718f0SJessica Hamilton return IsDevicePathEnd(secondNode); 7142e718f0SJessica Hamilton 7242e718f0SJessica Hamilton return IsDevicePathEnd(firstNode) && IsDevicePathEnd(secondNode); 7342e718f0SJessica Hamilton } 7442e718f0SJessica Hamilton 7542e718f0SJessica Hamilton 7642e718f0SJessica Hamilton static bool 7742e718f0SJessica Hamilton add_device_path(struct list *list, EFI_DEVICE_PATH* path, EFI_HANDLE handle) 7842e718f0SJessica Hamilton { 7942e718f0SJessica Hamilton device_handle *node = NULL; 8042e718f0SJessica Hamilton while ((node = (device_handle*)list_get_next_item(list, node)) != NULL) { 8142e718f0SJessica Hamilton if (compare_device_paths(node->device_path, path)) 8242e718f0SJessica Hamilton return false; 8342e718f0SJessica Hamilton } 8442e718f0SJessica Hamilton 8542e718f0SJessica Hamilton UINTN length = device_path_length(path); 8642e718f0SJessica Hamilton node = (device_handle*)malloc(sizeof(struct device_handle)); 8742e718f0SJessica Hamilton node->device_path = (EFI_DEVICE_PATH*)malloc(length); 8842e718f0SJessica Hamilton node->handle = handle; 8942e718f0SJessica Hamilton memcpy(node->device_path, path, length); 9042e718f0SJessica Hamilton 9142e718f0SJessica Hamilton list_add_item(list, node); 9242e718f0SJessica Hamilton 9342e718f0SJessica Hamilton return true; 9442e718f0SJessica Hamilton } 9542e718f0SJessica Hamilton 9642e718f0SJessica Hamilton 972da1cb75SJessica Hamilton class EfiDevice : public Node 982da1cb75SJessica Hamilton { 992da1cb75SJessica Hamilton public: 1002da1cb75SJessica Hamilton EfiDevice(EFI_BLOCK_IO *blockIo, EFI_DEVICE_PATH *devicePath); 1012da1cb75SJessica Hamilton virtual ~EfiDevice(); 1022da1cb75SJessica Hamilton 1032da1cb75SJessica Hamilton virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer, 1042da1cb75SJessica Hamilton size_t bufferSize); 1052da1cb75SJessica Hamilton virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer, 1062da1cb75SJessica Hamilton size_t bufferSize) { return B_UNSUPPORTED; } 1071d830665SFredrik Holmqvist virtual off_t Size() const { 1081d830665SFredrik Holmqvist return (fBlockIo->Media->LastBlock + 1) * BlockSize(); } 1092da1cb75SJessica Hamilton 1101d830665SFredrik Holmqvist uint32 BlockSize() const { return fBlockIo->Media->BlockSize; } 11142e718f0SJessica Hamilton bool ReadOnly() const { return fBlockIo->Media->ReadOnly; } 11242e718f0SJessica Hamilton int32 BootMethod() const { 11342e718f0SJessica Hamilton if (fDevicePath->Type == MEDIA_DEVICE_PATH) { 11442e718f0SJessica Hamilton if (fDevicePath->SubType == MEDIA_CDROM_DP) 11542e718f0SJessica Hamilton return BOOT_METHOD_CD; 11642e718f0SJessica Hamilton if (fDevicePath->SubType == MEDIA_HARDDRIVE_DP) 11742e718f0SJessica Hamilton return BOOT_METHOD_HARD_DISK; 11842e718f0SJessica Hamilton } 11942e718f0SJessica Hamilton 12042e718f0SJessica Hamilton return BOOT_METHOD_DEFAULT; 12142e718f0SJessica Hamilton } 12242e718f0SJessica Hamilton 12342e718f0SJessica Hamilton EFI_DEVICE_PATH* DevicePath() { return fDevicePath; } 12442e718f0SJessica Hamilton 1252da1cb75SJessica Hamilton private: 1262da1cb75SJessica Hamilton EFI_BLOCK_IO* fBlockIo; 1272da1cb75SJessica Hamilton EFI_DEVICE_PATH* fDevicePath; 1282da1cb75SJessica Hamilton }; 1292da1cb75SJessica Hamilton 1302da1cb75SJessica Hamilton 1312da1cb75SJessica Hamilton EfiDevice::EfiDevice(EFI_BLOCK_IO *blockIo, EFI_DEVICE_PATH *devicePath) 1322da1cb75SJessica Hamilton : 1332da1cb75SJessica Hamilton fBlockIo(blockIo), 1342da1cb75SJessica Hamilton fDevicePath(devicePath) 1352da1cb75SJessica Hamilton { 1362da1cb75SJessica Hamilton } 1372da1cb75SJessica Hamilton 1382da1cb75SJessica Hamilton 1392da1cb75SJessica Hamilton EfiDevice::~EfiDevice() 1402da1cb75SJessica Hamilton { 1412da1cb75SJessica Hamilton } 1422da1cb75SJessica Hamilton 1432da1cb75SJessica Hamilton 1442da1cb75SJessica Hamilton ssize_t 1452da1cb75SJessica Hamilton EfiDevice::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize) 1462da1cb75SJessica Hamilton { 1471d830665SFredrik Holmqvist uint32 offset = pos % BlockSize(); 1481d830665SFredrik Holmqvist pos /= BlockSize(); 1492da1cb75SJessica Hamilton 1501d830665SFredrik Holmqvist uint32 numBlocks = (offset + bufferSize + BlockSize()) / BlockSize(); 1511d830665SFredrik Holmqvist char readBuffer[numBlocks * BlockSize()]; 1522da1cb75SJessica Hamilton 1531d830665SFredrik Holmqvist if (fBlockIo->ReadBlocks(fBlockIo, fBlockIo->Media->MediaId, 1541d830665SFredrik Holmqvist pos, sizeof(readBuffer), readBuffer) != EFI_SUCCESS) 1552da1cb75SJessica Hamilton return B_ERROR; 1562da1cb75SJessica Hamilton 1572da1cb75SJessica Hamilton memcpy(buffer, readBuffer + offset, bufferSize); 1582da1cb75SJessica Hamilton 1592da1cb75SJessica Hamilton return bufferSize; 1602da1cb75SJessica Hamilton } 1612da1cb75SJessica Hamilton 1622da1cb75SJessica Hamilton 16342e718f0SJessica Hamilton static status_t 16442e718f0SJessica Hamilton build_device_handles() 16542e718f0SJessica Hamilton { 16642e718f0SJessica Hamilton EFI_GUID blockIoGuid = BLOCK_IO_PROTOCOL; 16742e718f0SJessica Hamilton EFI_GUID devicePathGuid = DEVICE_PATH_PROTOCOL; 16842e718f0SJessica Hamilton 16942e718f0SJessica Hamilton EFI_DEVICE_PATH *devicePath, *node; 17042e718f0SJessica Hamilton EFI_HANDLE *handles = NULL; 17142e718f0SJessica Hamilton EFI_STATUS status; 17242e718f0SJessica Hamilton UINTN size = 0; 17342e718f0SJessica Hamilton 17442e718f0SJessica Hamilton status = kBootServices->LocateHandle(ByProtocol, &blockIoGuid, 0, &size, 0); 17542e718f0SJessica Hamilton if (status != EFI_BUFFER_TOO_SMALL) 17642e718f0SJessica Hamilton return B_ENTRY_NOT_FOUND; 17742e718f0SJessica Hamilton 17842e718f0SJessica Hamilton handles = (EFI_HANDLE*)malloc(size); 17942e718f0SJessica Hamilton status = kBootServices->LocateHandle(ByProtocol, &blockIoGuid, 0, &size, 18042e718f0SJessica Hamilton handles); 18142e718f0SJessica Hamilton if (status != EFI_SUCCESS) { 18242e718f0SJessica Hamilton free(handles); 18342e718f0SJessica Hamilton return B_ENTRY_NOT_FOUND; 18442e718f0SJessica Hamilton } 18542e718f0SJessica Hamilton 18642e718f0SJessica Hamilton for (UINTN n = 0; n < (size / sizeof(EFI_HANDLE)); n++) { 18742e718f0SJessica Hamilton status = kBootServices->HandleProtocol(handles[n], &devicePathGuid, 18842e718f0SJessica Hamilton (void**)&devicePath); 18942e718f0SJessica Hamilton if (status != EFI_SUCCESS) 19042e718f0SJessica Hamilton continue; 19142e718f0SJessica Hamilton 19242e718f0SJessica Hamilton node = devicePath; 19342e718f0SJessica Hamilton while (!IsDevicePathEnd(NextDevicePathNode(node))) 19442e718f0SJessica Hamilton node = NextDevicePathNode(node); 19542e718f0SJessica Hamilton 19642e718f0SJessica Hamilton if (DevicePathType(node) == MEDIA_DEVICE_PATH) 19742e718f0SJessica Hamilton add_device_path(&sMediaDevices, devicePath, handles[n]); 19842e718f0SJessica Hamilton else if (DevicePathType(node) == MESSAGING_DEVICE_PATH) 19942e718f0SJessica Hamilton add_device_path(&sMessagingDevices, devicePath, handles[n]); 20042e718f0SJessica Hamilton } 20142e718f0SJessica Hamilton 20242e718f0SJessica Hamilton return B_OK; 20342e718f0SJessica Hamilton } 20442e718f0SJessica Hamilton 20542e718f0SJessica Hamilton 2062da1cb75SJessica Hamilton static off_t 2072da1cb75SJessica Hamilton get_next_check_sum_offset(int32 index, off_t maxSize) 2082da1cb75SJessica Hamilton { 2092da1cb75SJessica Hamilton if (index < 2) 2102da1cb75SJessica Hamilton return index * 512; 2112da1cb75SJessica Hamilton 2122da1cb75SJessica Hamilton if (index < 4) 2132da1cb75SJessica Hamilton return (maxSize >> 10) + index * 2048; 2142da1cb75SJessica Hamilton 2151d830665SFredrik Holmqvist return ((system_time() + index) % (maxSize >> 9)) * 512; 2162da1cb75SJessica Hamilton } 2172da1cb75SJessica Hamilton 2182da1cb75SJessica Hamilton 2192da1cb75SJessica Hamilton static uint32 2202da1cb75SJessica Hamilton compute_check_sum(Node *device, off_t offset) 2212da1cb75SJessica Hamilton { 2222da1cb75SJessica Hamilton char buffer[512]; 2232da1cb75SJessica Hamilton ssize_t bytesRead = device->ReadAt(NULL, offset, buffer, sizeof(buffer)); 2242da1cb75SJessica Hamilton if (bytesRead < B_OK) 2252da1cb75SJessica Hamilton return 0; 2262da1cb75SJessica Hamilton 2272da1cb75SJessica Hamilton if (bytesRead < (ssize_t)sizeof(buffer)) 2282da1cb75SJessica Hamilton memset(buffer + bytesRead, 0, sizeof(buffer) - bytesRead); 2292da1cb75SJessica Hamilton 2302da1cb75SJessica Hamilton uint32 *array = (uint32*)buffer; 2312da1cb75SJessica Hamilton uint32 sum = 0; 2322da1cb75SJessica Hamilton 2332da1cb75SJessica Hamilton for (uint32 i = 0; i < (bytesRead + sizeof(uint32) - 1) / sizeof(uint32); i++) 2342da1cb75SJessica Hamilton sum += array[i]; 2352da1cb75SJessica Hamilton 2362da1cb75SJessica Hamilton return sum; 2372da1cb75SJessica Hamilton } 2382da1cb75SJessica Hamilton 239e2e1558aSJessica Hamilton 24042e718f0SJessica Hamilton static device_handle* 24142e718f0SJessica Hamilton get_messaging_device_for_media_device(device_handle *media_device) 24242e718f0SJessica Hamilton { 24342e718f0SJessica Hamilton device_handle *device = NULL; 24442e718f0SJessica Hamilton while ((device = (device_handle*)list_get_next_item(&sMessagingDevices, 24542e718f0SJessica Hamilton device)) != NULL) { 24642e718f0SJessica Hamilton if (compare_device_paths(media_device->device_path, 24742e718f0SJessica Hamilton device->device_path, true)) 24842e718f0SJessica Hamilton return device; 24942e718f0SJessica Hamilton } 25042e718f0SJessica Hamilton 25142e718f0SJessica Hamilton return NULL; 25242e718f0SJessica Hamilton } 25342e718f0SJessica Hamilton 25442e718f0SJessica Hamilton 25542e718f0SJessica Hamilton static bool 25642e718f0SJessica Hamilton get_boot_uuid(void) 25742e718f0SJessica Hamilton { 25842e718f0SJessica Hamilton return false; 25942e718f0SJessica Hamilton } 26042e718f0SJessica Hamilton 26142e718f0SJessica Hamilton 26242e718f0SJessica Hamilton static status_t 26342e718f0SJessica Hamilton add_boot_device(NodeList *devicesList) 26442e718f0SJessica Hamilton { 26542e718f0SJessica Hamilton return B_ENTRY_NOT_FOUND; 26642e718f0SJessica Hamilton } 26742e718f0SJessica Hamilton 26842e718f0SJessica Hamilton 26942e718f0SJessica Hamilton static status_t 27042e718f0SJessica Hamilton add_boot_device_for_image(NodeList *devicesList) 271e2e1558aSJessica Hamilton { 2721d830665SFredrik Holmqvist EFI_LOADED_IMAGE *loadedImage; 2731d830665SFredrik Holmqvist if (kBootServices->HandleProtocol(kImage, &LoadedImageGUID, 2741d830665SFredrik Holmqvist (void**)&loadedImage) != EFI_SUCCESS) 2751d830665SFredrik Holmqvist return B_ERROR; 2761d830665SFredrik Holmqvist 2771d830665SFredrik Holmqvist EFI_DEVICE_PATH *devicePath, *node; 2781d830665SFredrik Holmqvist if (kBootServices->HandleProtocol(loadedImage->DeviceHandle, 2791d830665SFredrik Holmqvist &DevicePathGUID, (void**)&devicePath) != EFI_SUCCESS) 28042e718f0SJessica Hamilton return B_ERROR; 2811d830665SFredrik Holmqvist 2821d830665SFredrik Holmqvist for (node = devicePath; DevicePathType(node) != MESSAGING_DEVICE_PATH; 2831d830665SFredrik Holmqvist node = NextDevicePathNode(node)) { 2841d830665SFredrik Holmqvist if (IsDevicePathEnd(node)) 28542e718f0SJessica Hamilton return B_ERROR; 2861d830665SFredrik Holmqvist } 2871d830665SFredrik Holmqvist 2881d830665SFredrik Holmqvist SetDevicePathEndNode(NextDevicePathNode(node)); 2891d830665SFredrik Holmqvist 29042e718f0SJessica Hamilton UINTN length = device_path_length(devicePath); 29142e718f0SJessica Hamilton EFI_DEVICE_PATH *savedDevicePath = (EFI_DEVICE_PATH*)malloc(length); 29242e718f0SJessica Hamilton memcpy(savedDevicePath, devicePath, length); 29342e718f0SJessica Hamilton 2941d830665SFredrik Holmqvist EFI_HANDLE handle; 2951d830665SFredrik Holmqvist if (kBootServices->LocateDevicePath(&BlockIoGUID, &devicePath, &handle) 2961d830665SFredrik Holmqvist != EFI_SUCCESS) 29742e718f0SJessica Hamilton return B_ERROR; 29842e718f0SJessica Hamilton 29942e718f0SJessica Hamilton if (!IsDevicePathEnd(devicePath)) 30042e718f0SJessica Hamilton return B_ERROR; 3011d830665SFredrik Holmqvist 3021d830665SFredrik Holmqvist EFI_BLOCK_IO *blockIo; 3031d830665SFredrik Holmqvist if (kBootServices->HandleProtocol(handle, &BlockIoGUID, (void**)&blockIo) 3041d830665SFredrik Holmqvist != EFI_SUCCESS) 30542e718f0SJessica Hamilton return B_ERROR; 3061d830665SFredrik Holmqvist 3071d830665SFredrik Holmqvist if (!blockIo->Media->MediaPresent) 30842e718f0SJessica Hamilton return B_ERROR; 3091d830665SFredrik Holmqvist 31042e718f0SJessica Hamilton EfiDevice *device = new(std::nothrow)EfiDevice(blockIo, savedDevicePath); 3111d830665SFredrik Holmqvist if (device == NULL) 31242e718f0SJessica Hamilton return B_ERROR; 31342e718f0SJessica Hamilton 31442e718f0SJessica Hamilton add_device_path(&sMessagingDevices, savedDevicePath, handle); 31542e718f0SJessica Hamilton devicesList->Insert(device); 31642e718f0SJessica Hamilton 31742e718f0SJessica Hamilton return B_OK; 31842e718f0SJessica Hamilton } 31942e718f0SJessica Hamilton 32042e718f0SJessica Hamilton 32142e718f0SJessica Hamilton static status_t 32242e718f0SJessica Hamilton add_cd_devices(NodeList *devicesList) 32342e718f0SJessica Hamilton { 32442e718f0SJessica Hamilton device_handle *handle = NULL; 32542e718f0SJessica Hamilton while ((handle = (device_handle*)list_get_next_item(&sMediaDevices, handle)) 32642e718f0SJessica Hamilton != NULL) { 32742e718f0SJessica Hamilton EFI_DEVICE_PATH *node = handle->device_path; 32842e718f0SJessica Hamilton while (!IsDevicePathEnd(NextDevicePathNode(node))) 32942e718f0SJessica Hamilton node = NextDevicePathNode(node); 33042e718f0SJessica Hamilton 33142e718f0SJessica Hamilton if (DevicePathType(node) != MEDIA_DEVICE_PATH) 33242e718f0SJessica Hamilton continue; 33342e718f0SJessica Hamilton 33442e718f0SJessica Hamilton if (DevicePathSubType(node) != MEDIA_CDROM_DP) 33542e718f0SJessica Hamilton continue; 33642e718f0SJessica Hamilton 33742e718f0SJessica Hamilton device_handle *messaging_device 33842e718f0SJessica Hamilton = get_messaging_device_for_media_device(handle); 33942e718f0SJessica Hamilton if (messaging_device == NULL) 34042e718f0SJessica Hamilton continue; 34142e718f0SJessica Hamilton 34242e718f0SJessica Hamilton EFI_BLOCK_IO *blockIo; 34342e718f0SJessica Hamilton EFI_GUID blockIoGuid = BLOCK_IO_PROTOCOL; 34442e718f0SJessica Hamilton EFI_STATUS status = kBootServices->HandleProtocol(messaging_device->handle, 34542e718f0SJessica Hamilton &blockIoGuid, (void**)&blockIo); 34642e718f0SJessica Hamilton if (status != EFI_SUCCESS) 34742e718f0SJessica Hamilton continue; 34842e718f0SJessica Hamilton 34942e718f0SJessica Hamilton if (!blockIo->Media->MediaPresent) 35042e718f0SJessica Hamilton continue; 35142e718f0SJessica Hamilton 35242e718f0SJessica Hamilton EfiDevice *device = new(std::nothrow)EfiDevice(blockIo, handle->device_path); 35342e718f0SJessica Hamilton if (device == NULL) 35442e718f0SJessica Hamilton continue; 3551d830665SFredrik Holmqvist 3561d830665SFredrik Holmqvist devicesList->Insert(device); 35742e718f0SJessica Hamilton } 35842e718f0SJessica Hamilton 35942e718f0SJessica Hamilton return devicesList->Count() > 0 ? B_OK : B_ENTRY_NOT_FOUND; 36042e718f0SJessica Hamilton } 36142e718f0SJessica Hamilton 36242e718f0SJessica Hamilton 36342e718f0SJessica Hamilton static status_t 36442e718f0SJessica Hamilton add_remaining_devices(NodeList *devicesList) 36542e718f0SJessica Hamilton { 36642e718f0SJessica Hamilton device_handle *node = NULL; 36742e718f0SJessica Hamilton while ((node = (device_handle*)list_get_next_item(&sMessagingDevices, node)) != NULL) { 36842e718f0SJessica Hamilton NodeIterator it = devicesList->GetIterator(); 36942e718f0SJessica Hamilton bool found = false; 37042e718f0SJessica Hamilton while (it.HasNext()) { 37142e718f0SJessica Hamilton EfiDevice *device = (EfiDevice*)it.Next(); 37242e718f0SJessica Hamilton // device->DevicePath() is a Media Device Path instance 37342e718f0SJessica Hamilton if (compare_device_paths(device->DevicePath(), node->device_path, true)) { 37442e718f0SJessica Hamilton found = true; 37542e718f0SJessica Hamilton break; 37642e718f0SJessica Hamilton } 37742e718f0SJessica Hamilton } 37842e718f0SJessica Hamilton 37942e718f0SJessica Hamilton if (!found) { 38042e718f0SJessica Hamilton EFI_BLOCK_IO *blockIo; 38142e718f0SJessica Hamilton EFI_GUID blockIoGuid = BLOCK_IO_PROTOCOL; 38242e718f0SJessica Hamilton EFI_STATUS status = kBootServices->HandleProtocol(node->handle, 38342e718f0SJessica Hamilton &blockIoGuid, (void**)&blockIo); 38442e718f0SJessica Hamilton if (status != EFI_SUCCESS) 38542e718f0SJessica Hamilton continue; 38642e718f0SJessica Hamilton 38742e718f0SJessica Hamilton if (!blockIo->Media->MediaPresent) 38842e718f0SJessica Hamilton continue; 38942e718f0SJessica Hamilton 39042e718f0SJessica Hamilton EfiDevice *device = new(std::nothrow)EfiDevice(blockIo, node->device_path); 39142e718f0SJessica Hamilton if (device == NULL) 39242e718f0SJessica Hamilton continue; 39342e718f0SJessica Hamilton 39442e718f0SJessica Hamilton devicesList->Insert(device); 39542e718f0SJessica Hamilton } 39642e718f0SJessica Hamilton } 39742e718f0SJessica Hamilton 3981d830665SFredrik Holmqvist return B_OK; 399e2e1558aSJessica Hamilton } 400e2e1558aSJessica Hamilton 401e2e1558aSJessica Hamilton 402*6b4cbec0SJessica Hamilton static bool 403*6b4cbec0SJessica Hamilton device_contains_partition(EfiDevice *device, boot::Partition *partition) 404*6b4cbec0SJessica Hamilton { 405*6b4cbec0SJessica Hamilton EFI::Header *header = (EFI::Header*)partition->content_cookie; 406*6b4cbec0SJessica Hamilton if (header != NULL && header->InitCheck() == B_OK) { 407*6b4cbec0SJessica Hamilton // check if device is GPT, and contains partition entry 408*6b4cbec0SJessica Hamilton uint32 blockSize = device->BlockSize(); 409*6b4cbec0SJessica Hamilton EFI_PARTITION_TABLE_HEADER *deviceHeader = 410*6b4cbec0SJessica Hamilton (EFI_PARTITION_TABLE_HEADER*)malloc(blockSize); 411*6b4cbec0SJessica Hamilton ssize_t bytesRead = device->ReadAt(NULL, blockSize, deviceHeader, 412*6b4cbec0SJessica Hamilton blockSize); 413*6b4cbec0SJessica Hamilton if (bytesRead != blockSize) 414*6b4cbec0SJessica Hamilton return false; 415*6b4cbec0SJessica Hamilton 416*6b4cbec0SJessica Hamilton if (memcmp(deviceHeader, &header->TableHeader(), 417*6b4cbec0SJessica Hamilton sizeof(efi_table_header)) != 0) 418*6b4cbec0SJessica Hamilton return false; 419*6b4cbec0SJessica Hamilton 420*6b4cbec0SJessica Hamilton // partition->cookie == int partition entry index 421*6b4cbec0SJessica Hamilton uint32 index = (uint32)(addr_t)partition->cookie; 422*6b4cbec0SJessica Hamilton uint32 size = sizeof(EFI_PARTITION_ENTRY) * (index + 1); 423*6b4cbec0SJessica Hamilton EFI_PARTITION_ENTRY *entries = (EFI_PARTITION_ENTRY*)malloc(size); 424*6b4cbec0SJessica Hamilton bytesRead = device->ReadAt(NULL, 425*6b4cbec0SJessica Hamilton deviceHeader->PartitionEntryLBA * blockSize, entries, size); 426*6b4cbec0SJessica Hamilton if (bytesRead != size) 427*6b4cbec0SJessica Hamilton return false; 428*6b4cbec0SJessica Hamilton 429*6b4cbec0SJessica Hamilton if (memcmp(&entries[index], &header->EntryAt(index), 430*6b4cbec0SJessica Hamilton sizeof(efi_partition_entry)) != 0) 431*6b4cbec0SJessica Hamilton return false; 432*6b4cbec0SJessica Hamilton 433*6b4cbec0SJessica Hamilton for (size_t i = 0; i < sizeof(kTypeMap) / sizeof(struct type_map); ++i) 434*6b4cbec0SJessica Hamilton if (strcmp(kTypeMap[i].type, BFS_NAME) == 0) 435*6b4cbec0SJessica Hamilton if (kTypeMap[i].guid == header->EntryAt(index).partition_type) 436*6b4cbec0SJessica Hamilton return true; 437*6b4cbec0SJessica Hamilton 438*6b4cbec0SJessica Hamilton // Our partition has an EFI header, but we couldn't find one, so bail 439*6b4cbec0SJessica Hamilton return false; 440*6b4cbec0SJessica Hamilton } 441*6b4cbec0SJessica Hamilton 442*6b4cbec0SJessica Hamilton if ((partition->offset + partition->size) <= device->Size()) 443*6b4cbec0SJessica Hamilton return true; 444*6b4cbec0SJessica Hamilton 445*6b4cbec0SJessica Hamilton return false; 446*6b4cbec0SJessica Hamilton } 447*6b4cbec0SJessica Hamilton 448*6b4cbec0SJessica Hamilton 449e2e1558aSJessica Hamilton status_t 45042e718f0SJessica Hamilton platform_add_boot_device(struct stage2_args *args, NodeList *devicesList) 45142e718f0SJessica Hamilton { 45242e718f0SJessica Hamilton // This is the first entry point, so init the lists here 45342e718f0SJessica Hamilton list_init(&sMessagingDevices); 45442e718f0SJessica Hamilton list_init(&sMediaDevices); 45542e718f0SJessica Hamilton 45642e718f0SJessica Hamilton build_device_handles(); 45742e718f0SJessica Hamilton 45842e718f0SJessica Hamilton if (get_boot_uuid()) { 45942e718f0SJessica Hamilton // If we have the UUID, add the boot device containing that partition 46042e718f0SJessica Hamilton return add_boot_device(devicesList); 46142e718f0SJessica Hamilton } else { 46242e718f0SJessica Hamilton // If we don't have a UUID, add all CD devices with media, and the 46342e718f0SJessica Hamilton // device that haiku_loader.efi is located on 46442e718f0SJessica Hamilton add_boot_device_for_image(devicesList); 46542e718f0SJessica Hamilton // We do this first, so that booting from CD is the fallback 46642e718f0SJessica Hamilton add_cd_devices(devicesList); 46742e718f0SJessica Hamilton if (devicesList->Count() > 0) 46842e718f0SJessica Hamilton return B_OK; 46942e718f0SJessica Hamilton } 47042e718f0SJessica Hamilton 47142e718f0SJessica Hamilton // Otherwise, we don't know what the boot device is; defer to 47242e718f0SJessica Hamilton // platform_add_block_devices() to add the rest 47342e718f0SJessica Hamilton return B_ENTRY_NOT_FOUND; 47442e718f0SJessica Hamilton } 47542e718f0SJessica Hamilton 47642e718f0SJessica Hamilton 47742e718f0SJessica Hamilton status_t 478e2e1558aSJessica Hamilton platform_add_block_devices(struct stage2_args *args, NodeList *devicesList) 479e2e1558aSJessica Hamilton { 48042e718f0SJessica Hamilton return add_remaining_devices(devicesList); 481e2e1558aSJessica Hamilton } 482e2e1558aSJessica Hamilton 483e2e1558aSJessica Hamilton 484e2e1558aSJessica Hamilton status_t 485e2e1558aSJessica Hamilton platform_get_boot_partition(struct stage2_args *args, Node *bootDevice, 486e2e1558aSJessica Hamilton NodeList *partitions, boot::Partition **_partition) 487e2e1558aSJessica Hamilton { 4881d830665SFredrik Holmqvist NodeIterator iterator = partitions->GetIterator(); 4891d830665SFredrik Holmqvist boot::Partition *partition = NULL; 4901d830665SFredrik Holmqvist while ((partition = (boot::Partition *)iterator.Next()) != NULL) { 491*6b4cbec0SJessica Hamilton if (device_contains_partition((EfiDevice*)bootDevice, partition)) { 4922da1cb75SJessica Hamilton *_partition = partition; 4932da1cb75SJessica Hamilton return B_OK; 4942da1cb75SJessica Hamilton } 495*6b4cbec0SJessica Hamilton } 49642e718f0SJessica Hamilton 4971d830665SFredrik Holmqvist return B_ENTRY_NOT_FOUND; 498e2e1558aSJessica Hamilton } 499e2e1558aSJessica Hamilton 500e2e1558aSJessica Hamilton 501e2e1558aSJessica Hamilton status_t 502e2e1558aSJessica Hamilton platform_register_boot_device(Node *device) 503e2e1558aSJessica Hamilton { 5041d830665SFredrik Holmqvist EfiDevice *efiDevice = (EfiDevice *)device; 5052da1cb75SJessica Hamilton disk_identifier identifier; 5062da1cb75SJessica Hamilton 5071d830665SFredrik Holmqvist // TODO: Setup using device path 5082da1cb75SJessica Hamilton identifier.bus_type = UNKNOWN_BUS; 5092da1cb75SJessica Hamilton identifier.device_type = UNKNOWN_DEVICE; 5102da1cb75SJessica Hamilton identifier.device.unknown.size = device->Size(); 5112da1cb75SJessica Hamilton 5122da1cb75SJessica Hamilton for (uint32 i = 0; i < NUM_DISK_CHECK_SUMS; ++i) { 5132da1cb75SJessica Hamilton off_t offset = get_next_check_sum_offset(i, device->Size()); 5142da1cb75SJessica Hamilton identifier.device.unknown.check_sums[i].offset = offset; 5152da1cb75SJessica Hamilton identifier.device.unknown.check_sums[i].sum = compute_check_sum(device, offset); 5162da1cb75SJessica Hamilton } 5172da1cb75SJessica Hamilton 51842e718f0SJessica Hamilton gBootVolume.SetInt32(BOOT_METHOD, efiDevice->BootMethod()); 51942e718f0SJessica Hamilton gBootVolume.SetBool(BOOT_VOLUME_BOOTED_FROM_IMAGE, efiDevice->ReadOnly()); 5202da1cb75SJessica Hamilton gBootVolume.SetData(BOOT_VOLUME_DISK_IDENTIFIER, B_RAW_TYPE, 5212da1cb75SJessica Hamilton &identifier, sizeof(disk_identifier)); 5222da1cb75SJessica Hamilton 5232da1cb75SJessica Hamilton return B_OK; 524e2e1558aSJessica Hamilton } 525