从头开始了解和使用Hypervisor(第1部分)

来源:岁月联盟 编辑:猪蛋儿 时间:2020-01-29


毫不夸张地说,学习完本文,你完全可以创建自己的虚拟环境,并且可以了解VMWare,VirtualBox,KVM和其他虚拟化软件如何使用处理器的函数来创建虚拟环境。
Intel和AMD都在其现代CPU中支持虚拟化,Intel于2005年11月13日在奔腾4系列中推出了代号为“Vanderpool”的VT-x技术,VT-x是intel运用Virtualization虚拟化技术中的一个指令集。VT-x函数的CPU标志是“vmx”,代表虚拟机扩展。
另一方面,AMD开发了代号为“Pacifica”的第一代虚拟化扩展,并最初以AMD安全虚拟机(SVM)的形式发布,但后来以AMD Virtualization的商标销售,缩写为AMD-V。
虚拟机管理程序有两种类型,类型1的管理程序称为“裸机管理程序”或“本机”,因为它可以直接在裸机物理服务器上运行,因此类型1的管理程序可以直接访问硬件。使用类型1虚拟机管理程序时,没有要加载的操作系统作为虚拟机管理程序。
与类型1管理程序相反,就像其他任何应用程序一样,类型2管理程序加载在操作系统内部。由于类型2虚拟机管理程序必须通过操作系统并由操作系统进行管理,因此类型2虚拟机管理程序(及其虚拟机)的运行效率(较慢)将低于类型1虚拟机管理程序。
关于虚拟化的更多概念是相同的,但是在VT-x和AMD-V中需要有不同的考虑。这些教程的其余部分主要关注VT-x,因为IntelCPU越来越流行,使用也越来越广泛。在我看来,AMD在其手册中更清晰地描述了虚拟化,但是Intel在某种程度上使读者感到困惑,尤其是在虚拟化文件中。
虚拟机管理程序和平台
这些概念是与平台无关的,我的意思是你可以在Linux或Windows中轻松运行相同的代码例程,并期望CPU产生相同的行为,但我更喜欢使用Windows,因为Windows更易于调试。在需要时提供一些Linux系统的示例。就个人而言,由于Linux内核管理#GP和其他异常之类的错误,并尝试避免内核崩溃并保持系统正常运行,因此它更适合测试虚拟机管理程序或与CPU相关的任何事物。另一方面,Windows从不尝试管理任何意外的异常,每当你不管理异常时,它都会导致蓝屏死机,因此你可能会收到很多BSOD。最后,我可能(并且肯定)会犯错误,例如错误的实现或错误的信息。
需要的工具
安装WDK的Visual Studio,你可以在此处获取Windows Driver Kit(WDK)。
调试Windows和任何内核模式的最佳方法是使用Windows SDK中提供的Windbg。如果使用默认安装选项安装了WDK,则可能同时安装了WDK和SDK,因此可以跳过此步骤。
你应该能够使用Windbg调试操作系统(在本文中为Windows),更多信息请参见此处。OSR驱动程序加载器可以在这里下载,我们使用此工具将驱动程序加载到Windows计算机中。用于打印DbgPrint()结果的SysInternals调试视图:

创建测试环境
本教程中几乎所有代码都必须在内核级别运行,并且你必须设置Linux内核模块或Windows Driver Kit(WDK)模块。由于配置VMM涉及许多汇编代码,因此你应该知道如何在内核项目中运行内联汇编。在Linux中,你不需要做任何特别的事情,但在Windows中,WDK不再支持x64环境中的内联汇编,因此,如果你以前没有解决此问题,则可能会很难创建一个简单的x64内联项目,但是不用担心,在我后面的文章中我会一一讲到。
现在该创建驱动程序了!
如果你想从Windows Driver Kit(WDK)开始,则整个驱动程序是这样的:
#include
#include
#include
extern void inline AssemblyFunc1(void);
extern void inline AssemblyFunc2(void);
VOID DrvUnload(PDRIVER_OBJECT  DriverObject);
NTSTATUS DriverEntry(PDRIVER_OBJECT  pDriverObject, PUNICODE_STRING  pRegistryPath);
#pragma alloc_text(INIT, DriverEntry)
#pragma alloc_text(PAGE, Example_Unload)
NTSTATUS DriverEntry(PDRIVER_OBJECT  pDriverObject, PUNICODE_STRING  pRegistryPath)
{
 NTSTATUS NtStatus = STATUS_SUCCESS;
 UINT64 uiIndex = 0;
 PDEVICE_OBJECT pDeviceObject = NULL;
 UNICODE_STRING usDriverName, usDosDeviceName;
 DbgPrint("DriverEntry Called.");
 RtlInitUnicodeString(&usDriverName, L"/Device/MyHypervisor");
 RtlInitUnicodeString(&usDosDeviceName, L"/DosDevices/MyHypervisor");
 NtStatus = IoCreateDevice(pDriverObject, 0, &usDriverName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pDeviceObject);
 if (NtStatus == STATUS_SUCCESS)
 {
  pDriverObject->DriverUnload = DrvUnload;
  pDeviceObject->Flags |= IO_TYPE_DEVICE;
  pDeviceObject->Flags &= (~DO_DEVICE_INITIALIZING);
  IoCreateSymbolicLink(&usDosDeviceName, &usDriverName);
 }
 return NtStatus;
}
VOID DrvUnload(PDRIVER_OBJECT  DriverObject)

[1] [2] [3] [4] [5] [6]  下一页