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

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;
    }
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值