Virtualbox源码分析9 CPU manager1

Virtualbox源码分析9 CPU manager1

接下来3篇文章,介绍CPU虚拟化管理部分: CPUM

每个VM 都有一个或者多个VCPU,VCPU是VM运行的单位,类似于操作系统中的进程和线程的概念,VM是进程,VCPU是线程,一个host里可以有多个VM。

每个VCPU都需要全局变量保存相关信息,比如VCPU进入/退出 GuestOS都需要保存相关上下文信息。第一篇介绍一些重要的结构体。

9.1 vm.h里关于CPU的相关结构体

每个VCPU,都有一个对应的VMCPU结构体,保存每个VCPU对应的信息

VMCPUSTATE

//VCPU的状态
typedef enum VMCPUSTATE
{
    /** The customary invalid zero. */
    VMCPUSTATE_INVALID = 0,
    /** Virtual CPU has not yet been started.  */
    VMCPUSTATE_STOPPED,
    /** CPU started. */
    VMCPUSTATE_STARTED,
    /** CPU started in HM context. */
    VMCPUSTATE_STARTED_HM,
    /** Executing guest code and can be poked (RC or STI bits of HM). */
    VMCPUSTATE_STARTED_EXEC,
    /** Executing guest code in the recompiler. */
    VMCPUSTATE_STARTED_EXEC_REM,
    /** Executing guest code using NEM. */
    VMCPUSTATE_STARTED_EXEC_NEM,
    VMCPUSTATE_STARTED_EXEC_NEM_WAIT,
    VMCPUSTATE_STARTED_EXEC_NEM_CANCELED,
    /** Halted. */
    VMCPUSTATE_STARTED_HALTED,
} VMCPUSTATE;

VMCPU : 每个VCPU一个VMCPU结构体

typedef struct VMCPU
{
    //VCPU的状态
	  VMCPUSTATE volatile     enmState;
    //如果VCPU在运行Guest代码,保存这个VCPU是跑在哪个Guest上的
    RTCPUID volatile        idHostCpu;
    /** The CPU set index corresponding to idHostCpu, UINT32_MAX if not valid.
     * @remarks Best to make sure iHostCpuSet shares cache line with idHostCpu! */
    uint32_t volatile       iHostCpuSet;
    //VCPU id
    VMCPUID                 idCpu;
     /** Raw-mode Context VM Pointer. */
    PVMRC                   pVMRC;
    //VM结构体R3指针
    PVMR3                   pVMR3;
    //VM结构体R0指针
    PVMR0                   pVMR0;
    //PUVMCPU结构体R3指针
    PUVMCPU                 pUVCpu;
    //Emulate Thread handle, R3
    RTNATIVETHREAD          hNativeThread;
    //Emulate Thread handle, R0
    RTNATIVETHREAD          hNativeThreadR0;
    
    //各种manager保存的CPU信息
     /** HM part. */
    union VMCPUUNIONHM
    {
#ifdef VMM_INCLUDED_SRC_include_HMInternal_h
        struct HMCPU    s;
#endif
        uint8_t             padding[5888];      /* multiple of 64 */
    } hm;
    ...
      
    //CPUM
    union VMCPUUNIONCPUM
    {
#ifdef VMM_INCLUDED_SRC_include_CPUMInternal_h
        struct CPUMCPU      s;
#endif
#ifdef VMCPU_INCL_CPUM_GST_CTX
        CPUMCTX             GstCtx;
#endif
        uint8_t             padding[4096];      /* multiple of 4096 */
    } cpum;
    ...
}

9.2 cpumctx.h里的结构体

CPUMCTX

保存了所有VCPU寄存器相关的信息

typedef struct CPUMCTX
{
   //寄存器
  	union
    {
        uint16_t        ip;
        uint32_t        eip;
        uint64_t        rip;
    } CPUM_UNION_NM(rip);
  ...
  //gdtr等
  VBOXGDTR        gdtr;
  ....
  //msr寄存器
  uint64_t        msrEFER;
  uint64_t        msrSTAR;          
  uint64_t        msrPAT;
  ...
  //vmx相关寄存器
  struct
  {
    RTGCPHYS                GCPhysVmxon;
    RTGCPHYS                GCPhysVmcs;
    ...
  }vmx;
}

9.1.3 cpum.h里相关的结构体

