文章目录

  • Native execution manager (Hyper-V兼容)
  • 21.1 NEM初始化/Term 相关API
    • 21.1.1 NEMR3InitConfig
    • 21.1.2 NEMR3Init
      • nemR3WinInitProbeAndLoad
      • nemR3WinInitCheckCapabilities
      • nemR3WinInitCreatePartition
      • nemR3WinInitDiscoverIoControlProperties
      • NEMR0InitVM
    • 21.1.2 NEMR3InitAfterCPUM
      • nemR3NativeInitAfterCPUM
      • NEMR0InitVMPart2
    • 21.1.3 nemR3NativeTerm
    • 21.1.4 nemR3NativeReset

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 */);//是否开启NEMrc = CFGMR3QueryBoolDef(pCfgNem, "Enabled", &pVM->nem.s.fEnabled, true);rc = CFGMR3QueryBoolDef(pCfgNem, "Allow64BitGuests", &pVM->nem.s.fAllow64BitGuests, HC_ARCH_BITS == 64);//默认开启R0 loop,即直接调用VID.sys里的IOCTLbool fUseRing0Runloop = true;//可以在配置里关闭R0looprc = 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 partitionrc = nemR3WinInitCreatePartition(pVM, pErrInfo);if (RT_SUCCESS(rc)){//到这里启动NEM成,设置引擎模式成VM_EXEC_ENGINE_NATIVE_APIVM_SET_MAIN_EXECUTION_ENGINE(pVM, VM_EXEC_ENGINE_NATIVE_API);//NEM模式需要关闭x2APIC,使用xAPICnemR3WinDisableX2Apic(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_HVPif (!(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个leafif (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和异常的VMExitProperty.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 PartitionWHvDeletePartition(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的functionIdHV_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)
{//校验输入参数,防止获取错误的functionidAssertLogRelMsgReturn(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;//保存FunctionIDg_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,需要开启NXEelse if (CPUMR3GetGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_PAE))CPUMR3SetGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_NX);rc = nemR3NativeInitAfterCPUM(pVM);}
}

nemR3NativeInitAfterCPUM

根据CPUM初始化结果完成部分初始化功能

