Exemplo n.º 1
0
std::string getCanonicalEfiDevicePath(const CFDataRef& data) {
  std::string path;

  // Iterate through the EFI_DEVICE_PATH_PROTOCOL stacked structs.
  auto bytes = CFDataGetBytePtr((CFDataRef)data);
  size_t length = CFDataGetLength((CFDataRef)data);
  size_t search_offset = 0;

  while ((search_offset + sizeof(EFI_DEVICE_PATH_PROTOCOL)) < length) {
    auto node = (const EFI_DEVICE_PATH_PROTOCOL*)(bytes + search_offset);
    if (EfiIsDevicePathEnd(node)) {
      // End of the EFI device path stacked structs.
      break;
    }

    if (EfiDevicePathNodeLength(node) + search_offset > length) {
      // Malformed EFI device header.
      break;
    }

    // Only support paths and hard drive partitions.
    if (EfiDevicePathType(node) == MEDIA_DEVICE_PATH) {
      if (node->SubType == MEDIA_FILEPATH_DP) {
        for (int i = 0; i < EfiDevicePathNodeLength(node); i += 2) {
          // Strip UTF16 characters to UTF8.
          path += (((char*)(node)) + sizeof(EFI_DEVICE_PATH_PROTOCOL))[i];
        }
      } else if (node->SubType == MEDIA_HARDDRIVE_DP) {
        // Extract the device UUID to later join with block devices.
        auto uuid = ((const HARDDRIVE_DEVICE_PATH*)node)->Signature;
        boost::uuids::uuid hdd_signature = {{
          uuid[3], uuid[2], uuid[1], uuid[0],
          uuid[5], uuid[4],
          uuid[7], uuid[6],
          uuid[8], uuid[9],
          uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15],
        }};
        path += boost::to_upper_copy(boost::uuids::to_string(hdd_signature));
      }
    }

    search_offset += EfiDevicePathNodeLength(node);
  }

  return path;
}
//
// get partition handle by number
//
EFI_HANDLE DevPathGetPartitionHandleByNumber(EFI_DEVICE_PATH_PROTOCOL* referencePath, UINT32 number)
{
	UINTN nodeCount															= DevPathGetNodeCount(referencePath);
	if(!nodeCount)
		return nullptr;

	UINTN count																= 0;
	EFI_HANDLE* handleArray													= nullptr;
	if(EFI_ERROR(EfiBootServices->LocateHandleBuffer(ByProtocol, &EfiBlockIoProtocolGuid, nullptr, &count, &handleArray)))
		return nullptr;

	EFI_HANDLE retValue														= nullptr;
	for(UINTN i = 0; i < count; i ++)
	{
		EFI_HANDLE theHandle												= handleArray[i];
		if(!theHandle)
			continue;

		EFI_DEVICE_PATH_PROTOCOL* devicePath								= DevPathGetDevicePathProtocol(theHandle);
		if(!devicePath)
			continue;

		if(DevPathGetNodeCount(devicePath) != nodeCount)
			continue;

		EFI_DEVICE_PATH_PROTOCOL* pathA										= referencePath;
		EFI_DEVICE_PATH_PROTOCOL* pathB										= devicePath;
		BOOLEAN checkResult													= TRUE;
		for(UINTN i = 0; i < nodeCount && !EfiIsDevicePathEnd(pathA) && !EfiIsDevicePathEnd(pathB); i ++)
		{
			if(EfiDevicePathNodeLength(pathA) != EfiDevicePathNodeLength(pathB))
			{
				checkResult													= FALSE;
				break;
			}

		#if 0
			if(pathA->Type == MESSAGING_DEVICE_PATH && pathA->SubType == MSG_VENDOR_DP && !memcmp(pathA + 1, &EfiDevicePathMessagingSASGuid, sizeof(EFI_GUID)))
			{
				SAS_DEVICE_PATH* sasA										= _CR(pathA, SAS_DEVICE_PATH, Header);
				SAS_DEVICE_PATH* sasB										= _CR(pathB, SAS_DEVICE_PATH, Header);
				if(sasA->SasAddress != sasB->SasAddress || sasA->Lun != sasB->Lun || sasA->RelativeTargetPort != sasB->RelativeTargetPort)
				{
					checkResult												= FALSE;
					break;
				}
			}
		#endif

			if(memcmp(pathA, pathB, EfiDevicePathNodeLength(pathA)))
			{
				checkResult													= FALSE;
				break;
			}
		}
		if(!checkResult)
			continue;

		if(DevPathGetPartitionNumber(devicePath) != number)
			continue;

		retValue															= theHandle;
		break;
	}

	MmFreePool(handleArray);
	return retValue;
}