CPUMFEATURES

//保存CPU特性相关的结构体
typedef struct CPUMFEATURES
{
    //CPU型号相关的信息
    uint8_t         enmCpuVendor;
    uint8_t         uFamily;
    uint8_t         uModel;
    //CPU特性相关信息
    uint32_t        fMsr : 1;
    ...
    //是否支持AVX指令等
    uint32_t        fAvx : 1;
    ....
    //vmx支持相关指令
    uint32_t        fVmxExtIntExit : 1;
    ...
}

CPUMCPUIDLEAF

保存每个CPUID项返回值

typedef struct CPUMCPUIDLEAF
{
    //保存输入的EAX的值
    /** The leaf number. */
    uint32_t    uLeaf;
    /** The sub-leaf number. */
    uint32_t    uSubLeaf;
    /** Sub-leaf mask.  This is 0 when sub-leaves aren't used. */
    uint32_t    fSubLeafMask;

  	//四个寄存器的值,对应的CPUID指令的返回值
    /** The EAX value. */
    uint32_t    uEax;
    /** The EBX value. */
    uint32_t    uEbx;
    /** The ECX value. */
    uint32_t    uEcx;
    /** The EDX value. */
    uint32_t    uEdx;

    /** Flags. */
    uint32_t    fFlags;
} CPUMCPUIDLEAF;

CPUMCPUID

CPUID返回值结构体

typedef struct CPUMCPUID
{
    uint32_t uEax;
    uint32_t uEbx;
    uint32_t uEcx;
    uint32_t uEdx;
} CPUMCPUID;

CPUMMSRRANGE

保存每个MSR寄存器到对应值

typedef struct CPUMMSRRANGE
{
    //用于binary search的index
    uint32_t    uFirst;
    uint32_t    uLast;
    //这个MSR的读取函数
    uint16_t    enmRdFn;
    //写入函数
    uint16_t    enmWrFn;
    //相对于CPUMCPU的偏移,如果没有使用,默认是UINT16_MAX
    uint16_t    offCpumCpu;
    uint16_t    fReserved;
		//初始值
    uint64_t    uValue;
    //某些bit位ignore写操作,比如MSR_IA32_APICBASE的msr,ignore MSR_IA32_APICBASE_EXTD位的写入
    uint64_t    fWrIgnMask;
    //某些bit位写入的时候发生GP
    uint64_t    fWrGpMask,比如MSR_IA32_APICBASE的msr,写入MSR_IA32_APICBASE_EXTD位的时候发生GP
    //MSR寄存器名字
    char        szName[56];
} CPUMMSRRANGE;

CPUMMSRRDFN/CPUMMSRWRFN

定义了一系列函数列表,GuestOS读取相对应的MSR寄存器时,根据msrid调用向对应的函数

实现函数在VMMAll\CPUMAllMsrs.cpp函数里

//msr寄存器读取的函数列表
typedef enum CPUMMSRRDFN
{
    kCpumMsrRdFn_Ia32P5McAddr,
    kCpumMsrRdFn_Ia32P5McType,
    ....
}
//msr寄存器写入的函数列表
typedef enum CPUMMSRWRFN
{
    kCpumMsrWrFn_Ia32P5McAddr,
    kCpumMsrWrFn_Ia32P5McType,
    ....
}

9.1.4 CPUMInternal.h里的结构体

CPUMINFO

//Guest 模拟CPUID的时候,会吧每个输入的EAX对应的返回值保存到一个CPUMCPUIDLEAF的结构体里
//并分配一块内存保存这些结构体,并映射到R3和R0虚拟地址
//模拟MSR寄存器也是同样
typedef struct CPUMINFO
{
   //保存的msr数组个数
    uint32_t                    cMsrRanges;
    uint32_t                    fMsrMask;
    uint32_t                    fMxCsrMask;
   //保存的cpuid数组个数
    uint32_t                    cCpuIdLeaves;
    //cpuid数组里extended CPUID leaf第一个元素
    uint32_t                    iFirstExtCpuIdLeaf;
    //4种不同应对未知CPUID输入的方法
    //CPUMUNKNOWNCPUID_DEFAULTS / CPUMUNKNOWNCPUID_LAST_STD_LEAF 
    // CPUMUNKNOWNCPUID_LAST_STD_LEAF_WITH_ECX / CPUMUNKNOWNCPUID_PASSTHRU
    CPUMUNKNOWNCPUID            enmUnknownCpuIdMethod;
    //默认CPUID的返回值,如果在CPUID数组里找不到对应项,返回这个默认值
    CPUMCPUID                   DefCpuId;
    uint64_t                    uScalableBusFreq;
    //msr数组的R0指针
    R0PTRTYPE(PCPUMMSRRANGE)    paMsrRangesR0;
    //CPUID数组的R0指针
    R0PTRTYPE(PCPUMCPUIDLEAF)   paCpuIdLeavesR0;
    //msr数组的R3指针
    R3PTRTYPE(PCPUMMSRRANGE)    paMsrRangesR3;
    //CPUID数组的R3指针
    R3PTRTYPE(PCPUMCPUIDLEAF)   paCpuIdLeavesR3;   
} CPUMINFO;

