文章目录
上一章里介绍了CPUID的初始化和读取,这一章里,介绍模拟MSR寄存器的初始化和读写操作
12.1 MSR Ranges 初始化
g_apCpumDbEntries里定义了VMMR3\cpus目录下所有已知的CPU列表,这些.h文件里定义了每个CPU的所有MSR寄存器列表
static CPUMDBENTRY const * const g_apCpumDbEntries[] =
{
&g_Entry_Intel_Core_i7_6700K,
&g_Entry_Intel_Core_i7_5600U,
....
}
比如Intel I7-5600U CPU里定义了200多个MSR寄存器
static CPUMMSRRANGE const g_aMsrRanges_Intel_Core_i7_5600U[] =
{
MFX(0x00000000, "IA32_P5_MC_ADDR", Ia32P5McAddr, Ia32P5McAddr, 0, UINT64_C(0xffffffffffffff00), 0), /* value=0xff */
MFX(0x00000001, "IA32_P5_MC_TYPE", Ia32P5McType, Ia32P5McType, 0, 0, UINT64_MAX), /* value=0x0 */
...
}
cpumR3DbGetCpuInfo
这个函数在cpumR3InitCpuIdAndMsrs() 里调用, 根据CPU类型,初始化MSR Range
int cpumR3DbGetCpuInfo(const char *pszName, PCPUMINFO pInfo)
{
//如果通过“host” CPU信息决定VCPU型号
if (!strcmp(pszName, "host"))
{
//根据host CPUID里的信息获取当前CPU类型信息
CPUMCPUVENDOR const enmVendor = CPUMR3CpuIdDetectVendorEx(pInfo->paCpuIdLeavesR3[0].uEax,
pInfo->paCpuIdLeavesR3[0].uEbx,
pInfo->paCpuIdLeavesR3[0].uEcx,
pInfo->paCpuIdLeavesR3[0].uEdx);
uint8_t const uFamily = ASMGetCpuFamily(uStd1Eax);
uint8_t const uModel = ASMGetCpuModel(uStd1Eax, enmVendor == CPUMCPUVENDOR_INTEL);
uint8_t const uStepping = ASMGetCpuStepping(uStd1Eax);
CPUMMICROARCH const enmMicroarch = CPUMR3CpuIdDetermineMicroarchEx(enmVendor, uFamily, uModel, uStepping);
//根据host 信息从g_apCpumDbEntries找到匹配的CPU型号,可以模糊匹配
for (unsigned i = 0; i < RT_ELEMENTS(g_apCpumDbEntries); i++)
{
CPUMDBENTRY const *pCur = g_apCpumDbEntries[i];
if ((CPUMCPUVENDOR)pCur->enmVendor == enmVendor)
{
if (pCur->uFamily == uFamily)
{
if (pCur->enmMicroarch == enmMicroarch)
{
if (pCur->uModel == uModel)
{
if (pCur->uStepping == uStepping)
{
/* Perfect match. */
pEntry = pCur;
break;
}
//下面都是模糊匹配
if ( !pEntry
|| pEntry->uModel != uModel
|| pEntry->enmMicroarch != enmMicroarch
|| pEntry->uFamily != uFamily)
//当前CPU比之前找到的CPU型号更匹配,替换pEntry
pEntry = pCur;
else if ( pCur->uStepping >= uStepping
? pCur->uStepping < pEntry->uStepping || pEntry->uStepping < uStepping
: pCur->uStepping > pEntry->uStepping)
//当前uStepping值更接近,替换pEntry
pEntry = pCur;
}
else if ( !pEntry
|| pEntry->enmMicroarch != enmMicroarch
|| pEntry->uFamily != uFamily)
pEntry = pCur;
else if ( pCur->uModel >= uModel
? pCur->uModel < pEntry->uModel || pEntry->uModel < uModel
: pCur->uModel > pEntry->uModel)
//uModel值更接近,替换pEntry
pEntry = pCur;
}
else if ( !pEntry
|| pEntry->uFamily != uFamily)
pEntry = pCur;
/* Special march matching rules applies to intel family 06h. */
else if ( enmVendor == CPUMCPUVENDOR_INTEL
&& uFamily == 6
? cpumR3DbIsBetterIntelFam06Match(pCur->enmMicroarch, enmMicroarch, pEntry->enmMicroarch)
: cpumR3DbIsBetterMarchMatch(pCur->enmMicroarch, enmMicroarch, pEntry->enmMicroarch))
pEntry = pCur;
}
//如果模糊匹配都没匹配到,返回第一个CPU信息,这个分支只有第一个循环才可能走到
else if (!pEntry)
pEntry = pCur;
}
}
}
else
{
//通过CPU名字来决定VCPU型号
for (unsigned i = 0; i < RT_ELEMENTS(g_apCpumDbEntries); i++)
if (!strcmp(pszName, g_apCpumDbEntries[i]->pszName))
{
pEntry = g_apCpumDbEntries[i];
break;
}
}
//获取到了VCPU型号,根据对应CPU头文件里值,创建MsrRange列表
uint32_t cMsrs = 0;
PCPUMMSRRANGE paMsrs = NULL;
PCCPUMMSRRANGE pCurMsr = pEntry->paMsrRanges;
uint32_t cLeft = pEntry->cMsrRanges;
while (cLeft-- > 0)
{
//调用cpumR3MsrRangesInsert一个一个MSR寄存器信息加入到数组中
rc = cpumR3MsrRangesInsert(NULL /* pVM */, &paMsrs, &cMsrs, pCurMsr);
if (RT_FAILURE(rc))
{
RTMemFree(pInfo->paCpuIdLeavesR3);
pInfo->paCpuIdLeavesR3 = NULL;
return rc;
}
pCurMsr++;
}
//更新CPUMINFO里的变量
pInfo->paMsrRangesR3 = paMsrs;
pInfo->cMsrRanges = cMsrs;
return VINF_SUCCESS;
}
MSR Ranges 是一个CPUMMSRRANGE数组,而且是按照MSR id从小到大排序后的数组。
CPUMMSRRANGE 里都分别有一个uFirst 和 uLast, 而且:
1)paMsrRanges[i-1].ulast < paMsrRanges[i].uFirst
2)paMsrRanges[i].ufirst <= paMsrRanges[i].ulast
3)paMsrRanges[i].ulast < paMsrRanges[i+1].ufirst
cpumR3MsrRangesInsert
加入一项到MSRRange里
VMMR3DECL(int) CPUMR3MsrRangesInsert(PVM pVM, PCCPUMMSRRANGE pNewRange)
{
cpumR3MsrRangesInsert(pVM, NULL /* ppaMsrRanges */, NULL /* pcMsrRanges */, pNewRange);
}
//insert pNewRange into MsrRange
int cpumR3MsrRangesInsert(PVM pVM, PCPUMMSRRANGE *ppaMsrRanges, uint32_t *pcMsrRanges, PCCPUMMSRRANGE pNewRange)
{
//如果当前Msr值大于MsrRange中最后一项的MSR值,这项不在MsrRange中
if ( cMsrRanges > 0
&& paMsrRanges[cMsrRanges - 1].uLast < pNewRange->uFirst)
{
//申请内存
paMsrRanges = cpumR3MsrRangesEnsureSpace(pVM, ppaMsrRanges, cMsrRanges, 1);
if (!paMsrRanges)
return VERR_NO_MEMORY;
//加入到最后一项中
paMsrRanges[cMsrRanges] = *pNewRange;
*pcMsrRanges += 1;
}
else
{
//通过binary search找到对应的MsrRange节点,或者最近的一个MsrRange节点
uint32_t i = cpumR3MsrRangesBinSearch(paMsrRanges, cMsrRanges, pNewRange->uFirst);
//新节点
if ( i >= cMsrRanges
|| pNewRange->uLast < paMsrRanges[i].uFirst)
{
//申请内存
paMsrRanges = cpumR3MsrRangesEnsureSpace(pVM, ppaMsrRanges, cMsrRanges, 1);
if (!paMsrRanges)
return VERR_NO_MEMORY;
//后面的节点全部后移一位
if (i < cMsrRanges)
memmove(&paMsrRanges[i + 1], &paMsrRanges[i], (cMsrRanges - i) * sizeof(paMsrRanges[0]));
//pNewRange加入新节点
paMsrRanges[i] = *pNewRange;
*pcMsrRanges += 1;
}
//替换已有节点
else if ( pNewRange->uFirst == paMsrRanges[i].uFirst
&& pNewRange->uLast == paMsrRanges[i].uLast)
paMsrRanges[i] = *pNewRange;
//新的节点在老的节点中间,老的节点分成两个,然后中间插入新的节点,MSRRange会增加两个节点
else if ( pNewRange->uFirst > paMsrRanges[i].uFirst
&& pNewRange->uLast < paMsrRanges[i].uLast)
{
paMsrRanges = cpumR3MsrRangesEnsureSpace(pVM, ppaMsrRanges, cMsrRanges, 2);
if (!paMsrRanges)
return VERR_NO_MEMORY;
if (i < cMsrRanges)
memmove(&paMsrRanges[i + 2], &paMsrRanges[i], (cMsrRanges - i) * sizeof(paMsrRanges[0]));
paMsrRanges[i + 1] = *pNewRange;
paMsrRanges[i + 2] = paMsrRanges[i];
paMsrRanges[i ].uLast = pNewRange->uFirst - 1;
paMsrRanges[i + 2].uFirst = pNewRange->uLast + 1;
*pcMsrRanges += 2;
}
else
{
//其他的各种情况,最终保证pNewRange加入到MSRRange里而且MSRRange是排好序的。
....
}
}
}
cpumR3MsrReconcileWithCpuId
根据CPUID信息初始化部分MSRRange,因为microcode update或者CPU配置,会改变部分MSR特性,这个函数在cpumR3InitCpuIdAndMsrs() 里调用。
int cpumR3MsrReconcileWithCpuId(PVM pVM)
{
//IA32_FLUSH_CMD
if (pVM->cpum.s.GuestFeatures.fFlushCmd && !cpumLookupMsrRange(pVM, MSR_IA32_FLUSH_CMD))
{
static CPUMMSRRANGE const s_FlushCmd =
{
/*.uFirst =*/ MSR_IA32_FLUSH_CMD,
/*.uLast =*/ MSR_IA32_FLUSH_CMD,
/*.enmRdFn =*/ kCpumMsrRdFn_WriteOnly,
/*.enmWrFn =*/ kCpumMsrWrFn_Ia32FlushCmd,
/*.offCpumCpu =*/ UINT16_MAX,
/*.fReserved =*/ 0,
/*.uValue =*/ 0,
/*.fWrIgnMask =*/ 0,
/*.fWrGpMask =*/ ~MSR_IA32_FLUSH_CMD_F_L1D,
/*.szName = */ "IA32_FLUSH_CMD"
};
papToAdd[cToAdd++] = &s_FlushCmd;
}
//MSR_IA32_ARCH_CAPABILITIES
if (pVM->cpum.s.GuestFeatures.fArchCap && !cpumLookupMsrRange(pVM, MSR_IA32_ARCH_CAPABILITIES))
{
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"
};
papToAdd[cToAdd++] = &s_ArchCaps;
}
//加入MSR Range
for (uint32_t i = 0; i < cToAdd; i++)
{
PCCPUMMSRRANGE pRange = papToAdd[i];
int rc = cpumR3MsrRangesInsert(NULL /* pVM */, &pVM->cpum.s.GuestInfo.paMsrRangesR3, &pVM->cpum.s.GuestInfo.cMsrRanges,
pRange);
}
}
cpumR3MsrApplyFudge
为了能让虚拟机能在不同CPU机器上拷贝,需要对部分MSR寄存器做模糊化处理: 如果CPU没有对应MSRRange,设置一个模糊MSRRange,这个函数在cpumR3InitCpuIdAndMsrs() 里调用。
int cpumR3MsrApplyFudge(PVM pVM)
{
/*
* Basic.
*/
static CPUMMSRRANGE const s_aFudgeMsrs[] =
{
MFO(0x00000000, "IA32_P5_MC_ADDR", Ia32P5McAddr),
MFX(0x00000001, "IA32_P5_MC_TYPE", Ia32P5McType, Ia32P5McType, 0, 0, UINT64_MAX),
MVO(0x00000017, "IA32_PLATFORM_ID", 0),
MFN(0x0000001b, "IA32_APIC_BASE", Ia32ApicBase, Ia32ApicBase),
MVI(0x0000008b, "BIOS_SIGN", 0),
MFX(0x000000fe, "IA32_MTRRCAP", Ia32MtrrCap, ReadOnly, 0x508, 0, 0),
MFX(0x00000179, "IA32_MCG_CAP", Ia32McgCap, ReadOnly, 0x005, 0, 0),
MFX(0x0000017a, "IA32_MCG_STATUS", Ia32McgStatus, Ia32McgStatus, 0, ~(uint64_t)UINT32_MAX, 0),
MFN(0x000001a0, "IA32_MISC_ENABLE", Ia32MiscEnable, Ia32MiscEnable),
MFN(0x000001d9, "IA32_DEBUGCTL", Ia32DebugCtl, Ia32DebugCtl),
MFO(0x000001db, "P6_LAST_BRANCH_FROM_IP", P6LastBranchFromIp),
MFO(0x000001dc, "P6_LAST_BRANCH_TO_IP", P6LastBranchToIp),
MFO(0x000001dd, "P6_LAST_INT_FROM_IP", P6LastIntFromIp),
MFO(0x000001de, "P6_LAST_INT_TO_IP", P6LastIntToIp),
MFS(0x00000277, "IA32_PAT", Ia32Pat, Ia32Pat, Guest.msrPAT),
MFZ(0x000002ff, "IA32_MTRR_DEF_TYPE", Ia32MtrrDefType, Ia32MtrrDefType, GuestMsrs.msr.MtrrDefType, 0, ~(uint64_t)0xc07),
MFN(0x00000400, "IA32_MCi_CTL_STATUS_ADDR_MISC", Ia32McCtlStatusAddrMiscN, Ia32McCtlStatusAddrMiscN),
};
int rc = cpumR3MsrApplyFudgeTable(pVM, &s_aFudgeMsrs[0], RT_ELEMENTS(s_aFudgeMsrs));
AssertLogRelRCReturn(rc, rc);
/*
* XP might mistake opterons and other newer CPUs for P4s.
*/
if (pVM->cpum.s.GuestFeatures.uFamily >= 0xf)
{
static CPUMMSRRANGE const s_aP4FudgeMsrs[] =
{
MFX(0x0000002c, "P4_EBC_FREQUENCY_ID", IntelP4EbcFrequencyId, IntelP4EbcFrequencyId, 0xf12010f, UINT64_MAX, 0),
};
rc = cpumR3MsrApplyFudgeTable(pVM, &s_aP4FudgeMsrs[0], RT_ELEMENTS(s_aP4FudgeMsrs));
}
if (pVM->cpum.s.GuestFeatures.fRdTscP)
{
static CPUMMSRRANGE const s_aRdTscPFudgeMsrs[] =
{
MFX(0xc0000103, "AMD64_TSC_AUX", Amd64TscAux, Amd64TscAux, 0, 0, ~(uint64_t)UINT32_MAX),
};
rc = cpumR3MsrApplyFudgeTable(pVM, &s_aRdTscPFudgeMsrs[0], RT_ELEMENTS(s_aRdTscPFudgeMsrs));
}
return rc;
}
static int cpumR3MsrApplyFudgeTable(PVM pVM, PCCPUMMSRRANGE paRanges, size_t cRanges)
{
for (uint32_t i = 0; i < cRanges; i++)
//只有MsrRange里找不到,才会insert into MSRRange,而不会替换已有的MSRRange
if (!cpumLookupMsrRange(pVM, paRanges[i].uFirst))
{
int rc = cpumR3MsrRangesInsert(NULL /* pVM */, &pVM->cpum.s.GuestInfo.paMsrRangesR3, &pVM->cpum.s.GuestInfo.cMsrRanges,
&paRanges[i]);
}
return VINF_SUCCESS;
}
cpumR3LoadMsrOverrides
根据配置里的信息,覆盖部分MSR Range,这个函数在cpumR3InitCpuIdAndMsrs() 里调用。
static int cpumR3LoadMsrOverrides(PVM pVM, PCFGMNODE pMsrNode)
{
//遍历每一个“MSRs”项的子config
for (PCFGMNODE pNode = CFGMR3GetFirstChild(pMsrNode); pNode; pNode = CFGMR3GetNextChild(pNode))
{
//获取CPUMMSRRANGE里的每一项
CPUMMSRRANGE MsrRange;
MsrRange.offCpumCpu = 0;
MsrRange.fReserved = 0;
int rc = CFGMR3GetName(pNode, MsrRange.szName, sizeof(MsrRange.szName));
rc = CFGMR3QueryU32(pNode, "First", &MsrRange.uFirst);
rc = CFGMR3QueryU32Def(pNode, "Last", &MsrRange.uLast, MsrRange.uFirst);
char szType[32];
rc = CFGMR3QueryStringDef(pNode, "Type", szType, sizeof(szType), "FixedValue");
//Type一定要是FixedValue,否则返回错误
if (!RTStrICmp(szType, "FixedValue"))
{
MsrRange.enmRdFn = kCpumMsrRdFn_FixedValue;
MsrRange.enmWrFn = kCpumMsrWrFn_IgnoreWrite;
rc = CFGMR3QueryU64Def(pNode, "Value", &MsrRange.uValue, 0);
rc = CFGMR3QueryU64Def(pNode, "WrGpMask", &MsrRange.fWrGpMask, 0);
rc = CFGMR3QueryU64Def(pNode, "WrIgnMask", &MsrRange.fWrIgnMask, 0);
}
else
return VMSetError(pVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
"Invalid MSR entry '%s': Unknown type '%s'\n", MsrRange.szName, szType);
//insert into MsrRange
rc = cpumR3MsrRangesInsert(NULL /* pVM */, &pVM->cpum.s.GuestInfo.paMsrRangesR3, &pVM->cpum.s.GuestInfo.cMsrRanges,
&MsrRange);
}
}
12.2 MSR寄存器访问
MSR read function table (VMM\VMMAll\CPUMALLMsrs.cpp)
static const PFNCPUMRDMSR g_aCpumRdMsrFns[kCpumMsrRdFn_End] =
{
NULL, /* Invalid */
cpumMsrRd_FixedValue,
NULL, /* Alias */
cpumMsrRd_WriteOnly,
cpumMsrRd_Ia32P5McAddr,
cpumMsrRd_Ia32P5McType,
}
MSR write function table
static const PFNCPUMWRMSR g_aCpumWrMsrFns[kCpumMsrWrFn_End] =
{
NULL, /* Invalid */
cpumMsrWr_IgnoreWrite,
cpumMsrWr_ReadOnly,
NULL, /* Alias */
cpumMsrWr_Ia32P5McAddr,
cpumMsrWr_Ia32P5McType,
cpumMsrWr_Ia32TimestampCounter,
}
定义了一系列函数读取/写入Guest的MSR寄存器
//IA32_VMX_PINBASED_CTLS 读取
static DECLCALLBACK(VBOXSTRICTRC) cpumMsrRd_Ia32VmxPinbasedCtls(PVMCPUCC pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t *puValue)
{
*puValue = pVCpu->cpum.s.Guest.hwvirt.vmx.Msrs.PinCtls.u;
return VINF_SUCCESS;
}
//IA32_SYSENTER_CS 读取
static DECLCALLBACK(VBOXSTRICTRC) cpumMsrRd_Ia32SysEnterCs(PVMCPUCC pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t *puValue)
{
*puValue = pVCpu->cpum.s.Guest.SysEnter.cs;
return VINF_SUCCESS;
}
//IA32_SYSENTER_CS 写入
static DECLCALLBACK(VBOXSTRICTRC) cpumMsrWr_Ia32SysEnterCs(PVMCPUCC pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t uValue, uint64_t uRawValue)
{
pVCpu->cpum.s.Guest.SysEnter.cs = uValue;
return VINF_SUCCESS;
}
...
CPUMQueryGuestMsr
VMMDECL(VBOXSTRICTRC) CPUMQueryGuestMsr(PVMCPU pVCpu, uint32_t idMsr, uint64_t *puValue)
{
//idMsr binary search 找到对应pRange
PCPUMMSRRANGE pRange = cpumLookupMsrRange(pVM, idMsr);
if(pRange)
{
CPUMMSRRDFN enmRdFn = (CPUMMSRRDFN)pRange->enmRdFn;
//调用对应msr table里的function
PFNCPUMRDMSR pfnRdMsr = g_aCpumRdMsrFns[enmRdFn];
pfnRdMsr(pVCpu, idMsr, pRange, puValue);
}
else
{
rcStrict = VERR_CPUM_RAISE_GP_0;
}
}
CPUMSetGuestMsr
VMMDECL(VBOXSTRICTRC) CPUMSetGuestMsr(PVMCPU pVCpu, uint32_t idMsr, uint64_t uValue)
{
//idMsr binary search 找到对应pRange
PCPUMMSRRANGE pRange = cpumLookupMsrRange(pVM, idMsr);
if(pRange)
{
//如果设置了某个bit写入要产生GP异常,返回VERR_CPUM_RAISE_GP_0
if (!(uValue & pRange->fWrGpMask))
{
CPUMMSRWRFN enmWrFn = (CPUMMSRWRFN)pRange->enmWrFn;
PFNCPUMWRMSR pfnWrMsr = g_aCpumWrMsrFns[enmWrFn];
//去掉需要写ignore的bit
uint64_t uValueAdjusted = uValue & ~pRange->fWrIgnMask;
//调用对应WrFn写入
rcStrict = pfnWrMsr(pVCpu, idMsr, pRange, uValueAdjusted, uValue);
}
else
{
rcStrict = VERR_CPUM_RAISE_GP_0;
}
}
else
{
//没找到对应MSR Range,返回VERR_CPUM_RAISE_GP_0
rcStrict = VERR_CPUM_RAISE_GP_0;
}
}
cpumLookupMsrRange
//binary Search,这个函数不会做模糊匹配
PCPUMMSRRANGE cpumLookupMsrRange(PVM pVM, uint32_t idMsr)
{
uint32_t cRanges = pVM->cpum.s.GuestInfo.cMsrRanges;
if (!cRanges)
return NULL;
PCPUMMSRRANGE paRanges = pVM->cpum.s.GuestInfo.CTX_SUFF(paMsrRanges);
for (;;)
{
uint32_t i = cRanges / 2;
if (idMsr < paRanges[i].uFirst)
{
if (i == 0)
break;
cRanges = i;
}
else if (idMsr > paRanges[i].uLast)
{
i++;
if (i >= cRanges)
break;
cRanges -= i;
paRanges = &paRanges[i];
}
else
{
//idMsr 处于paRanges[i].uFirst,paRanges[i].uLast中间,表示找到了,否则,返回NULL
if (paRanges[i].enmRdFn == kCpumMsrRdFn_MsrAlias)
return cpumLookupMsrRange(pVM, paRanges[i].uValue);
return &paRanges[i];
}
}
return NULL;
}