DevAPIC.cpp revision 1cde4dd19cba0507a9cdab737272d88feba05d41
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico * Advanced Programmable Interrupt Controller (APIC) Device.
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico * Copyright (C) 2006-2013 Oracle Corporation
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico * This file is part of VirtualBox Open Source Edition (OSE), as
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico * available from http://www.virtualbox.org. This file is free software;
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico * you can redistribute it and/or modify it under the terms of the GNU
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico * General Public License (GPL) as published by the Free Software
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico * Foundation, in version 2 as it comes in the "COPYING" file of the
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico * --------------------------------------------------------------------
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico * This code is based on:
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico * apic.c revision 1.5 @@OSETODO
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico * APIC support
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico * Copyright (c) 2004-2005 Fabrice Bellard
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico * This library is free software; you can redistribute it and/or
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico * modify it under the terms of the GNU Lesser General Public
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico * License as published by the Free Software Foundation; either
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico * version 2 of the License, or (at your option) any later version.
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico * This library is distributed in the hope that it will be useful,
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico * but WITHOUT ANY WARRANTY; without even the implied warranty of
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico * Lesser General Public License for more details.
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico * You should have received a copy of the GNU Lesser General Public
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico * License along with this library; if not, write to the Free Software
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico/*******************************************************************************
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico* Header Files *
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico*******************************************************************************/
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico/*******************************************************************************
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico* Defined Constants And Macros *
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico*******************************************************************************/
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico/** The current saved state version.*/
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico/** The saved state version used by VirtualBox v3 and earlier.
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico * This does not include the config. */
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico/** Some ancient version... */
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico/* version 0x14: Pentium 4, Xeon; LVT count depends on that */
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico/** @def APIC_LOCK
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico * Acquires the PDM lock. */
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico int rc2 = PDMCritSectEnter((a_pDev)->CTX_SUFF(pCritSect), (rcBusy)); \
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico/** @def APIC_LOCK_VOID
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico * Acquires the PDM lock and does not expect failure (i.e. ring-3 only!). */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico int rc2 = PDMCritSectEnter((a_pDev)->CTX_SUFF(pCritSect), (rcBusy)); \
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico/** @def APIC_UNLOCK
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico * Releases the PDM lock. */
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico/** @def APIC_AND_TM_LOCK
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico * Acquires the virtual sync clock lock as well as the PDM lock. */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico#define APIC_AND_TM_LOCK(a_pDev, a_pAcpi, rcBusy) \
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico int rc2 = TMTimerLock((a_pAcpi)->CTX_SUFF(pTimer), (rcBusy)); \
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico rc2 = PDMCritSectEnter((a_pDev)->CTX_SUFF(pCritSect), (rcBusy)); \
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico/** @def APIC_AND_TM_UNLOCK
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico * Releases the PDM lock as well as the TM virtual sync clock lock. */
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico PDMCritSectLeave((a_pDev)->CTX_SUFF(pCritSect)); \
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico * Begins an APIC enumeration block.
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico * Code placed between this and the APIC_FOREACH_END macro will be executed for
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico * each APIC instance present in the system.
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico * @param a_pDev The APIC device.
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico APICState *pCurApic = (a_pDev)->CTX_SUFF(paLapics); \
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico for (VMCPUID iCurApic = 0; iCurApic < cApics; iCurApic++, pCurApic++) \
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico do { } while (0)
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico * Begins an APIC enumeration block, given a destination set.
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico * Code placed between this and the APIC_FOREACH_END macro will be executed for
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico * each APIC instance present in @a a_pDstSet.
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico * @param a_pDev The APIC device.
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico * @param a_pDstSet The destination set.
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico#define APIC_FOREACH_IN_SET_BEGIN(a_pDev, a_pDstSet) \
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico if (!VMCPUSET_IS_PRESENT((a_pDstSet), iCurApic)) \
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico do { } while (0)
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico/** Counterpart to APIC_FOREACH_IN_SET_BEGIN and APIC_FOREACH_BEGIN. */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico/*******************************************************************************
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico* Structures and Typedefs *
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico*******************************************************************************/
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico /** The bitmap data. */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico * Tests if a bit in the 256-bit APIC register is set.
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico * @returns true if set, false if clear.
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico * @param pReg The register.
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico * @param iBit The bit to test for.
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNicoDECLINLINE(bool) Apic256BitReg_IsBitSet(PCAPIC256BITREG pReg, unsigned iBit)
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico * Sets a bit in the 256-bit APIC register is set.
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico * @param pReg The register.
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico * @param iBit The bit to set.
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNicoDECLINLINE(void) Apic256BitReg_SetBit(PAPIC256BITREG pReg, unsigned iBit)
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico * Clears a bit in the 256-bit APIC register is set.
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico * @param pReg The register.
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico * @param iBit The bit to clear.
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNicoDECLINLINE(void) Apic256BitReg_ClearBit(PAPIC256BITREG pReg, unsigned iBit)
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico * Clears all bits in the 256-bit APIC register set.
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico * @param pReg The register.
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNicoDECLINLINE(void) Apic256BitReg_Empty(PAPIC256BITREG pReg)
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico memset(&pReg->au32Bitmap[0], 0, sizeof(pReg->au32Bitmap));
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico * Finds the last bit set in the register, i.e. the highest priority interrupt.
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico * @returns The index of the found bit, @a iRetAllClear if none was found.
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico * @param pReg The register.
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico * @param iRetAllClear What to return if all bits are clear.
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNicostatic int Apic256BitReg_FindLastSetBit(PCAPIC256BITREG pReg, int iRetAllClear)
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico while (i-- > 0)
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico u |= i << 5;
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico return (int)u;
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNicotypedef struct APICState
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico /* Task priority register (interrupt level) */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico /* Logical APIC id - user programmable */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico /* Physical APIC id - not visible to user, constant */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico /** @todo: is it logical or physical? Not really used anyway now. */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico APIC256BITREG irr; /**< interrupt request register */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico /** The time stamp of the initial_count load, i.e. when it was started. */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico /** The time stamp of the next timer callback. */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico /** The APIC timer - R3 Ptr. */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico /** The APIC timer - R0 Ptr. */
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico /** The APIC timer - RC Ptr. */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico /** Whether the timer is armed or not */
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico /** Alignment */
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico /** The initial_count value used for the current frequency hint. */
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico /** The count_shift value used for the current frequency hint. */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico /** Timer description timer. */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico /** The IRQ tags and source IDs for each (tracing purposes). */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNicoAssertCompileMemberAlignment(APICState, initial_count_load_time, 8);
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNicoAssertCompileMemberAlignment(APICState, StatTimerSetInitialCount, 8);
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNicotypedef struct
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico /** The device instance - R3 Ptr. */
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico /** The APIC helpers - R3 Ptr. */
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico /** LAPICs states - R3 Ptr */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico /** The critical section - R3 Ptr. */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico /** The device instance - R0 Ptr. */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico /** The APIC helpers - R0 Ptr. */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico /** LAPICs states - R0 Ptr */
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico /** The critical section - R3 Ptr. */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico /** The device instance - RC Ptr. */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico /** The APIC helpers - RC Ptr. */
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico /** LAPICs states - RC Ptr */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico /** The critical section - R3 Ptr. */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico /** APIC specification version in this virtual hardware configuration. */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico /** Number of attempts made to optimize TPR accesses. */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico /** Number of CPUs on the system (same as LAPIC count). */
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico /** Whether we've got an IO APIC or not. */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico /** Alignment padding. */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNicoAssertCompileMemberAlignment(APICDeviceInfo, StatMMIOReadGC, 8);
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico/*******************************************************************************
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico* Internal Functions *
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico*******************************************************************************/
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNicostatic void apic_update_tpr(APICDeviceInfo *pDev, APICState* s, uint32_t val);
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNicostatic void apic_eoi(APICDeviceInfo *pDev, APICState* s); /* */
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNicostatic PVMCPUSET apic_get_delivery_bitmask(APICDeviceInfo* pDev, uint8_t dest, uint8_t dest_mode, PVMCPUSET pDstSet);
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNicostatic int apic_deliver(APICDeviceInfo* pDev, APICState *s,
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNicostatic uint32_t apic_get_current_count(APICDeviceInfo const *pDev, APICState const *s);
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNicostatic void apicTimerSetInitialCount(APICDeviceInfo *pDev, APICState *s, uint32_t initial_count);
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNicostatic void apicTimerSetLvt(APICDeviceInfo *pDev, APICState *pApic, uint32_t fNew);
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNicostatic void apicSendInitIpi(APICDeviceInfo* pDev, APICState *s);
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNicostatic void apic_init_ipi(APICDeviceInfo* pDev, APICState *s);
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNicostatic void apic_set_irq(APICDeviceInfo* pDev, APICState *s, int vector_num, int trigger_mode, uint32_t uTagSrc);
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNicostatic bool apic_update_irq(APICDeviceInfo* pDev, APICState *s);
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNicoDECLINLINE(APICState*) getLapicById(APICDeviceInfo *pDev, VMCPUID id)
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico AssertFatalMsg(id < pDev->cCpus, ("CPU id %d out of range\n", id));
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNicoDECLINLINE(APICState*) getLapic(APICDeviceInfo* pDev)
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico /* LAPIC's array is indexed by CPU id */
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico VMCPUID id = pDev->CTX_SUFF(pApicHlp)->pfnGetCpuId(pDev->CTX_SUFF(pDevIns));
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNicoDECLINLINE(VMCPUID) getCpuFromLapic(APICDeviceInfo* pDev, APICState *s)
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico /* for now we assume LAPIC physical id == CPU id */
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNicoDECLINLINE(void) cpuSetInterrupt(APICDeviceInfo* pDev, APICState *s, PDMAPICIRQ enmType = PDMAPICIRQ_HARDWARE)
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico LogFlow(("apic: setting interrupt flag for cpu %d\n", getCpuFromLapic(pDev, s)));
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico pDev->CTX_SUFF(pApicHlp)->pfnSetInterruptFF(pDev->CTX_SUFF(pDevIns), enmType,
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNicoDECLINLINE(void) cpuClearInterrupt(APICDeviceInfo* pDev, APICState *s, PDMAPICIRQ enmType = PDMAPICIRQ_HARDWARE)
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico pDev->CTX_SUFF(pApicHlp)->pfnClearInterruptFF(pDev->CTX_SUFF(pDevIns), enmType,
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNicoDECLINLINE(void) cpuSendSipi(APICDeviceInfo* pDev, APICState *s, int vector)
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNicoDECLINLINE(void) cpuSendInitIpi(APICDeviceInfo* pDev, APICState *s)
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico# endif /* IN_RING3 */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNicoDECLINLINE(uint32_t) getApicEnableBits(APICDeviceInfo* pDev)
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico return MSR_IA32_APICBASE_ENABLE | MSR_IA32_APICBASE_X2ENABLE ;
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico AssertMsgFailed(("Unsupported APIC version %d\n", pDev->enmVersion));
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNicoDECLINLINE(PDMAPICVERSION) getApicMode(APICState *apic)
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico /* Invalid */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico LogFlow(("apic_bus_deliver mask=%R[vmcpuset] mode=%x vector=%x polarity=%x trigger_mode=%x uTagSrc=%#x\n",
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico pDstSet, delivery_mode, vector_num, polarity, trigger_mode, uTagSrc));
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico VMCPUID idDstCpu = VMCPUSET_FIND_FIRST_PRESENT(pDstSet);
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico apic_set_irq(pDev, pApic, vector_num, trigger_mode, uTagSrc);
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico /** @todo XXX: arbitration */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico /* normal INIT IPI sent to processors */
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico /* We shall send init IPI only in R3. */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico#endif /* IN_RING3 */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico /* handled in I/O APIC code */
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico apic_set_irq(pDev, pCurApic, vector_num, trigger_mode, uTagSrc);
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNicoPDMBOTHCBDECL(void) apicSetBase(PPDMDEVINS pDevIns, VMCPUID idCpu, uint64_t val)
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico Assert(PDMCritSectIsOwner(pDev->CTX_SUFF(pCritSect)));
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico /** @todo: do we need to lock here ? */
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico /* APIC_LOCK_VOID(pDev, VERR_INTERNAL_ERROR); */
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico /** @todo If this change is valid immediately, then we should change the MMIO registration! */
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico /* We cannot change if this CPU is BSP or not by writing to MSR - it's hardwired */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico (s->apicbase & MSR_IA32_APICBASE_BSP) /* keep BSP bit */;
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico /* Clear any pending APIC interrupt action flag. */
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico /** @todo: why do we do that? */
a332a4045e2f94ed20a00415b5a624da7721dc2aJazzyNico pDev->CTX_SUFF(pApicHlp)->pfnChangeFeature(pDevIns, PDMAPICVERSION_NONE);
case PDMAPICVERSION_APIC:
case PDMAPICVERSION_X2APIC:
return s->apicbase;
return s->tpr;
static int apicWriteRegisterInvalid(APICDeviceInfo *pDev, APICState *pApic, uint32_t iReg, uint64_t u64Value,
Log(("apicWriteRegisterInvalid/%u: iReg=%#x fMsr=%RTbool u64Value=%#llx\n", pApic->phys_id, iReg, fMsr, u64Value));
return rc;
static int apicWriteRegister(APICDeviceInfo *pDev, APICState *pApic, uint32_t iReg, uint64_t u64Value,
switch (iReg)
pApic->dest_mode = u64Value >> 28; /** @todo r=bird: range? This used to be 32-bit before morphed into an MSR handler. */
if (!fMsr)
if (fMsr)
&SelfSet,
return rc;
static int apicReadRegisterInvalid(APICDeviceInfo *pDev, APICState *pApic, uint32_t iReg, uint64_t *pu64Value,
*pu64Value = 0;
return rc;
static int apicReadRegister(APICDeviceInfo *pDev, APICState *pApic, uint32_t iReg, uint64_t *pu64Value,
switch (iReg)
*pu64Value = 0;
if (fMsr)
if (fMsr)
if (fMsr)
*pu64Value = 0;
return rc;
PDMBOTHCBDECL(int) apicWriteMSR(PPDMDEVINS pDevIns, VMCPUID idCpu, uint32_t u32Reg, uint64_t u64Value)
PDMBOTHCBDECL(int) apicReadMSR(PPDMDEVINS pDevIns, VMCPUID idCpu, uint32_t u32Reg, uint64_t *pu64Value)
return VERR_EM_INTERPRETER;
LogFlow(("apicBusDeliverCallback: pDevIns=%p u8Dest=%#x u8DestMode=%#x u8DeliveryMode=%#x iVector=%#x u8Polarity=%#x u8TriggerMode=%#x uTagSrc=%#x\n",
if (u8Level)
return VINF_SUCCESS;
switch (u8Delivery)
case APIC_DM_EXTINT:
if (u8Level)
return VINF_SUCCESS;
case APIC_DM_NMI:
return VINF_SUCCESS;
case APIC_DM_SMI:
case APIC_DM_FIXED:
static unsigned s_c = 0;
return VINF_SUCCESS;
case APIC_DM_INIT:
static unsigned s_c = 0;
AssertLogRelMsgFailed(("delivery type %d not implemented. u8Pin=%d u8Level=%d\n", u8Delivery, u8Pin, u8Level));
return VERR_INTERNAL_ERROR_4;
return VINF_SUCCESS;
int ppr;
return ppr;
if (irrv < 0)
if (!pDev)
if (irrv < 0)
bool fIrqIsActive = false;
bool fIrqWasActive = false;
static void apic_set_irq(APICDeviceInfo *pDev, APICState* s, 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));
if (trigger_mode)
if (isrv < 0)
static PVMCPUSET apic_get_delivery_bitmask(APICDeviceInfo *pDev, uint8_t dest, uint8_t dest_mode, PVMCPUSET pDstSet)
if (dest_mode == 0)
return pDstSet;
#ifdef IN_RING3
for(i = 0; i < APIC_LVT_NB; i++)
s->tpr = 0;
s->log_dest = 0;
s->esr = 0;
s->divide_conf = 0;
s->initial_count = 0;
s->initial_count_load_time = 0;
s->next_time = 0;
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));
switch (dest_shorthand)
switch (delivery_mode)
case APIC_DM_INIT:
return VINF_SUCCESS;
case APIC_DM_SIPI:
# ifdef IN_RING3
return VINF_SUCCESS;
return VINF_IOM_R3_MMIO_WRITE;
if (!pDev)
if (intno < 0)
*puTagSrc = 0;
return intno;
val = 0;
return val;
uHz = 0;
static void apicTimerSetInitialCount(APICDeviceInfo *pDev, APICState *pApic, uint32_t u32NewInitialCount)
&& u32NewInitialCount > 0)
Log(("apicTimerSetInitialCount: ic=%#x sh=%#x iclt=%#llx\n", u32NewInitialCount, pApic->count_shift, pApic->initial_count_load_time));
uint64_t cTicks = (TMTimerGet(pApic->CTX_SUFF(pTimer)) - pApic->initial_count_load_time) >> pApic->count_shift;
NextTS = ((cTicks / ((uint64_t)pApic->initial_count + 1)) + 1) * ((uint64_t)pApic->initial_count + 1);
/* Try avoid the assertion in TM.cpp... this isn't perfect! */
Log(("apicTimerSetLvt: ic=%#x sh=%#x nxt=%#llx\n", pApic->initial_count, pApic->count_shift, pApic->next_time));
# ifdef IN_RING3
Log2(("apicR3TimerCallback: ic=%#x sh=%#x nxt=%#llx\n", pApic->initial_count, pApic->count_shift, pApic->next_time));
for (i = 0; i < APIC_LVT_NB; i++) {
switch (version_id)
s->phys_id = 0;
case APIC_SAVED_STATE_VERSION:
for (i = 0; i < APIC_LVT_NB; i++) {
if (s->fTimerArmed)
PDMBOTHCBDECL(int) apicMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
switch (cb)
#ifndef IN_RING3
#ifdef IN_RC
pDevIns->pHlpR0->pfnPATMSetMMIOPatchInfo(pDevIns, GCPhysAddr, pDevIns + RT_OFFSETOF(APICState, tpr));
return VINF_PATM_HC_MMIO_PATCH_READ;
return rc;
return VERR_INTERNAL_ERROR;
return VINF_SUCCESS;
PDMBOTHCBDECL(int) apicMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb)
switch (cb)
return VERR_INTERNAL_ERROR;
return VINF_SUCCESS;
#ifdef IN_RING3
return u64Value;
static void apicR3DumpVec(APICDeviceInfo *pDev, APICState *pApic, PCDBGFINFOHLP pHlp, uint32_t iStartReg)
static const char * const s_apszDeliveryModes[] =
return VINF_SSM_DONT_CALL_AGAIN;
return VINF_SUCCESS;
static DECLCALLBACK(int) apicR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - cCpus: saved=%#x config=%#x"), cCpus, pDev->cCpus);
bool fIoApic;
return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - fIoApic: saved=%RTbool config=%RTbool"), fIoApic, pDev->fIoApic);
return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - uApicVersion: saved=%#x config=%#x"), uApicVersion, pDev->enmVersion);
return VINF_SUCCESS;
return rc;
/* Reset should re-enable the APIC, see comment in msi.h */
/* See comment in msi.h for LAPIC base info. */
for (int i = 0; i < APIC_LVT_NB; i++)
uint32_t i;
bool fIoApic;
bool fRZEnabled;
rc = MMHyperAlloc(pVM, cCpus * sizeof(APICState), 1, MM_TAG_PDM_DEVICE_USER, (void **)&pDev->paLapicsR3);
return VERR_NO_MEMORY;
for (i = 0; i < cCpus; i++)
if (fRZEnabled)
return rc;
if (fRZEnabled)
rc = PDMDevHlpMMIORegisterRC(pDevIns, ApicBase, 0x1000, NIL_RTRCPTR /*pvUser*/, "apicMMIOWrite", "apicMMIORead");
return rc;
rc = PDMDevHlpMMIORegisterR0(pDevIns, ApicBase, 0x1000, NIL_RTR0PTR /*pvUser*/, "apicMMIOWrite", "apicMMIORead");
return rc;
for (i = 0; i < cCpus; i++)
return rc;
return rc;
#ifdef VBOX_WITH_STATISTICS
PDMDevHlpSTAMRegister(pDevIns, &pDev->StatMMIOReadGC, STAMTYPE_COUNTER, "/Devices/APIC/MMIOReadGC", STAMUNIT_OCCURENCES, "Number of APIC MMIO reads in GC.");
PDMDevHlpSTAMRegister(pDevIns, &pDev->StatMMIOReadHC, STAMTYPE_COUNTER, "/Devices/APIC/MMIOReadHC", STAMUNIT_OCCURENCES, "Number of APIC MMIO reads in HC.");
PDMDevHlpSTAMRegister(pDevIns, &pDev->StatMMIOWriteGC, STAMTYPE_COUNTER, "/Devices/APIC/MMIOWriteGC", STAMUNIT_OCCURENCES, "Number of APIC MMIO writes in GC.");
PDMDevHlpSTAMRegister(pDevIns, &pDev->StatMMIOWriteHC, STAMTYPE_COUNTER, "/Devices/APIC/MMIOWriteHC", STAMUNIT_OCCURENCES, "Number of APIC MMIO writes in HC.");
PDMDevHlpSTAMRegister(pDevIns, &pDev->StatClearedActiveIrq,STAMTYPE_COUNTER, "/Devices/APIC/MaskedActiveIRQ", STAMUNIT_OCCURENCES, "Number of cleared irqs.");
for (i = 0; i < cCpus; i++)
PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetInitialCount, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Calls to apicTimerSetInitialCount.", "/Devices/APIC/%u/TimerSetInitialCount", i);
PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetInitialCountArm, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerSetRelative calls.", "/Devices/APIC/%u/TimerSetInitialCount/Arm", i);
PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetInitialCountDisarm, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerStop calls.", "/Devices/APIC/%u/TimerSetInitialCount/Disasm", i);
PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvt, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Calls to apicTimerSetLvt.", "/Devices/APIC/%u/TimerSetLvt", i);
PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtClearPeriodic, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Clearing APIC_LVT_TIMER_PERIODIC.", "/Devices/APIC/%u/TimerSetLvt/ClearPeriodic", i);
PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtPostponed, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerStop postponed.", "/Devices/APIC/%u/TimerSetLvt/Postponed", i);
PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtArmed, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerSet avoided.", "/Devices/APIC/%u/TimerSetLvt/Armed", i);
PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtArm, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerSet necessary.", "/Devices/APIC/%u/TimerSetLvt/Arm", i);
PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtArmRetries, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerSet retries.", "/Devices/APIC/%u/TimerSetLvt/ArmRetries", i);
PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtNoRelevantChange,STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "No relevant flags changed.", "/Devices/APIC/%u/TimerSetLvt/NoRelevantChange", i);
return VINF_SUCCESS;
PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64 | PDM_DEVREG_FLAGS_PAE36 | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
sizeof(APICState),
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,