Virtualbox源码分析11 CPU manager3:CPUID

这一章里,介绍模拟CPUID和CPU寄存器访问

11.1 GuestOS CpuId/MSR初始化

cpumR3InitCpuIdAndMsrs

在CpumInit()函数里调用

int cpumR3InitCpuIdAndMsrs(PVM pVM, PCCPUMMSRS pHostMsrs)
{
  // 读取配置
  CPUMCPUIDCONFIG Config;
  cpumR3CpuIdReadConfig(pVM, &Config, pCpumCfg, HMAreNestedPagingAndFullGuestExecEnabled(pVM));
  //从CPUDatabase里获取当前CPU型号,初始化MSRRange和CPUIDRange
  cpumR3DbGetCpuInfo(Config.szCpuName, &pCpum->GuestInfo);
  //去掉Guest CPU的MxCsrMask里Host不支持的特性
  if (pCpum->GuestInfo.fMxCsrMask & ~pVM->cpum.s.fHostMxCsrMask)
  {
     pCpum->GuestInfo.fMxCsrMask &= pVM->cpum.s.fHostMxCsrMask;
  }
  //从CPU Database里找到对应的CPU型号,并初始化MSRRange
  cpumR3DbGetCpuInfo(Config.szCpuName, &pCpum->GuestInfo);
  //通过config里的配置覆盖部分MSRRange里的内容
  cpumR3LoadMsrOverrides(pVM, CFGMR3GetChild(pCpumCfg, "MSRs"));
  //通过config里的配置覆盖部分CPUID leaves里的内容
  cpumR3LoadCpuIdOverrides(pVM, CFGMR3GetChild(pCpumCfg, "HostCPUID"), "HostCPUID");
  
  CFGMR3GetChild(pCpumCfg, "CPUID")
    
  //先保存到全局变量里  
  CPUMMSRS GuestMsrs;
  RT_ZERO(GuestMsrs);
    
  //根据CPU Leaves里的数据,初始化pCpum->GuestFeatures,和GuestMsrs里的部分值
  cpumR3CpuIdExplodeFeatures(pCpum->GuestInfo.paCpuIdLeavesR3, pCpum->GuestInfo.cCpuIdLeaves, &GuestMsrs,
                                        &pCpum->GuestFeatures);
  
  //初始化部分CPUID leaves里的值,本篇后面介绍
  if (RT_SUCCESS(rc))
  {
    rc = cpumR3CpuIdSanitize(pVM, pCpum, &Config);
    if (RT_SUCCESS(rc))
    {
      cpumR3CpuIdLimitLeaves(pCpum, &Config);
      cpumR3CpuIdLimitIntelFamModStep(pCpum, &Config);
    }
  }
  //根据CPUID的值初始化部分MSRRange,下一篇里介绍这个函数
  cpumR3MsrReconcileWithCpuId(pVM);
  
  //为了能让虚拟机能在不同CPU机器上拷贝,需要对部分MSR寄存器做模糊化处理: 如果CPU没有对应MSRRange,设置一个模糊MSRRange,下一篇里介绍这个函数
  bool fEnable;
  rc = CFGMR3QueryBoolDef(pCpumCfg, "FudgeMSRs", &fEnable, true); AssertRC(rc);
  if (RT_SUCCESS(rc) && fEnable)
  {
    rc = cpumR3MsrApplyFudge(pVM);
  }
  
  //把MSR ranges和CPUID leaves的内存拷贝到用MM(Memory manager申请出来的内存里
  void *pvFree = pCpum->GuestInfo.paCpuIdLeavesR3;
  //这个函数后面介绍
  int rc1 = cpumR3CpuIdInstallAndExplodeLeaves(pVM, pCpum, pCpum->GuestInfo.paCpuIdLeavesR3,
                                               pCpum->GuestInfo.cCpuIdLeaves, &GuestMsrs);
  RTMemFree(pvFree);
  pvFree = pCpum->GuestInfo.paMsrRangesR3;
  int rc2 = MMHyperDupMem(pVM, pvFree,
                          sizeof(pCpum->GuestInfo.paMsrRangesR3[0]) * pCpum->GuestInfo.cMsrRanges, 32,
                          MM_TAG_CPUM_MSRS, (void **)&pCpum->GuestInfo.paMsrRangesR3);
  RTMemFree(pvFree);
  pCpum->GuestInfo.paMsrRangesR0 = MMHyperR3ToR0(pVM, pCpum->GuestInfo.paMsrRangesR3);
  
  //初始化VMX的msr
  if (pVM->cpum.s.GuestFeatures.fVmx)
  {
    cpumR3InitVmxGuestFeaturesAndMsrs(pVM, &pHostMsrs->hwvirt.vmx, &GuestMsrs.hwvirt.vmx);

    //从全局变量里拷贝msr值到VCPU里
    PCVMXMSRS pVmxMsrs = &GuestMsrs.hwvirt.vmx;
    for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
    {
      PVMCPU pVCpu = pVM->apCpusR3[idCpu];
      memcpy(&pVCpu->cpum.s.Guest.hwvirt.vmx.Msrs, pVmxMsrs, sizeof(*pVmxMsrs));
    }
  }
  
  //根据配置设置部分CPUID
  //PAE
  bool fEnable;
  rc = CFGMR3QueryBoolDef(CFGMR3GetRoot(pVM), "EnablePAE", &fEnable, false);
  AssertRCReturn(rc, rc);
  if (fEnable)
    CPUMR3SetGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_PAE);
  //NX
  rc = CFGMR3QueryBoolDef(pCpumCfg, "EnableNX", &fEnable, false);
  if (fEnable)
    CPUMR3SetGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_NX);
  //speculation control
  rc = CFGMR3QueryBoolDef(pCpumCfg, "SpecCtrl", &fEnable, false);
  if (fEnable)
    CPUMR3SetGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_SPEC_CTRL);
}

cpumR3LoadCpuIdOverrides

//从配置文件里获取CPUID leaves 并覆盖已有的CPUID leaves
static int cpumR3LoadCpuIdOverrides(PVM pVM, PCFGMNODE pParentNode, const char *pszLabel)
{
  for (PCFGMNODE pNode = CFGMR3GetFirstChild(pParentNode); pNode; pNode = CFGMR3GetNextChild(pNode))
  {
    //获取Leaf和SubLeaf的值
    CFGMR3QueryU32(pNode, "Leaf", &uLeaf);
    CFGMR3QueryU32Def(pNode, "SubLeaf", &uSubLeaf, 0);
    CFGMR3QueryU32Def(pNode, "SubLeafMask", &fSubLeafMask, 0);
    
    //从CPUID leaves array里获取已有的Leaf
    PCCPUMCPUIDLEAF pLeaf = cpumR3CpuIdGetExactLeaf(&pVM->cpum.s, uLeaf, uSubLeaf);
    //根据配置文件里的值重新赋值这个Leaf
    if (pLeaf)
      Leaf = *pLeaf;
    else
      RT_ZERO(Leaf);
    Leaf.uLeaf          = uLeaf;
    Leaf.uSubLeaf       = uSubLeaf;
    Leaf.fSubLeafMask   = fSubLeafMask;
    CFGMR3QueryU32Def(pNode, "eax", &Leaf.uEax, Leaf.uEax);
    CFGMR3QueryU32Def(pNode, "ebx", &Leaf.uEbx, Leaf.uEbx);
    CFGMR3QueryU32Def(pNode, "ecx", &Leaf.uEcx, Leaf.uEcx);
    CFGMR3QueryU32Def(pNode, "edx", &Leaf.uEdx, Leaf.uEdx);
    
    //加入到paCpuIdLeavesR3 array里,如果已存在这个leaf,覆盖已有的leaf
    cpumR3CpuIdInsert(NULL /* pVM */, &pVM->cpum.s.GuestInfo.paCpuIdLeavesR3, &pVM->cpum.s.GuestInfo.cCpuIdLeaves,
                               &Leaf);
  }
}

cpumR3CpuIdExplodeFeatures

根据CPU Leaves里的数据,初始化PCPUMFEATURES结构体

