Native execution manager (Hyper-V兼容)
这一篇开始的几篇里,会详细介绍VirtualBox里的实现。
VirtualBox里的实现其实是有3个版本,
第一个版本全部API直接调用winhvplatform.dll里的APIs,
第二个版本部分API调用VID.dll里的API,用NEM_WIN_USE_OUR_OWN_RUN_API开关控制,
第三个版本部分API直接调用VID.sys的IOCTL,和hypercall API,用NEM_WIN_WITH_RING0_RUNLOOP和NEM_WIN_USE_HYPERCALLS_FOR_PAGES开关控制。
VirtualBox的开关开启了第三个版本,所以只会介绍第三个版本的实现(其他版本实现原理是一样的,只是调用方式不同而已)
21.1 NEM初始化/Term 相关API
21.1.1 NEMR3InitConfig
VMMR3_INT_DECL(int) NEMR3InitConfig(PVM pVM)
{
//获取配置
PCFGMNODE pCfgNem = CFGMR3GetChild(CFGMR3GetRoot(pVM), "NEM/");
int rc = CFGMR3ValidateConfig(pCfgNem,
"/NEM/",
"Enabled"
"|Allow64BitGuests"
"|UseRing0Runloop",
"" /* pszValidNodes */, "NEM" /* pszWho */, 0 /* uInstance */);
//是否开启NEM
rc = CFGMR3QueryBoolDef(pCfgNem, "Enabled", &pVM->nem.s.fEnabled, true);
rc = CFGMR3QueryBoolDef(pCfgNem, "Allow64BitGuests", &pVM->nem.s.fAllow64BitGuests, HC_ARCH_BITS == 64);
//默认开启R0 loop,即直接调用VID.sys里的IOCTL
bool fUseRing0Runloop = true;
//可以在配置里关闭R0loop
rc = CFGMR3QueryBoolDef(pCfgNem, "UseRing0Runloop", &fUseRing0Runloop, fUseRing0Runloop);
pVM->nem.s.fUseRing0Runloop = fUseRing0Runloop;
}
21.1.2 NEMR3Init
NEMR3Init call nemR3NativeInit
int nemR3NativeInit(PVM pVM, bool fFallback, bool fForced)
{
int rc = nemR3WinInitProbeAndLoad(fForced, pErrInfo);
//是否可以开启Hyper-V模式
rc = nemR3WinInitCheckCapabilities(pVM, pErrInfo);
//动态获取IOCTL的id号
rc = nemR3WinInitDiscoverIoControlProperties(pVM, pErrInfo);
if (rc == VERR_NEM_RING3_ONLY)
{
if (pVM->nem.s.fUseRing0Runloop)
{
pVM->nem.s.fUseRing0Runloop = false;
}
rc = VINF_SUCCESS;
}
//通知R0初始化NEM模式
rc = SUPR3CallVMMR0Ex(VMCC_GET_VMR0_FOR_CALL(pVM), 0 /*idCpu*/, VMMR0_DO_NEM_INIT_VM, 0, NULL);
//create partition
rc = nemR3WinInitCreatePartition(pVM, pErrInfo);
if (RT_SUCCESS(rc))
{
//到这里启动NEM成,设置引擎模式成VM_EXEC_ENGINE_NATIVE_API
VM_SET_MAIN_EXECUTION_ENGINE(pVM, VM_EXEC_ENGINE_NATIVE_API);
//NEM模式需要关闭x2APIC,使用xAPIC
nemR3WinDisableX2Apic(pVM);
}
}
nemR3WinInitProbeAndLoad
static int nemR3WinInitProbeAndLoad(bool fForced, PRTERRINFO pErrInfo)
{
WCHAR wszPath[MAX_PATH + 64];
UINT cwcPath = GetSystemDirectoryW(wszPath, MAX_PATH);
RTUtf16CopyAscii(&wszPath[cwcPath], RT_ELEMENTS(wszPath) - cwcPath, "WinHvPlatform.dll");
if (GetFileAttributesW(wszPath) == INVALID_FILE_ATTRIBUTES)
return RTErrInfoSetF(pErrInfo, VERR_NEM_NOT_AVAILABLE, "The native API dll was not found (%ls)", wszPath);
//CPUID检测
if (!ASMHasCpuId())
return RTErrInfoSet(pErrInfo, VERR_NEM_NOT_AVAILABLE, "No CPUID support");
if (!ASMIsValidStdRange(ASMCpuId_EAX(0)))
return RTErrInfoSet(pErrInfo, VERR_NEM_NOT_AVAILABLE, "No CPUID leaf #1");
//需要开启X86_CPUID_FEATURE_ECX_HVP
if (!(ASMCpuId_ECX(1) & X86_CPUID_FEATURE_ECX_HVP))
return RTErrInfoSet(pErrInfo, VERR_NEM_NOT_AVAILABLE, "Not in a hypervisor partition (HVP=0)");
//CPUID(0x40000000)Intel指令手册里居然找不到0x4000000开始的定义?
uint32_t cMaxHyperLeaf = 0;
uint32_t uEbx = 0;
uint32_t uEcx = 0;
uint32_t uEdx = 0;
ASMCpuIdExSlow(0x40000000, 0, 0, 0, &cMaxHyperLeaf, &uEbx, &uEcx, &uEdx);
if (!ASMIsValidHypervisorRange(cMaxHyperLeaf))
return RTErrInfoSetF(pErrInfo, VERR_NEM_NOT_AVAILABLE, "Invalid hypervisor CPUID range (%#x %#x %#x %#x)",
cMaxHyperLeaf, uEbx, uEcx, uEdx);
//magic字符串
if ( uEbx != UINT32_C(0x7263694d) /* Micr */
|| uEcx != UINT32_C(0x666f736f) /* osof */
|| uEdx != UINT32_C(0x76482074) /* t Hv */)
return RTErrInfoSetF(pErrInfo, VERR_NEM_NOT_AVAILABLE,
"Not Hyper-V CPUID signature: %#x %#x %#x (expected %#x %#x %#x)",
uEbx, uEcx, uEdx, UINT32_C(0x7263694d), UINT32_C(0x666f736f), UINT32_C(0x76482074));
//至少有5个leaf
if (cMaxHyperLeaf < UINT32_C(0x40000005))
return RTErrInfoSetF(pErrInfo, VERR_NEM_NOT_AVAILABLE, "Too narrow hypervisor CPUID range (%#x)", cMaxHyperLeaf);
//load两个dll并获取hyper-v函数地址
static const char * const s_apszDllNames[2] = { "WinHvPlatform.dll", "vid.dll" };
RTLDRMOD ahMods[2] = { NIL_RTLDRMOD, NIL_RTLDRMOD };
int rc = VINF_SUCCESS;
for (unsigned i = 0; i < RT_ELEMENTS(s_apszDllNames); i++)
{
int rc2 = RTLdrLoadSystem(s_apszDllNames[i], true /*fNoUnload*/, &ahMods[i]);
if (RT_FAILURE(rc2))
{
ahMods[i] = NIL_RTLDRMOD;
rc = VERR_NEM_INIT_FAILED;
}
}
if (RT_SUCCESS(rc))
//为了获取VID.sys的deviceioctl的ID号的ioctl,这里先获取VID.dll里的NtDeviceIoControlFile函数的IAT表的位置
rc = nemR3WinInitVidIntercepts(ahMods[1], pErrInfo);
if (RT_SUCCESS(rc))
{
//获取API的地址
for (unsigned i = 0; i < RT_ELEMENTS(g_aImports); i++)
{
int rc2 = RTLdrGetSymbol(ahMods[g_aImports[i].idxDll], g_aImports[i].pszName, (void **)g_aImports[i].ppfn);
if (RT_FAILURE(rc2))
{
*g_aImports[i].ppfn = NULL;
}
}
if (RT_SUCCESS(rc))
{
Assert(!RTErrInfoIsSet(pErrInfo));
}
}
for (unsigned i = 0; i < RT_ELEMENTS(ahMods); i++)
RTLdrClose(ahMods[i]);
return rc;
}
nemR3WinInitCheckCapabilities
static int nemR3WinInitCheckCapabilities(PVM pVM, PRTERRINFO pErrInfo)
{
//获取hypervisor是否开启信息
WHV_CAPABILITY Caps;
HRESULT hrc = WHvGetCapabilityWrapper(WHvCapabilityCodeHypervisorPresent, &Caps, sizeof(Caps));
if (!Caps.HypervisorPresent)
{
//如果没有开启Hypervisor,返回错误
return error;
}
//获取并保存VMExit信息
hrc = WHvGetCapabilityWrapper(WHvCapabilityCodeExtendedVmExits, &Caps, sizeof(Caps));
pVM->nem.s.fExtendedMsrExit = RT_BOOL(Caps.ExtendedVmExits.X64MsrExit);
pVM->nem.s.fExtendedCpuIdExit = RT_BOOL(Caps.ExtendedVmExits.X64CpuidExit);
pVM->nem.s.fExtendedXcptExit = RT_BOOL(Caps.ExtendedVmExits.ExceptionExit);
//获取LAPICEmulation,xsave等支持开关 (MS文档里显示暂时不支持这个参数),这里只是获取一下,什么都没做
hrc = WHvGetCapabilityWrapper(WHvCapabilityCodeFeatures, &Caps, sizeof(Caps));
//获取异常bitmap,什么也没做
hrc = WHvGetCapabilityWrapper(WHvCapabilityCodeExceptionExitBitmap, &Caps, sizeof(Caps));
//获取CPUvender并保存到全局变量里
hrc = WHvGetCapabilityWrapper(WHvCapabilityCodeProcessorVendor, &Caps, sizeof(Caps));
switch (Caps.ProcessorVendor)
{
case WHvProcessorVendorIntel:
pVM->nem.s.enmCpuVendor = CPUMCPUVENDOR_INTEL;
break;
case WHvProcessorVendorAmd:
pVM->nem.s.enmCpuVendor = CPUMCPUVENDOR_AMD;
break;
default:
return RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED, "Unknown processor vendor: %d", Caps.ProcessorVendor);
}
//获取CPU相关信息,什么也不做,只是打了log,(CPUM管理CPU feature相关信息,所以这边什么也没做)
hrc = WHvGetCapabilityWrapper(WHvCapabilityCodeProcessorFeatures, &Caps, sizeof(Caps));
//The cache line flush size.
hrc = WHvGetCapabilityWrapper(WHvCapabilityCodeProcessorClFlushSize, &Caps, sizeof(Caps));
if (Caps.ProcessorClFlushSize < 8 && Caps.ProcessorClFlushSize > 9)
return RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED, "Unsupported cache line flush size: %u", Caps.ProcessorClFlushSize);
pVM->nem.s.cCacheLineFlushShift = Caps.ProcessorClFlushSize;
//尝试传入其他CAPABILITY_CODE,但从文档里看,除去上面调用多的codeid,只有1003(WHvCapabilityCodeProcessorXsaveFeatures)是存在的,其他都是无效输入
if (!IsDebuggerPresent()) /* Too noisy when in debugger, so skip. */
{
static const struct
{
uint32_t iMin, iMax; } s_aUnknowns[] =
{
{ 0x0004, 0x000f },
{ 0x1003, 0x100f },
{ 0x2000, 0x200f },
{ 0x3000, 0x300f },
{ 0x4000, 0x400f },
};
for (uint32_t j = 0; j < RT_ELEMENTS(s_aUnknowns); j++)
for (uint32_t i = s_aUnknowns[j].iMin; i <= s_aUnknowns[j].iMax; i++)
{
hrc = WHvGetCapabilityWrapper((WHV_CAPABILITY_CODE)i, &Caps, sizeof(Caps));
//print log
}
}
//CPUID/MSR/异常 VMExit必须全部支持,否则返回异常
if (!pVM->nem.s.fExtendedCpuIdExit)
return RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED, "Missing required extended CPUID exit support");
if (!pVM->nem.s.fExtendedMsrExit)
return RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED, "Missing required extended MSR exit support");
if (!pVM->nem.s.fExtendedXcptExit)
return RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED, "Missing required extended exception exit support");
}
nemR3WinInitCreatePartition
static int nemR3WinInitCreatePartition(PVM pVM, PRTERRINFO pErrInfo)
{
//创建一个VM,这个API其实只是创建一个handle而已
WHV_PARTITION_HANDLE hPartition;
HRESULT hrc = WHvCreatePartition(&hPartition);
WHV_PARTITION_PROPERTY Property;
RT_ZERO(Property);
//设置VCPU个数
Property.ProcessorCount = pVM->cCpus;
hrc = WHvSetPartitionProperty(hPartition, WHvPartitionPropertyCodeProcessorCount, &Property, sizeof(Property));
if (SUCCEEDED(hrc))
{
RT_ZERO(Property);
//设置参数是否接受CPUID,MSR和异常的VMExit
Property.ExtendedVmExits.X64CpuidExit = pVM->nem.s.fExtendedCpuIdExit;
Property.ExtendedVmExits.X64MsrExit = pVM->nem.s.fExtendedMsrExit;
Property.ExtendedVmExits.ExceptionExit = pVM->nem.s.fExtendedXcptExit;
hrc = WHvSetPartitionProperty(hPartition, WHvPartitionPropertyCodeExtendedVmExits, &Property, sizeof(Property));
if (SUCCEEDED(hrc))
{
//保存handle到全局变量里
pVM->nem.s.fCreatedEmts = false;
pVM->nem.s.hPartition = hPartition;
return VINF_SUCCESS;
}
}
//创建失败,删除Guest Partition
WHvDeletePartition(hPartition);
}
nemR3WinInitDiscoverIoControlProperties
获取VID函数对应的IOCTL functionID
static int nemR3WinInitDiscoverIoControlProperties(PVM pVM, PRTERRINFO pErrInfo)
{
decltype(NtDeviceIoControlFile) * const pfnOrg = *g_ppfnVidNtDeviceIoControlFile;
//替换Vid里NtDeviceIoControlFile的函数地址成nemR3WinIoctlDetector_GetHvPartitionId
*g_ppfnVidNtDeviceIoControlFile = nemR3WinIoctlDetector_GetHvPartitionId;
//调用VidGetHvPartitionId,会调用到nemR3WinIoctlDetector_GetHvPartitionId里,这个函数记录下VidGetHvPartitionId的functionId
HV_PARTITION_ID idHvPartition = HV_PARTITION_ID_INVALID;
//构造一个假的调用
BOOL fRet = g_pfnVidGetHvPartitionId(NEM_WIN_IOCTL_DETECTOR_FAKE_HANDLE, &idHvPartition);
//恢复NtDeviceIoControlFile的地址
*g_ppfnVidNtDeviceIoControlFile = pfnOrg;
}
static NTSTATUS WINAPI
nemR3WinIoctlDetector_GetHvPartitionId(HANDLE hFile, HANDLE hEvt, PIO_APC_ROUTINE pfnApcCallback, PVOID pvApcCtx,
PIO_STATUS_BLOCK pIos, ULONG uFunction, PVOID pvInput, ULONG cbInput,
PVOID pvOutput, ULONG cbOutput)
{
//校验输入参数,防止获取错误的functionid
AssertLogRelMsgReturn(cbInput == 0, ("cbInput=%#x\n", cbInput), STATUS_INVALID_PARAMETER_8);
AssertLogRelMsgReturn(cbOutput == sizeof(HV_PARTITION_ID), ("cbInput=%#x\n", cbInput), STATUS_INVALID_PARAMETER_10);
g_IoCtlGetHvPartitionId.cbInput = cbInput;
g_IoCtlGetHvPartitionId.cbOutput = cbOutput;
//保存FunctionID
g_IoCtlGetHvPartitionId.uFunction = uFunction;
}
NEMR0InitVM
R0的初始化函数
VMMR0_INT_DECL(int) NEMR0InitVM(PGVM pGVM)
{
//获取两个函数地址
RTDBGKRNLINFO hKrnlInfo;
rc = RTR0DbgKrnlInfoOpen(&hKrnlInfo, 0);
//hypercall的函数地址
rc = RTR0DbgKrnlInfoQuerySymbol(hKrnlInfo, NULL, "HvlInvokeHypercall", (void **)&g_pfnHvlInvokeHypercall);
rc = RTR0DbgKrnlInfoQuerySymbol(hKrnlInfo, "winhvr.sys", "WinHvDepositMemory", (void **)&g_pfnWinHvDepositMemory);
RTR0DbgKrnlInfoRelease(hKrnlInfo);
//初始化hypercall的锁
RTCritSectInit(&pGVM->nemr0.s.HypercallDataCritSect);
//初始化全局的hypercall内存(用于传递hypercall参数和获取VMExit Info)
nemR0InitHypercallData(&pGVM->nemr0.s.HypercallData);
//给每个VCPU申请一个hypercall内存
for (VMCPUID i = 0; i < pGVM->cCpus; i++)
{
//(用于传递hypercall参数和获取VMExit Info)
rc = nemR0InitHypercallData(&pGVM->aCpus[i].nemr0.s.HypercallData);
if (RT_FAILURE(rc))
{
while (i-- > 0)
nemR0DeleteHypercallData(&pGVM->aCpus[i].nemr0.s.HypercallData);
break;
}
}
}
21.1.2 NEMR3InitAfterCPUM
开启NEM模式之后,VM结构体里的bMainExecutionEngine被设置成VM_EXEC_ENGINE_NATIVE_API
VMMR3_INT_DECL(int) NEMR3InitAfterCPUM(PVM pVM)
{
if (pVM->bMainExecutionEngine == VM_EXEC_ENGINE_NATIVE_API)
{
//为了支持NEM,CPU必须支持一些功能开启,设置CPUID开启这些功能
CPUMR3SetGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_SEP);
if ( CPUMGetGuestCpuVendor(pVM) == CPUMCPUVENDOR_AMD
|| CPUMGetGuestCpuVendor(pVM) == CPUMCPUVENDOR_HYGON)
CPUMR3SetGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_SYSCALL); /* 64 bits only on Intel CPUs */
if (pVM->nem.s.fAllow64BitGuests)
{
CPUMR3SetGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_SYSCALL);
CPUMR3SetGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_PAE);
CPUMR3SetGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_LONG_MODE);
CPUMR3SetGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_LAHF);
CPUMR3SetGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_NX);
}
//如果开启了PAE,需要开启NXE
else if (CPUMR3GetGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_PAE))
CPUMR3SetGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_NX);
rc = nemR3NativeInitAfterCPUM(pVM);
}
}
nemR3NativeInitAfterCPUM
根据CPUM初始化结果完成部分初始化功能
int nemR3NativeInitAfterCPUM(PVM pVM)
{
//获取hyper-V的partition
WHV_PARTITION_HANDLE hPartition = pVM->nem.s.hPartition;
WHV_PARTITION_PROPERTY Property;
//设置cacheline大小(WHvGetCapabilityWrapper获取的值)
RT_ZERO(Property);
Property.ProcessorClFlushSize = pVM->nem.s.cCacheLineFlushShift;
hrc = WHvSetPartitionProperty(hPartition, WHvPartitionPropertyCodeProcessorClFlushSize, &Property, sizeof(Property));
//注册DB/PF/BP/UD 中断需要产生VMExit
RT_ZERO(Property);
Property.ExceptionExitBitmap = RT_BIT_64(WHvX64ExceptionTypeDebugTrapOrFault)
| RT_BIT_64(WHvX64ExceptionTypeBreakpointTrap)
| RT_BIT_64(WHvX64ExceptionTypeInvalidOpcodeFault);
hrc = WHvSetPartitionProperty(hPartition, WHvPartitionPropertyCodeExceptionExitBitmap, &Property, sizeof(Property));
//设置cpufeature成WHvGetCapabilityWrapper 获取的返回值
RT_ZERO(Property);
Property.ProcessorFeatures.AsUINT64 = pVM->nem.s.uCpuFeatures.u64;
hrc = WHvSetPartitionProperty(hPartition, WHvPartitionPropertyCodeProcessorFeatures, &Property, sizeof(Property));
//创建VM
hrc = WHvSetupPartition(hPartition);
//获取VID_PARTITION_HANDLE handle
HANDLE hPartitionDevice;
__try
{
hPartitionDevice = ((HANDLE *)hPartition)[1];
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
hrc = GetExceptionCode();
hPartitionDevice = NULL;
}
//获取Partition ID
HV_PARTITION_ID idHvPartition = HV_PARTITION_ID_INVALID;
g_pfnVidGetHvPartitionId(hPartitionDevice, &idHvPartition);
//保存handle和id
pVM->nem.s.hPartitionDevice = hPartitionDevice;
pVM->nem.s.idHvPartition = idHvPartition;
//setup emulation thread
for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
{
PVMCPU pVCpu = pVM->apCpusR3[idCpu];
//获取R3的VMCPU结构体handle
pVCpu->nem.s.hNativeThreadHandle = (RTR3PTR)RTThreadGetNativeHandle(VMR3GetThreadHandle(pVCpu->pUVCpu));
//没有开启了R0 loop,直接调用WHv的API
if (!pVM->nem.s.fUseRing0Runloop)
{
//向Hyper-V注册VCPU
hrc = WHvCreateVirtualProcessor(hPartition, idCpu, 0 /*fFlags*/);
if (FAILED(hrc))
{
//注册VCPU失败,之前create的VCPU都删除,然后返回错误
NTSTATUS const rcNtLast = RTNtLastStatusValue();
DWORD const dwErrLast = RTNtLastErrorValue();
while (idCpu-- > 0)
{
HRESULT hrc2 = WHvDeleteVirtualProcessor(hPartition, idCpu);
}
return VMSetError(pVM, VERR_NEM_VM_CREATE_FAILED, RT_SRC_POS,
"Call to WHvCreateVirtualProcessor failed: %Rhrc (Last=%#x/%u)", hrc, rcNtLast, dwErrLast);
}
}
else
{
//获取当前CPU的pvMsgSlotMapping,VMExit的时候从这个Mapping里获取VMExit的参数
VID_MAPPED_MESSAGE_SLOT MappedMsgSlot = { NULL, UINT32_MAX, UINT32_MAX };
if (g_pfnVidMessageSlotMap(hPartitionDevice, &MappedMsgSlot, idCpu))
{
pVCpu->nem.s.pvMsgSlotMapping = MappedMsgSlot.pMsgBlock;
}
}
}
pVM->nem.s.fCreatedEmts = true;
//调用R0的NEMR0InitVMPart2函数
VMMR3CallR0Emt(pVM, pVM->apCpusR3[0], VMMR0_DO_NEM_INIT_VM_PART_2, 0, NULL);
VMMR3CallR0Emt(pVM, pVM->apCpusR3[0], VMMR0_DO_NEM_UPDATE_STATISTICS, 0, NULL);
}
NEMR0InitVMPart2
R0从R3拷贝数据
VMMR0_INT_DECL(int) NEMR0InitVMPart2(PGVM pGVM)
{
//GetHvPartitionId的ioctl ID
NEMWINIOCTL Copy = pGVM->nem.s.IoCtlGetHvPartitionId;
pGVM->nemr0.s.IoCtlGetHvPartitionId = Copy;
pGVM->nemr0.s.fMayUseRing0Runloop = pGVM->nem.s.fUseRing0Runloop;
//ioctl id
Copy = pGVM->nem.s.IoCtlStartVirtualProcessor;
pGVM->nemr0.s.IoCtlStartVirtualProcessor = Copy;
Copy = pGVM->nem.s.IoCtlStopVirtualProcessor;
pGVM->nemr0.s.IoCtlStopVirtualProcessor = Copy;
Copy = pGVM->nem.s.IoCtlMessageSlotHandleAndGetNext;
pGVM->nemr0.s.IoCtlMessageSlotHandleAndGetNext = Copy;
if ( RT_SUCCESS(rc)
|| !pGVM->nem.s.fUseRing0Runloop)
{
//获取VID.sys的pDevObject和pFileObject,用于后面调用IOCTL
rc = SUPR0IoCtlSetupForHandle(pGVM->pSession, pGVM->nem.s.hPartitionDevice, 0, &pGVM->nemr0.s.pIoCtlCtx);
for (VMCPUID idCpu = 0; idCpu < pGVM->cCpus; idCpu++)
{
PGVMCPU pGVCpu = &pGVM->aCpus[idCpu];
pGVCpu->nemr0.s.offRing3ConversionDelta = (uintptr_t)pGVM->aCpus[idCpu].pVCpuR3 - (uintptr_t)pGVCpu;
}
//调用IOCTL获取partitionID
PVMCPUCC pVCpu0 = &pGVM->aCpus[0];
NTSTATUS rcNt = nemR0NtPerformIoControl(pGVM, pVCpu0, pGVM->nemr0.s.IoCtlGetHvPartitionId.uFunction, NULL, 0,
&pVCpu0->nem.s.uIoCtlBuf.idPartition, sizeof(pVCpu0->nem.s.uIoCtlBuf.idPartition));
pGVM->nemr0.s.idHvPartition = pVCpu0->nem.s.uIoCtlBuf.idPartition;
}
}
21.1.3 nemR3NativeTerm
结束NEM,删除虚拟机
VMMR3_INT_DECL(int) NEMR3Term(PVM pVM)
{
nemR3NativeTerm(pVM);
//mark terminate
for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
{
PVMCPU pVCpu = pVM->apCpusR3[idCpu];
pVCpu->nem.s.u32Magic = NEMCPU_MAGIC_DEAD;
}
pVM->nem.s.u32Magic = NEM_MAGIC_DEAD;
}
int nemR3NativeTerm(PVM pVM);
{
//删除partition
WHV_PARTITION_HANDLE hPartition = pVM->nem.s.hPartition;
pVM->nem.s.hPartition = NULL;
pVM->nem.s.hPartitionDevice = NULL;
if (hPartition != NULL)
{
VMCPUID idCpu = pVM->nem.s.fCreatedEmts ? pVM->cCpus : 0;
while (idCpu-- > 0)
{
PVMCPU pVCpu = pVM->apCpusR3[idCpu];
pVCpu->nem.s.pvMsgSlotMapping = NULL;
if (!pVM->nem.s.fUseRing0Runloop)
{
//delete VCPU
HRESULT hrc = WHvDeleteVirtualProcessor(hPartition, idCpu);
}
}
WHvDeletePartition(hPartition);
}
}
21.1.4 nemR3NativeReset
重置NEM
void nemR3NativeResetCpu(PVMCPU pVCpu, bool fInitIpi)
{
if (fInitIpi && pVCpu->idCpu > 0)
{
PVM pVM = pVCpu->CTX_SUFF(pVM);
if (!pVM->nem.s.fA20Enabled)
nemR3NativeNotifySetA20(pVCpu, true);
pVM->nem.s.fA20Enabled = true;
pVM->nem.s.fA20Fixed = true;
}
}