//
// get node
//
EFI_DEVICE_PATH_PROTOCOL* DevPathGetNode(EFI_DEVICE_PATH_PROTOCOL* devicePath, UINT8 type, UINT8 subType)
{
	while(!EfiIsDevicePathEnd(devicePath))
	{
		if(EfiDevicePathType(devicePath) == type && devicePath->SubType == subType)
			return devicePath;

		devicePath															= EfiNextDevicePathNode(devicePath);
	}
	return nullptr;
}
//
// check net
//
BOOLEAN DevPathHasMacAddressNode(EFI_DEVICE_PATH_PROTOCOL* devicePath)
{
	while(!EfiIsDevicePathEnd(devicePath))
	{
		if(EfiDevicePathType(devicePath) == MESSAGING_DEVICE_PATH && devicePath->SubType == MSG_MAC_ADDR_DP)
			return TRUE;

		devicePath															= EfiNextDevicePathNode(devicePath);
	}
	return FALSE;
}
//
// get partition number
//
UINT32 DevPathGetPartitionNumber(EFI_DEVICE_PATH_PROTOCOL* devicePath)
{
	while(!EfiIsDevicePathEnd(devicePath))
	{
		if(EfiDevicePathType(devicePath) == MEDIA_DEVICE_PATH && devicePath->SubType == MEDIA_HARDDRIVE_DP)
		{
			HARDDRIVE_DEVICE_PATH* hardDriveDevicePath						= _CR(devicePath, HARDDRIVE_DEVICE_PATH, Header);
			if(hardDriveDevicePath->SignatureType == SIGNATURE_TYPE_GUID && hardDriveDevicePath->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER)
				return hardDriveDevicePath->PartitionNumber;
		}

		devicePath															= EfiNextDevicePathNode(devicePath);
	}
	return static_cast<UINT32>(-1);
}
Exemplo n.º 4
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;
}
//
// append file path
//
EFI_DEVICE_PATH_PROTOCOL* DevPathAppendLastComponent(EFI_DEVICE_PATH_PROTOCOL* devicePath, CHAR8 CONST* fileName, BOOLEAN replaceLastComponent)
{
	UINTN fileNameLength													= strlen(fileName);
	UINTN length															= DevPathGetSize(devicePath) + (fileNameLength + 1) * sizeof(CHAR16);
	EFI_DEVICE_PATH_PROTOCOL* newDevicePath									= static_cast<EFI_DEVICE_PATH_PROTOCOL*>(MmAllocatePool(length));
	if(!newDevicePath)
		return nullptr;

	EFI_DEVICE_PATH_PROTOCOL* dstDevicePath									= newDevicePath;
	EFI_DEVICE_PATH_PROTOCOL* srcDevicePath									= devicePath;
	FILEPATH_DEVICE_PATH* srcFilePath										= nullptr;
	FILEPATH_DEVICE_PATH* dstFilePath										= nullptr;

	while(!EfiIsDevicePathEnd(srcDevicePath))
	{
		if(EfiDevicePathType(srcDevicePath) == MEDIA_DEVICE_PATH && srcDevicePath->SubType == MEDIA_FILEPATH_DP)
		{
			srcFilePath														= _CR(srcDevicePath, FILEPATH_DEVICE_PATH, Header);
			dstFilePath														= _CR(dstDevicePath, FILEPATH_DEVICE_PATH, Header);
		}

		memcpy(dstDevicePath, srcDevicePath, DevicePathNodeLength(srcDevicePath));
		srcDevicePath														= EfiNextDevicePathNode(srcDevicePath);
		dstDevicePath														= EfiNextDevicePathNode(dstDevicePath);
	}

	if(!srcFilePath || !dstFilePath)
	{
		MmFreePool(newDevicePath);
		return nullptr;
	}

	dstFilePath->Header.Type												= MEDIA_DEVICE_PATH;
	dstFilePath->Header.SubType												= MEDIA_FILEPATH_DP;
	UINTN writePosition														= 0;

	if(replaceLastComponent)
	{
		CHAR16* pathName													= srcFilePath->PathName;
		CHAR16* lastDirectory												= nullptr;
		UINTN pathLength													= (DevicePathNodeLength(&srcFilePath->Header) - SIZE_OF_FILEPATH_DEVICE_PATH) / sizeof(CHAR16);
		for(UINTN i = 0; i < pathLength && pathName[i]; i ++)
		{
			if(pathName[i] == L'\\' || pathName[i] == L'/')
				lastDirectory												= pathName + i;
		}

		if(lastDirectory)
			lastDirectory													+= 1;
		else
			lastDirectory													= pathName;

		writePosition														= lastDirectory - pathName;
	}
	else
	{
		writePosition														= (DevicePathNodeLength(&srcFilePath->Header) - SIZE_OF_FILEPATH_DEVICE_PATH) / sizeof(CHAR16);
		while(!srcFilePath->PathName[writePosition - 1] && writePosition)
			writePosition													-= 1;
	}

	UINTN usedLength														= ArchConvertPointerToAddress(dstFilePath->PathName + writePosition) - ArchConvertPointerToAddress(newDevicePath);
	BlUtf8ToUnicode(fileName, fileNameLength, dstFilePath->PathName + writePosition, (length - usedLength - END_DEVICE_PATH_LENGTH) / sizeof(CHAR16));
	UINTN nodeLength														= SIZE_OF_FILEPATH_DEVICE_PATH + (wcslen(dstFilePath->PathName) + 1) * sizeof(CHAR16);
	SetDevicePathNodeLength(&dstFilePath->Header, nodeLength);
	EFI_DEVICE_PATH_PROTOCOL* endOfPath										= NextDevicePathNode(&dstFilePath->Header);
	SetDevicePathEndNode(endOfPath);
	return newDevicePath;
}