//根据CPUID的返回值,赋值PCPUMFEATURES
int cpumR3CpuIdExplodeFeatures(PCCPUMCPUIDLEAF paLeaves, uint32_t cLeaves, PCCPUMMSRS pMsrs, PCPUMFEATURES pFeatures)
{
  //CPUID(0)的返回值
  PCCPUMCPUIDLEAF const pStd0Leaf = cpumR3CpuIdFindLeafEx(paLeaves, cLeaves, 0, 0);
  //CPUID (1)的返回值
  PCCPUMCPUIDLEAF const pStd1Leaf = cpumR3CpuIdFindLeafEx(paLeaves, cLeaves, 1, 0);
  //CPUID (80000008)的返回值 : 
  //Intel: 物理地址相关的信息,AMD: X86_CPUID_AMD_EFEID_EBX_IBPB
  CCPUMCPUIDLEAF const pExtLeaf8 = cpumR3CpuIdFindLeaf(paLeaves, cLeaves, 0x80000008);
  //获取物理地址,和线性地址的位数
  if (pExtLeaf8)
  {
    pFeatures->cMaxPhysAddrWidth   = pExtLeaf8->uEax & 0xff;
    pFeatures->cMaxLinearAddrWidth = (pExtLeaf8->uEax >> 8) & 0xff;
  }
  //32位PageSizeExtersions开启
  else if (pStd1Leaf->uEdx & X86_CPUID_FEATURE_EDX_PSE36)
  {
    pFeatures->cMaxPhysAddrWidth   = 36;
    pFeatures->cMaxLinearAddrWidth = 36;
  }
  else
  {
    pFeatures->cMaxPhysAddrWidth   = 32;
    pFeatures->cMaxLinearAddrWidth = 32;
  }
  
  //CPU的基础信息
  pFeatures->fMsr                 = RT_BOOL(pStd1Leaf->uEdx & X86_CPUID_FEATURE_EDX_MSR);
  pFeatures->fApic                = RT_BOOL(pStd1Leaf->uEdx & X86_CPUID_FEATURE_EDX_APIC);
  pFeatures->fX2Apic              = RT_BOOL(pStd1Leaf->uEcx & X86_CPUID_FEATURE_ECX_X2APIC);
  pFeatures->fPse                 = RT_BOOL(pStd1Leaf->uEdx & X86_CPUID_FEATURE_EDX_PSE);
  pFeatures->fPse36               = RT_BOOL(pStd1Leaf->uEdx & X86_CPUID_FEATURE_EDX_PSE36);
  ...
  //VMX
  if (pFeatures->fVmx)
      cpumR3ExplodeVmxFeatures(&pMsrs->hwvirt.vmx, pFeatures);
  
  //CPUID (7)的返回值: Structured Extended Feature Flags 
  PCCPUMCPUIDLEAF const pSxfLeaf0 = cpumR3CpuIdFindLeafEx(paLeaves, cLeaves, 7, 0);
  if (pSxfLeaf0)
  {
    pFeatures->fFsGsBase            = RT_BOOL(pSxfLeaf0->uEbx & X86_CPUID_STEXT_FEATURE_EBX_FSGSBASE);
    pFeatures->fAvx2                = RT_BOOL(pSxfLeaf0->uEbx & X86_CPUID_STEXT_FEATURE_EBX_AVX2);
    pFeatures->fAvx512Foundation    = RT_BOOL(pSxfLeaf0->uEbx & X86_CPUID_STEXT_FEATURE_EBX_AVX512F);
    pFeatures->fClFlushOpt          = RT_BOOL(pSxfLeaf0->uEbx & X86_CPUID_STEXT_FEATURE_EBX_CLFLUSHOPT);
  }
  //CPUID (5)的返回值:MONITOR/MWAIT Leaf
  PCCPUMCPUIDLEAF const pMWaitLeaf = cpumR3CpuIdFindLeaf(paLeaves, cLeaves, 5);
  if (pMWaitLeaf)
    pFeatures->fMWaitExtensions = (pMWaitLeaf->uEcx & (X86_CPUID_MWAIT_ECX_EXT | X86_CPUID_MWAIT_ECX_BREAKIRQIF0))
    ==                    (X86_CPUID_MWAIT_ECX_EXT | X86_CPUID_MWAIT_ECX_BREAKIRQIF0);
  
  //CPUID (0x80000001)的返回值 Extended Processor Signature and Feature Bits.
  PCCPUMCPUIDLEAF const pExtLeaf  = cpumR3CpuIdFindLeaf(paLeaves, cLeaves, 0x80000001);
  if (pExtLeaf)
  {
    pFeatures->fLongMode        = RT_BOOL(pExtLeaf->uEdx & X86_CPUID_EXT_FEATURE_EDX_LONG_MODE);
    pFeatures->fSysCall         = RT_BOOL(pExtLeaf->uEdx & X86_CPUID_EXT_FEATURE_EDX_SYSCALL);
    pFeatures->fNoExecute       = RT_BOOL(pExtLeaf->uEdx & X86_CPUID_EXT_FEATURE_EDX_NX);
    ...
  }
  //如果不支持长模式(64位),则cVmxMaxPhysAddrWidth = 32
  pFeatures->cVmxMaxPhysAddrWidth = pFeatures->fLongMode ? pFeatures->cMaxPhysAddrWidth : 32;
  
  //AMD CPU
  if (   pExtLeaf
            && (   pFeatures->enmCpuVendor == CPUMCPUVENDOR_AMD
                || pFeatures->enmCpuVendor == CPUMCPUVENDOR_HYGON))
  {
    pFeatures->fMsr            |= RT_BOOL(pExtLeaf->uEdx & X86_CPUID_AMD_FEATURE_EDX_MSR);
    pFeatures->fApic           |= RT_BOOL(pExtLeaf->uEdx & X86_CPUID_AMD_FEATURE_EDX_APIC);
    pFeatures->fPse            |= RT_BOOL(pExtLeaf->uEdx & X86_CPUID_AMD_FEATURE_EDX_PSE);
    ....
  }
  //AMD CPU特性
  pFeatures->fLeakyFxSR = pExtLeaf
          && (pExtLeaf->uEdx & X86_CPUID_AMD_FEATURE_EDX_FFXSR)
          && (   (   pFeatures->enmCpuVendor == CPUMCPUVENDOR_AMD
                  && pFeatures->uFamily >= 6 /* K7 and up */)
              || pFeatures->enmCpuVendor == CPUMCPUVENDOR_HYGON)
    
  pFeatures->cbMaxExtendedState = pFeatures->fFxSaveRstor ? sizeof(X86FXSTATE) : sizeof(X86FPUSTATE);
  if (pFeatures->fXSaveRstor)
  {
    //Processor Extended State Enumeration
    PCCPUMCPUIDLEAF const pXStateLeaf0 = cpumR3CpuIdFindLeafEx(paLeaves, cLeaves, 13, 0);
    if (pXStateLeaf0)
    {
      if (   pXStateLeaf0->uEcx >= sizeof(X86FXSTATE)
          && pXStateLeaf0->uEcx <= CPUM_MAX_XSAVE_AREA_SIZE
          && RT_ALIGN_32(pXStateLeaf0->uEcx, 8) == pXStateLeaf0->uEcx
          && pXStateLeaf0->uEbx >= sizeof(X86FXSTATE)
          && pXStateLeaf0->uEbx <= pXStateLeaf0->uEcx
          && RT_ALIGN_32(pXStateLeaf0->uEbx, 8) == pXStateLeaf0->uEbx)
      {
        pFeatures->cbMaxExtendedState = pXStateLeaf0->uEcx;

        PCCPUMCPUIDLEAF const pXStateLeaf1 = cpumR3CpuIdFindLeafEx(paLeaves, cLeaves, 13, 1);
        if (   pXStateLeaf1
            && pXStateLeaf1->uEbx > pFeatures->cbMaxExtendedState
            && pXStateLeaf1->uEbx <= CPUM_MAX_XSAVE_AREA_SIZE
            && (pXStateLeaf1->uEcx || pXStateLeaf1->uEdx) )
          pFeatures->cbMaxExtendedState = pXStateLeaf1->uEbx;
      }
    }
  }
   
}

11.2 CPUID Leaves 初始化

VirtualBox的VCPU运行用户自己定义CPU的功能,所以需要提供API读取和设置CPU信息,并且需要模拟CPUID指令,GuestOS里调用CPUID指令,能够获取正确的返回值。代码位于CPUMR3Cpuid.cpp。

所有CPUID leaves安装uleaf大小从小到大排好序保存到pVM->cpum.s.GuestInfo.paCpuIdLeavesR3内存里,如果某个uleaf有subleaf,则按照subleaf从小到大顺序排列在一起。

这块内存同时会映射到pVM->cpum.s.GuestInfo.paCpuIdLeavesR0这个R0地址里,pVM->cpum.s.GuestInfo.cCpuIdLeaves保存了CPUID leaves的个数。

cpumR3CpuIdReadConfig

读取虚拟机对CPU的配置,可以控制CPU是否支持一些特殊功能,比如CMPXCHG16B/MONITOR/XSAVE指令等。

static int cpumR3CpuIdReadConfig(PVM pVM, PCPUMCPUIDCONFIG pConfig, PCFGMNODE pCpumCfg, bool fNestedPagingAndFullGuestExec)
{
  CFGMR3QueryU8Def(pCpumCfg, "PortableCpuIdLevel", &pVM->cpum.s.u8PortableCpuIdLevel, 0);
  CFGMR3QueryStringDef(pCpumCfg, "GuestCpuName", pConfig->szCpuName, sizeof(pConfig->szCpuName), "host");
  ....
}
 

CPUMR3CpuIdCollectLeaves

初始化CPUID leaves内存