int nemR3NativeInitAfterCPUM(PVM pVM)
{//获取hyper-V的partitionWHV_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 中断需要产生VMExitRT_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));//创建VMhrc = WHvSetupPartition(hPartition);//获取VID_PARTITION_HANDLE handleHANDLE hPartitionDevice;__try{hPartitionDevice = ((HANDLE *)hPartition)[1];}__except(EXCEPTION_EXECUTE_HANDLER){hrc = GetExceptionCode();hPartitionDevice = NULL;}//获取Partition IDHV_PARTITION_ID idHvPartition = HV_PARTITION_ID_INVALID;g_pfnVidGetHvPartitionId(hPartitionDevice, &idHvPartition);//保存handle和idpVM->nem.s.hPartitionDevice = hPartitionDevice;pVM->nem.s.idHvPartition    = idHvPartition;//setup emulation threadfor (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++){PVMCPU pVCpu = pVM->apCpusR3[idCpu];//获取R3的VMCPU结构体handlepVCpu->nem.s.hNativeThreadHandle = (RTR3PTR)RTThreadGetNativeHandle(VMR3GetThreadHandle(pVCpu->pUVCpu));//没有开启了R0 loop,直接调用WHv的APIif (!pVM->nem.s.fUseRing0Runloop){//向Hyper-V注册VCPUhrc = 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 IDNEMWINIOCTL Copy = pGVM->nem.s.IoCtlGetHvPartitionId;pGVM->nemr0.s.IoCtlGetHvPartitionId = Copy;pGVM->nemr0.s.fMayUseRing0Runloop = pGVM->nem.s.fUseRing0Runloop;//ioctl idCopy = 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,用于后面调用IOCTLrc = 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获取partitionIDPVMCPUCC 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 terminatefor (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);
{//删除partitionWHV_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 VCPUHRESULT 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;}
}

Virtualbox源码分析21 NEM(Hyper-V兼容)2 Hyper-V初始化和VM创建销毁相关推荐

  1. Virtualbox源码分析20 NEM(Hyper-V兼容)1 Hyper-V架构和API介绍

    文章目录 Native execution manager (Hyper-V兼容) 20.1 winhvplatform.dll里的APIs 20.2 VID.dll 的导出函数 20.3 直接调用V ...

  2. Virtualbox源码分析22 NEM(Hyper-V兼容)3 Emulation Thread

    Native execution manager (Emulation Thread ) 文章目录 Native execution manager (Emulation Thread ) 22.1. ...

  3. Virtualbox源码分析23 NEM(Hyper-V兼容)4 VMExit

    Native execution manager (VMExit) 文章目录 Native execution manager (VMExit) 23.1 EPT内存管理 23.1.1分配内存 23. ...

  4. Virtualbox源码分析4:VMM虚拟化实现源码分析1

    文章目录 Virtualbox源码分析4:VMM虚拟化框架实现源码分析 4.1 VMX原理 4.1.1 VMX的状态转化: 4.1.2 VMCS 4.1.3 VMExit:VMX异常 Virtualb ...

  5. 【转】ABP源码分析二:ABP中配置的注册和初始化

    一般来说,ASP.NET Web应用程序的第一个执行的方法是Global.asax下定义的Start方法.执行这个方法前HttpApplication 实例必须存在,也就是说其构造函数必然已完成了执行 ...

  6. Virtualbox源码分析16 APIC虚拟化1 APIC概念和初始化

    文章目录 中断是什么 中断是如何被发送给CPU的 16.1 xAPIC and x2APIC 16.2 Local APIC Page里的寄存器和对应的重要概念 APIC ID 中断优先级类型的寄存器 ...

  7. Mybatis源码分析之(二)根据配置文件创建SqlSessionFactory(Configuration的创建过程)

    SqlSessionFactoryBuilder.build创建SqlSessionFactory(粗略走一步流程) 看完上篇文章后,你对mybatis应该有个大概的了解了,那么我们知道new Sql ...

  8. Virtualbox源码分析17 APIC虚拟化2.APIC设备模拟

    文章目录 17.1 APIC设备模拟 apicR3Construct apicR3InitState apicRZConstruct: apicR3Reset apicR3Destruct 17.2 ...

  9. Hadoop源码分析21:namenode概要

    待续 转载于:https://www.cnblogs.com/leeeee/p/7276509.html

最新文章

  1. html 监听input输入框的值,利用原生JS实时监听input框输入值
  2. 解决修改/etc/sudoers文件后:报 语法错误 near line 23
  3. Object.assign()怎么用?
  4. 将tomcat添加到系统服务
  5. 欠拟合与过拟合概念和局部加权回归
  6. 如何制作动态桌面(视频版)
  7. matlab 三角函数积分,正弦函数与三角函数积分及Matlab编程.doc
  8. 运营方法 - 运营的思考方法
  9. masquerade词根词缀_词根词缀总结
  10. linux怎么生成arm文件,AMR 文件扩展名: 它是什么以及如何打开它?
  11. ArcGIS Server 切片数学关系阐释,小区域切图频繁出错解决方法
  12. 关于Optical Zoom
  13. centos 把文件打包为tar.gz命令
  14. 影响网站收录的几个因素
  15. tZERO母公司Overstock股票五个月暴涨37倍背后:已深耕区块链业务数年
  16. Fluent报错cl-set-default-save-dir: path does not exist.
  17. 绝妙的 channel
  18. 达芬奇调色 Blackmagic Design DaVinci Resolve Studio 17 中文版,整合剪辑、视觉特效、动态图形、调色和音频后期制作
  19. 无忌炼神功(热身层 )———— 初识JVM
  20. 实验三 敏捷开发与XP实践 实验报告 20135232王玥

热门文章

  1. 【记录】RS-232串口通信个人理解
  2. 国学入门书要目及其读法(梁启超)
  3. linux docker升级,Docker 升级到最新版本
  4. jsp预加载转圈_30种CSS3炫酷页面预加载loading动画特效(推荐)
  5. Download模块 (十三)
  6. Unity3d学习笔记 var 关键字
  7. 扫雷计算机教案,四下选修拓展《扫雷游戏》教案
  8. Ubuntu14.04-LTS 从系统安装到配置可用
  9. matlab提取车牌字符程序,如何用matlab提取和识别车牌数?
  10. java学习第6天,今天是循环结构