CPUMHOSTCTX

//保存host cpu信息
typedef struct CPUMHOSTCTX
{
  //host寄存器
  uint64_t        rbx;
  ...
  //ss寄存器
  RTSEL           ss;
  //msr等
  CPUMSYSENTER    SysEnter;
  uint64_t        FSbase;
  ...
}

CPUM : 每个VCPU都有一个向对应的CPUM结构体

 struct CPUM
 {
     //Host CPU 标记 CPUM_USE_SYSENTER/CPUM_USE_SYSCALL
       uint32_t                fHostUseFlags;
      CPUMHOSTCTX             Host;
      CPUMCTX                 Hyper;
   //保存Guest CPU AVX系列指令支持
   uint64_t                fXStateGuestMask;
   //保存hostCPU AVX系列指令支持 (xgetbv)
    uint64_t                fXStateHostMask;

   //host cpu相关feature信息,(见CPUMFEATURES解释)
   CPUMFEATURES            HostFeatures;
   //Guest cpu相关featrue信息
   CPUMFEATURES            GuestFeatures;
   //Guest CPU Info
   CPUMINFO                GuestInfo;
 }

CPUMCPU

struct CPUMCPU
{
    //Guest的CPU信息
    CPUMCTX                 Guest;
    CPUMCTXMSRS             GuestMsrs;
    //嵌套VMX使用的timer内存
    PTMTIMERR0              pNestedVmxPreemptTimerR0;
    PTMTIMERR3              pNestedVmxPreemptTimerR3;
    //标记这个CPUMCPU是否支持某些模式
    //CPUM_USED_FPU_HOST/CPUM_USED_FPU_GUEST/CPUM_USED_DEBUG_REGS_GUEST/...
    uint32_t                fUseFlags;
    //标记Guest寄存器哪些内容被修改
    uint32_t                fChanged;
    //32-64交换模式的temp变量
    uint32_t                u32RetCode;
    uint32_t                fApicDisVectors;
    //如果开启APIC,VCPU的APIC内存地址
    RTHCPTR                 pvApicBase;
    //CPU是否开启xAPIC
    bool                    fX2Apic;
    //是否进入recompiler
    bool                    fRemEntered;
    //CPUID里关于APIC的bit位是否被可获取到,比如IntelCPU,CPUID(1)返回edx的第9位是否可以是1
    bool                    fCpuIdApicFeatureVisible;
    //host CPU信息
    CPUMHOSTCTX             Host;
    //hypervisor context CPU 状态 (Drx寄存器和cr3)
    CPUMHYPERCTX            Hyper;
  #ifdef VBOX_WITH_CRASHDUMP_MAGIC
    //crash dump里的标记
    uint8_t                 aMagic[56];
    uint64_t                uMagic;
#endif
}

9.1.5 CPUMR3Db.cpp 里的结构体

VBox代码里保存了很多常见CPU系列的名字和相关信息,在VMMR3\cpus里,比如Intel 80x86系列,core-ix系列,AMD athlon系列等。

每个CPU系列都有一个database/CPUID range/ MSR range