VMMR3DECL(int) CPUMR3CpuIdCollectLeaves(PCPUMCPUIDLEAF *ppaLeaves, uint32_t *pcLeaves)
{
  	//最后一位是0的CPUID input一般都是query当前CPU有多少子项,try下面这些值
    //Intel CPU支持0x00000000,0x40000000,0x80000000和0xc0000000
  	static struct { uint32_t uMsr; bool fSpecial; } const s_aCandidates[] =
    {
        { UINT32_C(0x00000000), false },
        { UINT32_C(0x10000000), false },
        { UINT32_C(0x20000000), false },
        { UINT32_C(0x30000000), false },
        { UINT32_C(0x40000000), false },
        { UINT32_C(0x50000000), false },
        { UINT32_C(0x60000000), false },
        { UINT32_C(0x70000000), false },
        { UINT32_C(0x80000000), false },
        { UINT32_C(0x80860000), false },
        { UINT32_C(0x8ffffffe), true  },
        { UINT32_C(0x8fffffff), true  },
        { UINT32_C(0x90000000), false },
        { UINT32_C(0xa0000000), false },
        { UINT32_C(0xb0000000), false },
        { UINT32_C(0xc0000000), false },
        { UINT32_C(0xd0000000), false },
        { UINT32_C(0xe0000000), false },
        { UINT32_C(0xf0000000), false },
    };
  
   	for (uint32_t iOuter = 0; iOuter < RT_ELEMENTS(s_aCandidates); iOuter++)
    {
      	//获取每一项的leaf个数
        uint32_t uLeaf = s_aCandidates[iOuter].uMsr;
        uint32_t uEax, uEbx, uEcx, uEdx;
        ASMCpuIdExSlow(uLeaf, 0, 0, 0, &uEax, &uEbx, &uEcx, &uEdx);
      	//返回的uEax值正确
        if ( uEax > uLeaf && uEax - uLeaf < UINT32_C(0xff))
        {
            uint32_t cLeaves = uEax - uLeaf + 1;
            while (cLeaves-- > 0)
            {
              //获取每个子leaf的host返回值
              ASMCpuIdExSlow(uLeaf, 0, 0, 0, &uEax, &uEbx, &uEcx, &uEdx);
              
              //是否有APIC ID
              if (uLeaf == 1)
                fFlags |= CPUMCPUIDLEAF_F_CONTAINS_APIC_ID;
              else if (uLeaf == 0xb && uEcx != 0)
                fFlags |= CPUMCPUIDLEAF_F_CONTAINS_APIC_ID;
              else if (   uLeaf == UINT32_C(0x8000001e)
                       && (   uEax
                           || uEbx
                           || uEdx
                           || ASMIsAmdCpuEx((*ppaLeaves)[0].uEbx, (*ppaLeaves)[0].uEcx, (*ppaLeaves)[0].uEdx)
                           || ASMIsHygonCpuEx((*ppaLeaves)[0].uEbx, (*ppaLeaves)[0].uEcx, (*ppaLeaves)[0].uEdx)) )
                fFlags |= CPUMCPUIDLEAF_F_CONTAINS_APIC_ID;
              //获取subleaf个数,获取3次
              if (   cpumR3IsEcxRelevantForCpuIdLeaf(uLeaf, &cSubLeaves, &fFinalEcxUnchanged)
                    && cpumR3IsEcxRelevantForCpuIdLeaf(uLeaf, &cSubLeaves, &fFinalEcxUnchanged)
                    && cpumR3IsEcxRelevantForCpuIdLeaf(uLeaf, &cSubLeaves, &fFinalEcxUnchanged))
              {
                //subleave个数不正确,返回错误
                if (cSubLeaves > (uLeaf == 0xd ? 68U : 16U))
                {
                  return VERR_CPUM_TOO_MANY_CPUID_SUBLEAVES;
                }
                if (fFinalEcxUnchanged)
                    fFlags |= CPUMCPUIDLEAF_F_INTEL_TOPOLOGY_SUBLEAVES;
								//遍历每个subleaf,加入到ppaLeaves里
                for (uint32_t uSubLeaf = 0; uSubLeaf < cSubLeaves; uSubLeaf++)
                {
                  ASMCpuIdExSlow(uLeaf, 0, uSubLeaf, 0, &uEax, &uEbx, &uEcx, &uEdx);
                  cpumR3CollectCpuIdInfoAddOne(ppaLeaves, pcLeaves,
                                                        uLeaf, uSubLeaf, UINT32_MAX, uEax, uEbx, uEcx, uEdx, fFlags);
                }
							}
              else
              {
                //当前leaf没有subleaf,只加入当前leaf到ppaLeaves里
                cpumR3CollectCpuIdInfoAddOne(ppaLeaves, pcLeaves,
                                                          uLeaf, 0, 0, uEax, uEbx, uEcx, uEdx, fFlags);
              }
              uLeaf++;
            }
        }
        else if (s_aCandidates[iOuter].fSpecial)
        {
          	//几个特殊的CPUID
            bool fKeep = false;
            //AMD K6 Unofficial CPU signature, Returns the string "DEI" 
            if (uLeaf == 0x8ffffffe && uEax == UINT32_C(0x00494544))
                fKeep = true;
            //AMD CPU用这个CPUID,其实是个彩蛋,把输入的寄存器每一位用asci吗转化一下,输出是“IT'S HAMMER TIME”  ^_^
            else if (   uLeaf == 0x8fffffff  (AMD CPU用这个CPUID)
                     && RT_C_IS_PRINT(RT_BYTE1(uEax))
                     && RT_C_IS_PRINT(RT_BYTE2(uEax))
                     && RT_C_IS_PRINT(RT_BYTE3(uEax))
                     && RT_C_IS_PRINT(RT_BYTE4(uEax))
                     && RT_C_IS_PRINT(RT_BYTE1(uEbx))
                     && RT_C_IS_PRINT(RT_BYTE2(uEbx))
                     && RT_C_IS_PRINT(RT_BYTE3(uEbx))
                     && RT_C_IS_PRINT(RT_BYTE4(uEbx))
                     && RT_C_IS_PRINT(RT_BYTE1(uEcx))
                     && RT_C_IS_PRINT(RT_BYTE2(uEcx))
                     && RT_C_IS_PRINT(RT_BYTE3(uEcx))
                     && RT_C_IS_PRINT(RT_BYTE4(uEcx))
                     && RT_C_IS_PRINT(RT_BYTE1(uEdx))
                     && RT_C_IS_PRINT(RT_BYTE2(uEdx))
                     && RT_C_IS_PRINT(RT_BYTE3(uEdx))
                     && RT_C_IS_PRINT(RT_BYTE4(uEdx)) )
                fKeep = true;
            if (fKeep)
            {
                // 加入当前leaf到ppaLeaves里
                cpumR3CollectCpuIdInfoAddOne(ppaLeaves, pcLeaves,
                                                      uLeaf, 0, 0, uEax, uEbx, uEcx, uEdx, 0);
            }
        }
    }
}

cpumR3CpuIdSanitize

初始化部分CPUID leaves

