文章目录
10.1 R3Init相关APIs(CPUM.cpp)
CPUMR3Init 初始化CPUM
VMMR3DECL(int) CPUMR3Init(PVM pVM)
{
//根据host CPU信息设置一些flag
//获取host CPUID失败,直接返回
if (!ASMHasCpuId())
{
return VERR_UNSUPPORTED_CPU;
}
//获取MxCsr Mask
pVM->cpum.s.fHostMxCsrMask = CPUMR3DeterminHostMxCsrMask();
//获取VMX相关的MSR
cpumR3GetHostHwvirtMsrs(&HostMsrs);
//获取CPUID的所有leaves和sub leaves(后面初始化这些leaves,下一篇里会介绍这个函数
CPUMR3CpuIdCollectLeaves(&paLeaves, &cLeaves);
//CR4 mask
pVM->cpum.s.CR4.AndMask = X86_CR4_OSXMMEEXCPT | X86_CR4_PVI | X86_CR4_VME;
pVM->cpum.s.CR4.OrMask = X86_CR4_OSFXSR;
//获取host是否支持XSAVE/XRSTOR指令
//如果host支持XSave指令,才可以调用xgetbv指令
if ( pVM->cpum.s.HostFeatures.fXSaveRstor
&& pVM->cpum.s.HostFeatures.fOpSysXSaveRstor)
{
//调用xgetbv获取AVX指令支持状态
fXStateHostMask = fXcr0Host = ASMGetXcr0();
fXStateHostMask &= XSAVE_C_X87 | XSAVE_C_SSE | XSAVE_C_YMM | XSAVE_C_OPMASK | XSAVE_C_ZMM_HI256 | XSAVE_C_ZMM_16HI;
}
pVM->cpum.s.fXStateHostMask = fXStateHostMask;
//获取CPU的相关信息
cpumR3CpuIdExplodeFeatures(paLeaves, cLeaves, &HostMsrs, &pVM->cpum.s.HostFeatures);
pVM->cpum.s.GuestFeatures.enmCpuVendor = pVM->cpum.s.HostFeatures.enmCpuVendor;
//分配保存FPU/AVX寄存器的内存(用于XSAVE/XRSTOR的参数)
//每个VCPU各自有两块内存,分别保存Guest和Host的FPU寄存器,用于切换Guest/Host
uint32_t cbMaxXState = pVM->cpum.s.HostFeatures.cbMaxExtendedState;
cbMaxXState = RT_ALIGN(cbMaxXState, 128);
uint8_t *pbXStates;
rc = MMR3HyperAllocOnceNoRelEx(pVM, cbMaxXState * 2 * pVM->cCpus, PAGE_SIZE, MM_TAG_CPUM_CTX,
MMHYPER_AONR_FLAGS_KERNEL_MAPPING, (void **)&pbXStates);
for (VMCPUID i = 0; i < pVM->cCpus; i++)
{
PVMCPU pVCpu = pVM->apCpusR3[i];
//分配一块内存分别映射R3 R0虚拟地址 给Guest
pVCpu->cpum.s.Guest.pXStateR3 = (PX86XSAVEAREA)pbXStates;
pVCpu->cpum.s.Guest.pXStateR0 = MMHyperR3ToR0(pVM, pbXStates);
pbXStates += cbMaxXState;
//分配一块内存分别映射R3 R0虚拟地址 给Host
pVCpu->cpum.s.Host.pXStateR3 = (PX86XSAVEAREA)pbXStates;
pVCpu->cpum.s.Host.pXStateR0 = MMHyperR3ToR0(pVM, pbXStates);
pbXStates += cbMaxXState;
pVCpu->cpum.s.Host.fXStateMask = fXStateHostMask;
}
//注册SSM的回调,当虚拟机保存或者继续当时候,回调用到这些回调里的函数
rc = SSMR3RegisterInternal(pVM, "cpum", 1, CPUM_SAVED_STATE_VERSION, sizeof(CPUM),
NULL, cpumR3LiveExec, NULL,
NULL, cpumR3SaveExec, NULL,
cpumR3LoadPrep, cpumR3LoadExec, cpumR3LoadDone);
//注册一些调试信息
DBGFR3InfoRegisterInternalEx(pVM, "cpum", "Displays the all the cpu states.",
&cpumR3InfoAll, DBGFINFO_FLAGS_ALL_EMTS);
rc = cpumR3DbgInit(pVM);
//部分AMDCPU,需要标记在处理FXSAVE/FXRSTOR指令的时候会少保存部分寄存器
//这部分CPU,设置pVCpu->cpum.s.fUseFlags |= CPUM_USE_FFXSR_LEAKY;
cpumR3CheckLeakyFpu(pVM);
//初始化Guest OS CPUID和MSR信息,下一篇里介绍这个函数
rc = cpumR3InitCpuIdAndMsrs(pVM, &HostMsrs);
//申请VMX相关结构体内存
if (pVM->cpum.s.GuestFeatures.fVmx)
rc = cpumR3AllocVmxHwVirtState(pVM);
else if (pVM->cpum.s.GuestFeatures.fSvm)
rc = cpumR3AllocSvmHwVirtState(pVM);
//调用CPUMR3ResetCpu初始化每个VCPU
CPUMR3Reset(pVM);
}
cpumR3AllocVmxHwVirtState
//分派VMX使用的结构体
static int cpumR3AllocVmxHwVirtState(PVM pVM)
{
//每个VCPU都有自己的VMX信息
for (VMCPUID i = 0; i < pVM->cCpus; i++)
{
//嵌套Guest当前使用的VMCS
pCtx->hwvirt.vmx.pVmcsR3 = (PVMXVVMCS)SUPR3ContAlloc(VMX_V_VMCS_PAGES,
&pCtx->hwvirt.vmx.pVmcsR0,
&pCtx->hwvirt.vmx.HCPhysVmcs);
//嵌套Guest用于保存当前VMCS的shadow VMCS
pCtx->hwvirt.vmx.pShadowVmcsR3 = (PVMXVVMCS)SUPR3ContAlloc(VMX_V_VMCS_PAGES,
&pCtx->hwvirt.vmx.pShadowVmcsR0,
&pCtx->hwvirt.vmx.HCPhysShadowVmcs);
//虚拟APIC内存
pCtx->hwvirt.vmx.pvVirtA picPageR3 = SUPR3ContAlloc(VMX_V_VIRT_APIC_PAGES,
&pCtx->hwvirt.vmx.pvVirtApicPageR0,
&pCtx->hwvirt.vmx.HCPhysVirtApicPage);
//VMRead的bitmap
pCtx->hwvirt.vmx.pvVmreadBitmapR3 = SUPR3ContAlloc(VMX_V_VMREAD_VMWRITE_BITMAP_PAGES,
&pCtx->hwvirt.vmx.pvVmreadBitmapR0,
&pCtx->hwvirt.vmx.HCPhysVmreadBitmap);
//VMWRITE的bitmap
pCtx->hwvirt.vmx.pvVmwriteBitmapR3 = SUPR3ContAlloc(VMX_V_VMREAD_VMWRITE_BITMAP_PAGES,
&pCtx->hwvirt.vmx.pvVmwriteBitmapR0,
&pCtx->hwvirt.vmx.HCPhysVmwriteBitmap);
//VM-entry 的MSR-load 内存
pCtx->hwvirt.vmx.pEntryMsrLoadAreaR3 = (PVMXAUTOMSR)SUPR3ContAlloc(VMX_V_AUTOMSR_AREA_PAGES,
&pCtx->hwvirt.vmx.pEntryMsrLoadAreaR0,
&pCtx->hwvirt.vmx.HCPhysEntryMsrLoadArea);
//VM-exit的MSR-store内存
pCtx->hwvirt.vmx.pExitMsrStoreAreaR3 = (PVMXAUTOMSR)SUPR3ContAlloc(VMX_V_AUTOMSR_AREA_PAGES,
&pCtx->hwvirt.vmx.pExitMsrStoreAreaR0,
&pCtx->hwvirt.vmx.HCPhysExitMsrStoreArea);
//VM-exit的MSR-load内存
pCtx->hwvirt.vmx.pExitMsrLoadAreaR3 = (PVMXAUTOMSR)SUPR3ContAlloc(VMX_V_AUTOMSR_AREA_PAGES,
&pCtx->hwvirt.vmx.pExitMsrLoadAreaR0,
&pCtx->hwvirt.vmx.HCPhysExitMsrLoadArea);
//msr bitmap内存
pCtx->hwvirt.vmx.pvMsrBitmapR3 = SUPR3ContAlloc(VMX_V_MSR_BITMAP_PAGES,
&pCtx->hwvirt.vmx.pvMsrBitmapR0,
&pCtx->hwvirt.vmx.HCPhysMsrBitmap);
//I/O bitmap内存
pCtx->hwvirt.vmx.pvIoBitmapR3 = SUPR3ContAlloc(VMX_V_IO_BITMAP_A_PAGES + VMX_V_IO_BITMAP_B_PAGES,
&pCtx->hwvirt.vmx.pvIoBitmapR0,
&pCtx->hwvirt.vmx.HCPhysIoBitmap);
}
}
CPUMR3Term
//释放CPUMR3Init申请的内存
VMMR3DECL(int) CPUMR3Term(PVM pVM)
{
if (pVM->cpum.s.GuestFeatures.fVmx)
cpumR3FreeVmxHwVirtState(pVM);
else if (pVM->cpum.s.GuestFeatures.fSvm)
cpumR3FreeSvmHwVirtState(pVM);
}
CPUMR3InitCompleted
其他manager初始化完成之后,还需要根据其他manager的设置初始化部分设置
VMMR3DECL(int) CPUMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat)
{
case VMINITCOMPLETED_RING3:
{
//????
bool const fSupportsLongMode = VMR3IsLongModeAllowed(pVM);
for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
{
PVMCPU pVCpu = pVM->apCpusR3[idCpu];
if (fSupportsLongMode)
pVCpu->cpum.s.fUseFlags |= CPUM_USE_SUPPORTS_LONGMODE;
}
//初始化MSR寄存器的统计信息
cpumR3MsrRegStats(pVM);
//如果CPU支持VMX嵌套,需要初始化给嵌套Guest用的VMX timer
if (pVM->cpum.s.GuestFeatures.fVmx)
{
for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
{
PVMCPU pVCpu = pVM->apCpusR3[idCpu];
int rc = TMR3TimerCreateInternal(pVM, TMCLOCK_VIRTUAL_SYNC, cpumR3VmxPreemptTimerCallback, pVCpu,
"Nested Guest VMX-preempt. timer", &pVCpu->cpum.s.pNestedVmxPreemptTimerR3);
pVCpu->cpum.s.pNestedVmxPreemptTimerR0 = TMTimerR0Ptr(pVCpu->cpum.s.pNestedVmxPreemptTimerR3);
}
}
break;
}
}
CPUMR3ResetCpu
VMMR3DECL(void) CPUMR3ResetCpu(PVM pVM, PVMCPU pVCpu)
{
PCPUMCTX pCtx = &pVCpu->cpum.s.Guest;
memset(pCtx, 0, RT_UOFFSETOF(CPUMCTX, pXStateR0));
pCtx->cr0 = X86_CR0_CD | X86_CR0_NW | X86_CR0_ET; //0x60000010
pCtx->eip = 0x0000fff0;
pCtx->edx = 0x00000600; /* P6 processor */
pCtx->eflags.Bits.u1Reserved0 = 1;
//cs段寄存器
pCtx->cs.Sel = 0xf000;
pCtx->cs.ValidSel = 0xf000;
pCtx->cs.fFlags = CPUMSELREG_FLAGS_VALID;
pCtx->cs.u64Base = UINT64_C(0xffff0000);
pCtx->cs.u32Limit = 0x0000ffff;
pCtx->cs.Attr.n.u1DescType = 1; /* code/data segment */
pCtx->cs.Attr.n.u1Present = 1;
pCtx->cs.Attr.n.u4Type = X86_SEL_TYPE_ER_ACC;
//ds段寄存器
pCtx->ds.fFlags = CPUMSELREG_FLAGS_VALID;
pCtx->ds.u32Limit = 0x0000ffff;
pCtx->ds.Attr.n.u1DescType = 1; /* code/data segment */
pCtx->ds.Attr.n.u1Present = 1;
pCtx->ds.Attr.n.u4Type = X86_SEL_TYPE_RW_ACC;
//es
pCtx->es.fFlags = CPUMSELREG_FLAGS_VALID;
pCtx->es.u32Limit = 0x0000ffff;
pCtx->es.Attr.n.u1DescType = 1; /* code/data segment */
pCtx->es.Attr.n.u1Present = 1;
pCtx->es.Attr.n.u4Type = X86_SEL_TYPE_RW_ACC;
//fs
pCtx->fs.fFlags = CPUMSELREG_FLAGS_VALID;
pCtx->fs.u32Limit = 0x0000ffff;
pCtx->fs.Attr.n.u1DescType = 1; /* code/data segment */
pCtx->fs.Attr.n.u1Present = 1;
pCtx->fs.Attr.n.u4Type = X86_SEL_TYPE_RW_ACC;
//gs
pCtx->gs.fFlags = CPUMSELREG_FLAGS_VALID;
pCtx->gs.u32Limit = 0x0000ffff;
pCtx->gs.Attr.n.u1DescType = 1; /* code/data segment */
pCtx->gs.Attr.n.u1Present = 1;
pCtx->gs.Attr.n.u4Type = X86_SEL_TYPE_RW_ACC;
//ss
pCtx->ss.fFlags = CPUMSELREG_FLAGS_VALID;
pCtx->ss.u32Limit = 0x0000ffff;
pCtx->ss.Attr.n.u1Present = 1;
pCtx->ss.Attr.n.u1DescType = 1; /* code/data segment */
pCtx->ss.Attr.n.u4Type = X86_SEL_TYPE_RW_ACC;
pCtx->idtr.cbIdt = 0xffff;
pCtx->gdtr.cbGdt = 0xffff;
pCtx->ldtr.fFlags = CPUMSELREG_FLAGS_VALID;
pCtx->ldtr.u32Limit = 0xffff;
pCtx->ldtr.Attr.n.u1Present = 1;
pCtx->ldtr.Attr.n.u4Type = X86_SEL_TYPE_SYS_LDT;
pCtx->tr.fFlags = CPUMSELREG_FLAGS_VALID;
pCtx->tr.u32Limit = 0xffff;
pCtx->tr.Attr.n.u1Present = 1;
pCtx->tr.Attr.n.u4Type = X86_SEL_TYPE_SYS_386_TSS_BUSY; /* Deduction, not properly documented by Intel. */
pCtx->dr[6] = X86_DR6_INIT_VAL;
pCtx->dr[7] = X86_DR7_INIT_VAL;
PX86FXSTATE pFpuCtx = &pCtx->pXStateR3->x87; AssertReleaseMsg(RT_VALID_PTR(pFpuCtx), ("%p\n", pFpuCtx));
pFpuCtx->FTW = 0x00; /* All empty (abbridged tag reg edition). */
pFpuCtx->FCW = 0x37f;
pFpuCtx->MXCSR = 0x1F80;
pFpuCtx->MXCSR_MASK = pVM->cpum.s.GuestInfo.fMxCsrMask; /** @todo check if REM messes this up... */
pCtx->aXcr[0] = XSAVE_C_X87;
if (pVM->cpum.s.HostFeatures.cbMaxExtendedState >= RT_UOFFSETOF(X86XSAVEAREA, Hdr))
{
/* The entire FXSAVE state needs loading when we switch to XSAVE/XRSTOR
as we don't know what happened before. (Bother optimize later?) */
pCtx->pXStateR3->Hdr.bmXState = XSAVE_C_X87 | XSAVE_C_SSE;
}
pCtx->msrPAT = MSR_IA32_CR_PAT_INIT_VAL;
if (CPUMMICROARCH_IS_INTEL_CORE2(pVM->cpum.s.GuestFeatures.enmMicroarch))
pVCpu->cpum.s.GuestMsrs.msr.PkgCStateCfgCtrl = 0x202a01; /* From Mac Pro Harpertown, unlocked. */
else if (pVM->cpum.s.GuestFeatures.enmMicroarch == kCpumMicroarch_Intel_Core_Yonah)
pVCpu->cpum.s.GuestMsrs.msr.PkgCStateCfgCtrl = 0x26740c; /* From MacBookPro1,1. */
CPUMSetGuestGif(pCtx, true);
Assert(!pVM->cpum.s.GuestFeatures.fVmx || !pVM->cpum.s.GuestFeatures.fSvm); /* Paranoia. */
if (pVM->cpum.s.GuestFeatures.fVmx)
cpumR3ResetVmxHwVirtState(pVCpu);
else if (pVM->cpum.s.GuestFeatures.fSvm)
cpumR3ResetSvmHwVirtState(pVCpu);
}
CPUMR3DisasmInstrCPU
这个API用于解码一条指令,结果保存在PDISCPUSTATE里
VMMR3DECL(int) CPUMR3DisasmInstrCPU(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, RTGCPTR GCPtrPC, PDISCPUSTATE pCpu,
const char *pszPrefix)
{
//根据GuestOS状态设置State(32/64,cs段等)
if ( (pCtx->cr0 & X86_CR0_PE)
&& pCtx->eflags.Bits.u1VM == 0)
{
//32or64位保护模式
State.f64Bits = enmMode >= PGMMODE_AMD64 && pCtx->cs.Attr.n.u1Long;
//cs段寄存器,方便读取指令
State.GCPtrSegBase = pCtx->cs.u64Base;
State.GCPtrSegEnd = pCtx->cs.u32Limit + 1 + (RTGCUINTPTR)pCtx->cs.u64Base;
State.cbSegLimit = pCtx->cs.u32Limit;
enmDisCpuMode = (State.f64Bits)
? DISCPUMODE_64BIT
: pCtx->cs.Attr.n.u1DefBig
? DISCPUMODE_32BIT
: DISCPUMODE_16BIT;
}
else
{
//没有开启分页,是实模式或者保护模式
enmDisCpuMode = DISCPUMODE_16BIT;
State.GCPtrSegBase = pCtx->cs.Sel * 16;
State.GCPtrSegEnd = 0xFFFFFFFF;
State.cbSegLimit = 0xFFFFFFFF;
}
//调用decode lib解析这条指令
DISInstrWithReader(GCPtrPC, enmDisCpuMode, cpumR3DisasInstrRead, &State, pCpu, &cbInstr);
}
//decode lib用的callback函数,读取一条指令
//pfnReadBytes(pDis, 0, 1, sizeof(pDis->abInstr));
static DECLCALLBACK(int) cpumR3DisasInstrRead(PDISCPUSTATE pDis, uint8_t offInstr, uint8_t cbMinRead, uint8_t cbMaxRead)
{
for (;;)
{
//获取GC
RTGCUINTPTR GCPtr = pDis->uInstrAddr + offInstr + pState->GCPtrSegBase;
//如果当前页面已经映射了HostGC地址,则不需要重新映射一次
if ( !pState->pvPageR3
|| (GCPtr >> PAGE_SHIFT) != (pState->pvPageGC >> PAGE_SHIFT))
{
State->pvPageGC = GCPtr & PAGE_BASE_GC_MASK;
//GC page映射一个HostR3地址 (pState->pvPageR3)
PGMPhysGCPtr2CCPtrReadOnly(pState->pVCpu, pState->pvPageGC, &pState->pvPageR3, &pState->PageMapLock);
}
//计算需要读取的大小,
uint32_t cb = PAGE_SIZE - (GCPtr & PAGE_OFFSET_MASK);
if (!pState->f64Bits)
{
RTGCUINTPTR cbSeg = pState->GCPtrSegEnd - GCPtr;
if (cb > cbSeg && cbSeg)
cb = cbSeg;
}
if (cb > cbMaxRead)
cb = cbMaxRead;
//读取cb字节
memcpy(&pDis->abInstr[offInstr], (uint8_t *)pState->pvPageR3 + (GCPtr & PAGE_OFFSET_MASK), cb);
offInstr += (uint8_t)cb;
//如果已经读完,则直接返回,否则继续读
if (cb >= cbMinRead)
{
pDis->cbCachedInstr = offInstr;
return VINF_SUCCESS;
}
cbMinRead -= (uint8_t)cb;
cbMaxRead -= (uint8_t)cb;
}
}
10.2 用于保存VM的API
CPUMInit的时候,调用SSMR3RegisterInternal,注册虚拟机做保存和继续的回掉,当VM保存/做快照/从快照启动等会调用相关的函数
CPUM_SAVED_STATE_VERSION
保存状态的版本,标记需要保存和恢复哪些寄存器
//默认是开启VMX
#define CPUM_SAVED_STATE_VERSION CPUM_SAVED_STATE_VERSION_HWVIRT_VMX_IEM
/** The saved state version 包含VMX 状态. */
#define CPUM_SAVED_STATE_VERSION_HWVIRT_VMX_IEM 19
/** The saved state version 包含SVM 状态. */
#define CPUM_SAVED_STATE_VERSION_HWVIRT_SVM 18
/** The saved state version 包含XSAVE 状态. */
#define CPUM_SAVED_STATE_VERSION_XSAVE 17
/** The saved state version 包含正常的CPUID leaf状态. */
#define CPUM_SAVED_STATE_VERSION_GOOD_CPUID_COUNT 16
/** The saved state version 包含没有更新的CPUID leaf状态. */
#define CPUM_SAVED_STATE_VERSION_BAD_CPUID_COUNT 15
/** The saved state version before the CPUIDs changes. */
#define CPUM_SAVED_STATE_VERSION_PUT_STRUCT 14
/** The saved state version before using SSMR3PutStruct. */
#define CPUM_SAVED_STATE_VERSION_MEM 13
/** The saved state version before introducing the MSR size field. */
#define CPUM_SAVED_STATE_VERSION_NO_MSR_SIZE 12
/** The saved state version of 3.2, 3.1 and 3.3 trunk before the hidden
* selector register change (CPUM_CHANGED_HIDDEN_SEL_REGS_INVALID). */
#define CPUM_SAVED_STATE_VERSION_VER3_2 11
/** The saved state version of 3.0 and 3.1 trunk before the teleportation
* changes. */
#define CPUM_SAVED_STATE_VERSION_VER3_0 10
/** The saved state version for the 2.1 trunk before the MSR changes. */
#define CPUM_SAVED_STATE_VERSION_VER2_1_NOMSR 9
/** The saved state version of 2.0, used for backwards compatibility. */
#define CPUM_SAVED_STATE_VERSION_VER2_0 8
/** The saved state version of 1.6, used for backwards compatibility. */
#define CPUM_SAVED_STATE_VERSION_VER1_6 6
cpumR3SaveExec
保存CPU的虚拟机状态
static DECLCALLBACK(int) cpumR3SaveExec(PVM pVM, PSSMHANDLE pSSM)
{
SSMR3PutU32(pSSM, pVM->cCpus);
SSMR3PutU32(pSSM, sizeof(pVM->apCpusR3[0]->cpum.s.GuestMsrs.msr));
for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
{
//对每个VCPU
//保存pVCpu->cpum.s.Guest到g_aCpumCtxFields全局变量里
PCPUMCTX pGstCtx = &pVCpu->cpum.s.Guest;
SSMR3PutStructEx(pSSM, pGstCtx, sizeof(*pGstCtx), 0, g_aCpumCtxFields, NULL);
//pGstCtx->pXStateR3->x87保存到 g_aCpumX87Fields里
SSMR3PutStructEx(pSSM, &pGstCtx->pXStateR3->x87, sizeof(pGstCtx->pXStateR3->x87), 0, g_aCpumX87Fields, NULL);
}
//根据XSAVE的mask保存相应寄存器
//保存YMM寄存器到g_aCpumYmmHiFields
if (pGstCtx->fXStateMask & XSAVE_C_YMM)
{
PCX86XSAVEYMMHI pYmmHiCtx = CPUMCTX_XSAVE_C_PTR(pGstCtx, XSAVE_C_YMM_BIT, PCX86XSAVEYMMHI);
SSMR3PutStructEx(pSSM, pYmmHiCtx, sizeof(*pYmmHiCtx), SSMSTRUCT_FLAGS_FULL_STRUCT, g_aCpumYmmHiFields, NULL);
}
// BNDREGS - MPX bound register state
if (pGstCtx->fXStateMask & XSAVE_C_BNDREGS)
{
PCX86XSAVEBNDREGS pBndRegs = CPUMCTX_XSAVE_C_PTR(pGstCtx, XSAVE_C_BNDREGS_BIT, PCX86XSAVEBNDREGS);
SSMR3PutStructEx(pSSM, pBndRegs, sizeof(*pBndRegs), SSMSTRUCT_FLAGS_FULL_STRUCT, g_aCpumBndRegsFields, NULL);
}
//BNDCSR - MPX bound config and status state.
if (pGstCtx->fXStateMask & XSAVE_C_BNDCSR)
{
PCX86XSAVEBNDCFG pBndCfg = CPUMCTX_XSAVE_C_PTR(pGstCtx, XSAVE_C_BNDCSR_BIT, PCX86XSAVEBNDCFG);
SSMR3PutStructEx(pSSM, pBndCfg, sizeof(*pBndCfg), SSMSTRUCT_FLAGS_FULL_STRUCT, g_aCpumBndCfgFields, NULL);
}
//ZMM_Hi256 - Upper 256 bits of ZMM0-15 (AVX-512)
if (pGstCtx->fXStateMask & XSAVE_C_ZMM_HI256)
{
PCX86XSAVEZMMHI256 pZmmHi256 = CPUMCTX_XSAVE_C_PTR(pGstCtx, XSAVE_C_ZMM_HI256_BIT, PCX86XSAVEZMMHI256);
SSMR3PutStructEx(pSSM, pZmmHi256, sizeof(*pZmmHi256), SSMSTRUCT_FLAGS_FULL_STRUCT, g_aCpumZmmHi256Fields, NULL);
}
// Hi16_ZMM - 512-bits ZMM16-31 state
if (pGstCtx->fXStateMask & XSAVE_C_ZMM_16HI)
{
PCX86XSAVEZMM16HI pZmm16Hi = CPUMCTX_XSAVE_C_PTR(pGstCtx, XSAVE_C_ZMM_16HI_BIT, PCX86XSAVEZMM16HI);
SSMR3PutStructEx(pSSM, pZmm16Hi, sizeof(*pZmm16Hi), SSMSTRUCT_FLAGS_FULL_STRUCT, g_aCpumZmm16HiFields, NULL);
}
//VMX相关信息
if (pVM->cpum.s.GuestFeatures.fSvm)
{
Assert(pGstCtx->hwvirt.svm.CTX_SUFF(pVmcb));
SSMR3PutU64(pSSM, pGstCtx->hwvirt.svm.uMsrHSavePa);
SSMR3PutGCPhys(pSSM, pGstCtx->hwvirt.svm.GCPhysVmcb);
SSMR3PutU64(pSSM, pGstCtx->hwvirt.svm.uPrevPauseTick);
SSMR3PutU16(pSSM, pGstCtx->hwvirt.svm.cPauseFilter);
SSMR3PutU16(pSSM, pGstCtx->hwvirt.svm.cPauseFilterThreshold);
SSMR3PutBool(pSSM, pGstCtx->hwvirt.svm.fInterceptEvents);
SSMR3PutStructEx(pSSM, &pGstCtx->hwvirt.svm.HostState, sizeof(pGstCtx->hwvirt.svm.HostState), 0 /* fFlags */,
g_aSvmHwvirtHostState, NULL /* pvUser */);
SSMR3PutMem(pSSM, pGstCtx->hwvirt.svm.pVmcbR3, SVM_VMCB_PAGES << X86_PAGE_4K_SHIFT);
SSMR3PutMem(pSSM, pGstCtx->hwvirt.svm.pvMsrBitmapR3, SVM_MSRPM_PAGES << X86_PAGE_4K_SHIFT);
SSMR3PutMem(pSSM, pGstCtx->hwvirt.svm.pvIoBitmapR3, SVM_IOPM_PAGES << X86_PAGE_4K_SHIFT);
SSMR3PutU32(pSSM, pGstCtx->hwvirt.fLocalForcedActions);
SSMR3PutBool(pSSM, pGstCtx->hwvirt.fGif);
}
if (pVM->cpum.s.GuestFeatures.fVmx)
{
//保存GCPhysVmxon对应的物理内存
SSMR3PutGCPhys(pSSM, pGstCtx->hwvirt.vmx.GCPhysVmxon);
//vmcs和shadowVMCS内容
SSMR3PutGCPhys(pSSM, pGstCtx->hwvirt.vmx.GCPhysVmcs);
SSMR3PutGCPhys(pSSM, pGstCtx->hwvirt.vmx.GCPhysShadowVmcs);
//一些开关的保存
SSMR3PutBool(pSSM, pGstCtx->hwvirt.vmx.fInVmxRootMode);
SSMR3PutBool(pSSM, pGstCtx->hwvirt.vmx.fInVmxNonRootMode);
SSMR3PutBool(pSSM, pGstCtx->hwvirt.vmx.fInterceptEvents);
SSMR3PutBool(pSSM, pGstCtx->hwvirt.vmx.fNmiUnblockingIret);
//vmcsR3/ShadowVmcsR3/xxxbitmap保存
SSMR3PutStructEx(pSSM, pGstCtx->hwvirt.vmx.pVmcsR3, sizeof(VMXVVMCS), 0, g_aVmxHwvirtVmcs, NULL);
SSMR3PutStructEx(pSSM, pGstCtx->hwvirt.vmx.pShadowVmcsR3, sizeof(VMXVVMCS), 0, g_aVmxHwvirtVmcs, NULL);
SSMR3PutMem(pSSM, pGstCtx->hwvirt.vmx.pvVmreadBitmapR3, VMX_V_VMREAD_VMWRITE_BITMAP_SIZE);
SSMR3PutMem(pSSM, pGstCtx->hwvirt.vmx.pvVmwriteBitmapR3, VMX_V_VMREAD_VMWRITE_BITMAP_SIZE);
SSMR3PutMem(pSSM, pGstCtx->hwvirt.vmx.pEntryMsrLoadAreaR3, VMX_V_AUTOMSR_AREA_SIZE);
SSMR3PutMem(pSSM, pGstCtx->hwvirt.vmx.pExitMsrStoreAreaR3, VMX_V_AUTOMSR_AREA_SIZE);
SSMR3PutMem(pSSM, pGstCtx->hwvirt.vmx.pExitMsrLoadAreaR3, VMX_V_AUTOMSR_AREA_SIZE);
SSMR3PutMem(pSSM, pGstCtx->hwvirt.vmx.pvMsrBitmapR3, VMX_V_MSR_BITMAP_SIZE);
SSMR3PutMem(pSSM, pGstCtx->hwvirt.vmx.pvIoBitmapR3, VMX_V_IO_BITMAP_A_SIZE + VMX_V_IO_BITMAP_B_SIZE);
//一些VMX设置到保存
SSMR3PutU64(pSSM, pGstCtx->hwvirt.vmx.uFirstPauseLoopTick);
SSMR3PutU64(pSSM, pGstCtx->hwvirt.vmx.uPrevPauseTick);
SSMR3PutU64(pSSM, pGstCtx->hwvirt.vmx.uEntryTick);
SSMR3PutU16(pSSM, pGstCtx->hwvirt.vmx.offVirtApicWrite);
SSMR3PutBool(pSSM, pGstCtx->hwvirt.vmx.fVirtNmiBlocking);
SSMR3PutU64(pSSM, pGstCtx->hwvirt.vmx.Msrs.u64FeatCtrl);
SSMR3PutU64(pSSM, pGstCtx->hwvirt.vmx.Msrs.u64Basic);
SSMR3PutU64(pSSM, pGstCtx->hwvirt.vmx.Msrs.PinCtls.u);
SSMR3PutU64(pSSM, pGstCtx->hwvirt.vmx.Msrs.ProcCtls.u);
SSMR3PutU64(pSSM, pGstCtx->hwvirt.vmx.Msrs.ProcCtls2.u);
SSMR3PutU64(pSSM, pGstCtx->hwvirt.vmx.Msrs.ExitCtls.u);
SSMR3PutU64(pSSM, pGstCtx->hwvirt.vmx.Msrs.EntryCtls.u);
SSMR3PutU64(pSSM, pGstCtx->hwvirt.vmx.Msrs.TruePinCtls.u);
SSMR3PutU64(pSSM, pGstCtx->hwvirt.vmx.Msrs.TrueProcCtls.u);
SSMR3PutU64(pSSM, pGstCtx->hwvirt.vmx.Msrs.TrueEntryCtls.u);
SSMR3PutU64(pSSM, pGstCtx->hwvirt.vmx.Msrs.TrueExitCtls.u);
SSMR3PutU64(pSSM, pGstCtx->hwvirt.vmx.Msrs.u64Misc);
SSMR3PutU64(pSSM, pGstCtx->hwvirt.vmx.Msrs.u64Cr0Fixed0);
SSMR3PutU64(pSSM, pGstCtx->hwvirt.vmx.Msrs.u64Cr0Fixed1);
SSMR3PutU64(pSSM, pGstCtx->hwvirt.vmx.Msrs.u64Cr4Fixed0);
SSMR3PutU64(pSSM, pGstCtx->hwvirt.vmx.Msrs.u64Cr4Fixed1);
SSMR3PutU64(pSSM, pGstCtx->hwvirt.vmx.Msrs.u64VmcsEnum);
SSMR3PutU64(pSSM, pGstCtx->hwvirt.vmx.Msrs.u64VmFunc);
SSMR3PutU64(pSSM, pGstCtx->hwvirt.vmx.Msrs.u64EptVpidCaps);
}
SSMR3PutU32(pSSM, pVCpu->cpum.s.fUseFlags);
SSMR3PutU32(pSSM, pVCpu->cpum.s.fChanged);
//保存Guest的msr寄存器
SSMR3PutMem(pSSM, &pVCpu->cpum.s.GuestMsrs, sizeof(pVCpu->cpum.s.GuestMsrs.msr));
}
//保存CPUID的所有leaves
cpumR3SaveCpuId(pVM, pSSM);
}
cpumR3LoadPrep
//标记马上要开始load CPU相关信息
static DECLCALLBACK(int) cpumR3LoadPrep(PVM pVM, PSSMHANDLE pSSM)
{
pVM->cpum.s.fPendingRestore = true;
}
cpumR3LoadExec
从保存的状态里恢复CPU相关信息,恢复顺序和cpumR3SaveExec相同
static DECLCALLBACK(int) cpumR3LoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
{
//The special value for the final pass.
if (uPass == SSM_PASS_FINAL)
{
if (uVersion >= CPUM_SAVED_STATE_VERSION_XSAVE)
{
//需要LoadFPU寄存器
SSMR3GetStructEx(pSSM, &Ign, sizeof(Ign), fLoad | SSMSTRUCT_FLAGS_NO_TAIL_MARKER, paCpumCtx1Fields, NULL);
SSMR3GetStructEx(pSSM, &HyperCtxIgnored, sizeof(HyperCtxIgnored),
fLoad | SSMSTRUCT_FLAGS_NO_LEAD_MARKER, paCpumCtx2Fields, NULL);
}
if (uVersion >= CPUM_SAVED_STATE_VERSION_VER2_1_NOMSR)
{
//Load VCPU个数
uint32_t cCpus;
rc = SSMR3GetU32(pSSM, &cCpus); AssertRCReturn(rc, rc);
}
//load msr寄存器个数
uint32_t cbMsrs = 0;
if (uVersion > CPUM_SAVED_STATE_VERSION_NO_MSR_SIZE)
{
rc = SSMR3GetU32(pSSM, &cbMsrs);
}
//pre-vCPU
for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
{
if (uVersion >= CPUM_SAVED_STATE_VERSION_XSAVE)
{
//从各个全局变量里load FPU寄存器
SSMR3GetStructEx(pSSM, &HyperCtxIgnored, sizeof(HyperCtxIgnored), 0, g_aCpumCtxFields, NULL);
SSMR3GetStructEx(pSSM, pGstCtx, sizeof(*pGstCtx), 0, g_aCpumCtxFields, NULL);
SSMR3GetStructEx(pSSM, &pGstCtx->pXStateR3->x87, sizeof(pGstCtx->pXStateR3->x87), 0, g_aCpumX87Fields, NULL);
//检查加载的FPU寄存器是否正确
AssertLogRelMsgReturn(pGstCtx->aXcr[0] & XSAVE_C_X87, ("xcr0=%#RX64\n", pGstCtx->aXcr[0]), VERR_CPUM_INVALID_XCR0);
...
//SaveExec相反的操作,从全局变量里恢复相关寄存器
if (pGstCtx->fXStateMask & XSAVE_C_YMM)
{
PX86XSAVEYMMHI pYmmHiCtx = CPUMCTX_XSAVE_C_PTR(pGstCtx, XSAVE_C_YMM_BIT, PX86XSAVEYMMHI);
SSMR3GetStructEx(pSSM, pYmmHiCtx, sizeof(*pYmmHiCtx), SSMSTRUCT_FLAGS_FULL_STRUCT, g_aCpumYmmHiFields, NULL);
}
if (pGstCtx->fXStateMask & XSAVE_C_BNDREGS)
{
PX86XSAVEBNDREGS pBndRegs = CPUMCTX_XSAVE_C_PTR(pGstCtx, XSAVE_C_BNDREGS_BIT, PX86XSAVEBNDREGS);
SSMR3GetStructEx(pSSM, pBndRegs, sizeof(*pBndRegs), SSMSTRUCT_FLAGS_FULL_STRUCT, g_aCpumBndRegsFields, NULL);
}
if (pGstCtx->fXStateMask & XSAVE_C_BNDCSR)
{
PX86XSAVEBNDCFG pBndCfg = CPUMCTX_XSAVE_C_PTR(pGstCtx, XSAVE_C_BNDCSR_BIT, PX86XSAVEBNDCFG);
SSMR3GetStructEx(pSSM, pBndCfg, sizeof(*pBndCfg), SSMSTRUCT_FLAGS_FULL_STRUCT, g_aCpumBndCfgFields, NULL);
}
if (pGstCtx->fXStateMask & XSAVE_C_ZMM_HI256)
{
PX86XSAVEZMMHI256 pZmmHi256 = CPUMCTX_XSAVE_C_PTR(pGstCtx, XSAVE_C_ZMM_HI256_BIT, PX86XSAVEZMMHI256);
SSMR3GetStructEx(pSSM, pZmmHi256, sizeof(*pZmmHi256), SSMSTRUCT_FLAGS_FULL_STRUCT, g_aCpumZmmHi256Fields, NULL);
}
if (pGstCtx->fXStateMask & XSAVE_C_ZMM_16HI)
{
PX86XSAVEZMM16HI pZmm16Hi = CPUMCTX_XSAVE_C_PTR(pGstCtx, XSAVE_C_ZMM_16HI_BIT, PX86XSAVEZMM16HI);
SSMR3GetStructEx(pSSM, pZmm16Hi, sizeof(*pZmm16Hi), SSMSTRUCT_FLAGS_FULL_STRUCT, g_aCpumZmm16HiFields, NULL);
}
//恢复SVM相关的数据
if (uVersion >= CPUM_SAVED_STATE_VERSION_HWVIRT_SVM)
{
if (pVM->cpum.s.GuestFeatures.fSvm)
{
Assert(pGstCtx->hwvirt.svm.CTX_SUFF(pVmcb));
SSMR3GetU64(pSSM, &pGstCtx->hwvirt.svm.uMsrHSavePa);
SSMR3GetGCPhys(pSSM, &pGstCtx->hwvirt.svm.GCPhysVmcb);
SSMR3GetU64(pSSM, &pGstCtx->hwvirt.svm.uPrevPauseTick);
...
}
}
//恢复VMX相关的数据
if (uVersion >= CPUM_SAVED_STATE_VERSION_HWVIRT_VMX_IEM)
{
if (pVM->cpum.s.GuestFeatures.fVmx)
{
SSMR3GetGCPhys(pSSM, &pGstCtx->hwvirt.vmx.GCPhysVmxon);
SSMR3GetGCPhys(pSSM, &pGstCtx->hwvirt.vmx.GCPhysVmcs);
...
}
}
}
//恢复一些flags
SSMR3GetU32(pSSM, &pVCpu->cpum.s.fUseFlags);
SSMR3GetU32(pSSM, &pVCpu->cpum.s.fChanged);
//部分MSR寄存器信息
if (uVersion > CPUM_SAVED_STATE_VERSION_NO_MSR_SIZE)
rc = SSMR3GetMem(pSSM, &pVCpu->cpum.s.GuestMsrs.au64[0], cbMsrs);
else if (uVersion >= CPUM_SAVED_STATE_VERSION_VER3_0)
{
SSMR3GetMem(pSSM, &pVCpu->cpum.s.GuestMsrs.au64[0], 2 * sizeof(uint64_t));
rc = SSMR3Skip(pSSM, 62 * sizeof(uint64_t));
}
//重置Dr6 Dr7寄存器
pGstCtx->dr[6] &= ~(X86_DR6_RAZ_MASK | X86_DR6_MBZ_MASK);
pGstCtx->dr[6] |= X86_DR6_RA1_MASK;
pGstCtx->dr[7] &= ~(X86_DR7_RAZ_MASK | X86_DR7_MBZ_MASK);
pGstCtx->dr[7] |= X86_DR7_RA1_MASK;
}//end of pre-vCPU
}
//fPendingRestore设置成false,已经完成restore
pVM->cpum.s.fPendingRestore = false;
//恢复CPUID leaves和GuestMsrs
if (uVersion >= CPUM_SAVED_STATE_VERSION_VER3_2)
{
CPUMMSRS GuestMsrs;
CPUMFEATURES BaseFeatures;
bool const fVmxGstFeat = pVM->cpum.s.GuestFeatures.fVmx;
if (fVmxGstFeat)
{
BaseFeatures = pVM->cpum.s.GuestFeatures;
GuestMsrs.hwvirt.vmx = pVM->apCpusR3[0]->cpum.s.Guest.hwvirt.vmx.Msrs;
}
//恢复CPUID leaves和GuestMsrs
rc = cpumR3LoadCpuId(pVM, pSSM, uVersion, &GuestMsrs);
return rc;
}
return cpumR3LoadCpuIdPre32(pVM, pSSM, uVersion);
}
cpumR3LoadDone
static DECLCALLBACK(int) cpumR3LoadDone(PVM pVM, PSSMHANDLE pSSM)
{
//调到这个函数的时候fPendingRestore不能是1
if (pVM->cpum.s.fPendingRestore)
{
return VERR_INTERNAL_ERROR_2;
}
//如果支持64bit Guest
bool const fSupportsLongMode = VMR3IsLongModeAllowed(pVM);
for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
{
PVMCPU pVCpu = pVM->apCpusR3[idCpu];
//如果改变了EFER寄存器里的NX位,需要通知PGM修改相对应的全局变量
PGMNotifyNxeChanged(pVCpu, RT_BOOL(pVCpu->cpum.s.Guest.msrEFER & MSR_K6_EFER_NXE));
if (fSupportsLongMode)
pVCpu->cpum.s.fUseFlags |= CPUM_USE_SUPPORTS_LONGMODE;
}
}
CPUMR3IsStateRestorePending
//CPUM是否处于restore状态
VMMDECL(bool) CPUMR3IsStateRestorePending(PVM pVM)
{
return pVM->cpum.s.fPendingRestore;
}
10.3 R0相关APIs
VMM\VMMR0\CPUMR0.cpp CPUMR0.asm
这里大部分工作: 1. 检测CPU是否能开启VBOX,2, 支持APIC虚拟化(后面介绍 ), 3.调试支持
CPUMR0InitVM
VMMR0_INT_DECL(int) CPUMR0InitVM(PVM pVM)
{
uint32_t u32CR0 = ASMGetCR0();
if ((u32CR0 & (X86_CR0_PE | X86_CR0_PG)) != (X86_CR0_PE | X86_CR0_PG))
return VERR_UNSUPPORTED_CPU_MODE;
//部分CPU需要检查是否支持SYSENTER
if ( (fFeatures & X86_CPUID_FEATURE_EDX_SEP)
&& ( u32Family != 6 /* (> pentium pro) */
|| u32Model >= 3
|| u32Stepping >= 3
|| !ASMIsIntelCpu()))
{
uint32_t u32 = ASMRdMsr_Low(MSR_IA32_SYSENTER_CS);
if (u32)
{
pVM->cpum.s.fHostUseFlags |= CPUM_USE_SYSENTER;
}
}
//host是否支持syscall
uint32_t cExt = 0;
//获取Extended Function CPUID input的最大值.
ASMCpuId(0x80000000, &cExt, &u32Dummy, &u32Dummy, &u32Dummy);
if (ASMIsValidExtRange(cExt))
{
uint32_t fExtFeaturesEDX = ASMCpuId_EDX(0x80000001);
//edx bit11标示是否支持syscall/sysret
if (fExtFeaturesEDX & X86_CPUID_EXT_FEATURE_EDX_SYSCALL)
{
#ifdef RT_ARCH_X86
if (!ASMIsIntelCpu())
#endif
{
//64位CPU和32位AMDCPU 还需要检查MSR_K6_EFER_SCE寄存器是否打开
uint64_t fEfer = ASMRdMsr(MSR_K6_EFER);
if (fEfer & MSR_K6_EFER_SCE)
{
pVM->cpum.s.fHostUseFlags |= CPUM_USE_SYSCALL;
}
}
}
}
//获取 Function CPUID input的最大值.
uint32_t const cStdRange = ASMCpuId_EAX(0);
if ( ASMIsValidStdRange(cStdRange)
&& cStdRange >= 7)
{
//获取cpuid(7)返回的edx
uint32_t fEdxFeatures = ASMCpuId_EDX(7);
if ( (fEdxFeatures & X86_CPUID_STEXT_FEATURE_EDX_ARCHCAP)
&& (fFeatures & X86_CPUID_FEATURE_EDX_MSR))
{
uint64_t const fArchVal = ASMRdMsr(MSR_IA32_ARCH_CAPABILITIES);
pVM->cpum.s.GuestFeatures.fArchRdclNo
= pVM->cpum.s.HostFeatures.fArchRdclNo = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_RDCL_NO);
pVM->cpum.s.GuestFeatures.fArchIbrsAll
= pVM->cpum.s.HostFeatures.fArchIbrsAll = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_IBRS_ALL);
pVM->cpum.s.GuestFeatures.fArchRsbOverride
= pVM->cpum.s.HostFeatures.fArchRsbOverride = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_RSBO);
pVM->cpum.s.GuestFeatures.fArchVmmNeedNotFlushL1d
= pVM->cpum.s.HostFeatures.fArchVmmNeedNotFlushL1d = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_VMM_NEED_NOT_FLUSH_L1D);
pVM->cpum.s.GuestFeatures.fArchMdsNo
= pVM->cpum.s.HostFeatures.fArchMdsNo = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_MDS_NO);
if (pVM->cpum.s.GuestFeatures.fArchCap)
VMCC_FOR_EACH_VMCPU_STMT(pVM, pVCpu->cpum.s.GuestMsrs.msr.ArchCaps = fArchVal);
}
else
pVM->cpum.s.HostFeatures.fArchCap = 0;
}
}
CPUMR0ModuleInit
//只做了一件事情,初始化LocalAPIC, 后面会专门一篇介绍APIC虚拟化
VMMR0_INT_DECL(int) CPUMR0ModuleInit(void)
{
#ifdef VBOX_WITH_VMMR0_DISABLE_LAPIC_NMI
rc = cpumR0MapLocalApics();
#endif
}
CPUMR0Trap07Handler
支持Lazy FPU:
现代处理器采用多种技术来提高系统性能。其中一种技术是推迟保存和恢复任务交换机上的某些 CPU 上下文状态。
当操作系统发生线程切换的时候将发生任务/上下文切换。在任务切换时,处理器保存其当前执行上下文(各种寄存器、指令和堆栈指针等),并加载新进程的上下文。在执行此操作时,它可以延迟 FPU/SSE 上下文状态的还原,因为并非所有应用程序都使用浮点单元 (FPU)。如果新计划的进程不使用浮点 (FP) 指令,则不需要保存/还原 FPU 上下文状态。这可以节省宝贵的执行周期并提高性能。
在延迟还原方案下,在任务切换期间,进程执行的第一个 FP 指令将生成"设备不可用 (DNA)"异常;然后,DNA 异常处理程序将当前 FPU 上下文保存到旧任务的状态保存区域,并加载当前进程的新的 FPU 上下文。换句话说,FPU 状态的加载将延迟,直到当前任务调用 FP 指令 - Lazy FPU restore。
最近的处理器包括处理器扩展(“XSAVEOPT”),这些扩展在硬件中更高效地实现 FPU 还原,从而在无需依赖 DNA 异常的情况下,提供延迟 FPU 的性能优势。在支持XSAVEOPT的CPU上,不会产生这个DNA异常。
VMMR0_INT_DECL(int) CPUMR0Trap07Handler(PVMCC pVM, PVMCPUCC pVCpu)
{
//如果Guest的FPU state已经loaded过了,说明不是lazy FPU导致的异常
//返回给Guest处理
if (CPUMIsGuestFPUStateActive(pVCpu))
{
return VINF_EM_RAW_GUEST_TRAP;
}
//根据CR0的设置,决定是交给Guest处理还是LoadGuestFPU
switch (pVCpu->cpum.s.Guest.cr0 & (X86_CR0_MP | X86_CR0_EM | X86_CR0_TS))
{
case X86_CR0_MP | X86_CR0_TS:
case X86_CR0_MP | X86_CR0_TS | X86_CR0_EM:
return VINF_EM_RAW_GUEST_TRAP;
default:
break;
}
return CPUMR0LoadGuestFPU(pVM, pVCpu);
}
CPUMR0LoadGuestFPU
保存Host FPU/XMM, load guest FPU/XMM
VMMR0_INT_DECL(int) CPUMR0LoadGuestFPU(PVM pVM, PVMCPU pVCpu)
{
if (!pVM->cpum.s.HostFeatures.fLeakyFxSR)
{
//for 部分AMD CPU enable了FFXSR
rc = cpumR0SaveHostRestoreGuestFPUState(&pVCpu->cpum.s);
}
else
{
//如果Host开启了MSR_K6_EFER_FFXSR(fast FXSAVE/FXSTOR),需要先关闭MSR_K6_EFER_FFXSR,然后再调用cpumR0SaveGuestRestoreHostFPUState(因为cpumR0SaveGuestRestoreHostFPUState里需要调用FXSAVE/FXSTOR指令,如果开启了FFXSR,则无法保存XMM state)
uint64_t uHostEfer = ASMRdMsr(MSR_K6_EFER);
if (!(uHostEfer & MSR_K6_EFER_FFXSR))
rc = cpumR0SaveHostRestoreGuestFPUState(&pVCpu->cpum.s);
else
{
RTCCUINTREG const uSavedFlags = ASMIntDisableFlags();
pVCpu->cpum.s.fUseFlags |= CPUM_USED_MANUAL_XMM_RESTORE;
ASMWrMsr(MSR_K6_EFER, uHostEfer & ~MSR_K6_EFER_FFXSR);
rc = cpumR0SaveHostRestoreGuestFPUState(&pVCpu->cpum.s);
ASMWrMsr(MSR_K6_EFER, uHostEfer | MSR_K6_EFER_FFXSR);
ASMSetFlags(uSavedFlags);
}
}
}
cpumR0SaveHostRestoreGuestFPUState
这个函数是一个汇编函数,位于CPUMInternal.mac里
先调用XSAVE/FSSAVE指令把当前host的FPU/AVX/SSE寄存器保存到CPUMCPU.Host.pXStateR0
再从CPUMCPU.Guest.pXStateR0里执行xrstor/fxrstor指令加载FPU/AVX/SSE寄存器
CPUMR0FpuStateMaybeSaveGuestAndRestoreHost
保存Guest FPU,load host FPU
VMMR0_INT_DECL(bool) CPUMR0FpuStateMaybeSaveGuestAndRestoreHost(PVMCPU pVCpu)
{
//如果Guest和HostCPU都支持FPU
if (pVCpu->cpum.s.fUseFlags & (CPUM_USED_FPU_GUEST | CPUM_USED_FPU_HOST))
{
fSavedGuest = RT_BOOL(pVCpu->cpum.s.fUseFlags & CPUM_USED_FPU_GUEST);
//如果XMM state已经被手动restore的了(AMD only),调用cpumR0SaveGuestRestoreHostFPUState
if (!(pVCpu->cpum.s.fUseFlags & CPUM_USED_MANUAL_XMM_RESTORE))
cpumR0SaveGuestRestoreHostFPUState(&pVCpu->cpum.s);
else
{
//如果Host开启了MSR_K6_EFER_FFXSR(fast FXSAVE/FXSTOR),需要先关闭
uint64_t uHostEfer = ASMRdMsr(MSR_K6_EFER);
if (uHostEfer & MSR_K6_EFER_FFXSR)
{
RTCCUINTREG const uSavedFlags = ASMIntDisableFlags();
ASMWrMsr(MSR_K6_EFER, uHostEfer & ~MSR_K6_EFER_FFXSR);
cpumR0SaveGuestRestoreHostFPUState(&pVCpu->cpum.s);
ASMWrMsr(MSR_K6_EFER, uHostEfer | MSR_K6_EFER_FFXSR);
ASMSetFlags(uSavedFlags);
}
else
cpumR0SaveGuestRestoreHostFPUState(&pVCpu->cpum.s);
pVCpu->cpum.s.fUseFlags &= ~CPUM_USED_MANUAL_XMM_RESTORE;
}
}
}
cpumR0SaveGuestRestoreHostFPUState
这个函数是一个汇编函数,位于CPUMInternal.mac里
先调用XSAVE/FSSAVE指令把当前Guest的FPU/AVX/SSE寄存器保存到CPUMCPU.Guest.pXStateR0
再从CPUMCPU.Host.pXStateR0里执行xrstor/fxrstor指令加载FPU/AVX/SSE寄存器
CPUMR0FpuStateMaybeSaveGuestAndRestoreHost
上面函数的相反函数
VMMR0_INT_DECL(bool) CPUMR0FpuStateMaybeSaveGuestAndRestoreHost(PVMCPUCC pVCpu)
{
if (pVCpu->cpum.s.fUseFlags & (CPUM_USED_FPU_GUEST | CPUM_USED_FPU_HOST))
{
if (!(pVCpu->cpum.s.fUseFlags & CPUM_USED_MANUAL_XMM_RESTORE))
cpumR0SaveGuestRestoreHostFPUState(&pVCpu->cpum.s);
else
{
//如果Host开启了MSR_K6_EFER_FFXSR(fast FXSAVE/FXSTOR),需要先关闭
uint64_t uHostEfer = ASMRdMsr(MSR_K6_EFER);
if (uHostEfer & MSR_K6_EFER_FFXSR)
{
RTCCUINTREG const uSavedFlags = ASMIntDisableFlags();
ASMWrMsr(MSR_K6_EFER, uHostEfer & ~MSR_K6_EFER_FFXSR);
cpumR0SaveGuestRestoreHostFPUState(&pVCpu->cpum.s);
ASMWrMsr(MSR_K6_EFER, uHostEfer | MSR_K6_EFER_FFXSR);
ASMSetFlags(uSavedFlags);
}
else
cpumR0SaveGuestRestoreHostFPUState(&pVCpu->cpum.s);
pVCpu->cpum.s.fUseFlags &= ~CPUM_USED_MANUAL_XMM_RESTORE;
}
}
}
CPUMR0DebugStateMaybeSaveGuestAndRestoreHost
后面是几个调试寄存器的保存和恢复
VMMR0_INT_DECL(bool) CPUMR0DebugStateMaybeSaveGuestAndRestoreHost(PVMCPU pVCpu, bool fDr6)
{
//Guest DRx寄存器保存到pVCpu->cpum.s.Guest里
if (pVCpu->cpum.s.fUseFlags & CPUM_USED_DEBUG_REGS_GUEST)
{
pVCpu->cpum.s.Guest.dr[0] = ASMGetDR0();
pVCpu->cpum.s.Guest.dr[1] = ASMGetDR1();
pVCpu->cpum.s.Guest.dr[2] = ASMGetDR2();
pVCpu->cpum.s.Guest.dr[3] = ASMGetDR3();
if (fDr6)
pVCpu->cpum.s.Guest.dr[6] = ASMGetDR6();
}
//从pVCpu->cpum.s.Host里恢复DRx寄存器
if (pVCpu->cpum.s.fUseFlags & CPUM_USED_DEBUG_REGS_HOST)
{
//重置DR7
uint64_t uCurDR7 = ASMGetDR7();
if (uCurDR7 != X86_DR7_INIT_VAL)
ASMSetDR7(X86_DR7_INIT_VAL);
ASMSetDR0(pVCpu->cpum.s.Host.dr0);
ASMSetDR1(pVCpu->cpum.s.Host.dr1);
ASMSetDR2(pVCpu->cpum.s.Host.dr2);
ASMSetDR3(pVCpu->cpum.s.Host.dr3);
ASMSetDR6(pVCpu->cpum.s.Host.dr6);
ASMSetDR7(pVCpu->cpum.s.Host.dr7);
ASMAtomicAndU32(&pVCpu->cpum.s.fUseFlags, ~CPUM_USED_DEBUG_REGS_HOST);
}
}
CPUMR0DebugStateMaybeSaveGuest
VMMR0_INT_DECL(bool) CPUMR0DebugStateMaybeSaveGuest(PVMCPUCC pVCpu, bool fDr6)
{
//Guest DRx寄存器保存到pVCpu->cpum.s.Guest里
if (pVCpu->cpum.s.fUseFlags & CPUM_USED_DEBUG_REGS_GUEST)
{
pVCpu->cpum.s.Guest.dr[0] = ASMGetDR0();
pVCpu->cpum.s.Guest.dr[1] = ASMGetDR1();
pVCpu->cpum.s.Guest.dr[2] = ASMGetDR2();
pVCpu->cpum.s.Guest.dr[3] = ASMGetDR3();
if (fDr6)
pVCpu->cpum.s.Guest.dr[6] = ASMGetDR6();
return true;
}
}
CPUMR0LoadGuestDebugState
VMMR0_INT_DECL(void) CPUMR0LoadGuestDebugState(PVMCPUCC pVCpu, bool fDr6)
{
//DRx寄存器保存到pVCpu->cpum.s.Host里
cpumR0SaveHostDebugState(pVCpu);
//从pVCpu->cpum.s.Guest里恢复DRx寄存器 (DR7 不恢复)
ASMSetDR0(pVCpu->cpum.s.Guest.dr[0]);
ASMSetDR1(pVCpu->cpum.s.Guest.dr[1]);
ASMSetDR2(pVCpu->cpum.s.Guest.dr[2]);
ASMSetDR3(pVCpu->cpum.s.Guest.dr[3]);
if (fDr6)
ASMSetDR6(pVCpu->cpum.s.Guest.dr[6]);
}