CPUMDBENTRY

 //CPU database
 struct CPUMDBENTRY
 {
    //CPU名字 : 比如  "Intel 80486",,
    const char     *pszName;
    //CPU全名 : 比如 "Intel(R) 80486DX2",
    const char     *pszFullName;
    //CPU vendor : AMD/ intel
    uint8_t         enmVendor;
    //标示这个CPU类型的id,每个CPU类型都不同
    uint8_t         uFamily;
    uint8_t         uModel;
    /** The CPU stepping. */
    uint8_t         uStepping;
    /** The microarchitecture. */
    CPUMMICROARCH   enmMicroarch;
    //CPU bus频率?
    uint64_t        uScalableBusFreq;
    /** Flags - CPUDB_F_XXX. */
    uint32_t        fFlags;
    //物理地址有效位数
    uint8_t         cMaxPhysAddrWidth;
    /** The MXCSR mask. */
    uint32_t        fMxCsrMask;
    //自定义CPUID Range数组指针
    PCCPUMCPUIDLEAF paCpuIdLeaves;
    //自定义CPUID Range个数
    uint32_t        cCpuIdLeaves;
    //处理未知CPUID的方法
    CPUMUNKNOWNCPUID enmUnknownCpuId;
    //未知CPUID input的返回值
    CPUMCPUID       DefUnknownCpuId;
   	//部分CPUingore ecx的高位,默认是UINT32_MAX
    uint32_t        fMsrMask;
    //msr个数,如果当前CPU没有自定义msr列表,填0即可
    uint32_t        cMsrRanges;
    //自定义MSRRange
    PCCPUMMSRRANGE  paMsrRanges;
}

9.1.6 CPUM3Cpuid.cpp里的结构体

CPUMCPUIDCONFIG

//从config里获取的config
typedef struct CPUMCPUIDCONFIG
{
    //这一项开启之后,CPU只支持传入的eax值小于等于3
    bool            fNt4LeafLimit;
    //是否开启Invariant TSC, CPU有3种TSC行为(Variant TSC/Constant TSC/Invariant TSC)
    bool            fInvariantTsc;
    //AMD_Zen_Ryzen/Hygon_Dhyana CPU是否支持zen vme
    bool            fForceVme;
    //是否支持嵌套VT
    bool            fNestedHWVirt;
  	//是否开启对应的功能
    CPUMISAEXTCFG   enmCmpXchg16b;
    CPUMISAEXTCFG   enmMonitor;
    CPUMISAEXTCFG   enmMWaitExtensions;
    CPUMISAEXTCFG   enmSse41;
    CPUMISAEXTCFG   enmSse42;
    CPUMISAEXTCFG   enmAvx;
    CPUMISAEXTCFG   enmAvx2;
    CPUMISAEXTCFG   enmXSave;
    CPUMISAEXTCFG   enmAesNi;
    CPUMISAEXTCFG   enmPClMul;
    CPUMISAEXTCFG   enmPopCnt;
    CPUMISAEXTCFG   enmMovBe;
    CPUMISAEXTCFG   enmRdRand;
    CPUMISAEXTCFG   enmRdSeed;
    CPUMISAEXTCFG   enmCLFlushOpt;
    CPUMISAEXTCFG   enmFsGsBase;
    CPUMISAEXTCFG   enmPcid;
    CPUMISAEXTCFG   enmInvpcid;
    CPUMISAEXTCFG   enmFlushCmdMsr;
    CPUMISAEXTCFG   enmMdsClear;
    CPUMISAEXTCFG   enmArchCapMsr;
    CPUMISAEXTCFG   enmAbm;
    CPUMISAEXTCFG   enmSse4A;
    CPUMISAEXTCFG   enmMisAlnSse;
    CPUMISAEXTCFG   enm3dNowPrf;
    CPUMISAEXTCFG   enmAmdExtMmx;
	
  	//定义CPUID输入的EAX最大值
    //EAX高位是0的最大值
    uint32_t        uMaxStdLeaf;
    //EXA是0x80000000开头的最大值
    uint32_t        uMaxExtLeaf;
    //EAX是0xC0000000开头的最大值
    uint32_t        uMaxCentaurLeaf;
    uint32_t        uMaxIntelFamilyModelStep;
    //模拟的CPU名字
    char            szCpuName[128];
} CPUMCPUIDCONFIG;
Virtualbox源码分析9 CPU manager1Virtualbox源码分析9 CPU manager1 yangrong的blog 发布了10 篇原创文章 · 获赞 0 · 访问量 222 私信 关注
上一篇:SQL语句拼接


下一篇:go 获取linux cpuId 的方法