static int cpumR3CpuIdSanitize(PVM pVM, PCPUM pCpum, PCPUMCPUIDCONFIG pConfig)
{
  //Cpuid 1:
   //从全局CPUIDLeaves数组里获取对应的项,用于写入数据
    PCPUMCPUIDLEAF pStdFeatureLeaf = cpumR3CpuIdGetExactLeaf(pCpum, 1, 0); 
    pStdFeatureLeaf = cpumR3CpuIdMakeSingleLeaf(pCpum, pStdFeatureLeaf);

  	//edx值
    pStdFeatureLeaf->uEdx &= X86_CPUID_FEATURE_EDX_FPU
                           | X86_CPUID_FEATURE_EDX_VME
                           | X86_CPUID_FEATURE_EDX_DE
                           | X86_CPUID_FEATURE_EDX_PSE
                           ...
                           ;
    //部分ecx值,根据config里的值赋值
    pStdFeatureLeaf->uEcx &= 0
                           | X86_CPUID_FEATURE_ECX_SSE3
                           | (pConfig->enmPClMul ? X86_CPUID_FEATURE_ECX_PCLMUL : 0)
                           | ((pConfig->enmMonitor && pVM->cCpus == 1) ? X86_CPUID_FEATURE_ECX_MONITOR : 0)
                           ....
                           ;
   //u8PortableCpuIdLevel是config里的配置,配置越高,CPU支持功能越少
 	 if (pCpum->u8PortableCpuIdLevel > 0)
    {
       //去掉一些CPU高级功能
        PORTABLE_CLEAR_BITS_WHEN(1, pStdFeatureLeaf->uEax, ProcessorType, (UINT32_C(3) << 12), (UINT32_C(2) << 12));
        PORTABLE_DISABLE_FEATURE_BIT(    1, pStdFeatureLeaf->uEcx, SSSE3,  X86_CPUID_FEATURE_ECX_SSSE3);
        PORTABLE_DISABLE_FEATURE_BIT_CFG(1, pStdFeatureLeaf->uEcx, PCID,   X86_CPUID_FEATURE_ECX_PCID,   pConfig->enmPcid);
        PORTABLE_DISABLE_FEATURE_BIT_CFG(1, pStdFeatureLeaf->uEcx, SSE4_1, X86_CPUID_FEATURE_ECX_SSE4_1, pConfig->enmSse41);
        PORTABLE_DISABLE_FEATURE_BIT_CFG(1, pStdFeatureLeaf->uEcx, SSE4_2, X86_CPUID_FEATURE_ECX_SSE4_2, pConfig->enmSse42);
      ....
   }
  
  	//AMD 两个CPU根据microcode version决定是否支持VME
   uint32_t uMicrocodeRev;
    int rc = SUPR3QueryMicrocodeRev(&uMicrocodeRev);
    if (   (   pVM->cpum.s.GuestFeatures.enmMicroarch == kCpumMicroarch_AMD_Zen_Ryzen
            || pVM->cpum.s.GuestFeatures.enmMicroarch == kCpumMicroarch_Hygon_Dhyana)
        && uMicrocodeRev < 0x8001126
        && !pConfig->fForceVme)
    {
        pStdFeatureLeaf->uEdx &= ~X86_CPUID_FEATURE_EDX_VME;
    }
  
   //初始化APIC-ID
   pStdFeatureLeaf->uEbx &= UINT32_C(0x0000ffff); /* (APIC-ID := 0 and #LogCpus := 0) */
  
  if (pConfig->enmPClMul == CPUMISAEXTCFG_ENABLED_ALWAYS)
    pStdFeatureLeaf->uEcx |= X86_CPUID_FEATURE_ECX_PCLMUL;
  if (pConfig->enmMonitor == CPUMISAEXTCFG_ENABLED_ALWAYS)
    pStdFeatureLeaf->uEcx |= X86_CPUID_FEATURE_ECX_MONITOR;
  if (pConfig->enmCmpXchg16b == CPUMISAEXTCFG_ENABLED_ALWAYS)
    pStdFeatureLeaf->uEcx |= X86_CPUID_FEATURE_ECX_CX16;
  ...
    
   // CPUID 0x80000001
   //从全局CPUIDLeaves数组里获取对应的项,用于写入数据
   PCPUMCPUIDLEAF pExtFeatureLeaf = cpumR3CpuIdGetExactLeaf(pCpum, UINT32_C(0x80000001), 0);
   //去掉所有的subleaf 
   pExtFeatureLeaf = cpumR3CpuIdMakeSingleLeaf(pCpum, pExtFeatureLeaf);
   //edx赋值,Intel CPU edx很多是reserve,所以只对AMD CPU有用
   pExtFeatureLeaf->uEdx &= X86_CPUID_AMD_FEATURE_EDX_FPU
                               | X86_CPUID_AMD_FEATURE_EDX_VME
                               | X86_CPUID_AMD_FEATURE_EDX_DE
                               | X86_CPUID_AMD_FEATURE_EDX_PSE
                               | X86_CPUID_AMD_FEATURE_EDX_TSC
                             ...
   //ecx
   pExtFeatureLeaf->uEcx &= X86_CPUID_EXT_FEATURE_ECX_LAHF_SAHF
                               | (pConfig->fNestedHWVirt ? X86_CPUID_AMD_FEATURE_ECX_SVM : 0)
                               | X86_CPUID_AMD_FEATURE_ECX_CR8L        
                               | (pConfig->enmAbm       ? X86_CPUID_AMD_FEATURE_ECX_ABM : 0)
                               | (pConfig->enmSse4A     ? X86_CPUID_AMD_FEATURE_ECX_SSE4A : 0)
                             ...
     
     //多核AMD和HYGON CPU需要打开X86_CPUID_AMD_FEATURE_ECX_CMPL
     if (   pVM->cCpus > 1
         && (   pCpum->GuestFeatures.enmCpuVendor == CPUMCPUVENDOR_AMD
             || pCpum->GuestFeatures.enmCpuVendor == CPUMCPUVENDOR_HYGON))
       pExtFeatureLeaf->uEcx |= X86_CPUID_AMD_FEATURE_ECX_CMPL; /* CmpLegacy */

  //去掉一些高级功能如果u8PortableCpuIdLevel > 0
  if (pCpum->u8PortableCpuIdLevel > 0)
  {
    PORTABLE_DISABLE_FEATURE_BIT(    1, pExtFeatureLeaf->uEcx, CR8L,       X86_CPUID_AMD_FEATURE_ECX_CR8L);
    PORTABLE_DISABLE_FEATURE_BIT(    1, pExtFeatureLeaf->uEcx, SVM,        X86_CPUID_AMD_FEATURE_ECX_SVM);
    ....
  }

  //根据配置设置一些bit位
  if (pConfig->enmAbm       == CPUMISAEXTCFG_ENABLED_ALWAYS)
    pExtFeatureLeaf->uEcx |= X86_CPUID_AMD_FEATURE_ECX_ABM;
  if (pConfig->enmSse4A     == CPUMISAEXTCFG_ENABLED_ALWAYS)
    pExtFeatureLeaf->uEcx |= X86_CPUID_AMD_FEATURE_ECX_SSE4A;

  //CPUID 2: cache和TLB相关信息 (多少级缓存,缓存大小,几个通道等)
  while ((pCurLeaf = cpumR3CpuIdGetExactLeaf(pCpum, 2, uSubLeaf)) != NULL)
  {
    if ((pCurLeaf->uEax & 0xff) > 1)
    {
      pCurLeaf->uEax &= UINT32_C(0xffffff01);
    }
    uSubLeaf++;
  }
  
  //CPUID 3: CPU序列号
  pStdFeatureLeaf = cpumR3CpuIdGetExactLeaf(pCpum, 1, 0);
  if (!(pStdFeatureLeaf->uEdx & X86_CPUID_FEATURE_EDX_PSN))
  {
    uSubLeaf = 0;
    while ((pCurLeaf = cpumR3CpuIdGetExactLeaf(pCpum, 3, uSubLeaf)) != NULL)
    {
      pCurLeaf->uEcx = pCurLeaf->uEdx = 0;
      if (pCpum->u8PortableCpuIdLevel > 0)
        pCurLeaf->uEax = pCurLeaf->uEbx = 0;
      uSubLeaf++;
    }
  }
  	
  //CPUID 4 : Cache相关的参数(数据cache/指令cache,是否写直达等)
  uSubLeaf = 0;
  while ((pCurLeaf = cpumR3CpuIdGetExactLeaf(pCpum, 4, uSubLeaf)) != NULL)
  {
    pCurLeaf->uEax &= UINT32_C(0x00003fff); 
    if (   pVM->cCpus > 1
        && pCpum->GuestFeatures.enmCpuVendor == CPUMCPUVENDOR_INTEL)
    {
      pCurLeaf->uEax |= pVM->cCpus <= 0x40 ? ((pVM->cCpus - 1) << 26) : UINT32_C(0xfc000000); /* 6 bits only -> 64 cores! */
    }
    uSubLeaf++;
  }

  //CPUID 5: Monitor/mwaits
  while ((pCurLeaf = cpumR3CpuIdGetExactLeaf(pCpum, 5, uSubLeaf)) != NULL)
  {
    //如果CPUID 0 里设置了X86_CPUID_FEATURE_ECX_MONITOR, eax, ebx 设置成0
    pStdFeatureLeaf = cpumR3CpuIdGetExactLeaf(pCpum, 1, 0);
    if (!(pStdFeatureLeaf->uEcx & X86_CPUID_FEATURE_ECX_MONITOR))
      pCurLeaf->uEax = pCurLeaf->uEbx = 0;

    pCurLeaf->uEcx = pCurLeaf->uEdx = 0;
    //如果配置里开启了enmMWaitExtensions,设置对应的ecx, 但是edx没有设置
    if (pConfig->enmMWaitExtensions)
    {
      pCurLeaf->uEcx = X86_CPUID_MWAIT_ECX_EXT | X86_CPUID_MWAIT_ECX_BREAKIRQIF0;
    }
    else
      pCurLeaf->uEcx = pCurLeaf->uEdx = 0;
    uSubLeaf++;
  }

  //CPUID 6,8-10,14-22: 都返回zero leaf,不支持对应功能
  cpumR3CpuIdZeroLeaf(pCpum, cpuid);
  
  //CPUID 7;Structured Extended Feature Flags
 	//只有第一个subleaf有值
  while ((pCurLeaf = cpumR3CpuIdGetExactLeaf(pCpum, 7, uSubLeaf)) != NULL)
  {
    switch (uSubLeaf)
    {
      case 0:
        {
          pCurLeaf->uEax  = 0;    /* Max ECX input is 0. */
          ebx是一些功能的开关
          pCurLeaf->uEbx &= 0
            | (pConfig->enmFsGsBase ? X86_CPUID_STEXT_FEATURE_EBX_FSGSBASE : 0)
            | (pConfig->enmAvx2 ? X86_CPUID_STEXT_FEATURE_EBX_AVX2 : 0)
            ....
          ecx是一些AVX512之类的高级功能,这边先初始化成0
          pCurLeaf->uEcx &= 0
          pCurLeaf->uEdx &= 0
                               | (pConfig->enmMdsClear ? X86_CPUID_STEXT_FEATURE_EDX_MD_CLEAR : 0)
            | (pConfig->enmFlushCmdMsr ? X86_CPUID_STEXT_FEATURE_EDX_FLUSH_CMD : 0)
            ...
          //根据配置里的值设置开关(感觉有部分是重复的,上面已经设置了)
          if (pConfig->enmFsGsBase == CPUMISAEXTCFG_ENABLED_ALWAYS)
            pCurLeaf->uEbx |= X86_CPUID_STEXT_FEATURE_EBX_FSGSBASE;
          if (pConfig->enmAvx2 == CPUMISAEXTCFG_ENABLED_ALWAYS)
            pCurLeaf->uEbx |= X86_CPUID_STEXT_FEATURE_EBX_AVX2;
        }
      //其他subleaf,返回0
      default:
        pCurLeaf->uEax = 0;
        pCurLeaf->uEbx = 0;
        pCurLeaf->uEcx = 0;
        pCurLeaf->uEdx = 0;
    }
    uSubLeaf++;
  }

  //80000002h 80000003h 80000004h:返回处理器名称/商标字符串, 不设置在这里
  //80000005h, 80000006h : L1, L2, L3和tlb相关信息,直接从host里获取
	
  //后面针对每个CPUID,都有不同的初始化代码,这边不一一介绍。
  ....    
}

CPUMR3CpuIdInsert

