文章目录
18.1 利用APIC发送硬件中断到VCPU中
中断处理一般分成3个阶段:发送中断(保存中断信息到APIC里),获取中断(从APIC里获取一个最高优先级的中断),处理中断(设置VMCS里异常相关内容)。下面分别看看这3个类型的函数
Virtualbox在其他Manager发送中断到APIC的时候,会把中断向量先保存到APICCPU变量里的PIB内存里,APICUpdatePendingInterrupts把PIB里的中断送到APIC的IRR寄存器里排队,APICGetInterrupt从IRR里获取优先级最高的中断移动到ISR寄存器里,进入GuestOS执行中断,中断处理函数执行完毕之后,设置EOI寄存器(不是必须),然后从ISR里删除已完成的中断。
18.1.1 发送中断相关函数
apicSendIntr:
static VBOXSTRICTRC apicSendIntr(PVMCC pVM, PVMCPUCC pVCpu, uint8_t uVector, XAPICTRIGGERMODE enmTriggerMode,
XAPICDELIVERYMODE enmDeliveryMode, PCVMCPUSET pDestCpuSet, bool *pfIntrAccepted,
uint32_t uSrcTag, int rcRZ)
{
switch (enmDeliveryMode)
{
case XAPICDELIVERYMODE_FIXED:
//发送Fixed mode 中断到对应VCPU上,根据pDestCpuSet里的CPU设置,发送给目标CPU的
{
for (VMCPUID idCpu = 0; idCpu < cCpus; idCpu++)
if (VMCPUSET_IS_PRESENT(pDestCpuSet, idCpu))
{
PVMCPUCC pItVCpu = pVM->CTX_SUFF(apCpus)[idCpu];
if (APICIsEnabled(pItVCpu))
fAccepted = apicPostInterrupt(pItVCpu, uVector, enmTriggerMode, uSrcTag);
}
break;
}
case XAPICDELIVERYMODE_LOWEST_PRIO:
//发送LOWEST_PRIO mode中断
{
//找pDestCpuSet里index最小的VCPU作为目标VCPU
VMCPUID const idCpu = VMCPUSET_FIND_FIRST_PRESENT(pDestCpuSet);
PVMCPUCC pVCpuDst = pVM->CTX_SUFF(apCpus)[idCpu];
if (APICIsEnabled(pVCpuDst))
fAccepted = apicPostInterrupt(pVCpuDst, uVector, enmTriggerMode, uSrcTag);
break;
}
case XAPICDELIVERYMODE_SMI:
//SMI中断,高优先级,直接发送到pDestCpuSet对应VCPU
{
for (VMCPUID idCpu = 0; idCpu < cCpus; idCpu++)
if (VMCPUSET_IS_PRESENT(pDestCpuSet, idCpu))
{
apicSetInterruptFF(pVM->CTX_SUFF(apCpus)[idCpu], PDMAPICIRQ_SMI);
fAccepted = true;
}
break;
}
case XAPICDELIVERYMODE_NMI:
//NMI中断,高优先级,直接发送到pDestCpuSet对应VCPU
{
for (VMCPUID idCpu = 0; idCpu < cCpus; idCpu++)
if (VMCPUSET_IS_PRESENT(pDestCpuSet, idCpu))
{
PVMCPUCC pItVCpu = pVM->CTX_SUFF(apCpus)[idCpu];
if (APICIsEnabled(pItVCpu))
{
apicSetInterruptFF(pItVCpu, PDMAPICIRQ_NMI);
fAccepted = true;
}
}
break;
}
case XAPICDELIVERYMODE_INIT:
{
//ini IPI
#ifdef IN_RING3
for (VMCPUID idCpu = 0; idCpu < cCpus; idCpu++)
if (VMCPUSET_IS_PRESENT(pDestCpuSet, idCpu))
{
VMMR3SendInitIpi(pVM, idCpu);
fAccepted = true;
}
#else
rcStrict = rcRZ;
fAccepted = true;
#endif
break;
}
case XAPICDELIVERYMODE_STARTUP:
{
//startup IPI (SIPI)
#ifdef IN_RING3
for (VMCPUID idCpu = 0; idCpu < cCpus; idCpu++)
if (VMCPUSET_IS_PRESENT(pDestCpuSet, idCpu))
{
VMMR3SendStartupIpi(pVM, idCpu, uVector);
fAccepted = true;
}
#else
rcStrict = rcRZ;
fAccepted = true;
#endif
break;
}
case XAPICDELIVERYMODE_EXTINT:
//外部中断,直接发生到对应VCPU
{
for (VMCPUID idCpu = 0; idCpu < cCpus; idCpu++)
if (VMCPUSET_IS_PRESENT(pDestCpuSet, idCpu))
{
apicSetInterruptFF(pVM->CTX_SUFF(apCpus)[idCpu], PDMAPICIRQ_EXTINT);
fAccepted = true;
}
break;
}
}
apicSetInterruptFF:
设置中断标记并唤醒对应VCPU执行中断
static void apicSetInterruptFF(PVMCPUCC pVCpu, PDMAPICIRQ enmType)
{
//根据传入的中断类型设置VCPU的全局变量
switch (enmType)
{
case PDMAPICIRQ_HARDWARE:
VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC);
break;
case PDMAPICIRQ_UPDATE_PENDING: VMCPU_FF_SET(pVCpu, VMCPU_FF_UPDATE_APIC); break;
case PDMAPICIRQ_NMI: VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI); break;
case PDMAPICIRQ_SMI: VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_SMI); break;
case PDMAPICIRQ_EXTINT: VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_PIC); break;
default:
AssertMsgFailed(("enmType=%d\n", enmType));
break;
}
//唤醒target VCPU的emulation thread继续执行代码
#if defined(IN_RING0)
PVMCC pVM = pVCpu->CTX_SUFF(pVM);
VMCPUID idCpu = pVCpu->idCpu;
if ( enmType != PDMAPICIRQ_HARDWARE
&& VMMGetCpuId(pVM) != idCpu)
{
switch (VMCPU_GET_STATE(pVCpu))
{
//VCPU已经在运行GuestOS代码,Poke
case VMCPUSTATE_STARTED_EXEC:
GVMMR0SchedPokeNoGVMNoLock(pVM, idCpu);
break;
//VCPU在唤醒状态,唤醒这个VCPU
case VMCPUSTATE_STARTED_HALTED:
GVMMR0SchedWakeUpNoGVMNoLock(pVM, idCpu);
break;
default:
break; /* nothing to do in other states. */
}
}
#elif defined(IN_RING3)
if (enmType != PDMAPICIRQ_HARDWARE)
VMR3NotifyCpuFFU(pVCpu->pUVCpu, VMNOTIFYFF_FLAGS_DONE_REM | VMNOTIFYFF_FLAGS_POKE);
#endif
}
apicPostInterrupt
把一个中断vector保存在PIB里
bool apicPostInterrupt(PVMCPUCC pVCpu, uint8_t uVector, XAPICTRIGGERMODE enmTriggerMode, uint32_t uSrcTag)
{
if (RT_LIKELY(uVector > XAPIC_ILLEGAL_VECTOR_END))
{
PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
if (!apicTestVectorInReg(&pXApicPage->irr, uVector))
{
//uSrcTag保存在auSrcTags里(调试用)
if (!pApicCpu->auSrcTags[uVector])
pApicCpu->auSrcTags[uVector] = uSrcTag;
else
pApicCpu->auSrcTags[uVector] |= RT_BIT_32(31);
//edge triggle mode
if (enmTriggerMode == XAPICTRIGGERMODE_EDGE)
{
//VMCS里开启了VMX_PIN_CTLS_POSTED_INT
if (pApic->fPostedIntrsEnabled)
{ //现在什么都没做,而且VirtualBox里没有开启VMX_PIN_CTLS_POSTED_INT
}
else
{
//vector信息保存在pvApicPibRx内存里
apicSetVectorInPib(pApicCpu->CTX_SUFF(pvApicPib), uVector);
//设置有pending中断需要处理
uint32_t const fAlreadySet = apicSetNotificationBitInPib((PAPICPIB)pApicCpu->CTX_SUFF(pvApicPib));
if (!fAlreadySet)
{
apicSetInterruptFF(pVCpu, PDMAPICIRQ_UPDATE_PENDING);
}
}
}
else
{
//level triggle mode
//vector信息保存在ApicPibLevel内存里
apicSetVectorInPib(&pApicCpu->ApicPibLevel, uVector);
//设置有pending中断需要处理
uint32_t const fAlreadySet = apicSetNotificationBitInPib(&pApicCpu->ApicPibLevel);
if (!fAlreadySet)
{
apicSetInterruptFF(pVCpu, PDMAPICIRQ_UPDATE_PENDING);
}
}
}
}
}
APICLocalInterrupt
通过Local APIC的LINT0/LINT1引脚发送中断
//u8Pin : 发送给LNT0还是LINT1
//u8Level: 0表示clear 1表示set
VMM_INT_DECL(VBOXSTRICTRC) APICLocalInterrupt(PVMCPUCC pVCpu, uint8_t u8Pin, uint8_t u8Level, int rcRZ)
{
if (APICIsEnabled(pVCpu))
{
//根据u8Pin值获取对应的LVT表
static const uint16_t s_au16LvtOffsets[] =
{
XAPIC_OFF_LVT_LINT0,
XAPIC_OFF_LVT_LINT1
};
Assert(u8Pin < RT_ELEMENTS(s_au16LvtOffsets));
uint16_t const offLvt = s_au16LvtOffsets[u8Pin];
uint32_t const uLvt = apicReadRaw32(pXApicPage, offLvt);
//获取LVT里的参数
XAPICDELIVERYMODE const enmDeliveryMode = XAPIC_LVT_GET_DELIVERY_MODE(uLvt);
XAPICTRIGGERMODE enmTriggerMode = XAPIC_LVT_GET_TRIGGER_MODE(uLvt);
switch (enmDeliveryMode)
{
case XAPICDELIVERYMODE_INIT:
{
//INIT只支持发IPI
}
RT_FALL_THRU();
case XAPICDELIVERYMODE_FIXED:
{
PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
uint8_t const uVector = XAPIC_LVT_GET_VECTOR(uLvt);
bool fActive = RT_BOOL(u8Level & 1);
bool volatile *pfActiveLine = u8Pin == 0 ? &pApicCpu->fActiveLint0 : &pApicCpu->fActiveLint1;
if (!fActive)
{
ASMAtomicCmpXchgBool(pfActiveLine, false, true);
break;
}
//LINT1的中断不支持电平触发,修改成edge触发
if (offLvt == XAPIC_OFF_LVT_LINT1)
enmTriggerMode = XAPICTRIGGERMODE_EDGE;
bool fSendIntr;
if (enmTriggerMode == XAPICTRIGGERMODE_EDGE)
{
/* Recognize and send the interrupt only on an edge transition. */
fSendIntr = ASMAtomicCmpXchgBool(pfActiveLine, true, false);
}
else
{
/* For level-triggered interrupts, redundant interrupts are not a problem. */
ASMAtomicCmpXchgBool(pfActiveLine, true, false);
/* Only when the remote IRR isn't set, set it and send the interrupt. */
if (!(pXApicPage->lvt_lint0.all.u32LvtLint0 & XAPIC_LVT_REMOTE_IRR))
{
Assert(offLvt == XAPIC_OFF_LVT_LINT0);
ASMAtomicOrU32((volatile uint32_t *)&pXApicPage->lvt_lint0.all.u32LvtLint0, XAPIC_LVT_REMOTE_IRR);
fSendIntr = true;
}
else
fSendIntr = false;
}
//发送中断
if (fSendIntr)
{
VMCPUSET DestCpuSet;
VMCPUSET_EMPTY(&DestCpuSet);
VMCPUSET_ADD(&DestCpuSet, pVCpu->idCpu);
rcStrict = apicSendIntr(pVCpu->CTX_SUFF(pVM), pVCpu, uVector, enmTriggerMode, enmDeliveryMode, &DestCpuSet, NULL /* pfIntrAccepted */, 0 /* uSrcTag */, rcRZ);
}
break;
}
case XAPICDELIVERYMODE_SMI:
case XAPICDELIVERYMODE_NMI:
{
//SMI和NMI不可屏蔽中断,直接发送到目标VCPU
VMCPUSET DestCpuSet;
VMCPUSET_EMPTY(&DestCpuSet);
VMCPUSET_ADD(&DestCpuSet, pVCpu->idCpu);
uint8_t const uVector = XAPIC_LVT_GET_VECTOR(uLvt);
rcStrict = apicSendIntr(pVCpu->CTX_SUFF(pVM), pVCpu, uVector, enmTriggerMode, enmDeliveryMode, &DestCpuSet,NULL /* pfIntrAccepted */, 0 /* uSrcTag */, rcRZ);
break;
}
case XAPICDELIVERYMODE_EXTINT:
{
if (u8Level) //set
apicSetInterruptFF(pVCpu, PDMAPICIRQ_EXTINT);
else //clear
apicClearInterruptFF(pVCpu, PDMAPICIRQ_EXTINT);
break;
}
//不接受的参数
case XAPICDELIVERYMODE_LOWEST_PRIO:
case XAPICDELIVERYMODE_STARTUP:
default:
{
rcStrict = VERR_INTERNAL_ERROR_3;
break;
}
}
else
{
//APIC disable,说明该中断是从是从PIC设备发送来的
if (u8Pin == 0)
{
//LINT0 当作外部中断处理
if (u8Level) //set
apicSetInterruptFF(pVCpu, PDMAPICIRQ_EXTINT);
else //clear
apicClearInterruptFF(pVCpu, PDMAPICIRQ_EXTINT);
}
else
{
//LINT1当时NMI来处理
apicSetInterruptFF(pVCpu, PDMAPICIRQ_NMI);
}
}
}
APICBusDeliver
通过bus总线发送中断
VMM_INT_DECL(int) APICBusDeliver(PVMCC pVM, uint8_t uDest, uint8_t uDestMode, uint8_t uDeliveryMode, uint8_t uVector,
uint8_t uPolarity, uint8_t uTriggerMode, uint32_t uSrcTag)
{
XAPICTRIGGERMODE enmTriggerMode = (XAPICTRIGGERMODE)uTriggerMode;
XAPICDELIVERYMODE enmDeliveryMode = (XAPICDELIVERYMODE)uDeliveryMode;
XAPICDESTMODE enmDestMode = (XAPICDESTMODE)uDestMode;
uint32_t fDestMask = uDest;
uint32_t fBroadcastMa sk = UINT32_C(0xff);
bool fIntrAccepted;
VMCPUSET DestCpuSet;
apicGetDestCpuSet(pVM, fDestMask, fBroadcastMask, enmDestMode, enmDeliveryMode, &DestCpuSet);
//发送中断到指定VCPU
VBOXSTRICTRC rcStrict = apicSendIntr(pVM, NULL /* pVCpu */, uVector, enmTriggerMode, enmDeliveryMode, &DestCpuSet,
&fIntrAccepted, uSrcTag, VINF_SUCCESS /* rcRZ */);
if (fIntrAccepted)
return VBOXSTRICTRC_VAL(rcStrict);
return VERR_APIC_INTR_DISCARDED;
}
18.1.2 获取中断
APICGetInterrupt
获取pending队列里最高优先级的中断
VMM_INT_DECL(int) APICGetInterrupt(PVMCPUCC pVCpu, uint8_t *pu8Vector, uint32_t *puSrcTag)
{
PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
bool const fApicHwEnabled = APICIsEnabled(pVCpu);
//如果开启了软件和硬件中断
if ( fApicHwEnabled
&& pXApicPage->svr.u.fApicSoftwareEnable)
{
//获取IRR队列里最高优先级的中断
int const irrv = apicGetHighestSetBitInReg(&pXApicPage->irr, -1);
uint8_t const uVector = irrv;
//如果被选择的中断优先级小于等于当前VCPU设置的中断级,中断被屏蔽,返回错误
uint8_t const uTpr = pXApicPage->tpr.u8Tpr;
if ( uTpr > 0
&& XAPIC_TPR_GET_TP(uVector) <= XAPIC_TPR_GET_TP(uTpr))
{
*pu8Vector = uVector;
*puSrcTag = 0;
return VERR_APIC_INTR_MASKED_BY_TPR;
}
//打断当前正在运行的任务
uint8_t const uPpr = pXApicPage->ppr.u8Ppr;
if ( !uPpr
|| XAPIC_PPR_GET_PP(uVector) > XAPIC_PPR_GET_PP(uPpr))
{
//被选中CPU调度到ISR中
//从IRR里清除
apicClearVectorInReg(&pXApicPage->irr, uVector);
//加入ISR
apicSetVectorInReg(&pXApicPage->isr, uVector);
//更新Ppr
apicUpdatePpr(pVCpu);
//如果IRR还有中断没有处理,设置Guest VCPU状态有中断已经准备好运行
apicSignalNextPendingIntr(pVCpu);
/* Retrieve the interrupt source tag associated with this interrupt. */
PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
*puSrcTag = pApicCpu->auSrcTags[uVector];
pApicCpu->auSrcTags[uVector] = 0;
*pu8Vector = uVector;
return VINF_SUCCESS;
}
}
}
18.1.3 处理中断
APICUpdatePendingInterrupts
把中断从PIB里更新到IRR里
VMMDECL(void) APICUpdatePendingInterrupts(PVMCPUCC pVCpu)
{
PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
//是否有edge-triggered pending interrupts
//获取edge-triggered中断到PIB
PAPICPIB pPib = (PAPICPIB)pApicCpu->CTX_SUFF(pvApicPib);
for (;;)
{
//clear PIB notification bit,表示已经处理过了
uint32_t const fAlreadySet = apicClearNotificationBitInPib((PAPICPIB)pApicCpu->CTX_SUFF(pvApicPib));
if (!fAlreadySet)
break;
//遍历PIB里的每一项
for (size_t idxPib = 0, idxReg = 0; idxPib < RT_ELEMENTS(pPib->au64VectorBitmap); idxPib++, idxReg += 2)
{
//读取vector
uint64_t const u64Fragment = ASMAtomicXchgU64(&pPib->au64VectorBitmap[idxPib], 0);
if (u64Fragment)
{
uint32_t const u32FragmentLo = RT_LO_U32(u64Fragment);
uint32_t const u32FragmentHi = RT_HI_U32(u64Fragment);
//赋值到IRR对应的项
pXApicPage->irr.u[idxReg].u32Reg |= u32FragmentLo;
pXApicPage->irr.u[idxReg + 1].u32Reg |= u32FragmentHi;
//同时需要更新到tmr中
pXApicPage->tmr.u[idxReg].u32Reg &= ~u32FragmentLo;
pXApicPage->tmr.u[idxReg + 1].u32Reg &= ~u32FragmentHi;
fHasPendingIntrs = true;
}
}
}
//是否有level-triggered pending interrupts,ApicPibLevel里保存了level-triggered的PIB
pPib = (PAPICPIB)&pApicCpu->ApicPibLevel;
for (;;)
{
//clear PIB notification bit,表示已经处理过了
uint32_t const fAlreadySet = apicClearNotificationBitInPib((PAPICPIB)&pApicCpu->ApicPibLevel);
if (!fAlreadySet)
break;
for (size_t idxPib = 0, idxReg = 0; idxPib < RT_ELEMENTS(pPib->au64VectorBitmap); idxPib++, idxReg += 2)
{
//读取vector
uint64_t const u64Fragment = ASMAtomicXchgU64(&pPib->au64VectorBitmap[idxPib], 0);
if (u64Fragment)
{
uint32_t const u32FragmentLo = RT_LO_U32(u64Fragment);
uint32_t const u32FragmentHi = RT_HI_U32(u64Fragment);
//写入irr和tmr对应项
pXApicPage->irr.u[idxReg].u32Reg |= u32FragmentLo;
pXApicPage->irr.u[idxReg + 1].u32Reg |= u32FragmentHi;
pXApicPage->tmr.u[idxReg].u32Reg |= u32FragmentLo;
pXApicPage->tmr.u[idxReg + 1].u32Reg |= u32FragmentHi;
fHasPendingIntrs = true;
}
}
}
//如果发现有中断没有处理,选择一个最高优先级的中断,发送给VCPU处理
if ( fHasPendingIntrs
&& !VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC))
apicSignalNextPendingIntr(pVCpu);
}
hmR0VmxEvaluatePendingEvent
在进入GuestOS之前,查询是否有pending的event需要发送个GuestOS,如果有,则设置VMCS里相关项发送中断到GuestOS里
static VBOXSTRICTRC hmR0VmxEvaluatePendingEvent(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t *pfIntrState)
{
*pfIntrState = hmR0VmxGetGuestIntrStateAndUpdateFFs(pVCpu);
PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
bool const fIsNestedGuest = pVmxTransient->fIsNestedGuest;
if ( !pVCpu->hm.s.Event.fPending
&& !VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
{
//先查询高优先级的中断
//NMI
PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI))
{
if (!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_BLOCK_NMIS))
{
//在VMCS里设置pending Nmi中断信息
hmR0VmxSetPendingXcptNmi(pVCpu);
//去掉NMI中断标记
VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
return VINF_SUCCESS;
}
else if (!fIsNestedGuest)
hmR0VmxSetNmiWindowExitVmcs(pVCpu, pVmcsInfo);
}
//PIC/APIC中断
if ( VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)
&& !pVCpu->hm.s.fSingleInstruction)
{
//获取rflags值
int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_RFLAGS);
//是否开启了中断
if (pCtx->eflags.u32 & X86_EFL_IF)
{
//获取优先级最高的中断
uint8_t u8Interrupt;
rc = PDMGetInterrupt(pVCpu, &u8Interrupt);
if (RT_SUCCESS(rc))
{
//设置VMCS项发送对应中断到GuestOS里
hmR0VmxSetPendingExtInt(pVCpu, u8Interrupt);
}
else if (rc == VERR_APIC_INTR_MASKED_BY_TPR)
{
//中断被屏蔽了,设置TPR threshold
if ( !fIsNestedGuest
&& (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW))
hmR0VmxApicSetTprThreshold(pVmcsInfo, u8Interrupt >> 4);
}
}
}
else if (!fIsNestedGuest)
//发送interrupt-window中断,让GuestOS立刻触发一个收到中断的vmexit
hmR0VmxSetIntWindowExitVmcs(pVCpu, pVmcsInfo);
}
else if (!fIsNestedGuest)
{
if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI))
//发送NMI-window中断,让GuestOS立刻触发一个收到nmi中断的vmexit
hmR0VmxSetNmiWindowExitVmcs(pVCpu, pVmcsInfo);
else if ( VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)
&& !pVCpu->hm.s.fSingleInstruction)
//fSingleInstruction = false表示是在连续模拟执行多条指令中间发生异常
hmR0VmxSetIntWindowExitVmcs(pVCpu, pVmcsInfo);
}
}
//设置VMCS里的 TPR threshold,当当前TPR大于 TPR threhold的时候,会触发VMExit
DECLINLINE(void) hmR0VmxApicSetTprThreshold(PVMXVMCSINFO pVmcsInfo, uint32_t u32TprThreshold)
{
int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_TPR_THRESHOLD, u32TprThreshold);
}
18.2 IPI中断相关函数
vmmR3SendInitIpi
CPU加电之后会发送 Startup IPI中断,处理函数是vmmR3SendInitIpi
static DECLCALLBACK(int) vmmR3SendInitIpi(PVM pVM, VMCPUID idCpu)
{
//CPU被重置,调用所有Manager里的resetcpu函数
PGMR3ResetCpu(pVM, pVCpu);
PDMR3ResetCpu(pVCpu);
APICR3InitIpi(pVCpu);
TRPMR3ResetCpu(pVCpu);
CPUMR3ResetCpu(pVM, pVCpu);
EMR3ResetCpu(pVCpu);
HMR3ResetCpu(pVCpu);
NEMR3ResetCpu(pVCpu, true /*fInitIpi*/);
}
APICR3InitIpi
初始化所有APIC寄存器
void apicInitIpi(PVMCPUCC pVCpu)
{
//所有APIC寄存器全部设置成初始状态
RT_ZERO(pXApicPage->irr);
RT_ZERO(pXApicPage->irr);
RT_ZERO(pXApicPage->isr);
...
//lvt清空
RT_ZERO(pXApicPage->lvt_timer);
//u1Mask = 1表示屏蔽中断
pXApicPage->lvt_timer.u.u1Mask = 1;
RT_ZERO(pXApicPage->lvt_perf);
pXApicPage->lvt_perf.u.u1Mask = 1;
..
//reset self-ipi寄存器
RT_ZERO(pX2ApicPage->self_ipi);
//clear pib
RT_BZERO(&pApicCpu->ApicPibLevel, sizeof(APICPIB));
RT_BZERO(pApicCpu->CTX_SUFF(pvApicPib), sizeof(APICPIB));
pApicCpu->fActiveLint0 = false;
pApicCpu->fActiveLint1 = false;
}
apicSendIpi
通过Interrupt Command Register (ICR).向其他核发送IPI中断
DECLINLINE(VBOXSTRICTRC) apicSendIpi(PVMCPUCC pVCpu, int rcRZ)
{
//获取ICR里的异常信息 (具体信息可以参考16.2节中的LVT中断向量表的描述)
XAPICDELIVERYMODE const enmDeliveryMode = (XAPICDELIVERYMODE)pXApicPage->icr_lo.u.u3DeliveryMode;
XAPICDESTMODE const enmDestMode = (XAPICDESTMODE)pXApicPage->icr_lo.u.u1DestMode;
XAPICINITLEVEL const enmInitLevel = (XAPICINITLEVEL)pXApicPage->icr_lo.u.u1Level;
XAPICTRIGGERMODE const enmTriggerMode = (XAPICTRIGGERMODE)pXApicPage->icr_lo.u.u1TriggerMode;
XAPICDESTSHORTHAND const enmDestShorthand = (XAPICDESTSHORTHAND)pXApicPage->icr_lo.u.u2DestShorthand;
//中断向量表
uint8_t const uVector = pXApicPage->icr_lo.u.u8Vector;
//根据enmDestShorthand,决定发送给哪些VCPU
VMCPUSET DestCpuSet;
switch (enmDestShorthand)
{
case XAPICDESTSHORTHAND_NONE:
{
PVMCC pVM = pVCpu->CTX_SUFF(pVM);
uint32_t const fBroadcastMask = XAPIC_IN_X2APIC_MODE(pVCpu) ? X2APIC_ID_BROADCAST_MASK : XAPIC_ID_BROADCAST_MASK;
//使用enmDestMode和fDest决定发送给哪些CPU
apicGetDestCpuSet(pVM, fDest, fBroadcastMask, enmDestMode, enmDeliveryMode, &DestCpuSet);
break;
}
case XAPICDESTSHORTHAND_SELF:
{
//只发送给当前VCPU
VMCPUSET_EMPTY(&DestCpuSet);
VMCPUSET_ADD(&DestCpuSet, pVCpu->idCpu);
break;
}
case XAPIDDESTSHORTHAND_ALL_INCL_SELF:
{
//发送给所有VCPU包括自己
VMCPUSET_FILL(&DestCpuSet);
break;
}
case XAPICDESTSHORTHAND_ALL_EXCL_SELF:
{
//发送给所有VCPU不包括自己
VMCPUSET_FILL(&DestCpuSet);
VMCPUSET_DEL(&DestCpuSet, pVCpu->idCpu);
break;
}
}
//发送中断到目标VCPU
return apicSendIntr(pVCpu->CTX_SUFF(pVM), pVCpu, uVector, enmTriggerMode, enmDeliveryMode, &DestCpuSet,
NULL /* pfIntrAccepted */, 0 /* uSrcTag */, rcRZ);
}
apicGetDestCpuSet:
决定IPI发送给哪些VCPU
static void apicGetDestCpuSet(PVMCC pVM, uint32_t fDestMask, uint32_t fBroadcastMask, XAPICDESTMODE enmDestMode,
XAPICDELIVERYMODE enmDeliveryMode, PVMCPUSET pDestCpuSet)
{
//Physical Destination Mode 不支持最低优先级传输模式启动的中断
if ( enmDestMode == XAPICDESTMODE_PHYSICAL
&& enmDeliveryMode == XAPICDELIVERYMODE_LOWEST_PRIO)
{
//修改传送模式成Fixed模式
enmDeliveryMode = XAPICDELIVERYMODE_FIXED;
}
//最低优先级传送模式
if (enmDeliveryMode == XAPICDELIVERYMODE_LOWEST_PRIO)
{
//必须是logical model
Assert(enmDestMode == XAPICDESTMODE_LOGICAL);
VMCPUID idCpuLowestTpr = NIL_VMCPUID;
uint8_t u8LowestTpr = UINT8_C(0xff);
//遍历每个VCPU,找到优先级(TPR)最低的那个VCPU
for (VMCPUID idCpu = 0; idCpu < cCpus; idCpu++)
{
PVMCPUCC pVCpuDst = pVM->CTX_SUFF(apCpus)[idCpu];
if (apicIsLogicalDest(pVCpuDst, fDestMask))
{
PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpuDst);
//获取当前VCPU的APIC Page 的TPR(当前优先级)
uint8_t const u8Tpr = pXApicPage->tpr.u8Tpr;
if (u8Tpr <= u8LowestTpr)
{
u8LowestTpr = u8Tpr;
idCpuLowestTpr = idCpu;
}
}
}
//发送给最低优先级的那个VCPU
if (idCpuLowestTpr != NIL_VMCPUID)
VMCPUSET_ADD(pDestCpuSet, idCpuLowestTpr);
return;
}
//广播
if ((fDestMask & fBroadcastMask) == fBroadcastMask)
{
VMCPUSET_FILL(pDestCpuSet);
return;
}
if (enmDestMode == XAPICDESTMODE_PHYSICAL)
{
//Physical Destination Mode 根据DestMask设置对应到目录CPU
if (RT_LIKELY(fDestMask < cCpus))
VMCPUSET_ADD(pDestCpuSet, fDestMask);
}
else
{
//Logical Destination Mode需要根据LDR和DFR寄存器决定发送给哪些CPU
for (VMCPUID idCpu = 0; idCpu < cCpus; idCpu++)
{
PVMCPUCC pVCpuDst = pVM->CTX_SUFF(apCpus)[idCpu];
if (apicIsLogicalDest(pVCpuDst, fDestMask))
VMCPUSET_ADD(pDestCpuSet, pVCpuDst->idCpu);
}
}
}
static bool apicIsLogicalDest(PVMCPUCC pVCpu, uint32_t fDest)
{
if (XAPIC_IN_X2APIC_MODE(pVCpu))
{
//x2APIC模式不支持Flat logical mode
//clustered logical mode
//根据fDest,LDR寄存器的低16位值确定目标CPU, LDR的高16位是clusterID,必须和fDest里的clusterID相同
PCX2APICPAGE pX2ApicPage = VMCPU_TO_CX2APICPAGE(pVCpu);
uint32_t const u32Ldr = pX2ApicPage->ldr.u32LogicalApicId;
if (X2APIC_LDR_GET_CLUSTER_ID(u32Ldr) == (fDest & X2APIC_LDR_CLUSTER_ID))
return RT_BOOL(u32Ldr & fDest & X2APIC_LDR_LOGICAL_ID);
return false;
}
//xAPIC模式
//广播,全返回true
if ((fDest & XAPIC_LDR_FLAT_LOGICAL_ID) == XAPIC_LDR_FLAT_LOGICAL_ID)
return true;
PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
//从DFR寄存器里获取是flat还是cluster model
XAPICDESTFORMAT enmDestFormat = (XAPICDESTFORMAT)pXApicPage->dfr.u.u4Model;
if (enmDestFormat == XAPICDESTFORMAT_FLAT)
{
//根据fDest,LDR寄存器的24到31位值确定目标CPU
uint8_t const u8Ldr = pXApicPage->ldr.u.u8LogicalApicId;
return RT_BOOL(u8Ldr & fDest & XAPIC_LDR_FLAT_LOGICAL_ID);
}
//cluster model
uint8_t const u8Ldr = pXApicPage->ldr.u.u8LogicalApicId;
//根据fDest,LDR寄存器的28到21位值确定目标CPU, LDR的24到27位是clusterID,必须和fDest里的clusterID相同
if (XAPIC_LDR_CLUSTERED_GET_CLUSTER_ID(u8Ldr) == (fDest & XAPIC_LDR_CLUSTERED_CLUSTER_ID))
return RT_BOOL(u8Ldr & fDest & XAPIC_LDR_CLUSTERED_LOGICAL_ID);
return false;
}
参考资料:
https://blog.csdn.net/omnispace/article/details/61415994
Intel指令手册