xref: /haiku/src/system/boot/platform/efi/devices.cpp (revision 6b4cbec040a14542c7a03ca2050abbfcacfe97c1)
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