VMMR3DECL(int) CPUMR3CpuIdInsert(PVM pVM, PCPUMCPUIDLEAF pNewLeaf)
{
    //查找CPUID leaves数组,找到需要插入的下标
  	uint32_t i;
    if (   cLeaves > 0
        && paLeaves[cLeaves - 1].uLeaf < pNewLeaf->uLeaf)
    {
      	//在最后加入新节点
        i = cLeaves;
    }
    else if (   cLeaves > 0
             && paLeaves[cLeaves - 1].uLeaf == pNewLeaf->uLeaf)
    {
        //最后一个uLeaf相同,找到uLeaf的subleaf的第一项的前一项
        i = cLeaves - 1;
        while (   i > 0
               && paLeaves[i - 1].uLeaf == pNewLeaf->uLeaf)
            i--;
    }
    else
    {
      	//从头开始linear search,找到比当前uleaf小而去最接近的一个节点
        i = 0;
        while (   i < cLeaves
                  && paLeaves[i].uLeaf < pNewLeaf->uLeaf)
            i++;
    }
  	//找到uleaf,开始查找SubLeaf
    if (   i < cLeaves
        && paLeaves[i].uLeaf == pNewLeaf->uLeaf)
    {
        if (paLeaves[i].fSubLeafMask != pNewLeaf->fSubLeafMask)
        {
            //fSubLeafMask和原始值不同
            uint32_t c = 1;
            while (   i + c < cLeaves
                   && paLeaves[i + c].uLeaf == pNewLeaf->uLeaf)
                c++;
            if (c > 1 && i + c < cLeaves)
            {
                memmove(&paLeaves[i + c], &paLeaves[i + 1], (cLeaves - i - c) * sizeof(paLeaves[0]));
                *pcLeaves = cLeaves -= c - 1;
            }

            paLeaves[i] = *pNewLeaf;
            return VINF_SUCCESS;
        }

        //linesearch找到subleaf可以插入的位置
        while (   i < cLeaves
               && paLeaves[i].uSubLeaf < pNewLeaf->uSubLeaf
               && paLeaves[i].uLeaf == pNewLeaf->uLeaf)
            i++;

        //如果uLeaf已存在,直接替换
        if (   i < cLeaves
            && paLeaves[i].uLeaf    == pNewLeaf->uLeaf
            && paLeaves[i].uSubLeaf == pNewLeaf->uSubLeaf)
        {
            paLeaves[i] = *pNewLeaf;
            return VINF_SUCCESS;
        }
    }
  
  	//确保CPUID Leaves有足够的空间增加一个新的CPUID leaf
 		paLeaves = cpumR3CpuIdEnsureSpace(pVM, ppaLeaves, cLeaves);
    if (!paLeaves)
        return VERR_NO_MEMORY;
		//移动后面的Leaves
    if (i < cLeaves)
        memmove(&paLeaves[i + 1], &paLeaves[i], (cLeaves - i) * sizeof(paLeaves[0]));
    //加入pNewLeaf
    *pcLeaves += 1;
    paLeaves[i] = *pNewLeaf;
}

11.3 CPUID Leaves 访问

CPUMR3SetGuestCpuIdFeature

各种Manager初始化的时候根据配置动态设置CPUID/MSR leaves里的值,现在只支持部分CPU功能设置

VMMR3_INT_DECL(void) CPUMR3SetGuestCpuIdFeature(PVM pVM, CPUMCPUIDFEATURE enmFeature)
{
   	switch (enmFeature)
    {
      //APIC
      case CPUMCPUIDFEATURE_APIC:
        //设置CPUID(1)里APIC的设置
        Leaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x00000001));
        if (pLeaf && (pLeaf->fFlags & CPUMCPUIDLEAF_F_CONTAINS_APIC))
          pVM->cpum.s.aGuestCpuIdPatmStd[1].uEdx = pLeaf->uEdx |= X86_CPUID_FEATURE_EDX_APIC;
				//AMDCPU 设置CPUID(80000001)里的设置
        pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x80000001));
        if (pLeaf && (pLeaf->fFlags & CPUMCPUIDLEAF_F_CONTAINS_APIC))
          pVM->cpum.s.aGuestCpuIdPatmExt[1].uEdx = pLeaf->uEdx |= X86_CPUID_AMD_FEATURE_EDX_APIC;
        //设置MSR_IA32_APICBASE 的leaves
        pMsrRange = cpumLookupMsrRange(pVM, MSR_IA32_APICBASE);
        if (!pMsrRange)
        {
          static CPUMMSRRANGE const s_ApicBase =
          {
            /*.uFirst =*/ MSR_IA32_APICBASE, /*.uLast =*/ MSR_IA32_APICBASE,
            /*.enmRdFn =*/ kCpumMsrRdFn_Ia32ApicBase, /*.enmWrFn =*/ kCpumMsrWrFn_Ia32ApicBase,
            /*.offCpumCpu =*/ UINT16_MAX, /*.fReserved =*/ 0, /*.uValue =*/ 0, /*.fWrIgnMask =*/ 0, /*.fWrGpMask =*/ 0,
            /*.szName = */ "IA32_APIC_BASE"
          };
          int rc = CPUMR3MsrRangesInsert(pVM, &s_ApicBase);
        }
      //x2APIC
      case CPUMCPUIDFEATURE_X2APIC:
        //设置CPUID(1)里x2APIC的设置
        pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x00000001));
        if (pLeaf)
          pVM->cpum.s.aGuestCpuIdPatmStd[1].uEcx = pLeaf->uEcx |= X86_CPUID_FEATURE_ECX_X2APIC;
        pVM->cpum.s.GuestFeatures.fX2Apic = 1;
        //修改MSR_IA32_APICBASE里的mask,支持x2APIC
        pMsrRange = cpumLookupMsrRange(pVM, MSR_IA32_APICBASE);
        if (pMsrRange)
        {
          pMsrRange->fWrGpMask  &= ~MSR_IA32_APICBASE_EXTD;
          pMsrRange->fWrIgnMask &= ~MSR_IA32_APICBASE_EXTD;
        }
      //Sysenter/sysexit
      case CPUMCPUIDFEATURE_SEP:
        //修改CPUID(1)里对应的bit位
        pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x00000001));
        if (pLeaf)
          pVM->cpum.s.aGuestCpuIdPatmStd[1].uEdx = pLeaf->uEdx |= X86_CPUID_FEATURE_EDX_SEP;
        pVM->cpum.s.GuestFeatures.fSysEnter = 1;
      //syscall/sysret
      case CPUMCPUIDFEATURE_SYSCALL:
        //修改CPUID(80000001)里对应的bit位
        pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x80000001));
        pVM->cpum.s.aGuestCpuIdPatmExt[1].uEdx = pLeaf->uEdx |= X86_CPUID_EXT_FEATURE_EDX_SYSCALL;
        pVM->cpum.s.GuestFeatures.fSysCall = 1;
      //PAE 32位页表扩展
      case CPUMCPUIDFEATURE_PAE:
        //修改CPUID(1)里对应的bit位
        pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x00000001));
        if (pLeaf)
          pVM->cpum.s.aGuestCpuIdPatmStd[1].uEdx = pLeaf->uEdx |= X86_CPUID_FEATURE_EDX_PAE;
			  //AMD CPU修改CPUID(80000001)里对应的bit位
        pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x80000001));
        pVM->cpum.s.aGuestCpuIdPatmExt[1].uEdx = pLeaf->uEdx |= X86_CPUID_AMD_FEATURE_EDX_PAE;
      //长模式,支持64位Guest
      case CPUMCPUIDFEATURE_LONG_MODE:
        pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x80000001));
        pVM->cpum.s.aGuestCpuIdPatmExt[1].uEdx = pLeaf->uEdx |= X86_CPUID_EXT_FEATURE_EDX_LONG_MODE;
        pVM->cpum.s.GuestFeatures.fLongMode = 1;
        pVM->cpum.s.GuestFeatures.cVmxMaxPhysAddrWidth = pVM->cpum.s.GuestFeatures.cMaxPhysAddrWidth;
        if (pVM->cpum.s.GuestFeatures.fVmx)
          for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
          {
            PVMCPU pVCpu = pVM->apCpusR3[idCpu];
            pVCpu->cpum.s.Guest.hwvirt.vmx.Msrs.u64Basic &= ~VMX_BASIC_PHYSADDR_WIDTH_32BIT;
          }
      //NX,内存不可执行
      case CPUMCPUIDFEATURE_NX:
        pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x80000001));
        pVM->cpum.s.aGuestCpuIdPatmExt[1].uEdx = pLeaf->uEdx |= X86_CPUID_EXT_FEATURE_EDX_NX;
        pVM->cpum.s.GuestFeatures.fNoExecute = 1;
      //LAHF/SAHF指令支持
      case CPUMCPUIDFEATURE_LAHF:
        pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x80000001));
        pVM->cpum.s.aGuestCpuIdPatmExt[1].uEcx = pLeaf->uEcx |= X86_CPUID_EXT_FEATURE_ECX_LAHF_SAHF;
        pVM->cpum.s.GuestFeatures.fLahfSahf = 1;
      //the page attribute table bit.
      case CPUMCPUIDFEATURE_PAT:
        pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x00000001));
        if (pLeaf)
          pVM->cpum.s.aGuestCpuIdPatmStd[1].uEdx = pLeaf->uEdx |= X86_CPUID_FEATURE_EDX_PAT;
        pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x80000001));
        pVM->cpum.s.aGuestCpuIdPatmExt[1].uEdx = pLeaf->uEdx |= X86_CPUID_AMD_FEATURE_EDX_PAT;
        pVM->cpum.s.GuestFeatures.fPat = 1;
      //RDTSCP指令支持
      case CPUMCPUIDFEATURE_RDTSCP:
        //CPU修改CPUID(80000001)里对应的bit位
        pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x80000001));
        pVM->cpum.s.aGuestCpuIdPatmExt[1].uEdx = pLeaf->uEdx |= X86_CPUID_EXT_FEATURE_EDX_RDTSCP;
        pVM->cpum.s.HostFeatures.fRdTscP = 1;
      //Hypervisor Present bit 
      case CPUMCPUIDFEATURE_HVP:
        pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x00000001));
        pVM->cpum.s.aGuestCpuIdPatmStd[1].uEcx = pLeaf->uEcx |= X86_CPUID_FEATURE_ECX_HVP;
        pVM->cpum.s.GuestFeatures.fHypervisorPresent = 1;
      // MWAIT extensions
      case CPUMCPUIDFEATURE_MWAIT_EXTS:
        pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x00000005));
        pVM->cpum.s.aGuestCpuIdPatmStd[5].uEcx = pLeaf->uEcx |= X86_CPUID_MWAIT_ECX_EXT | X86_CPUID_MWAIT_ECX_BREAKIRQIF0;
        pVM->cpum.s.GuestFeatures.fMWaitExtensions = 1;
      /*
      speculation control: 幽灵漏洞预防
      ibrs: Indirect Branch Restricted Speculation
      当CPUID中存在SPEC_CTRL特性的时候,可以通过"noibrs"/ibrs_enabled来控制IBRS特性。是否支持这个特性可以通过SPEC_CTRL MSR来获取
      当ibrs_enabled设置为1(也就是spectre_v2=ibrs),内核态将“间接分支限制预测”。当IBRS设置为2(spectre_v2=ibrs_always),那么它同时限制用户态和内核态的“间接分支预测”。当该值设为3的时候(spectre_v2=retpoline,ibrs_user),它仅仅限制用户态“间接分支预测”功能。
      ibpb: Indirect Branch Prediction Barriers
      当ibpb_enabled 设置为1的时候,IBPB barrier会在guest mode或user mode(用户态)的上下文切换的时候去刷新间接分支预测器中的内容,以阻止同主机上的其他虚拟机攻击或是同主机上的其他进程攻击。
      如果CPUID中支持IBPB_SUPPORT 或者 SPEC_CTRL的话,那么可以通过控制PRED_CMD MSR来控制IBPB功能。
      */
      case CPUMCPUIDFEATURE_SPEC_CTRL:
        //暂时只支持INTEL CPU
        if (pVM->cpum.s.GuestFeatures.enmCpuVendor == CPUMCPUVENDOR_INTEL)
        {
          //CPUID(7)
          pLeaf = cpumR3CpuIdGetExactLeaf(&pVM->cpum.s, UINT32_C(0x00000007), 0);
          //需要host支持ibpb和ibrs
          if (   !pLeaf
              || !(pVM->cpum.s.HostFeatures.fIbpb || pVM->cpum.s.HostFeatures.fIbrs))
          {
            return;
          }
          pVM->cpum.s.GuestFeatures.fSpeculationControl = 1;
          if (pVM->cpum.s.HostFeatures.fIbrs)
          {
            //如果host支持ibrs。设置对应CPUID(7)bit位
            pLeaf->uEdx |= X86_CPUID_STEXT_FEATURE_EDX_IBRS_IBPB;
            pVM->cpum.s.GuestFeatures.fIbrs = 1;
            //stibp位: allow software to set IA32_SPEC_CTRL MSR
            if (pVM->cpum.s.HostFeatures.fStibp)
            {
              pLeaf->uEdx |= X86_CPUID_STEXT_FEATURE_EDX_STIBP;
              pVM->cpum.s.GuestFeatures.fStibp = 1;
            }
            //设置MSR_IA32_SPEC_CTRL
            pMsrRange = cpumLookupMsrRange(pVM, MSR_IA32_SPEC_CTRL);
            if (!pMsrRange)
            {
              static CPUMMSRRANGE const s_SpecCtrl =
              {
                /*.uFirst =*/ MSR_IA32_SPEC_CTRL, /*.uLast =*/ MSR_IA32_SPEC_CTRL,
                /*.enmRdFn =*/ kCpumMsrRdFn_Ia32SpecCtrl, /*.enmWrFn =*/ kCpumMsrWrFn_Ia32SpecCtrl,
                /*.offCpumCpu =*/ UINT16_MAX, /*.fReserved =*/ 0, /*.uValue =*/ 0, /*.fWrIgnMask =*/ 0, /*.fWrGpMask =*/ 0,
                /*.szName = */ "IA32_SPEC_CTRL"
              };
              CPUMR3MsrRangesInsert(pVM, &s_SpecCtrl);
            }
            //设置MSR_IA32_PRED_CMD msr leaf
            pMsrRange = cpumLookupMsrRange(pVM, MSR_IA32_PRED_CMD);
            if (!pMsrRange)
            {
              static CPUMMSRRANGE const s_SpecCtrl =
              {
                /*.uFirst =*/ MSR_IA32_PRED_CMD, /*.uLast =*/ MSR_IA32_PRED_CMD,
                /*.enmRdFn =*/ kCpumMsrRdFn_WriteOnly, /*.enmWrFn =*/ kCpumMsrWrFn_Ia32PredCmd,
                /*.offCpumCpu =*/ UINT16_MAX, /*.fReserved =*/ 0, /*.uValue =*/ 0, /*.fWrIgnMask =*/ 0, /*.fWrGpMask =*/ 0,
                /*.szName = */ "IA32_PRED_CMD"
              };
              CPUMR3MsrRangesInsert(pVM, &s_SpecCtrl);
            }
          }
				}
        //设置MSR_IA32_ARCH_CAPABILITIES
        if (pVM->cpum.s.HostFeatures.fArchCap)
        {
          pMsrRange = cpumLookupMsrRange(pVM, MSR_IA32_ARCH_CAPABILITIES);
          if (!pMsrRange)
          {
            static CPUMMSRRANGE const s_ArchCaps =
            {
              /*.uFirst =*/ MSR_IA32_ARCH_CAPABILITIES, /*.uLast =*/ MSR_IA32_ARCH_CAPABILITIES,
              /*.enmRdFn =*/ kCpumMsrRdFn_Ia32ArchCapabilities, /*.enmWrFn =*/ kCpumMsrWrFn_ReadOnly,
              /*.offCpumCpu =*/ UINT16_MAX, /*.fReserved =*/ 0, /*.uValue =*/ 0, /*.fWrIgnMask =*/ 0, /*.fWrGpMask =*/ UINT64_MAX,
              /*.szName = */ "IA32_ARCH_CAPABILITIES"
            };
            CPUMR3MsrRangesInsert(pVM, &s_ArchCaps);
          }
        }
    }
  
  	//设置CPUID change flag
    for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
    {
        PVMCPU pVCpu = pVM->apCpusR3[idCpu];
        pVCpu->cpum.s.fChanged |= CPUM_CHANGED_CPUID;
    }
}

