diff options
Diffstat (limited to 'src/VBox/Devices/PC/DevAPIC.cpp')
-rw-r--r-- | src/VBox/Devices/PC/DevAPIC.cpp | 636 |
1 files changed, 298 insertions, 338 deletions
diff --git a/src/VBox/Devices/PC/DevAPIC.cpp b/src/VBox/Devices/PC/DevAPIC.cpp index 9c01c68a..73b4a163 100644 --- a/src/VBox/Devices/PC/DevAPIC.cpp +++ b/src/VBox/Devices/PC/DevAPIC.cpp @@ -1,10 +1,13 @@ /* $Id: DevAPIC.cpp $ */ /** @file * Advanced Programmable Interrupt Controller (APIC) Device. + * + * @remarks This code does not use pThis, it uses pDev and pApic due to the + * non-standard arrangements of the APICs wrt PDM. */ /* - * Copyright (C) 2006-2011 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -59,11 +62,9 @@ /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ -#define MSR_IA32_APICBASE 0x1b -#define MSR_IA32_APICBASE_BSP (1<<8) #define MSR_IA32_APICBASE_ENABLE (1<<11) #define MSR_IA32_APICBASE_X2ENABLE (1<<10) -#define MSR_IA32_APICBASE_BASE (0xfffff<<12) +#define MSR_IA32_APICBASE_BASE (0xfffff<<12) /** @todo r=bird: This is not correct according to current specs! */ #ifdef _MSC_VER # pragma warning(disable:4244) @@ -104,24 +105,24 @@ /** @def APIC_AND_TM_LOCK * Acquires the virtual sync clock lock as well as the PDM lock. */ -#define APIC_AND_TM_LOCK(a_pDev, a_pAcpi, rcBusy) \ +#define APIC_AND_TM_LOCK(a_pDev, a_pApic, rcBusy) \ do { \ - int rc2 = TMTimerLock((a_pAcpi)->CTX_SUFF(pTimer), (rcBusy)); \ + int rc2 = TMTimerLock((a_pApic)->CTX_SUFF(pTimer), (rcBusy)); \ if (rc2 != VINF_SUCCESS) \ return rc2; \ rc2 = PDMCritSectEnter((a_pDev)->CTX_SUFF(pCritSect), (rcBusy)); \ if (rc2 != VINF_SUCCESS) \ { \ - TMTimerUnlock((a_pAcpi)->CTX_SUFF(pTimer)); \ + TMTimerUnlock((a_pApic)->CTX_SUFF(pTimer)); \ return rc2; \ } \ } while (0) /** @def APIC_AND_TM_UNLOCK * Releases the PDM lock as well as the TM virtual sync clock lock. */ -#define APIC_AND_TM_UNLOCK(a_pDev, a_pAcpi) \ +#define APIC_AND_TM_UNLOCK(a_pDev, a_pApic) \ do { \ - TMTimerUnlock((a_pAcpi)->CTX_SUFF(pTimer)); \ + TMTimerUnlock((a_pApic)->CTX_SUFF(pTimer)); \ PDMCritSectLeave((a_pDev)->CTX_SUFF(pCritSect)); \ } while (0) @@ -164,51 +165,19 @@ #define DEBUG_APIC -/* APIC Local Vector Table */ -#define APIC_LVT_TIMER 0 -#define APIC_LVT_THERMAL 1 -#define APIC_LVT_PERFORM 2 -#define APIC_LVT_LINT0 3 -#define APIC_LVT_LINT1 4 -#define APIC_LVT_ERROR 5 -#define APIC_LVT_NB 6 - -/* APIC delivery modes */ -#define APIC_DM_FIXED 0 -#define APIC_DM_LOWPRI 1 -#define APIC_DM_SMI 2 -#define APIC_DM_NMI 4 -#define APIC_DM_INIT 5 -#define APIC_DM_SIPI 6 -#define APIC_DM_EXTINT 7 - -/* APIC destination mode */ -#define APIC_DESTMODE_FLAT 0xf -#define APIC_DESTMODE_CLUSTER 0x0 - -#define APIC_TRIGGER_EDGE 0 -#define APIC_TRIGGER_LEVEL 1 - -#define APIC_LVT_TIMER_PERIODIC (1<<17) -#define APIC_LVT_MASKED (1<<16) -#define APIC_LVT_LEVEL_TRIGGER (1<<15) -#define APIC_LVT_REMOTE_IRR (1<<14) -#define APIC_INPUT_POLARITY (1<<13) -#define APIC_SEND_PENDING (1<<12) - #define ESR_ILLEGAL_ADDRESS (1 << 7) #define APIC_SV_ENABLE (1 << 8) #define APIC_MAX_PATCH_ATTEMPTS 100 -typedef uint32_t PhysApicId; -typedef uint32_t LogApicId; - /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ +typedef uint32_t PhysApicId; +typedef uint32_t LogApicId; + typedef struct APIC256BITREG { /** The bitmap data. */ @@ -293,30 +262,38 @@ static int Apic256BitReg_FindLastSetBit(PCAPIC256BITREG pReg, int iRetAllClear) } +/** + * The state of one APIC. + * + * @remarks This is generally pointed to by a parameter or variable named pApic. + */ typedef struct APICState { - uint32_t apicbase; + /** In service register (ISR). */ + APIC256BITREG isr; + /** Trigger mode register (TMR). */ + APIC256BITREG tmr; + /** Interrupt request register (IIR). */ + APIC256BITREG irr; + uint32_t lvt[APIC_LVT_NB]; + uint32_t apicbase; /* Task priority register (interrupt level) */ - uint32_t tpr; + uint32_t tpr; /* Logical APIC id - user programmable */ - LogApicId id; + LogApicId id; /* Physical APIC id - not visible to user, constant */ - PhysApicId phys_id; + PhysApicId phys_id; /** @todo: is it logical or physical? Not really used anyway now. */ - PhysApicId arb_id; - uint32_t spurious_vec; - uint8_t log_dest; - uint8_t dest_mode; - APIC256BITREG isr; /**< in service register */ - APIC256BITREG tmr; /**< trigger mode register */ - APIC256BITREG irr; /**< interrupt request register */ - uint32_t lvt[APIC_LVT_NB]; - uint32_t esr; /* error register */ - uint32_t icr[2]; - uint32_t divide_conf; - int count_shift; - uint32_t initial_count; - uint32_t Alignment0; + PhysApicId arb_id; + uint32_t spurious_vec; + uint8_t log_dest; + uint8_t dest_mode; + uint32_t esr; /* error register */ + uint32_t icr[2]; + uint32_t divide_conf; + int count_shift; + uint32_t initial_count; + uint32_t Alignment0; /** The time stamp of the initial_count load, i.e. when it was started. */ uint64_t initial_count_load_time; @@ -365,6 +342,11 @@ AssertCompileMemberAlignment(APICState, initial_count_load_time, 8); AssertCompileMemberAlignment(APICState, StatTimerSetInitialCount, 8); # endif +/** + * The wrapper device for the all the APICs. + * + * @remarks This is generally pointed to by a parameter or variable named pDev. + */ typedef struct { /** The device instance - R3 Ptr. */ @@ -424,81 +406,84 @@ AssertCompileMemberAlignment(APICDeviceInfo, StatMMIOReadGC, 8); /******************************************************************************* * Internal Functions * *******************************************************************************/ -static void apic_update_tpr(APICDeviceInfo *pDev, APICState* s, uint32_t val); +static void apic_update_tpr(APICDeviceInfo *pDev, APICState *pApic, uint32_t val); -static void apic_eoi(APICDeviceInfo *pDev, APICState* s); /* */ -static PVMCPUSET apic_get_delivery_bitmask(APICDeviceInfo* pDev, uint8_t dest, uint8_t dest_mode, PVMCPUSET pDstSet); -static int apic_deliver(APICDeviceInfo* pDev, APICState *s, +static void apic_eoi(APICDeviceInfo *pDev, APICState *pApic); /* */ +static PVMCPUSET apic_get_delivery_bitmask(APICDeviceInfo *pDev, uint8_t dest, uint8_t dest_mode, PVMCPUSET pDstSet); +static int apic_deliver(APICDeviceInfo *pDev, APICState *pApic, uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode, uint8_t vector_num, uint8_t polarity, uint8_t trigger_mode); -static int apic_get_arb_pri(APICState const *s); -static int apic_get_ppr(APICState const *s); -static uint32_t apic_get_current_count(APICDeviceInfo const *pDev, APICState const *s); -static void apicTimerSetInitialCount(APICDeviceInfo *pDev, APICState *s, uint32_t initial_count); +static int apic_get_arb_pri(APICState const *pApic); +static int apic_get_ppr(APICState const *pApic); +static uint32_t apic_get_current_count(APICDeviceInfo const *pDev, APICState const *pApic); +static void apicTimerSetInitialCount(APICDeviceInfo *pDev, APICState *pApic, uint32_t initial_count); static void apicTimerSetLvt(APICDeviceInfo *pDev, APICState *pApic, uint32_t fNew); -static void apicSendInitIpi(APICDeviceInfo* pDev, APICState *s); +static void apicSendInitIpi(APICDeviceInfo *pDev, APICState *pApic); -static void apic_init_ipi(APICDeviceInfo* pDev, APICState *s); -static void apic_set_irq(APICDeviceInfo* pDev, APICState *s, int vector_num, int trigger_mode, uint32_t uTagSrc); -static bool apic_update_irq(APICDeviceInfo* pDev, APICState *s); +static void apicR3InitIpi(APICDeviceInfo *pDev, APICState *pApic); +static void apic_set_irq(APICDeviceInfo *pDev, APICState *pApic, int vector_num, int trigger_mode, uint32_t uTagSrc); +static bool apic_update_irq(APICDeviceInfo *pDev, APICState *pApic); -DECLINLINE(APICState*) getLapicById(APICDeviceInfo *pDev, VMCPUID id) +DECLINLINE(APICState *) apicGetStateById(APICDeviceInfo *pDev, VMCPUID id) { AssertFatalMsg(id < pDev->cCpus, ("CPU id %d out of range\n", id)); return &pDev->CTX_SUFF(paLapics)[id]; } -DECLINLINE(APICState*) getLapic(APICDeviceInfo* pDev) +/** + * Get the APIC state for the calling EMT. + */ +DECLINLINE(APICState *) apicGetStateByCurEmt(APICDeviceInfo *pDev) { /* LAPIC's array is indexed by CPU id */ VMCPUID id = pDev->CTX_SUFF(pApicHlp)->pfnGetCpuId(pDev->CTX_SUFF(pDevIns)); - return getLapicById(pDev, id); + return apicGetStateById(pDev, id); } -DECLINLINE(VMCPUID) getCpuFromLapic(APICDeviceInfo* pDev, APICState *s) +DECLINLINE(VMCPUID) getCpuFromLapic(APICDeviceInfo *pDev, APICState *pApic) { /* for now we assume LAPIC physical id == CPU id */ - return VMCPUID(s->phys_id); + return (VMCPUID)pApic->phys_id; } -DECLINLINE(void) cpuSetInterrupt(APICDeviceInfo* pDev, APICState *s, PDMAPICIRQ enmType = PDMAPICIRQ_HARDWARE) +DECLINLINE(void) apicCpuSetInterrupt(APICDeviceInfo *pDev, APICState *pApic, PDMAPICIRQ enmType = PDMAPICIRQ_HARDWARE) { - LogFlow(("apic: setting interrupt flag for cpu %d\n", getCpuFromLapic(pDev, s))); + LogFlow(("apic: setting interrupt flag for cpu %d\n", getCpuFromLapic(pDev, pApic))); pDev->CTX_SUFF(pApicHlp)->pfnSetInterruptFF(pDev->CTX_SUFF(pDevIns), enmType, - getCpuFromLapic(pDev, s)); + getCpuFromLapic(pDev, pApic)); } -DECLINLINE(void) cpuClearInterrupt(APICDeviceInfo* pDev, APICState *s, PDMAPICIRQ enmType = PDMAPICIRQ_HARDWARE) +DECLINLINE(void) apicCpuClearInterrupt(APICDeviceInfo *pDev, APICState *pApic, PDMAPICIRQ enmType = PDMAPICIRQ_HARDWARE) { LogFlow(("apic: clear interrupt flag\n")); pDev->CTX_SUFF(pApicHlp)->pfnClearInterruptFF(pDev->CTX_SUFF(pDevIns), enmType, - getCpuFromLapic(pDev, s)); + getCpuFromLapic(pDev, pApic)); } # ifdef IN_RING3 -DECLINLINE(void) cpuSendSipi(APICDeviceInfo* pDev, APICState *s, int vector) +DECLINLINE(void) apicR3CpuSendSipi(APICDeviceInfo *pDev, APICState *pApic, int vector) { Log2(("apic: send SIPI vector=%d\n", vector)); pDev->pApicHlpR3->pfnSendSipi(pDev->pDevInsR3, - getCpuFromLapic(pDev, s), + getCpuFromLapic(pDev, pApic), vector); } -DECLINLINE(void) cpuSendInitIpi(APICDeviceInfo* pDev, APICState *s) +DECLINLINE(void) apicR3CpuSendInitIpi(APICDeviceInfo *pDev, APICState *pApic) { Log2(("apic: send init IPI\n")); pDev->pApicHlpR3->pfnSendInitIpi(pDev->pDevInsR3, - getCpuFromLapic(pDev, s)); + getCpuFromLapic(pDev, pApic)); } # endif /* IN_RING3 */ -DECLINLINE(uint32_t) getApicEnableBits(APICDeviceInfo* pDev) +DECLINLINE(uint32_t) getApicEnableBits(APICDeviceInfo *pDev) { switch (pDev->enmVersion) { @@ -531,7 +516,7 @@ DECLINLINE(PDMAPICVERSION) getApicMode(APICState *apic) } } -static int apic_bus_deliver(APICDeviceInfo* pDev, +static int apic_bus_deliver(APICDeviceInfo *pDev, PCVMCPUSET pDstSet, uint8_t delivery_mode, uint8_t vector_num, uint8_t polarity, uint8_t trigger_mode, uint32_t uTagSrc) @@ -546,7 +531,7 @@ static int apic_bus_deliver(APICDeviceInfo* pDev, VMCPUID idDstCpu = VMCPUSET_FIND_FIRST_PRESENT(pDstSet); if (idDstCpu != NIL_VMCPUID) { - APICState *pApic = getLapicById(pDev, idDstCpu); + APICState *pApic = apicGetStateById(pDev, idDstCpu); apic_set_irq(pDev, pApic, vector_num, trigger_mode, uTagSrc); } return VINF_SUCCESS; @@ -558,13 +543,13 @@ static int apic_bus_deliver(APICDeviceInfo* pDev, case APIC_DM_SMI: APIC_FOREACH_IN_SET_BEGIN(pDev, pDstSet); - cpuSetInterrupt(pDev, pCurApic, PDMAPICIRQ_SMI); + apicCpuSetInterrupt(pDev, pCurApic, PDMAPICIRQ_SMI); APIC_FOREACH_END(); return VINF_SUCCESS; case APIC_DM_NMI: APIC_FOREACH_IN_SET_BEGIN(pDev, pDstSet); - cpuSetInterrupt(pDev, pCurApic, PDMAPICIRQ_NMI); + apicCpuSetInterrupt(pDev, pCurApic, PDMAPICIRQ_NMI); APIC_FOREACH_END(); return VINF_SUCCESS; @@ -595,23 +580,22 @@ static int apic_bus_deliver(APICDeviceInfo* pDev, } -PDMBOTHCBDECL(void) apicSetBase(PPDMDEVINS pDevIns, uint64_t val) +PDMBOTHCBDECL(void) apicSetBase(PPDMDEVINS pDevIns, VMCPUID idCpu, uint64_t val) { APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *); Assert(PDMCritSectIsOwner(pDev->CTX_SUFF(pCritSect))); - APICState *s = getLapic(pDev); /** @todo fix interface */ + APICState *pApic = apicGetStateById(pDev, idCpu); Log(("apicSetBase: %016RX64\n", val)); /** @todo: do we need to lock here ? */ /* APIC_LOCK_VOID(pDev, VERR_INTERNAL_ERROR); */ /** @todo If this change is valid immediately, then we should change the MMIO registration! */ /* We cannot change if this CPU is BSP or not by writing to MSR - it's hardwired */ - PDMAPICVERSION oldMode = getApicMode(s); - s->apicbase = - (val & 0xfffff000) | /* base */ - (val & getApicEnableBits(pDev)) | /* mode */ - (s->apicbase & MSR_IA32_APICBASE_BSP) /* keep BSP bit */; - PDMAPICVERSION newMode = getApicMode(s); + PDMAPICVERSION oldMode = getApicMode(pApic); + pApic->apicbase = (val & 0xfffff000) /* base */ + | (val & getApicEnableBits(pDev)) /* mode */ + | (pApic->apicbase & MSR_IA32_APICBASE_BSP) /* keep BSP bit */; + PDMAPICVERSION newMode = getApicMode(pApic); if (oldMode != newMode) { @@ -619,10 +603,14 @@ PDMBOTHCBDECL(void) apicSetBase(PPDMDEVINS pDevIns, uint64_t val) { case PDMAPICVERSION_NONE: { - s->spurious_vec &= ~APIC_SV_ENABLE; + pApic->spurious_vec &= ~APIC_SV_ENABLE; /* Clear any pending APIC interrupt action flag. */ - cpuClearInterrupt(pDev, s); - /** @todo: why do we do that? */ + apicCpuClearInterrupt(pDev, pApic); + /* See @bugref{7097}. Intel IA-32/64 Spec 10.4.3: + * "When IA32_APIC_BASE[11] is 0, the processor is functionally equivalent to + * an IA-32 processor without an on-chip APIC. The CPUID feature flag for the + * APIC (see Section 10.4.2, 'Presence of the Local APIC') is also set to 0." + */ pDev->CTX_SUFF(pApicHlp)->pfnChangeFeature(pDevIns, PDMAPICVERSION_NONE); break; } @@ -639,31 +627,31 @@ PDMBOTHCBDECL(void) apicSetBase(PPDMDEVINS pDevIns, uint64_t val) /* APIC_UNLOCK(pDev); */ } -PDMBOTHCBDECL(uint64_t) apicGetBase(PPDMDEVINS pDevIns) +PDMBOTHCBDECL(uint64_t) apicGetBase(PPDMDEVINS pDevIns, VMCPUID idCpu) { APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *); Assert(PDMCritSectIsOwner(pDev->CTX_SUFF(pCritSect))); - APICState *s = getLapic(pDev); /** @todo fix interface */ - LogFlow(("apicGetBase: %016llx\n", (uint64_t)s->apicbase)); - return s->apicbase; + APICState *pApic = apicGetStateById(pDev, idCpu); + LogFlow(("apicGetBase: %016llx\n", (uint64_t)pApic->apicbase)); + return pApic->apicbase; } PDMBOTHCBDECL(void) apicSetTPR(PPDMDEVINS pDevIns, VMCPUID idCpu, uint8_t val) { APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *); Assert(PDMCritSectIsOwner(pDev->CTX_SUFF(pCritSect))); - APICState *s = getLapicById(pDev, idCpu); - LogFlow(("apicSetTPR: val=%#x (trp %#x -> %#x)\n", val, s->tpr, val)); - apic_update_tpr(pDev, s, val); + APICState *pApic = apicGetStateById(pDev, idCpu); + LogFlow(("apicSetTPR: val=%#x (trp %#x -> %#x)\n", val, pApic->tpr, val)); + apic_update_tpr(pDev, pApic, val); } PDMBOTHCBDECL(uint8_t) apicGetTPR(PPDMDEVINS pDevIns, VMCPUID idCpu) { /* We don't perform any locking here as that would cause a lot of contention for VT-x/AMD-V. */ APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *); - APICState *s = getLapicById(pDev, idCpu); - Log2(("apicGetTPR: returns %#x\n", s->tpr)); - return s->tpr; + APICState *pApic = apicGetStateById(pDev, idCpu); + Log2(("apicGetTPR: returns %#x\n", pApic->tpr)); + return pApic->tpr; } @@ -1054,8 +1042,8 @@ PDMBOTHCBDECL(int) apicWriteMSR(PPDMDEVINS pDevIns, VMCPUID idCpu, uint32_t u32R if (pDev->enmVersion < PDMAPICVERSION_X2APIC) return VERR_EM_INTERPRETER; /** @todo tell the caller to raise hell (\#GP(0)). */ - APICState *pApic = getLapicById(pDev, idCpu); - uint32_t iReg = (u32Reg - MSR_IA32_APIC_START) & 0xff; + APICState *pApic = apicGetStateById(pDev, idCpu); + uint32_t iReg = (u32Reg - MSR_IA32_X2APIC_START) & 0xff; return apicWriteRegister(pDev, pApic, iReg, u64Value, VINF_SUCCESS /*rcBusy*/, true /*fMsr*/); } @@ -1070,8 +1058,8 @@ PDMBOTHCBDECL(int) apicReadMSR(PPDMDEVINS pDevIns, VMCPUID idCpu, uint32_t u32Re if (pDev->enmVersion < PDMAPICVERSION_X2APIC) return VERR_EM_INTERPRETER; - APICState *pApic = getLapicById(pDev, idCpu); - uint32_t iReg = (u32Reg - MSR_IA32_APIC_START) & 0xff; + APICState *pApic = apicGetStateById(pDev, idCpu); + uint32_t iReg = (u32Reg - MSR_IA32_X2APIC_START) & 0xff; return apicReadRegister(pDev, pApic, iReg, pu64Value, VINF_SUCCESS /*rcBusy*/, true /*fMsr*/); } @@ -1098,20 +1086,20 @@ PDMBOTHCBDECL(int) apicBusDeliverCallback(PPDMDEVINS pDevIns, uint8_t u8Dest, ui */ PDMBOTHCBDECL(int) apicLocalInterrupt(PPDMDEVINS pDevIns, uint8_t u8Pin, uint8_t u8Level) { - APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *); - APICState *s = getLapicById(pDev, 0); + APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *); + APICState *pApic = apicGetStateById(pDev, 0); Assert(PDMCritSectIsOwner(pDev->CTX_SUFF(pCritSect))); LogFlow(("apicLocalInterrupt: pDevIns=%p u8Pin=%x u8Level=%x\n", pDevIns, u8Pin, u8Level)); /* If LAPIC is disabled, go straight to the CPU. */ - if (!(s->spurious_vec & APIC_SV_ENABLE)) + if (!(pApic->spurious_vec & APIC_SV_ENABLE)) { LogFlow(("apicLocalInterrupt: LAPIC disabled, delivering directly to CPU core.\n")); if (u8Level) - cpuSetInterrupt(pDev, s, PDMAPICIRQ_EXTINT); + apicCpuSetInterrupt(pDev, pApic, PDMAPICIRQ_EXTINT); else - cpuClearInterrupt(pDev, s, PDMAPICIRQ_EXTINT); + apicCpuClearInterrupt(pDev, pApic, PDMAPICIRQ_EXTINT); return VINF_SUCCESS; } @@ -1125,9 +1113,9 @@ PDMBOTHCBDECL(int) apicLocalInterrupt(PPDMDEVINS pDevIns, uint8_t u8Pin, uint8_t * should be delivered to all CPUs and it is the guest's responsibility to ensure * no more than one CPU has the interrupt unmasked. */ - uint32_t u32Lvec; + uint32_t u32Lvec; - u32Lvec = s->lvt[APIC_LVT_LINT0 + u8Pin]; /* Fetch corresponding LVT entry. */ + u32Lvec = pApic->lvt[APIC_LVT_LINT0 + u8Pin]; /* Fetch corresponding LVT entry. */ /* Drop int if entry is masked. May not be correct for level-triggered interrupts. */ if (!(u32Lvec & APIC_LVT_MASKED)) { uint8_t u8Delivery; @@ -1142,9 +1130,9 @@ PDMBOTHCBDECL(int) apicLocalInterrupt(PPDMDEVINS pDevIns, uint8_t u8Pin, uint8_t /* ExtINT can be both set and cleared, NMI/SMI/INIT can only be set. */ LogFlow(("apicLocalInterrupt: %s ExtINT interrupt\n", u8Level ? "setting" : "clearing")); if (u8Level) - cpuSetInterrupt(pDev, s, enmType); + apicCpuSetInterrupt(pDev, pApic, enmType); else - cpuClearInterrupt(pDev, s, enmType); + apicCpuClearInterrupt(pDev, pApic, enmType); return VINF_SUCCESS; case APIC_DM_NMI: /* External NMI should be wired to LINT1, but Linux sometimes programs @@ -1177,58 +1165,58 @@ PDMBOTHCBDECL(int) apicLocalInterrupt(PPDMDEVINS pDevIns, uint8_t u8Pin, uint8_t } } LogFlow(("apicLocalInterrupt: setting local interrupt type %d\n", enmType)); - cpuSetInterrupt(pDev, s, enmType); + apicCpuSetInterrupt(pDev, pApic, enmType); } return VINF_SUCCESS; } -static int apic_get_ppr(APICState const *s) +static int apic_get_ppr(APICState const *pApic) { int ppr; - int tpr = (s->tpr >> 4); - int isrv = Apic256BitReg_FindLastSetBit(&s->isr, 0); + int tpr = (pApic->tpr >> 4); + int isrv = Apic256BitReg_FindLastSetBit(&pApic->isr, 0); isrv >>= 4; if (tpr >= isrv) - ppr = s->tpr; + ppr = pApic->tpr; else ppr = isrv << 4; return ppr; } -static int apic_get_ppr_zero_tpr(APICState *s) +static int apic_get_ppr_zero_tpr(APICState *pApic) { - return Apic256BitReg_FindLastSetBit(&s->isr, 0); + return Apic256BitReg_FindLastSetBit(&pApic->isr, 0); } -static int apic_get_arb_pri(APICState const *s) +static int apic_get_arb_pri(APICState const *pApic) { /** @todo XXX: arbitration */ return 0; } /* signal the CPU if an irq is pending */ -static bool apic_update_irq(APICDeviceInfo *pDev, APICState* s) +static bool apic_update_irq(APICDeviceInfo *pDev, APICState *pApic) { - if (!(s->spurious_vec & APIC_SV_ENABLE)) + if (!(pApic->spurious_vec & APIC_SV_ENABLE)) { /* Clear any pending APIC interrupt action flag. */ - cpuClearInterrupt(pDev, s); + apicCpuClearInterrupt(pDev, pApic); return false; } - int irrv = Apic256BitReg_FindLastSetBit(&s->irr, -1); + int irrv = Apic256BitReg_FindLastSetBit(&pApic->irr, -1); if (irrv < 0) return false; - int ppr = apic_get_ppr(s); + int ppr = apic_get_ppr(pApic); if (ppr && (irrv & 0xf0) <= (ppr & 0xf0)) return false; - cpuSetInterrupt(pDev, s); + apicCpuSetInterrupt(pDev, pApic); return true; } /* Check if the APIC has a pending interrupt/if a TPR change would active one. */ -PDMBOTHCBDECL(bool) apicHasPendingIrq(PPDMDEVINS pDevIns) +PDMBOTHCBDECL(bool) apicHasPendingIrq(PPDMDEVINS pDevIns, VMCPUID idCpu, uint8_t *pu8PendingIrq) { APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *); if (!pDev) @@ -1236,71 +1224,76 @@ PDMBOTHCBDECL(bool) apicHasPendingIrq(PPDMDEVINS pDevIns) /* We don't perform any locking here as that would cause a lot of contention for VT-x/AMD-V. */ - APICState *s = getLapic(pDev); /** @todo fix interface */ + APICState *pApic = apicGetStateById(pDev, idCpu); /* * All our callbacks now come from single IOAPIC, thus locking * seems to be excessive now */ /** @todo check excessive locking whatever... */ - int irrv = Apic256BitReg_FindLastSetBit(&s->irr, -1); + int irrv = Apic256BitReg_FindLastSetBit(&pApic->irr, -1); if (irrv < 0) return false; - int ppr = apic_get_ppr_zero_tpr(s); + int ppr = apic_get_ppr_zero_tpr(pApic); if (ppr && (irrv & 0xf0) <= (ppr & 0xf0)) return false; + if (pu8PendingIrq) + { + Assert(irrv >= 0 && irrv <= (int)UINT8_MAX); + *pu8PendingIrq = (uint8_t)irrv; + } return true; } -static void apic_update_tpr(APICDeviceInfo *pDev, APICState* s, uint32_t val) +static void apic_update_tpr(APICDeviceInfo *pDev, APICState *pApic, uint32_t val) { bool fIrqIsActive = false; bool fIrqWasActive = false; - fIrqWasActive = apic_update_irq(pDev, s); - s->tpr = val; - fIrqIsActive = apic_update_irq(pDev, s); + fIrqWasActive = apic_update_irq(pDev, pApic); + pApic->tpr = val; + fIrqIsActive = apic_update_irq(pDev, pApic); /* If an interrupt is pending and now masked, then clear the FF flag. */ if (fIrqWasActive && !fIrqIsActive) { Log(("apic_update_tpr: deactivate interrupt that was masked by the TPR update (%x)\n", val)); STAM_COUNTER_INC(&pDev->StatClearedActiveIrq); - cpuClearInterrupt(pDev, s); + apicCpuClearInterrupt(pDev, pApic); } } -static void apic_set_irq(APICDeviceInfo *pDev, APICState* s, int vector_num, int trigger_mode, uint32_t uTagSrc) +static void apic_set_irq(APICDeviceInfo *pDev, APICState *pApic, int vector_num, int trigger_mode, uint32_t uTagSrc) { - LogFlow(("CPU%d: apic_set_irq vector=%x trigger_mode=%x uTagSrc=%#x\n", s->phys_id, vector_num, trigger_mode, uTagSrc)); + LogFlow(("CPU%d: apic_set_irq vector=%x trigger_mode=%x uTagSrc=%#x\n", pApic->phys_id, vector_num, trigger_mode, uTagSrc)); - Apic256BitReg_SetBit(&s->irr, vector_num); + Apic256BitReg_SetBit(&pApic->irr, vector_num); if (trigger_mode) - Apic256BitReg_SetBit(&s->tmr, vector_num); + Apic256BitReg_SetBit(&pApic->tmr, vector_num); else - Apic256BitReg_ClearBit(&s->tmr, vector_num); + Apic256BitReg_ClearBit(&pApic->tmr, vector_num); - if (!s->auTags[vector_num]) - s->auTags[vector_num] = uTagSrc; + if (!pApic->auTags[vector_num]) + pApic->auTags[vector_num] = uTagSrc; else - s->auTags[vector_num] |= RT_BIT_32(31); + pApic->auTags[vector_num] |= RT_BIT_32(31); - apic_update_irq(pDev, s); + apic_update_irq(pDev, pApic); } -static void apic_eoi(APICDeviceInfo *pDev, APICState* s) +static void apic_eoi(APICDeviceInfo *pDev, APICState *pApic) { - int isrv = Apic256BitReg_FindLastSetBit(&s->isr, -1); + int isrv = Apic256BitReg_FindLastSetBit(&pApic->isr, -1); if (isrv < 0) return; - Apic256BitReg_ClearBit(&s->isr, isrv); - LogFlow(("CPU%d: apic_eoi isrv=%x\n", s->phys_id, isrv)); + Apic256BitReg_ClearBit(&pApic->isr, isrv); + LogFlow(("CPU%d: apic_eoi isrv=%x\n", pApic->phys_id, isrv)); /** @todo XXX: send the EOI packet to the APIC bus to allow the I/O APIC to * set the remote IRR bit for level triggered interrupts. */ - apic_update_irq(pDev, s); + apic_update_irq(pDev, pApic); } static PVMCPUSET apic_get_delivery_bitmask(APICDeviceInfo *pDev, uint8_t dest, uint8_t dest_mode, PVMCPUSET pDstSet) @@ -1336,49 +1329,51 @@ static PVMCPUSET apic_get_delivery_bitmask(APICDeviceInfo *pDev, uint8_t dest, u } #ifdef IN_RING3 -static void apic_init_ipi(APICDeviceInfo* pDev, APICState *s) + +static void apicR3InitIpi(APICDeviceInfo *pDev, APICState *pApic) { int i; for(i = 0; i < APIC_LVT_NB; i++) - s->lvt[i] = 1 << 16; /* mask LVT */ - s->tpr = 0; - s->spurious_vec = 0xff; - s->log_dest = 0; - s->dest_mode = 0xff; /** @todo 0xff???? */ - Apic256BitReg_Empty(&s->isr); - Apic256BitReg_Empty(&s->tmr); - Apic256BitReg_Empty(&s->irr); - s->esr = 0; - memset(s->icr, 0, sizeof(s->icr)); - s->divide_conf = 0; - s->count_shift = 1; - s->initial_count = 0; - s->initial_count_load_time = 0; - s->next_time = 0; + pApic->lvt[i] = 1 << 16; /* mask LVT */ + pApic->tpr = 0; + pApic->spurious_vec = 0xff; + pApic->log_dest = 0; + pApic->dest_mode = 0xff; /** @todo 0xff???? */ + Apic256BitReg_Empty(&pApic->isr); + Apic256BitReg_Empty(&pApic->tmr); + Apic256BitReg_Empty(&pApic->irr); + pApic->esr = 0; + memset(pApic->icr, 0, sizeof(pApic->icr)); + pApic->divide_conf = 0; + pApic->count_shift = 1; + pApic->initial_count = 0; + pApic->initial_count_load_time = 0; + pApic->next_time = 0; } -static void apicSendInitIpi(APICDeviceInfo* pDev, APICState *s) +static void apicSendInitIpi(APICDeviceInfo *pDev, APICState *pApic) { - apic_init_ipi(pDev, s); - cpuSendInitIpi(pDev, s); + apicR3InitIpi(pDev, pApic); + apicR3CpuSendInitIpi(pDev, pApic); } /* send a SIPI message to the CPU to start it */ -static void apic_startup(APICDeviceInfo* pDev, APICState *s, int vector_num) +static void apicR3Startup(APICDeviceInfo *pDev, APICState *pApic, int vector_num) { - Log(("[SMP] apic_startup: %d on CPUs %d\n", vector_num, s->phys_id)); - cpuSendSipi(pDev, s, vector_num); + Log(("[SMP] apicR3Startup: %d on CPUs %d\n", vector_num, pApic->phys_id)); + apicR3CpuSendSipi(pDev, pApic, vector_num); } + #endif /* IN_RING3 */ -static int apic_deliver(APICDeviceInfo *pDev, APICState *s, +static int apic_deliver(APICDeviceInfo *pDev, APICState *pApic, uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode, uint8_t vector_num, uint8_t polarity, uint8_t trigger_mode) { - int dest_shorthand = (s->icr[0] >> 18) & 3; + int dest_shorthand = (pApic->icr[0] >> 18) & 3; LogFlow(("apic_deliver dest=%x dest_mode=%x dest_shorthand=%x delivery_mode=%x vector_num=%x polarity=%x trigger_mode=%x uTagSrc=%#x\n", dest, dest_mode, dest_shorthand, delivery_mode, vector_num, polarity, trigger_mode)); VMCPUSET DstSet; @@ -1389,14 +1384,14 @@ static int apic_deliver(APICDeviceInfo *pDev, APICState *s, break; case 1: VMCPUSET_EMPTY(&DstSet); - VMCPUSET_ADD(&DstSet, s->id); + VMCPUSET_ADD(&DstSet, pApic->id); break; case 2: VMCPUSET_FILL(&DstSet); break; case 3: VMCPUSET_FILL(&DstSet); - VMCPUSET_DEL(&DstSet, s->id); + VMCPUSET_DEL(&DstSet, pApic->id); break; } @@ -1404,14 +1399,14 @@ static int apic_deliver(APICDeviceInfo *pDev, APICState *s, { case APIC_DM_INIT: { - uint32_t const trig_mode = (s->icr[0] >> 15) & 1; - uint32_t const level = (s->icr[0] >> 14) & 1; + uint32_t const trig_mode = (pApic->icr[0] >> 15) & 1; + uint32_t const level = (pApic->icr[0] >> 14) & 1; if (level == 0 && trig_mode == 1) { APIC_FOREACH_IN_SET_BEGIN(pDev, &DstSet); pCurApic->arb_id = pCurApic->id; APIC_FOREACH_END(); - Log(("CPU%d: APIC_DM_INIT arbitration id(s) set\n", s->phys_id)); + Log(("CPU%d: APIC_DM_INIT arbitration id(s) set\n", pApic->phys_id)); return VINF_SUCCESS; } break; @@ -1420,7 +1415,7 @@ static int apic_deliver(APICDeviceInfo *pDev, APICState *s, case APIC_DM_SIPI: # ifdef IN_RING3 APIC_FOREACH_IN_SET_BEGIN(pDev, &DstSet); - apic_startup(pDev, pCurApic, vector_num); + apicR3Startup(pDev, pCurApic, vector_num); APIC_FOREACH_END(); return VINF_SUCCESS; # else @@ -1436,51 +1431,50 @@ static int apic_deliver(APICDeviceInfo *pDev, APICState *s, } -PDMBOTHCBDECL(int) apicGetInterrupt(PPDMDEVINS pDevIns, uint32_t *puTagSrc) +PDMBOTHCBDECL(int) apicGetInterrupt(PPDMDEVINS pDevIns, VMCPUID idCpu, uint32_t *puTagSrc) { APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *); - /* if the APIC is not installed or enabled, we let the 8259 handle the - IRQs */ + /* if the APIC is not installed or enabled, we let the 8259 handle the IRQs */ if (!pDev) { - Log(("apic_get_interrupt: returns -1 (!s)\n")); + Log(("apic_get_interrupt: returns -1 (!pDev)\n")); return -1; } Assert(PDMCritSectIsOwner(pDev->CTX_SUFF(pCritSect))); - APICState *s = getLapic(pDev); /** @todo fix interface */ + APICState *pApic = apicGetStateById(pDev, idCpu); - if (!(s->spurious_vec & APIC_SV_ENABLE)) + if (!(pApic->spurious_vec & APIC_SV_ENABLE)) { - Log(("CPU%d: apic_get_interrupt: returns -1 (APIC_SV_ENABLE)\n", s->phys_id)); + Log(("CPU%d: apic_get_interrupt: returns -1 (APIC_SV_ENABLE)\n", pApic->phys_id)); return -1; } /** @todo XXX: spurious IRQ handling */ - int intno = Apic256BitReg_FindLastSetBit(&s->irr, -1); + int intno = Apic256BitReg_FindLastSetBit(&pApic->irr, -1); if (intno < 0) { - Log(("CPU%d: apic_get_interrupt: returns -1 (irr)\n", s->phys_id)); + Log(("CPU%d: apic_get_interrupt: returns -1 (irr)\n", pApic->phys_id)); return -1; } - if (s->tpr && (uint32_t)intno <= s->tpr) + if (pApic->tpr && (uint32_t)intno <= pApic->tpr) { *puTagSrc = 0; - Log(("apic_get_interrupt: returns %d (sp)\n", s->spurious_vec & 0xff)); - return s->spurious_vec & 0xff; + Log(("apic_get_interrupt: returns %d (sp)\n", pApic->spurious_vec & 0xff)); + return pApic->spurious_vec & 0xff; } - Apic256BitReg_ClearBit(&s->irr, intno); - Apic256BitReg_SetBit(&s->isr, intno); + Apic256BitReg_ClearBit(&pApic->irr, intno); + Apic256BitReg_SetBit(&pApic->isr, intno); - *puTagSrc = s->auTags[intno]; - s->auTags[intno] = 0; + *puTagSrc = pApic->auTags[intno]; + pApic->auTags[intno] = 0; - apic_update_irq(pDev, s); + apic_update_irq(pDev, pApic); - LogFlow(("CPU%d: apic_get_interrupt: returns %d / %#x\n", s->phys_id, intno, *puTagSrc)); + LogFlow(("CPU%d: apic_get_interrupt: returns %d / %#x\n", pApic->phys_id, intno, *puTagSrc)); return intno; } @@ -1680,6 +1674,7 @@ static void apicTimerSetLvt(APICDeviceInfo *pDev, APICState *pApic, uint32_t fNe } # ifdef IN_RING3 + /** * Timer callback function. * @@ -1690,7 +1685,7 @@ static void apicTimerSetLvt(APICDeviceInfo *pDev, APICState *pApic, uint32_t fNe static DECLCALLBACK(void) apicR3TimerCallback(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser) { APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *); - APICState *pApic = (APICState *)pvUser; + APICState *pApic = (APICState *)pvUser; Assert(pApic->pTimerR3 == pTimer); Assert(pApic->fTimerArmed); Assert(PDMCritSectIsOwner(pDev->pCritSectR3)); @@ -1723,44 +1718,44 @@ static DECLCALLBACK(void) apicR3TimerCallback(PPDMDEVINS pDevIns, PTMTIMER pTime static void apic_save(SSMHANDLE* f, void *opaque) { - APICState *s = (APICState*)opaque; + APICState *pApic = (APICState*)opaque; int i; - SSMR3PutU32(f, s->apicbase); - SSMR3PutU32(f, s->id); - SSMR3PutU32(f, s->phys_id); - SSMR3PutU32(f, s->arb_id); - SSMR3PutU32(f, s->tpr); - SSMR3PutU32(f, s->spurious_vec); - SSMR3PutU8(f, s->log_dest); - SSMR3PutU8(f, s->dest_mode); + SSMR3PutU32(f, pApic->apicbase); + SSMR3PutU32(f, pApic->id); + SSMR3PutU32(f, pApic->phys_id); + SSMR3PutU32(f, pApic->arb_id); + SSMR3PutU32(f, pApic->tpr); + SSMR3PutU32(f, pApic->spurious_vec); + SSMR3PutU8(f, pApic->log_dest); + SSMR3PutU8(f, pApic->dest_mode); for (i = 0; i < 8; i++) { - SSMR3PutU32(f, s->isr.au32Bitmap[i]); - SSMR3PutU32(f, s->tmr.au32Bitmap[i]); - SSMR3PutU32(f, s->irr.au32Bitmap[i]); + SSMR3PutU32(f, pApic->isr.au32Bitmap[i]); + SSMR3PutU32(f, pApic->tmr.au32Bitmap[i]); + SSMR3PutU32(f, pApic->irr.au32Bitmap[i]); } for (i = 0; i < APIC_LVT_NB; i++) { - SSMR3PutU32(f, s->lvt[i]); + SSMR3PutU32(f, pApic->lvt[i]); } - SSMR3PutU32(f, s->esr); - SSMR3PutU32(f, s->icr[0]); - SSMR3PutU32(f, s->icr[1]); - SSMR3PutU32(f, s->divide_conf); - SSMR3PutU32(f, s->count_shift); - SSMR3PutU32(f, s->initial_count); - SSMR3PutU64(f, s->initial_count_load_time); - SSMR3PutU64(f, s->next_time); - - TMR3TimerSave(s->CTX_SUFF(pTimer), f); + SSMR3PutU32(f, pApic->esr); + SSMR3PutU32(f, pApic->icr[0]); + SSMR3PutU32(f, pApic->icr[1]); + SSMR3PutU32(f, pApic->divide_conf); + SSMR3PutU32(f, pApic->count_shift); + SSMR3PutU32(f, pApic->initial_count); + SSMR3PutU64(f, pApic->initial_count_load_time); + SSMR3PutU64(f, pApic->next_time); + + TMR3TimerSave(pApic->CTX_SUFF(pTimer), f); } static int apic_load(SSMHANDLE *f, void *opaque, int version_id) { - APICState *s = (APICState*)opaque; + APICState *pApic = (APICState*)opaque; int i; /** @todo XXX: what if the base changes? (registered memory regions) */ - SSMR3GetU32(f, &s->apicbase); + SSMR3GetU32(f, &pApic->apicbase); switch (version_id) { @@ -1768,49 +1763,49 @@ static int apic_load(SSMHANDLE *f, void *opaque, int version_id) { uint8_t val = 0; SSMR3GetU8(f, &val); - s->id = val; + pApic->id = val; /* UP only in old saved states */ - s->phys_id = 0; + pApic->phys_id = 0; SSMR3GetU8(f, &val); - s->arb_id = val; + pApic->arb_id = val; break; } case APIC_SAVED_STATE_VERSION: case APIC_SAVED_STATE_VERSION_VBOX_30: - SSMR3GetU32(f, &s->id); - SSMR3GetU32(f, &s->phys_id); - SSMR3GetU32(f, &s->arb_id); + SSMR3GetU32(f, &pApic->id); + SSMR3GetU32(f, &pApic->phys_id); + SSMR3GetU32(f, &pApic->arb_id); break; default: return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION; } - SSMR3GetU32(f, &s->tpr); - SSMR3GetU32(f, &s->spurious_vec); - SSMR3GetU8(f, &s->log_dest); - SSMR3GetU8(f, &s->dest_mode); + SSMR3GetU32(f, &pApic->tpr); + SSMR3GetU32(f, &pApic->spurious_vec); + SSMR3GetU8(f, &pApic->log_dest); + SSMR3GetU8(f, &pApic->dest_mode); for (i = 0; i < 8; i++) { - SSMR3GetU32(f, &s->isr.au32Bitmap[i]); - SSMR3GetU32(f, &s->tmr.au32Bitmap[i]); - SSMR3GetU32(f, &s->irr.au32Bitmap[i]); + SSMR3GetU32(f, &pApic->isr.au32Bitmap[i]); + SSMR3GetU32(f, &pApic->tmr.au32Bitmap[i]); + SSMR3GetU32(f, &pApic->irr.au32Bitmap[i]); } for (i = 0; i < APIC_LVT_NB; i++) { - SSMR3GetU32(f, &s->lvt[i]); + SSMR3GetU32(f, &pApic->lvt[i]); } - SSMR3GetU32(f, &s->esr); - SSMR3GetU32(f, &s->icr[0]); - SSMR3GetU32(f, &s->icr[1]); - SSMR3GetU32(f, &s->divide_conf); - SSMR3GetU32(f, (uint32_t *)&s->count_shift); - SSMR3GetU32(f, (uint32_t *)&s->initial_count); - SSMR3GetU64(f, (uint64_t *)&s->initial_count_load_time); - SSMR3GetU64(f, (uint64_t *)&s->next_time); - - int rc = TMR3TimerLoad(s->CTX_SUFF(pTimer), f); + SSMR3GetU32(f, &pApic->esr); + SSMR3GetU32(f, &pApic->icr[0]); + SSMR3GetU32(f, &pApic->icr[1]); + SSMR3GetU32(f, &pApic->divide_conf); + SSMR3GetU32(f, (uint32_t *)&pApic->count_shift); + SSMR3GetU32(f, (uint32_t *)&pApic->initial_count); + SSMR3GetU64(f, (uint64_t *)&pApic->initial_count_load_time); + SSMR3GetU64(f, (uint64_t *)&pApic->next_time); + + int rc = TMR3TimerLoad(pApic->CTX_SUFF(pTimer), f); AssertRCReturn(rc, rc); - s->uHintedCountShift = s->uHintedInitialCount = 0; - s->fTimerArmed = TMTimerIsActive(s->CTX_SUFF(pTimer)); - if (s->fTimerArmed) - apicDoFrequencyHinting(s); + pApic->uHintedCountShift = pApic->uHintedInitialCount = 0; + pApic->fTimerArmed = TMTimerIsActive(pApic->CTX_SUFF(pTimer)); + if (pApic->fTimerArmed) + apicDoFrequencyHinting(pApic); return VINF_SUCCESS; /** @todo darn mess! */ } @@ -1821,90 +1816,55 @@ static int apic_load(SSMHANDLE *f, void *opaque, int version_id) PDMBOTHCBDECL(int) apicMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb) { APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *); - APICState *s = getLapic(pDev); + APICState *pApic = apicGetStateByCurEmt(pDev); - Log(("CPU%d: apicMMIORead at %llx\n", s->phys_id, (uint64_t)GCPhysAddr)); + Log(("CPU%d: apicMMIORead at %RGp\n", pApic->phys_id, GCPhysAddr)); + Assert(cb == 4); /** @todo add LAPIC range validity checks (different LAPICs can * theoretically have different physical addresses, see @bugref{3092}) */ STAM_COUNTER_INC(&CTXSUFF(pDev->StatMMIORead)); - switch (cb) - { - case 1: - /** @todo this is not how recent APIC behave! We will fix - * this via the IOM. */ - *(uint8_t *)pv = 0; - break; - - case 2: - /** @todo this is not how recent APIC behave! */ - *(uint16_t *)pv = 0; - break; - - case 4: - { -#if 0 /** @note experimental */ +#if 0 /* Note! experimental */ #ifndef IN_RING3 - uint32_t index = (GCPhysAddr >> 4) & 0xff; + uint32_t index = (GCPhysAddr >> 4) & 0xff; - if ( index == 0x08 /* TPR */ - && ++s->cTPRPatchAttempts < APIC_MAX_PATCH_ATTEMPTS) - { -#ifdef IN_RC - pDevIns->pDevHlpGC->pfnPATMSetMMIOPatchInfo(pDevIns, GCPhysAddr, &s->tpr); -#else - RTGCPTR pDevInsGC = PDMINS2DATA_GCPTR(pDevIns); - pDevIns->pHlpR0->pfnPATMSetMMIOPatchInfo(pDevIns, GCPhysAddr, pDevIns + RT_OFFSETOF(APICState, tpr)); -#endif - return VINF_PATM_HC_MMIO_PATCH_READ; - } + if ( index == 0x08 /* TPR */ + && ++pApic->cTPRPatchAttempts < APIC_MAX_PATCH_ATTEMPTS) + { +# ifdef IN_RC + pDevIns->pDevHlpGC->pfnPATMSetMMIOPatchInfo(pDevIns, GCPhysAddr, &pApic->tpr); +# else + RTGCPTR pDevInsGC = PDMINS2DATA_GCPTR(pDevIns); + pDevIns->pHlpR0->pfnPATMSetMMIOPatchInfo(pDevIns, GCPhysAddr, pDevIns + RT_OFFSETOF(APICState, tpr)); +# endif + return VINF_PATM_HC_MMIO_PATCH_READ; + } #endif #endif /* experimental */ - /* It does its own locking. */ - uint64_t u64Value = 0; - int rc = apicReadRegister(pDev, s, (GCPhysAddr >> 4) & 0xff, &u64Value, - VINF_IOM_R3_MMIO_READ, false /*fMsr*/); - *(uint32_t *)pv = (uint32_t)u64Value; - return rc; - } - - default: - AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */ - return VERR_INTERNAL_ERROR; - } - return VINF_SUCCESS; + /* Note! apicReadRegister does its own locking. */ + uint64_t u64Value = 0; + int rc = apicReadRegister(pDev, pApic, (GCPhysAddr >> 4) & 0xff, &u64Value, VINF_IOM_R3_MMIO_READ, false /*fMsr*/); + *(uint32_t *)pv = (uint32_t)u64Value; + return rc; } PDMBOTHCBDECL(int) apicMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb) { APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *); - APICState *s = getLapic(pDev); + APICState *pApic = apicGetStateByCurEmt(pDev); - Log(("CPU%d: apicMMIOWrite at %llx\n", s->phys_id, (uint64_t)GCPhysAddr)); + Log(("CPU%d: apicMMIOWrite at %RGp\n", pApic->phys_id, GCPhysAddr)); + Assert(cb == 4); /** @todo: add LAPIC range validity checks (multiple LAPICs can theoretically have * different physical addresses, see @bugref{3092}) */ STAM_COUNTER_INC(&CTXSUFF(pDev->StatMMIOWrite)); - switch (cb) - { - case 1: - case 2: - /* ignore */ - break; - - case 4: - /* It does its own locking. */ - return apicWriteRegister(pDev, s, (GCPhysAddr >> 4) & 0xff, *(uint32_t const *)pv, - VINF_IOM_R3_MMIO_WRITE, false /*fMsr*/); - - default: - AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */ - return VERR_INTERNAL_ERROR; - } - return VINF_SUCCESS; + /* Note! It does its own locking. */ + return apicWriteRegister(pDev, pApic, (GCPhysAddr >> 4) & 0xff, *(uint32_t const *)pv, + VINF_IOM_R3_MMIO_WRITE, false /*fMsr*/); } #ifdef IN_RING3 @@ -1948,7 +1908,7 @@ static void apicR3DumpVec(APICDeviceInfo *pDev, APICState *pApic, PCDBGFINFOHLP * @param pApic The Local APIC in question. * @param pHlp The output helper. */ -static void apicR3InfoBasic(APICDeviceInfo *pDev, APICState *pApic, PCDBGFINFOHLP pHlp) +static void apicR3InfoBasic(APICDeviceInfo *pDev, APICState *pApic, PCDBGFINFOHLP pHlp) { uint64_t u64; @@ -2054,9 +2014,9 @@ static void apicR3InfoTimer(APICDeviceInfo *pDev, APICState *pApic, PCDBGFINFOHL static DECLCALLBACK(void) apicR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs) { APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *); - APICState *pApic = getLapic(pDev); + APICState *pApic = apicGetStateByCurEmt(pDev); - if (pszArgs == NULL || !strcmp(pszArgs, "basic")) + if (pszArgs == NULL || !*pszArgs || !strcmp(pszArgs, "basic")) apicR3InfoBasic(pDev, pApic, pHlp); else if (!strcmp(pszArgs, "lvt")) apicR3InfoLVT(pDev, pApic, pHlp); @@ -2165,9 +2125,9 @@ static DECLCALLBACK(void) apicR3Reset(PPDMDEVINS pDevIns) TMTimerStop(pApic->CTX_SUFF(pTimer)); /* Clear LAPIC state as if an INIT IPI was sent. */ - apic_init_ipi(pDev, pApic); + apicR3InitIpi(pDev, pApic); - /* The IDs are not touched by apic_init_ipi() and must be reset now. */ + /* The IDs are not touched by apicR3InitIpi() and must be reset now. */ pApic->arb_id = pApic->id = i; Assert(pApic->id == pApic->phys_id); /* The two should match again. */ @@ -2177,7 +2137,7 @@ static DECLCALLBACK(void) apicR3Reset(PPDMDEVINS pDevIns) pApic->apicbase |= MSR_IA32_APICBASE_BSP; /* Clear any pending APIC interrupt action flag. */ - cpuClearInterrupt(pDev, pApic); + apicCpuClearInterrupt(pDev, pApic); } /** @todo r=bird: Why is this done everytime, while the constructor first * checks the CPUID? Who is right? */ @@ -2209,7 +2169,7 @@ static DECLCALLBACK(void) apicR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta * @param pApic The Local APIC state to init. * @param id The Local APIC ID. */ -DECLINLINE(void) initApicData(APICState *pApic, uint8_t id) +static void apicR3StateInit(APICState *pApic, uint8_t id) { memset(pApic, 0, sizeof(*pApic)); @@ -2295,7 +2255,7 @@ static DECLCALLBACK(int) apicR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFG pDev->paLapicsRC = MMHyperR3ToRC(pVM, pDev->paLapicsR3); for (i = 0; i < cCpus; i++) - initApicData(&pDev->paLapicsR3[i], i); + apicR3StateInit(&pDev->paLapicsR3[i], i); /* * Register the APIC. @@ -2392,7 +2352,7 @@ static DECLCALLBACK(int) apicR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFG /** @todo: shall reregister, if base changes. */ uint32_t ApicBase = pDev->paLapicsR3[0].apicbase & ~0xfff; rc = PDMDevHlpMMIORegister(pDevIns, ApicBase, 0x1000, pDev, - IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU, + IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_ONLY_DWORD, apicMMIOWrite, apicMMIORead, "APIC Memory"); if (RT_FAILURE(rc)) return rc; @@ -2500,7 +2460,7 @@ const PDMDEVREG g_DeviceAPIC = NULL, /* pfnRelocate */ apicR3Relocate, - /* pfnIOCtl */ + /* pfnMemSetup */ NULL, /* pfnPowerOn */ NULL, |