赞
踩
VirtualBox里,把APIC作为一个R0的PNP设备来模拟:
const PDMDEVREG g_DeviceAPIC = { /* .u32Version = */ PDM_DEVREG_VERSION, /* .uReserved0 = */ 0, /* .szName = */ "apic", /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE | PDM_DEVREG_FLAGS_REQUIRE_R0 | PDM_DEVREG_FLAGS_REQUIRE_RC, /* .fClass = */ PDM_DEVREG_CLASS_PIC, /* .cMaxInstances = */ 1, /* .uSharedVersion = */ 42, /* .cbInstanceShared = */ sizeof(APICDEV), /* .cbInstanceCC = */ 0, /* .cbInstanceRC = */ 0, /* .cMaxPciDevices = */ 0, /* .cMaxMsixVectors = */ 0, /* .pszDescription = */ "Advanced Programmable Interrupt Controller", #if defined(IN_RING3) /* .szRCMod = */ "VMMRC.rc", /* .szR0Mod = */ "VMMR0.r0", /* .pfnConstruct = */ apicR3Construct, /* .pfnDestruct = */ apicR3Destruct, /* .pfnRelocate = */ apicR3Relocate, /* .pfnMemSetup = */ NULL, /* .pfnPowerOn = */ NULL, /* .pfnReset = */ apicR3Reset, /* .pfnSuspend = */ NULL, /* .pfnResume = */ NULL, /* .pfnAttach = */ NULL, /* .pfnDetach = */ NULL, /* .pfnQueryInterface = */ NULL, /* .pfnInitComplete = */ apicR3InitComplete, /* .pfnPowerOff = */ NULL, .... #elif defined(IN_RING0) /* .pfnEarlyConstruct = */ NULL, /* .pfnConstruct = */ apicRZConstruct, /* .pfnDestruct = */ NULL, /* .pfnFinalDestruct = */ NULL, /* .pfnRequest = */ NULL, ... #elif defined(IN_RC) /* .pfnConstruct = */ apicRZConstruct, ... #else # error "Not in IN_RING3, IN_RING0 or IN_RC!" #endif /* .u32VersionEnd = */ PDM_DEVREG_VERSION };
并且在PDMR0Init初始化的时候加入到g_PDMDevModList里,PDMR0DeviceCreateReqHandler函数会遍历g_PDMDevModList,create APIC devices。(虚拟机设备的创建过程在PDM一章里说明)
static const PDMDEVREGR0 *g_apVMM0DevRegs[] = { &g_DeviceAPIC, }; /** * Module device registration record for VMMR0. */ static PDMDEVMODREGR0 g_VBoxDDR0ModDevReg = { /* .u32Version = */ PDM_DEVMODREGR0_VERSION, /* .cDevRegs = */ RT_ELEMENTS(g_apVMM0DevRegs), /* .papDevRegs = */ &g_apVMM0DevRegs[0], /* .hMod = */ NULL, /* .ListEntry = */ { NULL, NULL }, }; VMMR0_INT_DECL(void) PDMR0Init(void *hMod) { RTListInit(&g_PDMDevModList); g_VBoxDDR0ModDevReg.hMod = hMod; RTListAppend(&g_PDMDevModList, &g_VBoxDDR0ModDevReg.ListEntry); }
实现代码在VMM\VMMAlll\APICAll.cpp,VMM\VMMR3\APIC.cpp中
R3的初始化函数
DECLCALLBACK(int) apicR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg) { //读取配置,是否支持IOAPIC int rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "IOAPIC", &pApic->fIoApicPresent, true); //获取MAX APIC模式 uint8_t uMaxMode; rc = pHlp->pfnCFGMQueryU8Def(pCfg, "Mode", &uMaxMode, PDMAPICMODE_APIC); switch ((PDMAPICMODE)uMaxMode) { case PDMAPICMODE_NONE: case PDMAPICMODE_APIC: case PDMAPICMODE_X2APIC: break; default: return VMR3SetError(pVM->pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS, "APIC mode %d unknown.", uMaxMode); } pApic->enmMaxMode = (PDMAPICMODE)uMaxMode; //向PNP设备管理器里注册APIC设备 rc = PDMDevHlpApicRegister(pDevIns); //如果支持x2APIC,加入x2APIC对应的MSR寄存器到MSRRange数组里 if (pApic->enmMaxMode == PDMAPICMODE_X2APIC) { rc = CPUMR3MsrRangesInsert(pVM, &g_MsrRange_x2Apic); AssertLogRelRCReturn(rc, rc); } else { //不支持x2APIC,加入一个会产生GP的handle rc = CPUMR3MsrRangesInsert(pVM, &g_MsrRange_x2Apic_Invalid); AssertLogRelRCReturn(rc, rc); } apicR3SetCpuIdFeatureLevel(pVM, pApic->enmMaxMode); //初始化APIC的相关数据 rc = apicR3InitState(pVM); //注册MMIO范围,GCPhysApicBase开头的XAPICPAGE结构体大小都是MMIO地址 //APIC内存的读写调用到apicWriteMmio/apicReadMmio这两个函数 PAPICCPU pApicCpu0 = VMCPU_TO_APICCPU(pVM->apCpusR3[0]); RTGCPHYS GCPhysApicBase = MSR_IA32_APICBASE_GET_ADDR(pApicCpu0->uApicBaseMsr); rc = PDMDevHlpMmioCreateAndMap(pDevIns, GCPhysApicBase, sizeof(XAPICPAGE), apicWriteMmio, apicReadMmio, IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_DWORD_ZEROED, "APIC", &pApicDev->hMmio); //给每个VCPU 创建APIC timer for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++) { PVMCPU pVCpu = pVM->apCpusR3[idCpu]; PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu); rc = PDMDevHlpTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, apicR3TimerCallback, pVCpu, TMTIMER_FLAGS_NO_CRIT_SECT, pApicCpu->szTimerDesc, &pApicCpu->hTimer); } //注册SSM的callback rc = PDMDevHlpSSMRegister(pDevIns, APIC_SAVED_STATE_VERSION, sizeof(*pApicDev), apicR3SaveExec, apicR3LoadExec); }
//APIC Pending-Interrupt Bitmap (PIB). 里面保存了所有pending的中断 //pending的中断有两种类型,一种是edge trigglemode,一种是level trigglemode typedef struct APICPIB { uint64_t volatile au64VectorBitmap[4]; uint32_t volatile fOutstandingNotification; uint8_t au8Reserved[APIC_CACHE_LINE_SIZE - sizeof(uint32_t) - (sizeof(uint64_t) * 4)]; } APICPIB; static int apicR3InitState(PVM pVM) { //分配保存edge trigglemode用的内存,这个内存同时映射到R0和R3 //计算需要多少个页面,每个VCPU都有自己的PIB pApic->cbApicPib = RT_ALIGN_Z(pVM->cCpus * sizeof(APICPIB), PAGE_SIZE); size_t const cPages = pApic->cbApicPib >> PAGE_SHIFT; if (cPages == 1) { SUPPAGE SupApicPib; RT_ZERO(SupApicPib); SupApicPib.Phys = NIL_RTHCPHYS; //分配1个page大小的页面 int rc = SUPR3PageAllocEx(1 /* cPages */, 0 /* fFlags */, &pApic->pvApicPibR3, &pApic->pvApicPibR0, &SupApicPib); if (RT_SUCCESS(rc)) { pApic->HCPhysApicPib = SupApicPib.Phys; } } else //分配物理地址连续的cPage大小页面 pApic->pvApicPibR3 = SUPR3ContAlloc(cPages, &pApic->pvApicPibR0, &pApic->HCPhysApicPib); if (pApic->pvApicPibR3) { RT_BZERO(pApic->pvApicPibR3, pApic->cbApicPib); for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++) { //给每个VCPU分配申请一个Virtual APIC page SUPPAGE SupApicPage; RT_ZERO(SupApicPage); SupApicPage.Phys = NIL_RTHCPHYS; pApicCpu->cbApicPage = sizeof(XAPICPAGE); int rc = SUPR3PageAllocEx(1 /* cPages */, 0 /* fFlags */, &pApicCpu->pvApicPageR3, &pApicCpu->pvApicPageR0, &SupApicPage); if (RT_SUCCESS(rc)) { pApicCpu->HCPhysApicPage = SupApicPage.Phys; //根据CPUID获取自己的PIB内存地址 uint32_t const offApicPib = idCpu * sizeof(APICPIB); pApicCpu->pvApicPibR0 = (RTR0PTR)((RTR0UINTPTR)pApic->pvApicPibR0 + offApicPib); pApicCpu->pvApicPibR3 = (RTR3PTR)((RTR3UINTPTR)pApic->pvApicPibR3 + offApicPib); //初始化APIC RT_BZERO(pApicCpu->pvApicPageR3, pApicCpu->cbApicPage); apicResetCpu(pVCpu, true /* fResetApicBaseMsr */); } } } }
R0的设备初始化函数
static DECLCALLBACK(int) apicRZConstruct(PPDMDEVINS pDevIns) { PAPICDEV pThis = PDMDEVINS_2_DATA(pDevIns, PAPICDEV); PVMCC pVM = PDMDevHlpGetVM(pDevIns); pVM->apicr0.s.pDevInsR0 = pDevIns; int rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns)); //设置APIC设备 rc = PDMDevHlpApicSetUpContext(pDevIns); //设置MMIO内存读写的callback函数 rc = PDMDevHlpMmioSetUpContext(pDevIns, pThis->hMmio, apicWriteMmio, apicReadMmio, NULL /*pvUser*/); return VINF_SUCCESS; } static DECLCALLBACK(int) pdmR0DevHlp_ApicSetUpContext(PPDMDEVINS pDevIns) { pGVM->pdm.s.Apic.pDevInsR0 = pDevIns; return VINF_SUCCESS; } static DECLCALLBACK(int) pdmR0DevHlp_MmioSetUpContextEx(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, PFNIOMMMIONEWWRITE pfnWrite, PFNIOMMMIONEWREAD pfnRead, PFNIOMMMIONEWFILL pfnFill, void *pvUser) { PGVM pGVM = pDevIns->Internal.s.pGVM; //调用IOM里的函数设置mmio内存对应的read/write的函数 int rc = IOMR0MmioSetUpContext(pGVM, pDevIns, hRegion, pfnWrite, pfnRead, pfnFill, pvUser); return rc; }
R3的重置函数
DECLCALLBACK(void) apicR3Reset(PPDMDEVINS pDevIns) { for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++) { PVMCPU pVCpuDest = pVM->apCpusR3[idCpu]; PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpuDest); //如果当前CPU开启了APIC timer,先停掉timer if (PDMDevHlpTimerIsActive(pDevIns, pApicCpu->hTimer)) PDMDevHlpTimerStop(pDevIns, pApicCpu->hTimer); apicResetCpu(pVCpuDest, true /* fResetApicBaseMsr */); //clear APIC相关的中断信息 apicClearInterruptFF(pVCpuDest, PDMAPICIRQ_HARDWARE); } } //重新初始化每个APIC CPU void apicResetCpu(PVMCPUCC pVCpu, bool fResetApicBaseMsr) { //初始化Ipi apicInitIpi(pVCpu); PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu); pXApicPage->version.u.u8MaxLvtEntry = XAPIC_MAX_LVT_ENTRIES_P4 - 1; pXApicPage->version.u.u8Version = XAPIC_HARDWARE_VERSION_P4; if (fResetApicBaseMsr) apicResetBaseMsr(pVCpu); pXApicPage->id.u8ApicId = pVCpu->idCpu; } //重置APICBase MSR的值,其实就是保存到ApicCPU的全局变量里 static void apicResetBaseMsr(PVMCPUCC pVCpu) { PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu); PAPIC pApic = VM_TO_APIC(pVCpu->CTX_SUFF(pVM)); //msrbase设置成默认值(fee00000) uint64_t uApicBaseMsr = MSR_IA32_APICBASE_ADDR; //0号CPU设置成启动的核: BSP: the bootstrap processor if (pVCpu->idCpu == 0) uApicBaseMsr |= MSR_IA32_APICBASE_BSP; //非APICMODE_NONE,表示开启了LAPIC if (pApic->enmMaxMode != PDMAPICMODE_NONE) { //设置APICBASE enable uApicBaseMsr |= MSR_IA32_APICBASE_EN; //设置CPUM CPUMSetGuestCpuIdPerCpuApicFeature(pVCpu, true /*fVisible*/); } //设置ApicBase到ApicCpu中 ASMAtomicWriteU64(&pApicCpu->uApicBaseMsr, uApicBaseMsr); }
//释放掉apicR3InitState里申请的内存 static void apicR3TermState(PVM pVM) { //释放PIB内存 if (pApic->pvApicPibR3 != NIL_RTR3PTR) { size_t const cPages = pApic->cbApicPib >> PAGE_SHIFT; if (cPages == 1) SUPR3PageFreeEx(pApic->pvApicPibR3, cPages); else SUPR3ContFree(pApic->pvApicPibR3, cPages); pApic->pvApicPibR3 = NIL_RTR3PTR; pApic->pvApicPibR0 = NIL_RTR0PTR; } //释放Virtual APIC page for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++) { PVMCPU pVCpu = pVM->apCpusR3[idCpu]; PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu); pApicCpu->pvApicPibR3 = NIL_RTR3PTR; pApicCpu->pvApicPibR0 = NIL_RTR0PTR; if (pApicCpu->pvApicPageR3 != NIL_RTR3PTR) { SUPR3PageFreeEx(pApicCpu->pvApicPageR3, 1 /* cPages */); pApicCpu->pvApicPageR3 = NIL_RTR3PTR; pApicCpu->pvApicPageR0 = NIL_RTR0PTR; } } }
VMM_INT_DECL(int) APICSetBaseMsr(PVMCPUCC pVCpu, uint64_t u64BaseMsr) { APICMODE enmOldMode = apicGetMode(pApicCpu->uApicBaseMsr); APICMODE enmNewMode = apicGetMode(u64BaseMsr); uint64_t uBaseMsr = pApicCpu->uApicBaseMsr; //如果修改了APIC模式 if (enmNewMode != enmOldMode) { switch (enmNewMode) { //关闭APIC case APICMODE_DISABLED: { //重置APIC CPU信息 apicResetCpu(pVCpu, false /* fResetApicBaseMsr */); uBaseMsr &= ~(MSR_IA32_APICBASE_EN | MSR_IA32_APICBASE_EXTD); //通知CPUM APIC已被关闭 CPUMSetGuestCpuIdPerCpuApicFeature(pVCpu, false /*fVisible*/); break; } //切换成xAPIC case APICMODE_XAPIC: { //只能从disable模式切换到xAPIC模式 if (enmOldMode != APICMODE_DISABLED) { return apicMsrAccessError(pVCpu, MSR_IA32_APICBASE, APICMSRACCESS_WRITE_INVALID); } uBaseMsr |= MSR_IA32_APICBASE_EN; //设置开启APIC CPUMSetGuestCpuIdPerCpuApicFeature(pVCpu, true /*fVisible*/); break; } case APICMODE_X2APIC: { //配置不支持x2APIC,返回错误 if (pApic->enmMaxMode != PDMAPICMODE_X2APIC) { return apicMsrAccessError(pVCpu, MSR_IA32_APICBASE, APICMSRACCESS_WRITE_INVALID); } //只能从xAPIC模式切换到x2APIC模式 if (enmOldMode != APICMODE_XAPIC) { return apicMsrAccessError(pVCpu, MSR_IA32_APICBASE, APICMSRACCESS_WRITE_INVALID); } uBaseMsr |= MSR_IA32_APICBASE_EN | MSR_IA32_APICBASE_EXTD; //u32ApicId设置成当前VCPUID,x2APIC不支持软件设置APIC ID PX2APICPAGE pX2ApicPage = VMCPU_TO_X2APICPAGE(pVCpu); ASMMemZero32(&pX2ApicPage->id, sizeof(pX2ApicPage->id)); pX2ApicPage->id.u32ApicId = pVCpu->idCpu; //LDR initialization occurs when entering x2APIC mode. pX2ApicPage->ldr.u32LogicalApicId = ((pX2ApicPage->id.u32ApicId & UINT32_C(0xffff0)) << 16) | (UINT32_C(1) << pX2ApicPage->id.u32ApicId & UINT32_C(0xf)); break; } } } }
DECLCALLBACK(VBOXSTRICTRC) apicReadMmio(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb) { VBOXSTRICTRC rc = VBOXSTRICTRC_VAL(apicReadRegister(pDevIns, pVCpu, offReg, &uValue)); } //大部分APIC寄存器直接读取 DECLINLINE(VBOXSTRICTRC) apicReadRegister(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t *puValue) { PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu); uint32_t uValue = 0; VBOXSTRICTRC rc = VINF_SUCCESS; switch (offReg) { case XAPIC_OFF_ID: case XAPIC_OFF_VERSION: case XAPIC_OFF_TPR: case XAPIC_OFF_EOI: case XAPIC_OFF_RRD: case XAPIC_OFF_LDR: case XAPIC_OFF_DFR: case XAPIC_OFF_SVR: case XAPIC_OFF_ISR0: case XAPIC_OFF_ISR1: case XAPIC_OFF_ISR2: case XAPIC_OFF_ISR3: case XAPIC_OFF_ISR4: case XAPIC_OFF_ISR5: case XAPIC_OFF_ISR6: case XAPIC_OFF_ISR7: case XAPIC_OFF_TMR0: case XAPIC_OFF_TMR1: case XAPIC_OFF_TMR2: case XAPIC_OFF_TMR3: case XAPIC_OFF_TMR4: case XAPIC_OFF_TMR5: case XAPIC_OFF_TMR6: case XAPIC_OFF_TMR7: case XAPIC_OFF_IRR0: case XAPIC_OFF_IRR1: case XAPIC_OFF_IRR2: case XAPIC_OFF_IRR3: case XAPIC_OFF_IRR4: case XAPIC_OFF_IRR5: case XAPIC_OFF_IRR6: case XAPIC_OFF_IRR7: case XAPIC_OFF_ESR: case XAPIC_OFF_ICR_LO: case XAPIC_OFF_ICR_HI: case XAPIC_OFF_LVT_TIMER: #if XAPIC_HARDWARE_VERSION == XAPIC_HARDWARE_VERSION_P4 case XAPIC_OFF_LVT_THERMAL: #endif case XAPIC_OFF_LVT_PERF: case XAPIC_OFF_LVT_LINT0: case XAPIC_OFF_LVT_LINT1: case XAPIC_OFF_LVT_ERROR: case XAPIC_OFF_TIMER_ICR: case XAPIC_OFF_TIMER_DCR: { //直接读取Virtual APIC page里的值 uValue = apicReadRaw32(pXApicPage, offReg); break; } case XAPIC_OFF_PPR: { //获取当前进程的优先级 uValue = apicGetPpr(pVCpu); break; } case XAPIC_OFF_TIMER_CCR: { //获取APIC时间计时器 rc = apicGetTimerCcr(pDevIns, pVCpu, VINF_IOM_R3_MMIO_READ, &uValue); break; } case XAPIC_OFF_APR: { #if XAPIC_HARDWARE_VERSION == XAPIC_HARDWARE_VERSION_P4 /* Unsupported on Pentium 4 and Xeon CPUs, invalid in x2APIC mode. */ Assert(!XAPIC_IN_X2APIC_MODE(pVCpu)); #else # error "Implement Pentium and P6 family APIC architectures" #endif break; } default: { //设置错误标记 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "VCPU[%u]: offReg=%#RX16\n", pVCpu->idCpu, offReg); apicSetError(pVCpu, XAPIC_ESR_ILLEGAL_REG_ADDRESS); break; } } *puValue = uValue; return rc; }
APIC寄存器的写操作就要复杂很多,很多项都需要特殊处理
DECLINLINE(VBOXSTRICTRC) apicWriteRegister(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t uValue) { VMCPU_ASSERT_EMT(pVCpu); Assert(offReg <= XAPIC_OFF_MAX_VALID); Assert(!XAPIC_IN_X2APIC_MODE(pVCpu)); VBOXSTRICTRC rcStrict = VINF_SUCCESS; switch (offReg) { case XAPIC_OFF_TPR: { rcStrict = apicSetTprEx(pVCpu, uValue, false /* fForceX2ApicBehaviour */); break; } case XAPIC_OFF_LVT_TIMER: #if XAPIC_HARDWARE_VERSION == XAPIC_HARDWARE_VERSION_P4 case XAPIC_OFF_LVT_THERMAL: #endif case XAPIC_OFF_LVT_PERF: case XAPIC_OFF_LVT_LINT0: case XAPIC_OFF_LVT_LINT1: case XAPIC_OFF_LVT_ERROR: { rcStrict = apicSetLvtEntry(pVCpu, offReg, uValue); break; } case XAPIC_OFF_TIMER_ICR: { rcStrict = apicSetTimerIcr(pDevIns, pVCpu, VINF_IOM_R3_MMIO_WRITE, uValue); break; } case XAPIC_OFF_EOI: { rcStrict = apicSetEoi(pVCpu, uValue, VINF_IOM_R3_MMIO_WRITE, false /* fForceX2ApicBehaviour */); break; } case XAPIC_OFF_LDR: { rcStrict = apicSetLdr(pVCpu, uValue); break; } case XAPIC_OFF_DFR: { rcStrict = apicSetDfr(pVCpu, uValue); break; } case XAPIC_OFF_SVR: { rcStrict = apicSetSvr(pVCpu, uValue); break; } case XAPIC_OFF_ICR_LO: { rcStrict = apicSetIcrLo(pVCpu, uValue, VINF_IOM_R3_MMIO_WRITE, true /* fUpdateStat */); break; } case XAPIC_OFF_ICR_HI: { rcStrict = apicSetIcrHi(pVCpu, uValue); break; } case XAPIC_OFF_TIMER_DCR: { rcStrict = apicSetTimerDcr(pVCpu, uValue); break; } case XAPIC_OFF_ESR: { rcStrict = apicSetEsr(pVCpu, uValue); break; } case XAPIC_OFF_APR: case XAPIC_OFF_RRD: { //暂时的不支持这两个寄存器写入 #if XAPIC_HARDWARE_VERSION == XAPIC_HARDWARE_VERSION_P4 #else # error "Implement Pentium and P6 family APIC architectures" #endif break; } /* Read-only, write ignored: */ case XAPIC_OFF_VERSION: case XAPIC_OFF_ID: break; /* Unavailable/reserved in xAPIC mode: */ case X2APIC_OFF_SELF_IPI: /* Read-only registers: */ case XAPIC_OFF_PPR: case XAPIC_OFF_ISR0: case XAPIC_OFF_ISR1: case XAPIC_OFF_ISR2: case XAPIC_OFF_ISR3: case XAPIC_OFF_ISR4: case XAPIC_OFF_ISR5: case XAPIC_OFF_ISR6: case XAPIC_OFF_ISR7: case XAPIC_OFF_TMR0: case XAPIC_OFF_TMR1: case XAPIC_OFF_TMR2: case XAPIC_OFF_TMR3: case XAPIC_OFF_TMR4: case XAPIC_OFF_TMR5: case XAPIC_OFF_TMR6: case XAPIC_OFF_TMR7: case XAPIC_OFF_IRR0: case XAPIC_OFF_IRR1: case XAPIC_OFF_IRR2: case XAPIC_OFF_IRR3: case XAPIC_OFF_IRR4: case XAPIC_OFF_IRR5: case XAPIC_OFF_IRR6: case XAPIC_OFF_IRR7: case XAPIC_OFF_TIMER_CCR: default: { //只读的寄存器读取需要设置异常标记 rcStrict = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "APIC%u: offReg=%#RX16\n", pVCpu->idCpu, offReg); apicSetError(pVCpu, XAPIC_ESR_ILLEGAL_REG_ADDRESS); break; } } return rcStrict; }
下面一个一个看所有的set函数
static int apicSetTprEx(PVMCPUCC pVCpu, uint32_t uTpr, bool fForceX2ApicBehaviour) { bool const fX2ApicMode = XAPIC_IN_X2APIC_MODE(pVCpu) || fForceX2ApicBehaviour; if ( fX2ApicMode && (uTpr & ~XAPIC_TPR_VALID)) return apicMsrAccessError(pVCpu, MSR_IA32_X2APIC_TPR, APICMSRACCESS_WRITE_RSVD_BITS); PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu); //写入Tpr pXApicPage->tpr.u8Tpr = uTpr; //更新ppr apicUpdatePpr(pVCpu); //检查是否有pending的中断可以唤醒,发送中断到VCPU中 apicSignalNextPendingIntr(pVCpu); return VINF_SUCCESS; } //设置了Tpr或者有有中断被唤醒的时候,都会调用这个函数更新Ppr static void apicUpdatePpr(PVMCPUCC pVCpu) { PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu); //获取当前正在处理的中断的最高优先级 uint8_t const uIsrv = apicGetHighestSetBitInReg(&pXApicPage->isr, 0 /* rcNotFound */); uint8_t uPpr; //PPR赋值成TPR的值和ISR中最大优先级中较大的一个 if (XAPIC_TPR_GET_TP(pXApicPage->tpr.u8Tpr) >= XAPIC_PPR_GET_PP(uIsrv)) uPpr = pXApicPage->tpr.u8Tpr; else uPpr = XAPIC_PPR_GET_PP(uIsrv); pXApicPage->ppr.u8Ppr = uPpr; } //唤醒下一个高优先级中断 static void apicSignalNextPendingIntr(PVMCPUCC pVCpu) { VMCPU_ASSERT_EMT_OR_NOT_RUNNING(pVCpu); PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu); if (pXApicPage->svr.u.fApicSoftwareEnable) { //从irr里获取优先级最高的pending中断 int const irrv = apicGetHighestSetBitInReg(&pXApicPage->irr, -1 /* rcNotFound */); if (irrv >= 0) { uint8_t const uVector = irrv; uint8_t const uPpr = pXApicPage->ppr.u8Ppr; //如果这个中断优先级大于当前CPU的中断优先级,设置标记位表示有中断可以被唤醒 if ( !uPpr || XAPIC_PPR_GET_PP(uVector) > XAPIC_PPR_GET_PP(uPpr)) { apicSetInterruptFF(pVCpu, PDMAPICIRQ_HARDWARE); } } } }
static VBOXSTRICTRC apicSetLvtEntry(PVMCPUCC pVCpu, uint16_t offLvt, uint32_t uLvt) { PCAPIC pApic = VM_TO_APIC(pVCpu->CTX_SUFF(pVM)); if (offLvt == XAPIC_OFF_LVT_TIMER) { //如果是APIC Timer,不支持Tsc Deadline模式,但是Lvt里又设置了Tsc Deadline模式 if ( !pApic->fSupportsTscDeadline && (uLvt & XAPIC_LVT_TIMER_TSCDEADLINE)) { //x2APIC返回错误 if (XAPIC_IN_X2APIC_MODE(pVCpu)) return apicMsrAccessError(pVCpu, XAPIC_GET_X2APIC_MSR(offLvt), APICMSRACCESS_WRITE_RSVD_BITS); //xAPIC模式直接去掉这个bit uLvt &= ~XAPIC_LVT_TIMER_TSCDEADLINE; } } //获取7个LVT里的顺序 uint16_t const idxLvt = (offLvt - XAPIC_OFF_LVT_START) >> 4; //检查输入的值是否正确,不同的LVT中断,LVT里有效位是不同的。具体有效位见上一篇的图3 if ( XAPIC_IN_X2APIC_MODE(pVCpu) && (uLvt & ~g_au32LvtValidMasks[idxLvt])) return apicMsrAccessError(pVCpu, XAPIC_GET_X2APIC_MSR(offLvt), APICMSRACCESS_WRITE_RSVD_BITS); //获取LVT Mask uLvt &= g_au32LvtValidMasks[idxLvt]; //如果没有开启SoftwareEnable(只运行硬件中断)需要设置上XAPIC_LVT_MASK PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu); if (!pXApicPage->svr.u.fApicSoftwareEnable) uLvt |= XAPIC_LVT_MASK; //检查通过,写入LVT寄存器 apicWriteRaw32(pXApicPage, offLvt, uLvt); return VINF_SUCCESS; }
ICR写入相当于发送一个IPI中断,先写入高位,后写入低位,写入低位的时候发送IPI中断
static VBOXSTRICTRC apicSetIcrHi(PVMCPUCC pVCpu, uint32_t uIcrHi)
{
//写入寄存器高位
PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
pXApicPage->icr_hi.all.u32IcrHi = uIcrHi & XAPIC_ICR_HI_DEST;
return VINF_SUCCESS;
}
static VBOXSTRICTRC apicSetIcrLo(PVMCPUCC pVCpu, uint32_t uIcrLo, int rcRZ, bool fUpdateStat)
{
//写入寄存器低位
PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
pXApicPage->icr_lo.all.u32IcrLo = uIcrLo & XAPIC_ICR_LO_WR_VALID;
//发送IPI中断
return apicSendIpi(pVCpu, rcRZ);
}
当处理器将其PPR(任务优先级)提高到大于或等于当前断言处理器INTR信号的中断级别时,可能会出现特殊情况。如果在发出INTA周期时,要分配的中断已被屏蔽(由软件编程),则本地APIC将传递一个虚假的中断向量。分配假中断向量不会影响ISR,因此该向量的处理程序应在没有EOI的情况下返回。
static int apicSetSvr(PVMCPUCC pVCpu, uint32_t uSvr) { uint32_t uValidMask = XAPIC_SVR_VALID; PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu); //如果开启了禁止EOI broadcast,加上XAPIC_SVR_SUPRESS_EOI_BROADCAST标记 if (pXApicPage->version.u.fEoiBroadcastSupression) uValidMask |= XAPIC_SVR_SUPRESS_EOI_BROADCAST; //x2APIC模式不允许非有效位是1 if ( XAPIC_IN_X2APIC_MODE(pVCpu) && (uSvr & ~uValidMask)) return apicMsrAccessError(pVCpu, MSR_IA32_X2APIC_SVR, APICMSRACCESS_WRITE_RSVD_BITS); //直接写入SVR寄存器 apicWriteRaw32(pXApicPage, XAPIC_OFF_SVR, uSvr); //如果关闭了软件中断,需要重置LVT里的mask if (!pXApicPage->svr.u.fApicSoftwareEnable) { pXApicPage->lvt_timer.u.u1Mask = 1; #if XAPIC_HARDWARE_VERSION == XAPIC_HARDWARE_VERSION_P4 pXApicPage->lvt_thermal.u.u1Mask = 1; #endif pXApicPage->lvt_perf.u.u1Mask = 1; pXApicPage->lvt_lint0.u.u1Mask = 1; pXApicPage->lvt_lint1.u.u1Mask = 1; pXApicPage->lvt_error.u.u1Mask = 1; } }
static int apicSetEsr(PVMCPUCC pVCpu, uint32_t uEsr)
{
//x2APIC模式不允许非有效位是1
if ( XAPIC_IN_X2APIC_MODE(pVCpu)
&& (uEsr & ~XAPIC_ESR_WO_VALID))
return apicMsrAccessError(pVCpu, MSR_IA32_X2APIC_ESR, APICMSRACCESS_WRITE_RSVD_BITS);
//这边只是清除所有内部错误,并没有真正设置ESR寄存器
PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
pXApicPage->esr.all.u32Errors = apicClearAllErrors(pVCpu);
return VINF_SUCCESS;
}
Timer Divide Configuration Register (DCR).
static VBOXSTRICTRC apicSetTimerDcr(PVMCPUCC pVCpu, uint32_t uTimerDcr)
{
//如果是x2APIC模式,只接受有效位有值的输入
if ( XAPIC_IN_X2APIC_MODE(pVCpu)
&& (uTimerDcr & ~XAPIC_TIMER_DCR_VALID))
return apicMsrAccessError(pVCpu, MSR_IA32_X2APIC_TIMER_DCR, APICMSRACCESS_WRITE_RSVD_BITS);
//写入DCR值
PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
apicWriteRaw32(pXApicPage, XAPIC_OFF_TIMER_DCR, uTimerDcr);
return VINF_SUCCESS;
}
timer’s Initial-Count Register (ICR).
static VBOXSTRICTRC apicSetTimerIcr(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, int rcBusy, uint32_t uInitialCount) { PAPIC pApic = VM_TO_APIC(pVCpu->CTX_SUFF(pVM)); PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu); PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu); // TSC-deadline mode不使用ICR,忽略 if ( pApic->fSupportsTscDeadline && pXApicPage->lvt_timer.u.u2TimerMode == XAPIC_TIMER_MODE_TSC_DEADLINE) return VINF_SUCCESS; TMTIMERHANDLE hTimer = pApicCpu->hTimer; VBOXSTRICTRC rc = PDMDevHlpTimerLockClock(pDevIns, hTimer, rcBusy); if (rc == VINF_SUCCESS) { pXApicPage->timer_icr.u32InitialCount = uInitialCount; //设置CCR的值等于ICR pXApicPage->timer_ccr.u32CurrentCount = uInitialCount; //如果ICR不等于0,启动Timer if (uInitialCount) apicStartTimer(pVCpu, uInitialCount); else //ICR等于0,停止Timer apicStopTimer(pVCpu); PDMDevHlpTimerUnlockClock(pDevIns, hTimer); } return rc; }
中断完成设置
static VBOXSTRICTRC apicSetEoi(PVMCPUCC pVCpu, uint32_t uEoi, int rcBusy, bool fForceX2ApicBehaviour) { bool const fX2ApicMode = XAPIC_IN_X2APIC_MODE(pVCpu) || fForceX2ApicBehaviour; if ( fX2ApicMode && (uEoi & ~XAPIC_EOI_WO_VALID)) return apicMsrAccessError(pVCpu, MSR_IA32_X2APIC_EOI, APICMSRACCESS_WRITE_RSVD_BITS); int isrv = apicGetHighestSetBitInReg(&pXApicPage->isr, -1 /* rcNotFound */); //获取下一个需要处理的中断 if (isrv >= 0) { uint8_t const uVector = isrv; //是否是电平触发的中断 bool const fLevelTriggered = apicTestVectorInReg(&pXApicPage->tmr, uVector); if (fLevelTriggered) { //广播EOI VBOXSTRICTRC rc = PDMIoApicBroadcastEoi(pVCpu->CTX_SUFF(pVM), uVector); if (rc == VINF_SUCCESS) { /* likely */ } else return rcBusy; //clear TMR寄存器 (中断完成) apicClearVectorInReg(&pXApicPage->tmr, uVector); //LINT0上的, 电平触发,fixedmode的中断需要在收到EOI命令之后清除Remote IRR标记 uint32_t const uLvtLint0 = pXApicPage->lvt_lint0.all.u32LvtLint0; if ( XAPIC_LVT_GET_REMOTE_IRR(uLvtLint0) && XAPIC_LVT_GET_VECTOR(uLvtLint0) == uVector && XAPIC_LVT_GET_DELIVERY_MODE(uLvtLint0) == XAPICDELIVERYMODE_FIXED) { ASMAtomicAndU32((volatile uint32_t *)&pXApicPage->lvt_lint0.all.u32LvtLint0, ~XAPIC_LVT_REMOTE_IRR); } } //清除ISR寄存器(当前中断已处理完成) apicClearVectorInReg(&pXApicPage->isr, uVector); //更新Ppr apicUpdatePpr(pVCpu); //选择下一个要处理的中断 apicSignalNextPendingIntr(pVCpu); } }
设置Logical Destination Register (LDR).
static VBOXSTRICTRC apicSetLdr(PVMCPUCC pVCpu, uint32_t uLdr)
{
//直接写入Virtual APIC-page
PCAPIC pApic = VM_TO_APIC(pVCpu->CTX_SUFF(pVM));
PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
apicWriteRaw32(pXApicPage, XAPIC_OFF_LDR, uLdr & XAPIC_LDR_VALID);
return VINF_SUCCESS;
}
Destination Format Register (DFR).
static VBOXSTRICTRC apicSetDfr(PVMCPUCC pVCpu, uint32_t uDfr)
{
uDfr &= XAPIC_DFR_VALID;
uDfr |= XAPIC_DFR_RSVD_MB1;
PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
apicWriteRaw32(pXApicPage, XAPIC_OFF_DFR, uDfr);
return VINF_SUCCESS;
}
VMMDECL(int) APICGetTpr(PCVMCPUCC pVCpu, uint8_t *pu8Tpr, bool *pfPending, uint8_t *pu8PendingIntr) { VMCPU_ASSERT_EMT(pVCpu); if (APICIsEnabled(pVCpu)) { PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu); if (pfPending) { //获取IRR里pending中断中最高的一个优先级 *pfPending = apicGetHighestPendingInterrupt(pVCpu, pu8PendingIntr); } //返回这个中断的TPR寄存器里的值 *pu8Tpr = pXApicPage->tpr.u8Tpr; return VINF_SUCCESS; } *pu8Tpr = 0; return VERR_PDM_NO_APIC_INSTANCE; }
当ICR写入时,会调用这些函数
void apicStartTimer(PVMCPUCC pVCpu, uint32_t uInitialCount)
{
PCXAPICPAGE pXApicPage = APICCPU_TO_CXAPICPAGE(pApicCpu);
uint8_t const uTimerShift = apicGetTimerShift(pXApicPage);
uint64_t const cTicksToNext = (uint64_t)uInitialCount << uTimerShift;
//最终调用到TM里的TMTimerSetRelative,这个函数在TM(Time Manager)里介绍
PDMDevHlpTimerSetRelative(pDevIns, pApicCpu->hTimer, cTicksToNext, &pApicCpu->u64TimerInitial);
apicHintTimerFreq(pDevIns, pApicCpu, uInitialCount, uTimerShift);
}
static void apicStopTimer(PVMCPUCC pVCpu)
{
//调用TM里的TMTimerStop函数停止定时器
PDMDevHlpTimerStop(pDevIns, pApicCpu->hTimer);
pApicCpu->uHintedTimerInitialCount = 0;
pApicCpu->uHintedTimerShift = 0;
}
告诉TM当前APIC的频率
void apicHintTimerFreq(PPDMDEVINS pDevIns, PAPICCPU pApicCpu, uint32_t uInitialCount, uint8_t uTimerShift) { //Timer启动之后只会设置一次 if ( pApicCpu->uHintedTimerInitialCount != uInitialCount || pApicCpu->uHintedTimerShift != uTimerShift) { uint32_t uHz; if (uInitialCount) { //开启了定时器,调用TMTimerGetFreq函数获取频率 uint64_t cTicksPerPeriod = (uint64_t)uInitialCount << uTimerShift; uHz = PDMDevHlpTimerGetFreq(pDevIns, pApicCpu->hTimer) / cTicksPerPeriod; } else uHz = 0; //调用TMTimerSetFrequencyHint设置时间频率 PDMDevHlpTimerSetFrequencyHint(pDevIns, pApicCpu->hTimer, uHz); pApicCpu->uHintedTimerInitialCount = uInitialCount; pApicCpu->uHintedTimerShift = uTimerShift; } }
获取当前APIC的频率
VMM_INT_DECL(int) APICGetTimerFreq(PVMCC pVM, uint64_t *pu64Value)
{
PVMCPUCC pVCpu = pVM->CTX_SUFF(apCpus)[0];
if (APICIsEnabled(pVCpu))
{
PCAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
// 调用TMTimerGetFreq函数获取频率
*pu64Value = PDMDevHlpTimerGetFreq(VMCPU_TO_DEVINS(pVCpu), pApicCpu->hTimer);
return VINF_SUCCESS;
}
return VERR_PDM_NO_APIC_INSTANCE;
}
时间片到之后的callback
static DECLCALLBACK(void) apicR3TimerCallback(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser) { PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu); uint32_t const uLvtTimer = pXApicPage->lvt_timer.all.u32LvtTimer; if (!XAPIC_LVT_IS_MASKED(uLvtTimer)) { //时间片到, 根据LVT Timer里的信息发送中断到目标VCPU uint8_t uVector = XAPIC_LVT_GET_VECTOR(uLvtTimer); apicPostInterrupt(pVCpu, uVector, XAPICTRIGGERMODE_EDGE, 0 /* uSrcTag */); } //根据Timer mode决定是否重置定时器 XAPICTIMERMODE enmTimerMode = XAPIC_LVT_GET_TIMER_MODE(uLvtTimer); switch (enmTimerMode) { case XAPICTIMERMODE_PERIODIC: { //PERIODIC需要重置定时器并重新把u32CurrentCount赋值 uint32_t const uInitialCount = pXApicPage->timer_icr.u32InitialCount; pXApicPage->timer_ccr.u32CurrentCount = uInitialCount; if (uInitialCount) { //重新启动定时器 apicStartTimer(pVCpu, uInitialCount); } break; } case XAPICTIMERMODE_ONESHOT: { //时间片到,不会重置,所以只设置u32CurrentCount成0 pXApicPage->timer_ccr.u32CurrentCount = 0; break; } case XAPICTIMERMODE_TSC_DEADLINE: { //暂时不支持创建TSC deadline的timer break; } } }
参考资料:
https://blog.csdn.net/omnispace/article/details/61415994
https://blog.csdn.net/ustc_dylan/article/details/4132046
Intel指令手册
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。