speculation control:详细可以参考下面的链接

https://software.intel.com/security-software-guidance/insights/deep-dive-cpuid-enumeration-and-architectural-msrs

CPUMR3ClearGuestCpuIdFeature

CPUMR3SetGuestCpuIdFeature的相反函数

11.4 VMExit里模拟CPUID

上面看到一列函数初始化CPUID leaves 数组,当GuestOS里调用CPUID指令的时候,是怎么返回这些CPUID值的呢?

在之前的文章中介绍了GuestOS里调用CPUID的时候会触发VMExit事件,hmR0VmxExitCpuid->IEMExecDecodedCpuid->iemCImpl_cpuid 最终调用IEM里的CPUID模拟执行函数

iemCImpl_cpuid

IEM_CIMPL_DEF_0(iemCImpl_cpuid)
{
  	//如果当前代码运行在non-root模式,返回
    if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
    {
        IEM_VMX_VMEXIT_INSTR_RET(pVCpu, VMX_EXIT_CPUID, cbInstr);
    }
    if (IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_CPUID))
    {
        IEM_SVM_UPDATE_NRIP(pVCpu);
        IEM_SVM_VMEXIT_RET(pVCpu, SVM_EXIT_CPUID, 0 /* uExitInfo1 */, 0 /* uExitInfo2 */);
    }

  	//获取CPUID
    CPUMGetGuestCpuId(pVCpu, pVCpu->cpum.GstCtx.eax, pVCpu->cpum.GstCtx.ecx,
                      &pVCpu->cpum.GstCtx.eax, &pVCpu->cpum.GstCtx.ebx, &pVCpu->cpum.GstCtx.ecx, &pVCpu->cpum.GstCtx.edx);
    //高位清零
    pVCpu->cpum.GstCtx.rax &= UINT32_C(0xffffffff);
    pVCpu->cpum.GstCtx.rbx &= UINT32_C(0xffffffff);
    pVCpu->cpum.GstCtx.rcx &= UINT32_C(0xffffffff);
    pVCpu->cpum.GstCtx.rdx &= UINT32_C(0xffffffff);
    pVCpu->cpum.GstCtx.fExtrn &= ~(CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RCX | CPUMCTX_EXTRN_RDX | CPUMCTX_EXTRN_RBX);

    iemRegAddToRipAndClearRF(pVCpu, cbInstr);
    return VINF_SUCCESS;
}

CPUMGetGuestCpuId

VMMDECL(void) CPUMGetGuestCpuId(PVMCPUCC pVCpu, uint32_t uLeaf, uint32_t uSubLeaf,
                                uint32_t *pEax, uint32_t *pEbx, uint32_t *pEcx, uint32_t *pEdx)
{
  //根据uLeaf和uSubLeaf从CPUID leaves数组里获取对应的CPUID leaf, fExactSubLeafHit表示是否找到exact match的节点
  PCCPUMCPUIDLEAF pLeaf = cpumCpuIdGetLeafEx(pVM, uLeaf, uSubLeaf, &fExactSubLeafHit);
  if (pLeaf)
  {
    if (fExactSubLeafHit)
    {
      //精确找到了对应的leaf,读取4个寄存器即可
      *pEax = pLeaf->uEax;
      *pEbx = pLeaf->uEbx;
      *pEcx = pLeaf->uEcx;
      *pEdx = pLeaf->uEdx;
      
      //剩下一些需要特殊处理的,因为GuestOS 的APIC是虚拟APIC,所以需要特殊处理
      if (pLeaf->fFlags & (  CPUMCPUIDLEAF_F_CONTAINS_APIC_ID
                                 | CPUMCPUIDLEAF_F_CONTAINS_OSXSAVE
                                 | CPUMCPUIDLEAF_F_CONTAINS_APIC ))
      {
        if (uLeaf == 1)
        {
          //特殊处理APIC ID
          *pEbx = (pLeaf->uEbx & UINT32_C(0x00ffffff)) | (pVCpu->idCpu << 24);
          //根据CPUFeature,修改相应bit位
          if (!pVCpu->cpum.s.fCpuIdApicFeatureVisible && (pLeaf->fFlags & CPUMCPUIDLEAF_F_CONTAINS_APIC))
                        *pEdx &= ~X86_CPUID_FEATURE_EDX_APIC;
          //根据pVCpu->cpum.s.Guest.cr4设置X86_CPUID_FEATURE_ECX_OSXSAVEbit位
          *pEcx = (pLeaf->uEcx & ~X86_CPUID_FEATURE_ECX_OSXSAVE)
                          | (pVCpu->cpum.s.Guest.cr4 & X86_CR4_OSXSAVE ? X86_CPUID_FEATURE_ECX_OSXSAVE : 0);
        }
        else if (uLeaf == 0xb)
        {
          //修改APIC ID
          *pEdx = pVCpu->idCpu;
        }
        else if (uLeaf == UINT32_C(0x8000001e))
        {
          //AMD CPU的APIC ID
          *pEax = pVCpu->idCpu;
        }
        else if (uLeaf == UINT32_C(0x80000001))
        {
          //AMD CPU:APIC 是否开启
          if (!pVCpu->cpum.s.fCpuIdApicFeatureVisible)
            *pEdx &= ~X86_CPUID_AMD_FEATURE_EDX_APIC;
        }
		}
    else
    {
      //感觉这边也不太知道要怎么处理
      *pEax = *pEbx = *pEcx = *pEdx = 0;
      if (pLeaf->fFlags & CPUMCPUIDLEAF_F_INTEL_TOPOLOGY_SUBLEAVES)
      {
        *pEcx = uSubLeaf & 0xff;
        *pEdx = pVCpu->idCpu;
      }
		}
  }
  else
  {
    //没有找到对应的leaf, 根据enmUnknownCpuIdMethod里的设置不同处理
    switch (pVM->cpum.s.GuestInfo.enmUnknownCpuIdMethod)
    {
      default:
        AssertFailed();
        RT_FALL_THRU();
      //DefCpuId返回DefCpuId里的值
      case CPUMUNKNOWNCPUID_DEFAULTS:
      case CPUMUNKNOWNCPUID_LAST_STD_LEAF: /* ASSUME this is executed */
      case CPUMUNKNOWNCPUID_LAST_STD_LEAF_WITH_ECX: 
        *pEax = pVM->cpum.s.GuestInfo.DefCpuId.uEax;
        *pEbx = pVM->cpum.s.GuestInfo.DefCpuId.uEbx;
        *pEcx = pVM->cpum.s.GuestInfo.DefCpuId.uEcx;
        *pEdx = pVM->cpum.s.GuestInfo.DefCpuId.uEdx;
        break;
      //返回原始的输入
      case CPUMUNKNOWNCPUID_PASSTHRU:
        *pEax = uLeaf;
        *pEbx = 0;
        *pEcx = uSubLeaf;
        *pEdx = 0;
        break;
    }
  }
}

11.5 虚拟机保存/加载的callback函数

cpumR3SaveCpuId

void cpumR3SaveCpuId(PVM pVM, PSSMHANDLE pSSM)
{
    //save CPUID leaves
    //每个leaf的大小
		SSMR3PutU32(pSSM, sizeof(pVM->cpum.s.GuestInfo.paCpuIdLeavesR3[0]));
    //一共有多少个leave是
    SSMR3PutU32(pSSM, pVM->cpum.s.GuestInfo.cCpuIdLeaves);
    //把真块CPUID leaves内存保存起来
    SSMR3PutMem(pSSM, pVM->cpum.s.GuestInfo.paCpuIdLeavesR3,
                sizeof(pVM->cpum.s.GuestInfo.paCpuIdLeavesR3[0]) * pVM->cpum.s.GuestInfo.cCpuIdLeaves);

  	//保存CPUMCPUID  default CPUID
    SSMR3PutMem(pSSM, &pVM->cpum.s.GuestInfo.DefCpuId, sizeof(pVM->cpum.s.GuestInfo.DefCpuId));

  	//保存CPUID (0~F)和 CPUID(80000000到8000001F)的原始返回值,用于检查恢复后的值是否正确
    CPUMCPUID   aRawStd[16];
    for (unsigned i = 0; i < RT_ELEMENTS(aRawStd); i++)
        ASMCpuIdExSlow(i, 0, 0, 0, &aRawStd[i].uEax, &aRawStd[i].uEbx, &aRawStd[i].uEcx, &aRawStd[i].uEdx);
    SSMR3PutU32(pSSM, RT_ELEMENTS(aRawStd));
    SSMR3PutMem(pSSM, &aRawStd[0], sizeof(aRawStd));

    CPUMCPUID   aRawExt[32];
    for (unsigned i = 0; i < RT_ELEMENTS(aRawExt); i++)
        ASMCpuIdExSlow(i | UINT32_C(0x80000000), 0, 0, 0, &aRawExt[i].uEax, &aRawExt[i].uEbx, &aRawExt[i].uEcx, &aRawExt[i].uEdx);
    SSMR3PutU32(pSSM, RT_ELEMENTS(aRawExt));
    SSMR3PutMem(pSSM, &aRawExt[0], sizeof(aRawExt));
}

cpumR3LoadCpuId

int cpumR3LoadCpuId(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, PCCPUMMSRS pMsrs)
{
    //从SSM里恢复CPUID leaves array
  	int rc = cpumR3LoadGuestCpuIdArray(pVM, pSSM, uVersion, &paLeaves, &cLeaves);
    if (RT_SUCCESS(rc))
    {
        //恢复CPUID leaves里的数据
        rc = cpumR3LoadCpuIdInner(pVM, pSSM, uVersion, paLeaves, cLeaves, pMsrs);
        RTMemFree(paLeaves);
    }
}

//从SSM里恢复CPUID leaves 数组,并保存在normal heap里
static int cpumR3LoadGuestCpuIdArray(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, PCPUMCPUIDLEAF *ppaLeaves, uint32_t *pcLeaves)
{
  if (uVersion > CPUM_SAVED_STATE_VERSION_PUT_STRUCT)
  {
    //获取leaf个数和大小
    SSMR3GetU32(pSSM, &cbLeaf);
    SSMR3GetU32(pSSM, &cLeaves);
    uint32_t uPrev = 0;
		//对每个leaf
    for (uint32_t i = 0; i < cLeaves && RT_SUCCESS(rc); i++)
    {
      CPUMCPUIDLEAF Leaf;
      //从SSM里恢复一个Leaf
      rc = SSMR3GetMem(pSSM, &Leaf, sizeof(Leaf));
      if (RT_SUCCESS(rc))
      {
 				//CPUID值必须大于等于前一个leaf的CPUID值
        if (   uVersion != CPUM_SAVED_STATE_VERSION_BAD_CPUID_COUNT
            || Leaf.uLeaf >= uPrev)
        {
          //insert CPUID leaves 数组里
          rc = cpumR3CpuIdInsert(NULL /* pVM */, ppaLeaves, pcLeaves, &Leaf);
          uPrev = Leaf.uLeaf;
        }
        else
          uPrev = UINT32_MAX;
      }
    }
	}
}
//检查CPUID的值是否正确,如果正确,提交到hyper heap 内存里
int cpumR3LoadCpuIdInner(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, PCPUMCPUIDLEAF paLeaves, uint32_t cLeaves, PCCPUMMSRS pMsrs)
{
  //default CPUID
  CPUMCPUID   GuestDefCpuId;
  int rc = SSMR3GetMem(pSSM, &GuestDefCpuId, sizeof(GuestDefCpuId));
  
  //恢复保存的CPUID (0~F)和 CPUID(80000000到8000001F)的原始返回值
  CPUMCPUID   aRawStd[16];
  uint32_t    cRawStd;
  rc = SSMR3GetU32(pSSM, &cRawStd); 
  rc = SSMR3GetMem(pSSM, &aRawStd[0], cRawStd * sizeof(aRawStd[0]));
  //如果没有保存,则从CPUID里获取
  for (uint32_t i = cRawStd; i < RT_ELEMENTS(aRawStd); i++)
    ASMCpuIdExSlow(i, 0, 0, 0, &aRawStd[i].uEax, &aRawStd[i].uEbx, &aRawStd[i].uEcx, &aRawStd[i].uEdx);

  CPUMCPUID   aRawExt[32];
  uint32_t    cRawExt;
  rc = SSMR3GetU32(pSSM, &cRawExt); AssertRCReturn(rc, rc);
  rc = SSMR3GetMem(pSSM, &aRawExt[0], cRawExt * sizeof(aRawExt[0]));
  //如果没有保存,则从CPUID里获取
  for (uint32_t i = cRawExt; i < RT_ELEMENTS(aRawExt); i++)
    ASMCpuIdExSlow(i | UINT32_C(0x80000000), 0, 0, 0, &aRawExt[i].uEax, &aRawExt[i].uEbx, &aRawExt[i].uEcx, &aRawExt[i].uEdx);
  
  //从配置文件里恢复部分CPUID leaves
  PCFGMNODE   pOverrideCfg = CFGMR3GetChild(CFGMR3GetRoot(pVM), "CPUM/HostCPUID");
  CPUMCPUID   aHostOverrideStd[2];
  memcpy(&aHostOverrideStd[0], &aHostRawStd[0], sizeof(aHostOverrideStd));
  cpumR3CpuIdInitLoadOverrideSet(UINT32_C(0x00000000), &aHostOverrideStd[0], RT_ELEMENTS(aHostOverrideStd), pOverrideCfg);

  CPUMCPUID   aHostOverrideExt[2];
  memcpy(&aHostOverrideExt[0], &aHostRawExt[0], sizeof(aHostOverrideExt));
  cpumR3CpuIdInitLoadOverrideSet(UINT32_C(0x80000000), &aHostOverrideExt[0], RT_ELEMENTS(aHostOverrideExt), pOverrideCfg);
  
  //检查恢复到CPUID leaves是否正确, Guest CPU和Host CPU的feature是否能匹配,和CPUM里恢复的值是否匹配等
  /* CPUID(1).ecx */
  CPUID_GST_FEATURE_RET(Std, uEcx, X86_CPUID_FEATURE_ECX_SSE3);    
  CPUID_GST_FEATURE_RET(Std, uEcx, X86_CPUID_FEATURE_ECX_PCLMUL);
  CPUID_GST_FEATURE_RET(Std, uEcx, X86_CPUID_FEATURE_ECX_DTES64);  
  。。。
    
  //CPUID leaves恢复正确,拷贝到hypervisor heap内存里
  //hypervisor heap 是 MM (memory manager)申请的内存
  MMHyperFree(pVM, pVM->cpum.s.GuestInfo.paCpuIdLeavesR3);
  pVM->cpum.s.GuestInfo.paCpuIdLeavesR3 = NULL;
  pVM->cpum.s.GuestInfo.paCpuIdLeavesR0 = NIL_RTR0PTR;
  pVM->cpum.s.GuestInfo.DefCpuId = GuestDefCpuId;
  rc = cpumR3CpuIdInstallAndExplodeLeaves(pVM, &pVM->cpum.s, paLeaves, cLeaves, pMsrs);
}

static int cpumR3CpuIdInstallAndExplodeLeaves(PVM pVM, PCPUM pCpum, PCPUMCPUIDLEAF paLeaves, uint32_t cLeaves, PCCPUMMSRS pMsrs)
{
    //申请一块hyper Mem,然后把paLeaves里的值拷贝到新的内存里,新的指针地址保存到pCpum->GuestInfo.paCpuIdLeavesR3里
    int rc = MMHyperDupMem(pVM, paLeaves, sizeof(paLeaves[0]) * cLeaves, 32,
                           MM_TAG_CPUM_CPUID, (void **)&pCpum->GuestInfo.paCpuIdLeavesR3);
    pCpum->GuestInfo.cCpuIdLeaves = cLeaves;
    pCpum->GuestInfo.paCpuIdLeavesR0 = MMHyperR3ToR0(pVM, pCpum->GuestInfo.paCpuIdLeavesR3);
  
  	//根据CPU Leaves里的数据,初始化pCpum->GuestFeatures,和GuestMsrs里的部分值
    cpumR3CpuIdExplodeFeatures(pCpum->GuestInfo.paCpuIdLeavesR3, pCpum->GuestInfo.cCpuIdLeaves, pMsrs,
                                    &pCpum->GuestFeatures);
  
  	//部分寄存器,从真机中获取并保存在pCpum的局部变量里 (好像是用于检查用?)
  	struct { PCPUMCPUID paCpuIds; uint32_t cCpuIds, uBase; } aOldRanges[] =
    {
        { pCpum->aGuestCpuIdPatmStd,        RT_ELEMENTS(pCpum->aGuestCpuIdPatmStd),     0x00000000 },
        { pCpum->aGuestCpuIdPatmExt,        RT_ELEMENTS(pCpum->aGuestCpuIdPatmExt),     0x80000000 },
        { pCpum->aGuestCpuIdPatmCentaur,    RT_ELEMENTS(pCpum->aGuestCpuIdPatmCentaur), 0xc0000000 },
    };
    for (uint32_t i = 0; i < RT_ELEMENTS(aOldRanges); i++)
    {
        uint32_t    cLeft       = aOldRanges[i].cCpuIds;
        uint32_t    uLeaf       = aOldRanges[i].uBase + cLeft;
        PCPUMCPUID  pLegacyLeaf = &aOldRanges[i].paCpuIds[cLeft];
        while (cLeft-- > 0)
        {
            uLeaf--;
            pLegacyLeaf--;
            PCCPUMCPUIDLEAF pLeaf = cpumR3CpuIdGetExactLeaf(pCpum, uLeaf, 0 /* uSubLeaf */);
            if (pLeaf)
            {
                pLegacyLeaf->uEax = pLeaf->uEax;
                pLegacyLeaf->uEbx = pLeaf->uEbx;
                pLegacyLeaf->uEcx = pLeaf->uEcx;
                pLegacyLeaf->uEdx = pLeaf->uEdx;
            }
            else
                *pLegacyLeaf = pCpum->GuestInfo.DefCpuId;
        }
    }
  
    //根据CPUID的返回值设置具体寄存器在X86XSAVEAREA里的偏移
    //详情可见X86XSAVEAREA定义(include\iprt\x64.h)文件里
    //先设置VCPU0
    PVMCPU pVCpu0 = pVM->apCpusR3[0];
    memset(&pVCpu0->cpum.s.Guest.aoffXState[0], 0xff, sizeof(pVCpu0->cpum.s.Guest.aoffXState));
    //x87 和SSE在XSAVEAREA的第一个结构体X86FXSTATE里
    pVCpu0->cpum.s.Guest.aoffXState[XSAVE_C_X87_BIT] = 0;
    pVCpu0->cpum.s.Guest.aoffXState[XSAVE_C_SSE_BIT] = 0;
    //从第二位开始,获取subleaf 的 ebx项,获取对应寄存器在XSAVE内存中的偏移
    for (uint32_t iComponent = XSAVE_C_SSE_BIT + 1; iComponent < 63; iComponent++)
      if (pCpum->fXStateGuestMask & RT_BIT_64(iComponent))
      {
        PCPUMCPUIDLEAF pSubLeaf = cpumR3CpuIdGetExactLeaf(pCpum, 0xd, iComponent);
        pVCpu0->cpum.s.Guest.aoffXState[iComponent] = pSubLeaf->uEbx;
      }
 	  //其他几个VCPU拷贝VCPU0里的值即可
  	for (VMCPUID idCpu = 1; idCpu < pVM->cCpus; idCpu++)
    {
        PVMCPU pVCpu = pVM->apCpusR3[idCpu];
        memcpy(&pVCpu->cpum.s.Guest.aoffXState[0], &pVCpu0->cpum.s.Guest.aoffXState[0], sizeof(pVCpu0->cpum.s.Guest.aoffXState));
    }
}

11.6 Guest寄存器访问

CPUMAllRegs.cpp里同时提供了一系列getter/setter读取和写入Guest Regs的API,直接操作pVCpu->cpum.s.Guest里的寄存器

VMMDECL(int) CPUMGetGuestCRx(PCVMCPUCC pVCpu, unsigned iReg, uint64_t *pValue)VMMDECL(uint32_t)       CPUMGetGuestEFlags(PCVMCPU pVCpu);
VMMDECL(uint32_t)       CPUMGetGuestEIP(PCVMCPU pVCpu);
VMMDECL(int)           CPUMSetGuestTR(PVMCPU pVCpu, uint16_t tr);
VMMDECL(int)           CPUMSetGuestLDTR(PVMCPU pVCpu, uint16_t ldtr);
...

一系列API获取Host/Guest CPU信息

VMMDECL(CPUMCPUVENDOR)  CPUMGetGuestCpuVendor(PVM pVM);
VMMDECL(CPUMMICROARCH)  CPUMGetGuestMicroarch(PCVM pVM);
VMMDECL(CPUMCPUVENDOR)  CPUMGetHostCpuVendor(PVM pVM);
VMMDECL(CPUMMICROARCH)  CPUMGetHostMicroarch(PCVM pVM);
VMMDECL(bool)       CPUMIsGuestIn64BitCode(PVMCPU pVCpu);
VMMDECL(bool)       CPUMIsGuestNXEnabled(PCVMCPU pVCpu);
....

参考资料

https://www.amd.com/system/files/TechDocs/25481.pdf

https://software.intel.com/security-software-guidance/insights/deep-dive-cpuid-enumeration-and-architectural-msrs

Intel指令手册

发布了26 篇原创文章 · 获赞 10 · 访问量 1257

猜你喜欢

转载自blog.csdn.net/qq_29684547/article/details/104109794
cpu