VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/DevAPIC.cpp@ 62293

Last change on this file since 62293 was 61776, checked in by vboxsync, 9 years ago

CPUM,APIC: Per-CPU APIC CPUID feature bit and MSR_IA32_APICBASE GP mask adjustments.

  • Changed the PDMAPICHLPR3::pfnChangeFeature to pfnSetFeatureLevel, removing the RC and R0 versions.
  • Only use pfnSetFeatureLevel from the APIC constructor to communicate to CPUM the max APIC feature level, not to globally flip CPUID[1].EDX[9].
  • Renamed APIC enmOriginalMode to enmMaxMode, changing the type of it and the corresponding config values to PDMAPICMODE. This makes the above simpler and eliminates two conversion functions. It also makes APICMODE private to the APIC again.
  • Introduced CPUMSetGuestCpuIdPerCpuApicFeature for the per-CPU APIC feature bit management.
  • Introduced CPUMCPUIDLEAF_F_CONTAINS_APIC which works same as CPUMCPUIDLEAF_F_CONTAINS_OSXSAVE and CPUMCPUIDLEAF_F_CONTAINS_APIC_ID. Updated existing CPU profiles with this.
  • Made the patch manager helper function actually handle CPUMCPUIDLEAF_F_CONTAINS_APIC and CPUMCPUIDLEAF_F_CONTAINS_OSXSAVE (the latter previously relied on CPUMSetGuestCpuIdFeature/CPUMClearGuestCpuIdFeature from CPUMSetGuestCR4).
  • Pushed CPUMSetGuestCpuIdFeature, CPUMGetGuestCpuIdFeature and CPUMClearGuestCpuIdFeature down to ring-3 only (now CPUMR3*). The latter two function are deprecated.
  • Added call to CPUMSetGuestCpuIdPerCpuApicFeature from load function just in case the APIC is disabled by the guest at the time of saving.
  • CPUMSetGuestCpuIdFeature ensures we've got a MSR_IA32_APICBASE register when enabling the APIC.
  • CPUMSetGuestCpuIdFeature adjust the MSR_IA32_APICBASE GP mask when enabling x2APIC so setting MSR_IA32_APICBASE_EXTD does not trap.
  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 95.3 KB
Line 
1/* $Id: DevAPIC.cpp 61776 2016-06-20 23:25:06Z vboxsync $ */
2/** @file
3 * Advanced Programmable Interrupt Controller (APIC) Device.
4 *
5 * @remarks This code does not use pThis, it uses pDev and pApic due to the
6 * non-standard arrangements of the APICs wrt PDM.
7 */
8
9/*
10 * Copyright (C) 2006-2015 Oracle Corporation
11 *
12 * This file is part of VirtualBox Open Source Edition (OSE), as
13 * available from http://www.virtualbox.org. This file is free software;
14 * you can redistribute it and/or modify it under the terms of the GNU
15 * General Public License (GPL) as published by the Free Software
16 * Foundation, in version 2 as it comes in the "COPYING" file of the
17 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
18 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
19 * --------------------------------------------------------------------
20 *
21 * This code is based on:
22 *
23 * apic.c revision 1.5 @@OSETODO
24 *
25 * APIC support
26 *
27 * Copyright (c) 2004-2005 Fabrice Bellard
28 *
29 * This library is free software; you can redistribute it and/or
30 * modify it under the terms of the GNU Lesser General Public
31 * License as published by the Free Software Foundation; either
32 * version 2 of the License, or (at your option) any later version.
33 *
34 * This library is distributed in the hope that it will be useful,
35 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
37 * Lesser General Public License for more details.
38 *
39 * You should have received a copy of the GNU Lesser General Public
40 * License along with this library; if not, write to the Free Software
41 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
42 */
43
44
45/*********************************************************************************************************************************
46* Header Files *
47*********************************************************************************************************************************/
48#define LOG_GROUP LOG_GROUP_DEV_APIC
49#include <VBox/vmm/pdmdev.h>
50
51#include <VBox/log.h>
52#include <VBox/vmm/stam.h>
53#include <VBox/vmm/vmcpuset.h>
54#include <VBox/vmm/vm.h>
55#include <iprt/asm.h>
56#include <iprt/assert.h>
57#ifdef APIC_FUZZY_SSM_COMPAT_TEST
58# include <iprt/rand.h>
59#endif
60
61#include <VBox/msi.h>
62
63#include "VBoxDD2.h"
64#include "DevApic.h"
65
66
67/*********************************************************************************************************************************
68* Defined Constants And Macros *
69*********************************************************************************************************************************/
70#define MSR_IA32_APICBASE_ENABLE (1<<11)
71#define MSR_IA32_APICBASE_X2ENABLE (1<<10)
72#define MSR_IA32_APICBASE_BASE (0xfffff<<12) /** @todo r=bird: This is not correct according to current specs! */
73
74#ifdef _MSC_VER
75# pragma warning(disable:4244)
76#endif
77
78/** The current saved state version.*/
79#define APIC_SAVED_STATE_VERSION 3
80/** The saved state version used by VirtualBox v3 and earlier.
81 * This does not include the config. */
82#define APIC_SAVED_STATE_VERSION_VBOX_30 2
83/** Some ancient version... */
84#define APIC_SAVED_STATE_VERSION_ANCIENT 1
85
86/* version 0x14: Pentium 4, Xeon; LVT count depends on that */
87#define APIC_HW_VERSION 0x14
88
89/** @def APIC_LOCK
90 * Acquires the PDM lock. */
91#define APIC_LOCK(a_pDev, rcBusy) \
92 do { \
93 int rc2 = PDMCritSectEnter((a_pDev)->CTX_SUFF(pCritSect), (rcBusy)); \
94 if (rc2 != VINF_SUCCESS) \
95 return rc2; \
96 } while (0)
97
98/** @def APIC_LOCK_VOID
99 * Acquires the PDM lock and does not expect failure (i.e. ring-3 only!). */
100#define APIC_LOCK_VOID(a_pDev, rcBusy) \
101 do { \
102 int rc2 = PDMCritSectEnter((a_pDev)->CTX_SUFF(pCritSect), (rcBusy)); \
103 AssertLogRelRCReturnVoid(rc2); \
104 } while (0)
105
106/** @def APIC_UNLOCK
107 * Releases the PDM lock. */
108#define APIC_UNLOCK(a_pDev) \
109 PDMCritSectLeave((a_pDev)->CTX_SUFF(pCritSect))
110
111/** @def APIC_AND_TM_LOCK
112 * Acquires the virtual sync clock lock as well as the PDM lock. */
113#define APIC_AND_TM_LOCK(a_pDev, a_pApic, rcBusy) \
114 do { \
115 int rc2 = TMTimerLock((a_pApic)->CTX_SUFF(pTimer), (rcBusy)); \
116 if (rc2 != VINF_SUCCESS) \
117 return rc2; \
118 rc2 = PDMCritSectEnter((a_pDev)->CTX_SUFF(pCritSect), (rcBusy)); \
119 if (rc2 != VINF_SUCCESS) \
120 { \
121 TMTimerUnlock((a_pApic)->CTX_SUFF(pTimer)); \
122 return rc2; \
123 } \
124 } while (0)
125
126/** @def APIC_AND_TM_UNLOCK
127 * Releases the PDM lock as well as the TM virtual sync clock lock. */
128#define APIC_AND_TM_UNLOCK(a_pDev, a_pApic) \
129 do { \
130 TMTimerUnlock((a_pApic)->CTX_SUFF(pTimer)); \
131 PDMCritSectLeave((a_pDev)->CTX_SUFF(pCritSect)); \
132 } while (0)
133
134/**
135 * Begins an APIC enumeration block.
136 *
137 * Code placed between this and the APIC_FOREACH_END macro will be executed for
138 * each APIC instance present in the system.
139 *
140 * @param a_pDev The APIC device.
141 */
142#define APIC_FOREACH_BEGIN(a_pDev) \
143 do { \
144 VMCPUID const cApics = (a_pDev)->cCpus; \
145 APICState *pCurApic = (a_pDev)->CTX_SUFF(paLapics); \
146 for (VMCPUID iCurApic = 0; iCurApic < cApics; iCurApic++, pCurApic++) \
147 { \
148 do { } while (0)
149
150/**
151 * Begins an APIC enumeration block, given a destination set.
152 *
153 * Code placed between this and the APIC_FOREACH_END macro will be executed for
154 * each APIC instance present in @a a_pDstSet.
155 *
156 * @param a_pDev The APIC device.
157 * @param a_pDstSet The destination set.
158 */
159#define APIC_FOREACH_IN_SET_BEGIN(a_pDev, a_pDstSet) \
160 APIC_FOREACH_BEGIN(a_pDev); \
161 if (!VMCPUSET_IS_PRESENT((a_pDstSet), iCurApic)) \
162 continue; \
163 do { } while (0)
164
165
166/** Counterpart to APIC_FOREACH_IN_SET_BEGIN and APIC_FOREACH_BEGIN. */
167#define APIC_FOREACH_END() \
168 } \
169 } while (0)
170
171#define DEBUG_APIC
172
173#define ESR_ILLEGAL_ADDRESS (1 << 7)
174
175#define APIC_SV_ENABLE (1 << 8)
176
177#define APIC_MAX_PATCH_ATTEMPTS 100
178
179
180/*********************************************************************************************************************************
181* Structures and Typedefs *
182*********************************************************************************************************************************/
183typedef uint32_t PhysApicId;
184typedef uint32_t LogApicId;
185
186typedef struct APIC256BITREG
187{
188 /** The bitmap data. */
189 uint32_t au32Bitmap[8 /*256/32*/];
190} APIC256BITREG;
191typedef APIC256BITREG *PAPIC256BITREG;
192typedef APIC256BITREG const *PCAPIC256BITREG;
193
194/**
195 * Tests if a bit in the 256-bit APIC register is set.
196 *
197 * @returns true if set, false if clear.
198 *
199 * @param pReg The register.
200 * @param iBit The bit to test for.
201 */
202DECLINLINE(bool) Apic256BitReg_IsBitSet(PCAPIC256BITREG pReg, unsigned iBit)
203{
204 Assert(iBit < 256);
205 return ASMBitTest(&pReg->au32Bitmap[0], iBit);
206}
207
208
209/**
210 * Sets a bit in the 256-bit APIC register is set.
211 *
212 * @param pReg The register.
213 * @param iBit The bit to set.
214 */
215DECLINLINE(void) Apic256BitReg_SetBit(PAPIC256BITREG pReg, unsigned iBit)
216{
217 Assert(iBit < 256);
218 return ASMBitSet(&pReg->au32Bitmap[0], iBit);
219}
220
221
222/**
223 * Clears a bit in the 256-bit APIC register is set.
224 *
225 * @param pReg The register.
226 * @param iBit The bit to clear.
227 */
228DECLINLINE(void) Apic256BitReg_ClearBit(PAPIC256BITREG pReg, unsigned iBit)
229{
230 Assert(iBit < 256);
231 return ASMBitClear(&pReg->au32Bitmap[0], iBit);
232}
233
234/**
235 * Clears all bits in the 256-bit APIC register set.
236 *
237 * @param pReg The register.
238 */
239DECLINLINE(void) Apic256BitReg_Empty(PAPIC256BITREG pReg)
240{
241 memset(&pReg->au32Bitmap[0], 0, sizeof(pReg->au32Bitmap));
242}
243
244/**
245 * Finds the last bit set in the register, i.e. the highest priority interrupt.
246 *
247 * @returns The index of the found bit, @a iRetAllClear if none was found.
248 *
249 * @param pReg The register.
250 * @param iRetAllClear What to return if all bits are clear.
251 */
252static int Apic256BitReg_FindLastSetBit(PCAPIC256BITREG pReg, int iRetAllClear)
253{
254 uint32_t i = RT_ELEMENTS(pReg->au32Bitmap);
255 while (i-- > 0)
256 {
257 uint32_t u = pReg->au32Bitmap[i];
258 if (u)
259 {
260 u = ASMBitLastSetU32(u);
261 u--;
262 u |= i << 5;
263 return (int)u;
264 }
265 }
266 return iRetAllClear;
267}
268
269
270/**
271 * The state of one APIC.
272 *
273 * @remarks This is generally pointed to by a parameter or variable named pApic.
274 */
275typedef struct APICState
276{
277 /** In service register (ISR). */
278 APIC256BITREG isr;
279 /** Trigger mode register (TMR). */
280 APIC256BITREG tmr;
281 /** Interrupt request register (IIR). */
282 APIC256BITREG irr;
283 uint32_t lvt[APIC_LVT_NB];
284 uint32_t apicbase;
285 /* Task priority register (interrupt level) */
286 uint32_t tpr;
287 /* Logical APIC id - user programmable */
288 LogApicId id;
289 /* Physical APIC id - not visible to user, constant */
290 PhysApicId phys_id;
291 /** @todo is it logical or physical? Not really used anyway now. */
292 PhysApicId arb_id;
293 uint32_t spurious_vec;
294 uint8_t log_dest;
295 uint8_t dest_mode;
296 uint32_t esr; /* error register */
297 uint32_t icr[2];
298 uint32_t divide_conf;
299 int count_shift;
300 uint32_t initial_count;
301 uint32_t Alignment0;
302
303 /** The time stamp of the initial_count load, i.e. when it was started. */
304 uint64_t initial_count_load_time;
305 /** The time stamp of the next timer callback. */
306 uint64_t next_time;
307 /** The APIC timer - R3 Ptr. */
308 PTMTIMERR3 pTimerR3;
309 /** The APIC timer - R0 Ptr. */
310 PTMTIMERR0 pTimerR0;
311 /** The APIC timer - RC Ptr. */
312 PTMTIMERRC pTimerRC;
313 /** Whether the timer is armed or not */
314 bool fTimerArmed;
315 /** Alignment */
316 bool afAlignment[3];
317 /** The initial_count value used for the current frequency hint. */
318 uint32_t uHintedInitialCount;
319 /** The count_shift value used for the current frequency hint. */
320 uint32_t uHintedCountShift;
321 /** Timer description timer. */
322 R3PTRTYPE(char *) pszDesc;
323
324 /** The IRQ tags and source IDs for each (tracing purposes). */
325 uint32_t auTags[256];
326
327# ifdef VBOX_WITH_STATISTICS
328# if HC_ARCH_BITS == 32
329 uint32_t u32Alignment0;
330# endif
331 STAMCOUNTER StatTimerSetInitialCount;
332 STAMCOUNTER StatTimerSetInitialCountArm;
333 STAMCOUNTER StatTimerSetInitialCountDisarm;
334 STAMCOUNTER StatTimerSetLvt;
335 STAMCOUNTER StatTimerSetLvtClearPeriodic;
336 STAMCOUNTER StatTimerSetLvtPostponed;
337 STAMCOUNTER StatTimerSetLvtArmed;
338 STAMCOUNTER StatTimerSetLvtArm;
339 STAMCOUNTER StatTimerSetLvtArmRetries;
340 STAMCOUNTER StatTimerSetLvtNoRelevantChange;
341# endif
342
343} APICState;
344
345AssertCompileMemberAlignment(APICState, initial_count_load_time, 8);
346# ifdef VBOX_WITH_STATISTICS
347AssertCompileMemberAlignment(APICState, StatTimerSetInitialCount, 8);
348# endif
349
350/**
351 * The wrapper device for the all the APICs.
352 *
353 * @remarks This is generally pointed to by a parameter or variable named pDev.
354 */
355typedef struct
356{
357 /** The device instance - R3 Ptr. */
358 PPDMDEVINSR3 pDevInsR3;
359 /** The APIC helpers - R3 Ptr. */
360 PCPDMAPICHLPR3 pApicHlpR3;
361 /** LAPICs states - R3 Ptr */
362 R3PTRTYPE(APICState *) paLapicsR3;
363 /** The critical section - R3 Ptr. */
364 R3PTRTYPE(PPDMCRITSECT) pCritSectR3;
365
366 /** The device instance - R0 Ptr. */
367 PPDMDEVINSR0 pDevInsR0;
368 /** The APIC helpers - R0 Ptr. */
369 PCPDMAPICHLPR0 pApicHlpR0;
370 /** LAPICs states - R0 Ptr */
371 R0PTRTYPE(APICState *) paLapicsR0;
372 /** The critical section - R3 Ptr. */
373 R0PTRTYPE(PPDMCRITSECT) pCritSectR0;
374
375 /** The device instance - RC Ptr. */
376 PPDMDEVINSRC pDevInsRC;
377 /** The APIC helpers - RC Ptr. */
378 PCPDMAPICHLPRC pApicHlpRC;
379 /** LAPICs states - RC Ptr */
380 RCPTRTYPE(APICState *) paLapicsRC;
381 /** The critical section - R3 Ptr. */
382 RCPTRTYPE(PPDMCRITSECT) pCritSectRC;
383
384 /** APIC specification mode in this virtual hardware configuration. */
385 PDMAPICMODE enmMode;
386
387 /** Number of attempts made to optimize TPR accesses. */
388 uint32_t cTPRPatchAttempts;
389
390 /** Number of CPUs on the system (same as LAPIC count). */
391 uint32_t cCpus;
392 /** Whether we've got an IO APIC or not. */
393 bool fIoApic;
394 /** Alignment padding. */
395 bool afPadding[3];
396
397# ifdef VBOX_WITH_STATISTICS
398 STAMCOUNTER StatMMIOReadGC;
399 STAMCOUNTER StatMMIOReadHC;
400 STAMCOUNTER StatMMIOWriteGC;
401 STAMCOUNTER StatMMIOWriteHC;
402 STAMCOUNTER StatClearedActiveIrq;
403# endif
404} APICDeviceInfo;
405# ifdef VBOX_WITH_STATISTICS
406AssertCompileMemberAlignment(APICDeviceInfo, StatMMIOReadGC, 8);
407# endif
408
409#ifndef VBOX_DEVICE_STRUCT_TESTCASE
410
411
412/*********************************************************************************************************************************
413* Internal Functions *
414*********************************************************************************************************************************/
415static void apic_update_tpr(APICDeviceInfo *pDev, APICState *pApic, uint32_t val);
416
417static void apic_eoi(APICDeviceInfo *pDev, APICState *pApic); /* */
418static PVMCPUSET apic_get_delivery_bitmask(APICDeviceInfo *pDev, uint8_t dest, uint8_t dest_mode, PVMCPUSET pDstSet);
419static int apic_deliver(APICDeviceInfo *pDev, APICState *pApic,
420 uint8_t dest, uint8_t dest_mode,
421 uint8_t delivery_mode, uint8_t vector_num,
422 uint8_t polarity, uint8_t trigger_mode);
423static int apic_get_arb_pri(APICState const *pApic);
424static int apic_get_ppr(APICState const *pApic);
425static uint32_t apic_get_current_count(APICDeviceInfo const *pDev, APICState const *pApic);
426static void apicTimerSetInitialCount(APICDeviceInfo *pDev, APICState *pApic, uint32_t initial_count);
427static void apicTimerSetLvt(APICDeviceInfo *pDev, APICState *pApic, uint32_t fNew);
428static void apicSendInitIpi(APICDeviceInfo *pDev, APICState *pApic);
429
430static void apicR3InitIpi(APICDeviceInfo *pDev, APICState *pApic);
431static void apic_set_irq(APICDeviceInfo *pDev, APICState *pApic, int vector_num, int trigger_mode, uint32_t uTagSrc);
432static bool apic_update_irq(APICDeviceInfo *pDev, APICState *pApic);
433
434
435DECLINLINE(APICState *) apicGetStateById(APICDeviceInfo *pDev, VMCPUID id)
436{
437 AssertFatalMsg(id < pDev->cCpus, ("CPU id %d out of range\n", id));
438 return &pDev->CTX_SUFF(paLapics)[id];
439}
440
441/**
442 * Get the APIC state for the calling EMT.
443 */
444DECLINLINE(APICState *) apicGetStateByCurEmt(APICDeviceInfo *pDev)
445{
446 /* LAPIC's array is indexed by CPU id */
447 VMCPUID id = pDev->CTX_SUFF(pApicHlp)->pfnGetCpuId(pDev->CTX_SUFF(pDevIns));
448 return apicGetStateById(pDev, id);
449}
450
451DECLINLINE(VMCPUID) getCpuFromLapic(APICDeviceInfo *pDev, APICState *pApic)
452{
453 /* for now we assume LAPIC physical id == CPU id */
454 return (VMCPUID)pApic->phys_id;
455}
456
457DECLINLINE(void) apicCpuSetInterrupt(APICDeviceInfo *pDev, APICState *pApic, PDMAPICIRQ enmType = PDMAPICIRQ_HARDWARE)
458{
459 LogFlow(("apic: setting interrupt flag for cpu %d\n", getCpuFromLapic(pDev, pApic)));
460 pDev->CTX_SUFF(pApicHlp)->pfnSetInterruptFF(pDev->CTX_SUFF(pDevIns), enmType,
461 getCpuFromLapic(pDev, pApic));
462}
463
464DECLINLINE(void) apicCpuClearInterrupt(APICDeviceInfo *pDev, APICState *pApic, PDMAPICIRQ enmType = PDMAPICIRQ_HARDWARE)
465{
466 LogFlow(("apic: clear interrupt flag\n"));
467 pDev->CTX_SUFF(pApicHlp)->pfnClearInterruptFF(pDev->CTX_SUFF(pDevIns), enmType,
468 getCpuFromLapic(pDev, pApic));
469}
470
471# ifdef IN_RING3
472
473DECLINLINE(void) apicR3CpuSendSipi(APICDeviceInfo *pDev, APICState *pApic, int vector)
474{
475 Log2(("apic: send SIPI vector=%d\n", vector));
476
477 pDev->pApicHlpR3->pfnSendStartupIpi(pDev->pDevInsR3, getCpuFromLapic(pDev, pApic), vector);
478}
479
480DECLINLINE(void) apicR3CpuSendInitIpi(APICDeviceInfo *pDev, APICState *pApic)
481{
482 Log2(("apic: send init IPI\n"));
483
484 pDev->pApicHlpR3->pfnSendInitIpi(pDev->pDevInsR3,
485 getCpuFromLapic(pDev, pApic));
486}
487
488# endif /* IN_RING3 */
489
490DECLINLINE(uint32_t) getApicEnableBits(APICDeviceInfo *pDev)
491{
492 switch (pDev->enmMode)
493 {
494 case PDMAPICMODE_NONE:
495 return 0;
496 case PDMAPICMODE_APIC:
497 return MSR_IA32_APICBASE_ENABLE;
498 case PDMAPICMODE_X2APIC:
499 return MSR_IA32_APICBASE_ENABLE | MSR_IA32_APICBASE_X2ENABLE;
500 default:
501 AssertMsgFailed(("Unsupported APIC mode %d\n", pDev->enmMode));
502 return 0;
503 }
504}
505
506DECLINLINE(PDMAPICMODE) getApicMode(APICState *apic)
507{
508 switch (((apic->apicbase) >> 10) & 0x3)
509 {
510 case 0:
511 return PDMAPICMODE_NONE;
512 case 1:
513 default:
514 /* Invalid */
515 return PDMAPICMODE_NONE;
516 case 2:
517 return PDMAPICMODE_APIC;
518 case 3:
519 return PDMAPICMODE_X2APIC;
520 }
521}
522
523
524static int apic_get_ppr_zero_tpr(APICState *pApic)
525{
526 return Apic256BitReg_FindLastSetBit(&pApic->isr, 0);
527}
528
529
530/* Check if the APIC has a pending interrupt/if a TPR change would active one. */
531static bool apicHasPendingIntr(PPDMDEVINS pDevIns, PVMCPU pVCpu, uint8_t *pu8PendingIrq)
532{
533 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
534 if (!pDev)
535 return false;
536
537 /* We don't perform any locking here as that would cause a lot of contention for VT-x/AMD-V. */
538
539 APICState *pApic = apicGetStateById(pDev, pVCpu->idCpu);
540
541 /*
542 * All our callbacks now come from single IOAPIC, thus locking
543 * seems to be excessive now
544 */
545 /** @todo check excessive locking whatever... */
546 int irrv = Apic256BitReg_FindLastSetBit(&pApic->irr, -1);
547 if (irrv < 0)
548 return false;
549
550 int isrv = apic_get_ppr_zero_tpr(pApic);
551
552 if (isrv && (irrv & 0xf0) <= (isrv & 0xf0))
553 return false;
554
555 if (pu8PendingIrq)
556 {
557 Assert(irrv >= 0 && irrv <= (int)UINT8_MAX);
558 *pu8PendingIrq = (uint8_t)irrv;
559 }
560 return true;
561}
562
563
564static int apic_bus_deliver(APICDeviceInfo *pDev,
565 PCVMCPUSET pDstSet, uint8_t delivery_mode,
566 uint8_t vector_num, uint8_t polarity,
567 uint8_t trigger_mode, uint32_t uTagSrc)
568{
569 LogFlow(("apic_bus_deliver mask=%R[vmcpuset] mode=%x vector=%x polarity=%x trigger_mode=%x uTagSrc=%#x\n",
570 pDstSet, delivery_mode, vector_num, polarity, trigger_mode, uTagSrc));
571
572 switch (delivery_mode)
573 {
574 case APIC_DM_LOWPRI:
575 {
576 VMCPUID idDstCpu = VMCPUSET_FIND_FIRST_PRESENT(pDstSet);
577 if (idDstCpu != NIL_VMCPUID)
578 {
579 APICState *pApic = apicGetStateById(pDev, idDstCpu);
580 apic_set_irq(pDev, pApic, vector_num, trigger_mode, uTagSrc);
581 }
582 return VINF_SUCCESS;
583 }
584
585 case APIC_DM_FIXED:
586 /** @todo XXX: arbitration */
587 break;
588
589 case APIC_DM_SMI:
590 APIC_FOREACH_IN_SET_BEGIN(pDev, pDstSet);
591 apicCpuSetInterrupt(pDev, pCurApic, PDMAPICIRQ_SMI);
592 APIC_FOREACH_END();
593 return VINF_SUCCESS;
594
595 case APIC_DM_NMI:
596 APIC_FOREACH_IN_SET_BEGIN(pDev, pDstSet);
597 apicCpuSetInterrupt(pDev, pCurApic, PDMAPICIRQ_NMI);
598 APIC_FOREACH_END();
599 return VINF_SUCCESS;
600
601 case APIC_DM_INIT:
602 /* normal INIT IPI sent to processors */
603#ifdef IN_RING3
604 APIC_FOREACH_IN_SET_BEGIN(pDev, pDstSet);
605 apicSendInitIpi(pDev, pCurApic);
606 APIC_FOREACH_END();
607 return VINF_SUCCESS;
608#else
609 /* We shall send init IPI only in R3. */
610 return VINF_IOM_R3_MMIO_READ_WRITE;
611#endif /* IN_RING3 */
612
613 case APIC_DM_EXTINT:
614 /* handled in I/O APIC code */
615 break;
616
617 default:
618 return VINF_SUCCESS;
619 }
620
621 APIC_FOREACH_IN_SET_BEGIN(pDev, pDstSet);
622 apic_set_irq(pDev, pCurApic, vector_num, trigger_mode, uTagSrc);
623 APIC_FOREACH_END();
624 return VINF_SUCCESS;
625}
626
627
628PDMBOTHCBDECL(VBOXSTRICTRC) apicSetBase(PPDMDEVINS pDevIns, PVMCPU pVCpu, uint64_t val)
629{
630 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
631 Assert(PDMCritSectIsOwner(pDev->CTX_SUFF(pCritSect)));
632 APICState *pApic = apicGetStateById(pDev, pVCpu->idCpu);
633 Log(("apicSetBase: %016RX64\n", val));
634
635 /** @todo do we need to lock here ? */
636 /* APIC_LOCK_VOID(pDev, VERR_INTERNAL_ERROR); */
637 /** @todo If this change is valid immediately, then we should change the MMIO registration! */
638 /* We cannot change if this CPU is BSP or not by writing to MSR - it's hardwired */
639 PDMAPICMODE oldMode = getApicMode(pApic);
640 pApic->apicbase = (val & 0xfffff000) /* base */
641 | (val & getApicEnableBits(pDev)) /* mode */
642 | (pApic->apicbase & MSR_IA32_APICBASE_BSP) /* keep BSP bit */;
643 PDMAPICMODE newMode = getApicMode(pApic);
644
645 if (oldMode != newMode)
646 {
647 switch (newMode)
648 {
649 case PDMAPICMODE_NONE:
650 {
651 pApic->spurious_vec &= ~APIC_SV_ENABLE;
652 /* Clear any pending APIC interrupt action flag. */
653 apicCpuClearInterrupt(pDev, pApic);
654 /* See @bugref{7097}. Intel IA-32/64 Spec 10.4.3:
655 * "When IA32_APIC_BASE[11] is 0, the processor is functionally equivalent to
656 * an IA-32 processor without an on-chip APIC. The CPUID feature flag for the
657 * APIC (see Section 10.4.2, 'Presence of the Local APIC') is also set to 0."
658 */
659 CPUMSetGuestCpuIdPerCpuApicFeature(PDMDevHlpGetVMCPU(pDevIns), false);
660 break;
661 }
662 case PDMAPICMODE_APIC:
663 /** @todo map MMIO ranges, if needed */
664 break;
665 case PDMAPICMODE_X2APIC:
666 /** @todo unmap MMIO ranges of this APIC, according to the spec. This is how
667 * real hw works! (Remember the problem disabling NMI watchdog timers in
668 * the world switchers when host used x2apic?)! */
669 break;
670 default:
671 break;
672 }
673 }
674 /* APIC_UNLOCK(pDev); */
675 return VINF_SUCCESS;
676}
677
678PDMBOTHCBDECL(uint64_t) apicGetBase(PPDMDEVINS pDevIns, PVMCPU pVCpu)
679{
680 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
681 Assert(PDMCritSectIsOwner(pDev->CTX_SUFF(pCritSect)));
682 APICState *pApic = apicGetStateById(pDev, pVCpu->idCpu);
683 LogFlow(("apicGetBase: %016llx\n", (uint64_t)pApic->apicbase));
684 return pApic->apicbase;
685}
686
687PDMBOTHCBDECL(void) apicSetTPR(PPDMDEVINS pDevIns, PVMCPU pVCpu, uint8_t val)
688{
689 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
690 Assert(PDMCritSectIsOwner(pDev->CTX_SUFF(pCritSect)));
691 APICState *pApic = apicGetStateById(pDev, pVCpu->idCpu);
692 Log4(("apicSetTPR: val=%#x (trp %#x -> %#x)\n", val, pApic->tpr, val));
693 apic_update_tpr(pDev, pApic, val);
694}
695
696PDMBOTHCBDECL(uint8_t) apicGetTPR(PPDMDEVINS pDevIns, PVMCPU pVCpu, bool *pfPending, uint8_t *pu8PendingIntr)
697{
698 /* We don't perform any locking here as that would cause a lot of contention for VT-x/AMD-V. */
699 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
700 APICState *pApic = apicGetStateById(pDev, pVCpu->idCpu);
701 Log4(("apicGetTPR: returns %#x\n", pApic->tpr));
702
703 if (pfPending)
704 *pfPending = apicHasPendingIntr(pDevIns, pVCpu, pu8PendingIntr);
705 return pApic->tpr;
706}
707
708
709PDMBOTHCBDECL(uint64_t) apicGetTimerFreq(PPDMDEVINS pDevIns)
710{
711 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
712 APICState *pApic = apicGetStateById(pDev, 0);
713 uint64_t uTimer = TMTimerGetFreq(pApic->CTX_SUFF(pTimer));
714 Log2(("apicGetTimerFreq: returns %#RX64\n", uTimer));
715 return uTimer;
716}
717
718
719/**
720 * apicWriteRegister helper for dealing with invalid register access.
721 *
722 * @returns Strict VBox status code.
723 * @param pDev The PDM device instance.
724 * @param pApic The APIC being written to.
725 * @param iReg The APIC register index.
726 * @param u64Value The value being written.
727 * @param rcBusy The busy return code to employ. See
728 * PDMCritSectEnter for a description.
729 * @param fMsr Set if called via MSR, clear if MMIO.
730 */
731static int apicWriteRegisterInvalid(APICDeviceInfo *pDev, APICState *pApic, uint32_t iReg, uint64_t u64Value,
732 int rcBusy, bool fMsr)
733{
734 Log(("apicWriteRegisterInvalid/%u: iReg=%#x fMsr=%RTbool u64Value=%#llx\n", pApic->phys_id, iReg, fMsr, u64Value));
735 int rc = PDMDevHlpDBGFStop(pDev->CTX_SUFF(pDevIns), RT_SRC_POS,
736 "iReg=%#x fMsr=%RTbool u64Value=%#llx id=%u\n", iReg, fMsr, u64Value, pApic->phys_id);
737 APIC_LOCK(pDev, rcBusy);
738 pApic->esr |= ESR_ILLEGAL_ADDRESS;
739 APIC_UNLOCK(pDev);
740 return rc;
741}
742
743
744
745/**
746 * Writes to an APIC register via MMIO or MSR.
747 *
748 * @returns Strict VBox status code.
749 * @param pDev The PDM device instance.
750 * @param pApic The APIC being written to.
751 * @param iReg The APIC register index.
752 * @param u64Value The value being written.
753 * @param rcBusy The busy return code to employ. See
754 * PDMCritSectEnter for a description.
755 * @param fMsr Set if called via MSR, clear if MMIO.
756 */
757static int apicWriteRegister(APICDeviceInfo *pDev, APICState *pApic, uint32_t iReg, uint64_t u64Value,
758 int rcBusy, bool fMsr)
759{
760 Assert(!PDMCritSectIsOwner(pDev->CTX_SUFF(pCritSect)));
761
762 int rc = VINF_SUCCESS;
763 switch (iReg)
764 {
765 case 0x02:
766 APIC_LOCK(pDev, rcBusy);
767 pApic->id = (u64Value >> 24); /** @todo r=bird: Is the range supposed to be 40 bits??? */
768 APIC_UNLOCK(pDev);
769 break;
770
771 case 0x03:
772 /* read only, ignore write. */
773 break;
774
775 case 0x08:
776 APIC_LOCK(pDev, rcBusy);
777 apic_update_tpr(pDev, pApic, u64Value);
778 APIC_UNLOCK(pDev);
779 break;
780
781 case 0x09: case 0x0a:
782 Log(("apicWriteRegister: write to read-only register %d ignored\n", iReg));
783 break;
784
785 case 0x0b: /* EOI */
786 APIC_LOCK(pDev, rcBusy);
787 apic_eoi(pDev, pApic);
788 APIC_UNLOCK(pDev);
789 break;
790
791 case 0x0d:
792 APIC_LOCK(pDev, rcBusy);
793 pApic->log_dest = (u64Value >> 24) & 0xff;
794 APIC_UNLOCK(pDev);
795 break;
796
797 case 0x0e:
798 APIC_LOCK(pDev, rcBusy);
799 pApic->dest_mode = u64Value >> 28; /** @todo r=bird: range? This used to be 32-bit before morphed into an MSR handler. */
800 APIC_UNLOCK(pDev);
801 break;
802
803 case 0x0f:
804 APIC_LOCK(pDev, rcBusy);
805 pApic->spurious_vec = u64Value & 0x1ff;
806 apic_update_irq(pDev, pApic);
807 APIC_UNLOCK(pDev);
808 break;
809
810 case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
811 case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
812 case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
813 case 0x28:
814 Log(("apicWriteRegister: write to read-only register %d ignored\n", iReg));
815 break;
816
817 case 0x30:
818 APIC_LOCK(pDev, rcBusy);
819 pApic->icr[0] = (uint32_t)u64Value;
820 if (fMsr) /* Here one of the differences with regular APIC: ICR is single 64-bit register */
821 pApic->icr[1] = (uint32_t)(u64Value >> 32);
822 rc = apic_deliver(pDev, pApic, (pApic->icr[1] >> 24) & 0xff, (pApic->icr[0] >> 11) & 1,
823 (pApic->icr[0] >> 8) & 7, (pApic->icr[0] & 0xff),
824 (pApic->icr[0] >> 14) & 1, (pApic->icr[0] >> 15) & 1);
825 APIC_UNLOCK(pDev);
826 break;
827
828 case 0x31:
829 if (!fMsr)
830 {
831 APIC_LOCK(pDev, rcBusy);
832 pApic->icr[1] = (uint64_t)u64Value;
833 APIC_UNLOCK(pDev);
834 }
835 else
836 rc = apicWriteRegisterInvalid(pDev, pApic, iReg, u64Value, rcBusy, fMsr);
837 break;
838
839 case 0x32 + APIC_LVT_TIMER:
840 AssertCompile(APIC_LVT_TIMER == 0);
841 APIC_AND_TM_LOCK(pDev, pApic, rcBusy);
842 apicTimerSetLvt(pDev, pApic, u64Value);
843 APIC_AND_TM_UNLOCK(pDev, pApic);
844 break;
845
846 case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
847 APIC_LOCK(pDev, rcBusy);
848 pApic->lvt[iReg - 0x32] = u64Value;
849 APIC_UNLOCK(pDev);
850 break;
851
852 case 0x38:
853 APIC_AND_TM_LOCK(pDev, pApic, rcBusy);
854 apicTimerSetInitialCount(pDev, pApic, u64Value);
855 APIC_AND_TM_UNLOCK(pDev, pApic);
856 break;
857
858 case 0x39:
859 Log(("apicWriteRegister: write to read-only register %d ignored\n", iReg));
860 break;
861
862 case 0x3e:
863 {
864 APIC_LOCK(pDev, rcBusy);
865 pApic->divide_conf = u64Value & 0xb;
866 int v = (pApic->divide_conf & 3) | ((pApic->divide_conf >> 1) & 4);
867 pApic->count_shift = (v + 1) & 7;
868 APIC_UNLOCK(pDev);
869 break;
870 }
871
872 case 0x3f:
873 if (fMsr)
874 {
875 /* Self IPI, see x2APIC book 2.4.5 */
876 APIC_LOCK(pDev, rcBusy);
877 int vector = u64Value & 0xff;
878 VMCPUSET SelfSet;
879 VMCPUSET_EMPTY(&SelfSet);
880 VMCPUSET_ADD(&SelfSet, pApic->id);
881 rc = apic_bus_deliver(pDev,
882 &SelfSet,
883 0 /* Delivery mode - fixed */,
884 vector,
885 0 /* Polarity - conform to the bus */,
886 0 /* Trigger mode - edge */,
887 pDev->CTX_SUFF(pApicHlp)->pfnCalcIrqTag(pDev->CTX_SUFF(pDevIns), PDM_IRQ_LEVEL_HIGH));
888 APIC_UNLOCK(pDev);
889 break;
890 }
891 /* else: fall thru */
892
893 default:
894 rc = apicWriteRegisterInvalid(pDev, pApic, iReg, u64Value, rcBusy, fMsr);
895 break;
896 }
897
898 return rc;
899}
900
901
902/**
903 * apicReadRegister helper for dealing with invalid register access.
904 *
905 * @returns Strict VBox status code.
906 * @param pDev The PDM device instance.
907 * @param pApic The APIC being read to.
908 * @param iReg The APIC register index.
909 * @param pu64Value Where to store the value we've read.
910 * @param rcBusy The busy return code to employ. See
911 * PDMCritSectEnter for a description.
912 * @param fMsr Set if called via MSR, clear if MMIO.
913 */
914static int apicReadRegisterInvalid(APICDeviceInfo *pDev, APICState *pApic, uint32_t iReg, uint64_t *pu64Value,
915 int rcBusy, bool fMsr)
916{
917 Log(("apicReadRegisterInvalid/%u: iReg=%#x fMsr=%RTbool\n", pApic->phys_id, iReg, fMsr));
918 int rc = PDMDevHlpDBGFStop(pDev->CTX_SUFF(pDevIns), RT_SRC_POS,
919 "iReg=%#x fMsr=%RTbool id=%u\n", iReg, fMsr, pApic->phys_id);
920 APIC_LOCK(pDev, rcBusy);
921 pApic->esr |= ESR_ILLEGAL_ADDRESS;
922 APIC_UNLOCK(pDev);
923 *pu64Value = 0;
924 return rc;
925}
926
927
928/**
929 * Read from an APIC register via MMIO or MSR.
930 *
931 * @returns Strict VBox status code.
932 * @param pDev The PDM device instance.
933 * @param pApic The APIC being read to.
934 * @param iReg The APIC register index.
935 * @param pu64Value Where to store the value we've read.
936 * @param rcBusy The busy return code to employ. See
937 * PDMCritSectEnter for a description.
938 * @param fMsr Set if called via MSR, clear if MMIO.
939 */
940static int apicReadRegister(APICDeviceInfo *pDev, APICState *pApic, uint32_t iReg, uint64_t *pu64Value,
941 int rcBusy, bool fMsr)
942{
943 Assert(!PDMCritSectIsOwner(pDev->CTX_SUFF(pCritSect)));
944
945 int rc = VINF_SUCCESS;
946 switch (iReg)
947 {
948 case 0x02: /* id */
949 APIC_LOCK(pDev, rcBusy);
950 *pu64Value = pApic->id << 24;
951 APIC_UNLOCK(pDev);
952 break;
953
954 case 0x03: /* version */
955 APIC_LOCK(pDev, rcBusy);
956 *pu64Value = APIC_HW_VERSION
957 | ((APIC_LVT_NB - 1) << 16) /* Max LVT index */
958#if 0
959 | (0 << 24) /* Support for EOI broadcast suppression */
960#endif
961 ;
962 APIC_UNLOCK(pDev);
963 break;
964
965 case 0x08:
966 APIC_LOCK(pDev, rcBusy);
967 *pu64Value = pApic->tpr;
968 APIC_UNLOCK(pDev);
969 break;
970
971 case 0x09:
972 *pu64Value = apic_get_arb_pri(pApic);
973 break;
974
975 case 0x0a:
976 /* ppr */
977 APIC_LOCK(pDev, rcBusy);
978 *pu64Value = apic_get_ppr(pApic);
979 APIC_UNLOCK(pDev);
980 break;
981
982 case 0x0b:
983 Log(("apicReadRegister: %x -> write only returning 0\n", iReg));
984 *pu64Value = 0;
985 break;
986
987 case 0x0d:
988 APIC_LOCK(pDev, rcBusy);
989 *pu64Value = (uint64_t)pApic->log_dest << 24;
990 APIC_UNLOCK(pDev);
991 break;
992
993 case 0x0e:
994 /* Bottom 28 bits are always 1 */
995 APIC_LOCK(pDev, rcBusy);
996 *pu64Value = ((uint64_t)pApic->dest_mode << 28) | UINT32_C(0xfffffff);
997 APIC_UNLOCK(pDev);
998 break;
999
1000 case 0x0f:
1001 APIC_LOCK(pDev, rcBusy);
1002 *pu64Value = pApic->spurious_vec;
1003 APIC_UNLOCK(pDev);
1004 break;
1005
1006 case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
1007 APIC_LOCK(pDev, rcBusy);
1008 *pu64Value = pApic->isr.au32Bitmap[iReg & 7];
1009 APIC_UNLOCK(pDev);
1010 break;
1011
1012 case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
1013 APIC_LOCK(pDev, rcBusy);
1014 *pu64Value = pApic->tmr.au32Bitmap[iReg & 7];
1015 APIC_UNLOCK(pDev);
1016 break;
1017
1018 case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
1019 APIC_LOCK(pDev, rcBusy);
1020 *pu64Value = pApic->irr.au32Bitmap[iReg & 7];
1021 APIC_UNLOCK(pDev);
1022 break;
1023
1024 case 0x28:
1025 APIC_LOCK(pDev, rcBusy);
1026 *pu64Value = pApic->esr;
1027 APIC_UNLOCK(pDev);
1028 break;
1029
1030 case 0x30:
1031 /* Here one of the differences with regular APIC: ICR is single 64-bit register */
1032 APIC_LOCK(pDev, rcBusy);
1033 if (fMsr)
1034 *pu64Value = RT_MAKE_U64(pApic->icr[0], pApic->icr[1]);
1035 else
1036 *pu64Value = pApic->icr[0];
1037 APIC_UNLOCK(pDev);
1038 break;
1039
1040 case 0x31:
1041 if (fMsr)
1042 rc = apicReadRegisterInvalid(pDev, pApic, iReg, pu64Value, rcBusy, fMsr);
1043 else
1044 {
1045 APIC_LOCK(pDev, rcBusy);
1046 *pu64Value = pApic->icr[1];
1047 APIC_UNLOCK(pDev);
1048 }
1049 break;
1050
1051 case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
1052 APIC_LOCK(pDev, rcBusy);
1053 *pu64Value = pApic->lvt[iReg - 0x32];
1054 APIC_UNLOCK(pDev);
1055 break;
1056
1057 case 0x38:
1058 APIC_LOCK(pDev, rcBusy);
1059 *pu64Value = pApic->initial_count;
1060 APIC_UNLOCK(pDev);
1061 break;
1062
1063 case 0x39:
1064 APIC_AND_TM_LOCK(pDev, pApic, rcBusy);
1065 *pu64Value = apic_get_current_count(pDev, pApic);
1066 APIC_AND_TM_UNLOCK(pDev, pApic);
1067 break;
1068
1069 case 0x3e:
1070 APIC_LOCK(pDev, rcBusy);
1071 *pu64Value = pApic->divide_conf;
1072 APIC_UNLOCK(pDev);
1073 break;
1074
1075 case 0x3f:
1076 if (fMsr)
1077 {
1078 /* Self IPI register is write only */
1079 Log(("apicReadMSR: read from write-only register %d ignored\n", iReg));
1080 *pu64Value = 0;
1081 }
1082 else
1083 rc = apicReadRegisterInvalid(pDev, pApic, iReg, pu64Value, rcBusy, fMsr);
1084 break;
1085 case 0x2f: /** @todo Correctable machine check exception vector, implement me! */
1086 default:
1087 /**
1088 * @todo: according to spec when APIC writes to ESR it msut raise error interrupt,
1089 * i.e. LVT[5]
1090 */
1091 rc = apicReadRegisterInvalid(pDev, pApic, iReg, pu64Value, rcBusy, fMsr);
1092 break;
1093 }
1094 return rc;
1095}
1096
1097/**
1098 * @interface_method_impl{PDMAPICREG,pfnWriteMSRR3}
1099 */
1100PDMBOTHCBDECL(VBOXSTRICTRC) apicWriteMSR(PPDMDEVINS pDevIns, PVMCPU pVCpu, uint32_t u32Reg, uint64_t u64Value)
1101{
1102 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
1103 if (pDev->enmMode < PDMAPICMODE_X2APIC)
1104 return VERR_EM_INTERPRETER; /** @todo tell the caller to raise hell (\#GP(0)). */
1105
1106 APICState *pApic = apicGetStateById(pDev, pVCpu->idCpu);
1107 uint32_t iReg = (u32Reg - MSR_IA32_X2APIC_START) & 0xff;
1108 return apicWriteRegister(pDev, pApic, iReg, u64Value, VINF_SUCCESS /*rcBusy*/, true /*fMsr*/);
1109}
1110
1111
1112/**
1113 * @interface_method_impl{PDMAPICREG,pfnReadMSRR3}
1114 */
1115PDMBOTHCBDECL(VBOXSTRICTRC) apicReadMSR(PPDMDEVINS pDevIns, PVMCPU pVCpu, uint32_t u32Reg, uint64_t *pu64Value)
1116{
1117 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
1118
1119 if (pDev->enmMode < PDMAPICMODE_X2APIC)
1120 return VERR_EM_INTERPRETER;
1121
1122 APICState *pApic = apicGetStateById(pDev, pVCpu->idCpu);
1123 uint32_t iReg = (u32Reg - MSR_IA32_X2APIC_START) & 0xff;
1124 return apicReadRegister(pDev, pApic, iReg, pu64Value, VINF_SUCCESS /*rcBusy*/, true /*fMsr*/);
1125}
1126
1127/**
1128 * More or less private interface between IOAPIC, only PDM is responsible
1129 * for connecting the two devices.
1130 */
1131PDMBOTHCBDECL(int) apicBusDeliverCallback(PPDMDEVINS pDevIns, uint8_t u8Dest, uint8_t u8DestMode,
1132 uint8_t u8DeliveryMode, uint8_t iVector, uint8_t u8Polarity,
1133 uint8_t u8TriggerMode, uint32_t uTagSrc)
1134{
1135 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
1136 Assert(PDMCritSectIsOwner(pDev->CTX_SUFF(pCritSect)));
1137 LogFlow(("apicBusDeliverCallback: pDevIns=%p u8Dest=%#x u8DestMode=%#x u8DeliveryMode=%#x iVector=%#x u8Polarity=%#x u8TriggerMode=%#x uTagSrc=%#x\n",
1138 pDevIns, u8Dest, u8DestMode, u8DeliveryMode, iVector, u8Polarity, u8TriggerMode, uTagSrc));
1139 VMCPUSET DstSet;
1140 return apic_bus_deliver(pDev, apic_get_delivery_bitmask(pDev, u8Dest, u8DestMode, &DstSet),
1141 u8DeliveryMode, iVector, u8Polarity, u8TriggerMode, uTagSrc);
1142}
1143
1144/**
1145 * Local interrupt delivery, for devices attached to the CPU's LINT0/LINT1 pin.
1146 * Normally used for 8259A PIC and NMI.
1147 */
1148PDMBOTHCBDECL(VBOXSTRICTRC) apicLocalInterrupt(PPDMDEVINS pDevIns, PVMCPU pVCpu, uint8_t u8Pin, uint8_t u8Level, int rcRZ)
1149{
1150 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
1151 NOREF(rcRZ);
1152
1153 /* NB: We currently only deliver local interrupts to the first CPU. In theory they
1154 * should be delivered to all CPUs and it is the guest's responsibility to ensure
1155 * no more than one CPU has the interrupt unmasked.
1156 */
1157 APICState *pApic = apicGetStateById(pDev, pVCpu->idCpu);
1158
1159 Assert(PDMCritSectIsOwner(pDev->CTX_SUFF(pCritSect)));
1160 LogFlow(("apicLocalInterrupt: pDevIns=%p u8Pin=%x u8Level=%x\n", pDevIns, u8Pin, u8Level));
1161
1162 /* If LAPIC is disabled, go straight to the CPU. */
1163 if (!(pApic->spurious_vec & APIC_SV_ENABLE))
1164 {
1165 LogFlow(("apicLocalInterrupt: LAPIC disabled, delivering directly to CPU core.\n"));
1166 if (u8Level)
1167 apicCpuSetInterrupt(pDev, pApic, PDMAPICIRQ_EXTINT);
1168 else
1169 apicCpuClearInterrupt(pDev, pApic, PDMAPICIRQ_EXTINT);
1170
1171 return VINF_SUCCESS;
1172 }
1173
1174 /* If LAPIC is enabled, interrupts are subject to LVT programming. */
1175
1176 /* There are only two local interrupt pins. */
1177 AssertMsgReturn(u8Pin <= 1, ("Invalid LAPIC pin %d\n", u8Pin), VERR_INVALID_PARAMETER);
1178
1179 uint32_t u32Lvec;
1180
1181 u32Lvec = pApic->lvt[APIC_LVT_LINT0 + u8Pin]; /* Fetch corresponding LVT entry. */
1182 /* Drop int if entry is masked. May not be correct for level-triggered interrupts. */
1183 if (!(u32Lvec & APIC_LVT_MASKED))
1184 {
1185 uint8_t u8Delivery;
1186 PDMAPICIRQ enmType;
1187
1188 u8Delivery = (u32Lvec >> 8) & 7;
1189 switch (u8Delivery)
1190 {
1191 case APIC_DM_EXTINT:
1192 Assert(u8Pin == 0); /* PIC should be wired to LINT0. */
1193 enmType = PDMAPICIRQ_EXTINT;
1194 /* ExtINT can be both set and cleared, NMI/SMI/INIT can only be set. */
1195 LogFlow(("apicLocalInterrupt: %s ExtINT interrupt\n", u8Level ? "setting" : "clearing"));
1196 if (u8Level)
1197 apicCpuSetInterrupt(pDev, pApic, enmType);
1198 else
1199 apicCpuClearInterrupt(pDev, pApic, enmType);
1200 return VINF_SUCCESS;
1201 case APIC_DM_NMI:
1202 /* External NMI should be wired to LINT1, but Linux sometimes programs
1203 * LVT0 to NMI delivery mode as well.
1204 */
1205 enmType = PDMAPICIRQ_NMI;
1206 /* Currently delivering NMIs through here causes problems with NMI watchdogs
1207 * on certain Linux kernels, e.g. 64-bit CentOS 5.3. Disable NMIs for now.
1208 */
1209 return VINF_SUCCESS;
1210 case APIC_DM_SMI:
1211 enmType = PDMAPICIRQ_SMI;
1212 break;
1213 case APIC_DM_FIXED:
1214 {
1215 /** @todo implement APIC_DM_FIXED! */
1216 LogRelMax(5, ("APIC: Delivery type APIC_DM_FIXED not implemented. u8Pin=%d u8Level=%d\n", u8Pin, u8Level));
1217 return VINF_SUCCESS;
1218 }
1219 case APIC_DM_INIT:
1220 /** @todo implement APIC_DM_INIT? */
1221 default:
1222 {
1223 static unsigned s_c = 0;
1224 if (s_c++ < 100)
1225 AssertLogRelMsgFailed(("delivery type %d not implemented. u8Pin=%d u8Level=%d\n", u8Delivery, u8Pin, u8Level));
1226 return VERR_INTERNAL_ERROR_4;
1227 }
1228 }
1229 LogFlow(("apicLocalInterrupt: setting local interrupt type %d\n", enmType));
1230 apicCpuSetInterrupt(pDev, pApic, enmType);
1231 }
1232 return VINF_SUCCESS;
1233}
1234
1235static int apic_get_ppr(APICState const *pApic)
1236{
1237 int ppr;
1238
1239 int tpr = (pApic->tpr >> 4);
1240 int isrv = Apic256BitReg_FindLastSetBit(&pApic->isr, 0);
1241 isrv >>= 4;
1242 if (tpr >= isrv)
1243 ppr = pApic->tpr;
1244 else
1245 ppr = isrv << 4;
1246 return ppr;
1247}
1248
1249static int apic_get_arb_pri(APICState const *pApic)
1250{
1251 /** @todo XXX: arbitration */
1252 return 0;
1253}
1254
1255/* signal the CPU if an irq is pending */
1256static bool apic_update_irq(APICDeviceInfo *pDev, APICState *pApic)
1257{
1258 if (!(pApic->spurious_vec & APIC_SV_ENABLE))
1259 {
1260 /* Clear any pending APIC interrupt action flag. */
1261 apicCpuClearInterrupt(pDev, pApic);
1262 return false;
1263 }
1264
1265 int irrv = Apic256BitReg_FindLastSetBit(&pApic->irr, -1);
1266 if (irrv < 0)
1267 return false;
1268 int ppr = apic_get_ppr(pApic);
1269 if (ppr && (irrv & 0xf0) <= (ppr & 0xf0))
1270 return false;
1271 apicCpuSetInterrupt(pDev, pApic);
1272 return true;
1273}
1274
1275static void apic_update_tpr(APICDeviceInfo *pDev, APICState *pApic, uint32_t val)
1276{
1277 bool fIrqIsActive = false;
1278 bool fIrqWasActive = false;
1279
1280 fIrqWasActive = apic_update_irq(pDev, pApic);
1281 pApic->tpr = val;
1282 fIrqIsActive = apic_update_irq(pDev, pApic);
1283
1284 /* If an interrupt is pending and now masked, then clear the FF flag. */
1285 if (fIrqWasActive && !fIrqIsActive)
1286 {
1287 Log(("apic_update_tpr: deactivate interrupt that was masked by the TPR update (%x)\n", val));
1288 STAM_COUNTER_INC(&pDev->StatClearedActiveIrq);
1289 apicCpuClearInterrupt(pDev, pApic);
1290 }
1291}
1292
1293static void apic_set_irq(APICDeviceInfo *pDev, APICState *pApic, int vector_num, int trigger_mode, uint32_t uTagSrc)
1294{
1295 LogFlow(("CPU%d: apic_set_irq vector=%x trigger_mode=%x uTagSrc=%#x\n", pApic->phys_id, vector_num, trigger_mode, uTagSrc));
1296
1297 Apic256BitReg_SetBit(&pApic->irr, vector_num);
1298 if (trigger_mode)
1299 Apic256BitReg_SetBit(&pApic->tmr, vector_num);
1300 else
1301 Apic256BitReg_ClearBit(&pApic->tmr, vector_num);
1302
1303 if (!pApic->auTags[vector_num])
1304 pApic->auTags[vector_num] = uTagSrc;
1305 else
1306 pApic->auTags[vector_num] |= RT_BIT_32(31);
1307
1308 apic_update_irq(pDev, pApic);
1309}
1310
1311static void apic_eoi(APICDeviceInfo *pDev, APICState *pApic)
1312{
1313 int isrv = Apic256BitReg_FindLastSetBit(&pApic->isr, -1);
1314 if (isrv < 0)
1315 return;
1316 Apic256BitReg_ClearBit(&pApic->isr, isrv);
1317 LogFlow(("CPU%d: apic_eoi isrv=%x\n", pApic->phys_id, isrv));
1318 /** @todo XXX: send the EOI packet to the APIC bus to allow the I/O APIC to
1319 * set the remote IRR bit for level triggered interrupts. */
1320 apic_update_irq(pDev, pApic);
1321}
1322
1323static PVMCPUSET apic_get_delivery_bitmask(APICDeviceInfo *pDev, uint8_t dest, uint8_t dest_mode, PVMCPUSET pDstSet)
1324{
1325 VMCPUSET_EMPTY(pDstSet);
1326
1327 if (dest_mode == 0)
1328 {
1329 if (dest == 0xff) /* The broadcast ID. */
1330 VMCPUSET_FILL(pDstSet);
1331 else
1332 VMCPUSET_ADD(pDstSet, dest);
1333 }
1334 else
1335 {
1336 /** @todo XXX: cluster mode */
1337 APIC_FOREACH_BEGIN(pDev);
1338 if (pCurApic->dest_mode == APIC_DESTMODE_FLAT)
1339 {
1340 if (dest & pCurApic->log_dest)
1341 VMCPUSET_ADD(pDstSet, iCurApic);
1342 }
1343 else if (pCurApic->dest_mode == APIC_DESTMODE_CLUSTER)
1344 {
1345 if ( (dest & 0xf0) == (pCurApic->log_dest & 0xf0)
1346 && (dest & pCurApic->log_dest & 0x0f))
1347 VMCPUSET_ADD(pDstSet, iCurApic);
1348 }
1349 APIC_FOREACH_END();
1350 }
1351
1352 return pDstSet;
1353}
1354
1355#ifdef IN_RING3
1356
1357static void apicR3InitIpi(APICDeviceInfo *pDev, APICState *pApic)
1358{
1359 int i;
1360
1361 for(i = 0; i < APIC_LVT_NB; i++)
1362 pApic->lvt[i] = 1 << 16; /* mask LVT */
1363 pApic->tpr = 0;
1364 pApic->spurious_vec = 0xff;
1365 pApic->log_dest = 0;
1366 pApic->dest_mode = 0xff; /** @todo 0xff???? */
1367 Apic256BitReg_Empty(&pApic->isr);
1368 Apic256BitReg_Empty(&pApic->tmr);
1369 Apic256BitReg_Empty(&pApic->irr);
1370 pApic->esr = 0;
1371 memset(pApic->icr, 0, sizeof(pApic->icr));
1372 pApic->divide_conf = 0;
1373 pApic->count_shift = 1;
1374 pApic->initial_count = 0;
1375 pApic->initial_count_load_time = 0;
1376 pApic->next_time = 0;
1377}
1378
1379
1380static void apicSendInitIpi(APICDeviceInfo *pDev, APICState *pApic)
1381{
1382 apicR3InitIpi(pDev, pApic);
1383 apicR3CpuSendInitIpi(pDev, pApic);
1384}
1385
1386/* send a SIPI message to the CPU to start it */
1387static void apicR3Startup(APICDeviceInfo *pDev, APICState *pApic, int vector_num)
1388{
1389 Log(("[SMP] apicR3Startup: %d on CPUs %d\n", vector_num, pApic->phys_id));
1390 apicR3CpuSendSipi(pDev, pApic, vector_num);
1391}
1392
1393#endif /* IN_RING3 */
1394
1395static int apic_deliver(APICDeviceInfo *pDev, APICState *pApic,
1396 uint8_t dest, uint8_t dest_mode,
1397 uint8_t delivery_mode, uint8_t vector_num,
1398 uint8_t polarity, uint8_t trigger_mode)
1399{
1400 int dest_shorthand = (pApic->icr[0] >> 18) & 3;
1401 LogFlow(("apic_deliver dest=%x dest_mode=%x dest_shorthand=%x delivery_mode=%x vector_num=%x polarity=%x trigger_mode=%x\n", dest, dest_mode, dest_shorthand, delivery_mode, vector_num, polarity, trigger_mode));
1402
1403 VMCPUSET DstSet;
1404 switch (dest_shorthand)
1405 {
1406 case 0:
1407 apic_get_delivery_bitmask(pDev, dest, dest_mode, &DstSet);
1408 break;
1409 case 1:
1410 VMCPUSET_EMPTY(&DstSet);
1411 VMCPUSET_ADD(&DstSet, pApic->id);
1412 break;
1413 case 2:
1414 VMCPUSET_FILL(&DstSet);
1415 break;
1416 case 3:
1417 VMCPUSET_FILL(&DstSet);
1418 VMCPUSET_DEL(&DstSet, pApic->id);
1419 break;
1420 }
1421
1422 switch (delivery_mode)
1423 {
1424 case APIC_DM_INIT:
1425 {
1426 uint32_t const trig_mode = (pApic->icr[0] >> 15) & 1;
1427 uint32_t const level = (pApic->icr[0] >> 14) & 1;
1428 if (level == 0 && trig_mode == 1)
1429 {
1430 APIC_FOREACH_IN_SET_BEGIN(pDev, &DstSet);
1431 pCurApic->arb_id = pCurApic->id;
1432 APIC_FOREACH_END();
1433 Log(("CPU%d: APIC_DM_INIT arbitration id(s) set\n", pApic->phys_id));
1434 return VINF_SUCCESS;
1435 }
1436 break;
1437 }
1438
1439 case APIC_DM_SIPI:
1440# ifdef IN_RING3
1441 APIC_FOREACH_IN_SET_BEGIN(pDev, &DstSet);
1442 apicR3Startup(pDev, pCurApic, vector_num);
1443 APIC_FOREACH_END();
1444 return VINF_SUCCESS;
1445# else
1446 /* We shall send SIPI only in R3, R0 calls should be
1447 rescheduled to R3 */
1448 return VINF_IOM_R3_MMIO_WRITE;
1449# endif
1450 }
1451
1452 return apic_bus_deliver(pDev, &DstSet, delivery_mode, vector_num,
1453 polarity, trigger_mode,
1454 pDev->CTX_SUFF(pApicHlp)->pfnCalcIrqTag(pDev->CTX_SUFF(pDevIns), PDM_IRQ_LEVEL_HIGH));
1455}
1456
1457
1458PDMBOTHCBDECL(int) apicGetInterrupt(PPDMDEVINS pDevIns, PVMCPU pVCpu, uint8_t *pu8Vector, uint32_t *pu32TagSrc)
1459{
1460 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
1461 /* if the APIC is not installed or enabled, we let the 8259 handle the IRQs */
1462 if (!pDev)
1463 {
1464 Log(("apic_get_interrupt: returns -1 (!pDev)\n"));
1465 return VERR_APIC_INTR_NOT_PENDING;
1466 }
1467
1468 Assert(PDMCritSectIsOwner(pDev->CTX_SUFF(pCritSect)));
1469
1470 APICState *pApic = apicGetStateById(pDev, pVCpu->idCpu);
1471
1472 if (!(pApic->spurious_vec & APIC_SV_ENABLE))
1473 {
1474 Log(("CPU%d: apic_get_interrupt: returns -1 (APIC_SV_ENABLE)\n", pApic->phys_id));
1475 return VERR_APIC_INTR_NOT_PENDING;
1476 }
1477
1478 /** @todo XXX: spurious IRQ handling */
1479 int intno = Apic256BitReg_FindLastSetBit(&pApic->irr, -1);
1480 if (intno < 0)
1481 {
1482 Log(("CPU%d: apic_get_interrupt: returns -1 (irr)\n", pApic->phys_id));
1483 return VERR_APIC_INTR_NOT_PENDING;
1484 }
1485
1486 if (pApic->tpr && (uint32_t)intno <= pApic->tpr)
1487 {
1488 *pu32TagSrc = 0;
1489 *pu8Vector = pApic->spurious_vec & 0xff;
1490 Log(("apic_get_interrupt: returns %d (sp)\n", *pu8Vector));
1491 return VINF_SUCCESS;
1492 }
1493
1494 Apic256BitReg_ClearBit(&pApic->irr, intno);
1495 Apic256BitReg_SetBit(&pApic->isr, intno);
1496
1497 *pu32TagSrc = pApic->auTags[intno];
1498 pApic->auTags[intno] = 0;
1499
1500 apic_update_irq(pDev, pApic);
1501
1502 LogFlow(("CPU%d: apic_get_interrupt: returns %d / %#x\n", pApic->phys_id, intno, *pu32TagSrc));
1503 *pu8Vector = (uint8_t)intno;
1504 return VINF_SUCCESS;
1505}
1506
1507/**
1508 * @remarks Caller (apicReadRegister) takes both the TM and APIC locks before
1509 * calling this function.
1510 */
1511static uint32_t apic_get_current_count(APICDeviceInfo const *pDev, APICState const *pApic)
1512{
1513 int64_t d = (TMTimerGet(pApic->CTX_SUFF(pTimer)) - pApic->initial_count_load_time)
1514 >> pApic->count_shift;
1515
1516 uint32_t val;
1517 if (pApic->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC)
1518 /* periodic */
1519 val = pApic->initial_count - (d % ((uint64_t)pApic->initial_count + 1));
1520 else if (d >= pApic->initial_count)
1521 val = 0;
1522 else
1523 val = pApic->initial_count - d;
1524
1525 return val;
1526}
1527
1528/**
1529 * Does the frequency hinting and logging.
1530 *
1531 * @param pApic The device state.
1532 */
1533DECLINLINE(void) apicDoFrequencyHinting(APICState *pApic)
1534{
1535 if ( pApic->uHintedInitialCount != pApic->initial_count
1536 || pApic->uHintedCountShift != (uint32_t)pApic->count_shift)
1537 {
1538 pApic->uHintedInitialCount = pApic->initial_count;
1539 pApic->uHintedCountShift = pApic->count_shift;
1540
1541 uint32_t uHz;
1542 if (pApic->initial_count > 0)
1543 {
1544 Assert((unsigned)pApic->count_shift < 30);
1545 uint64_t cTickPerPeriod = ((uint64_t)pApic->initial_count + 1) << pApic->count_shift;
1546 uHz = TMTimerGetFreq(pApic->CTX_SUFF(pTimer)) / cTickPerPeriod;
1547 }
1548 else
1549 uHz = 0;
1550 TMTimerSetFrequencyHint(pApic->CTX_SUFF(pTimer), uHz);
1551 Log(("apic: %u Hz\n", uHz));
1552 }
1553}
1554
1555/**
1556 * Implementation of the 0380h access: Timer reset + new initial count.
1557 *
1558 * @param pDev The device state.
1559 * @param pApic The APIC sub-device state.
1560 * @param u32NewInitialCount The new initial count for the timer.
1561 */
1562static void apicTimerSetInitialCount(APICDeviceInfo *pDev, APICState *pApic, uint32_t u32NewInitialCount)
1563{
1564 STAM_COUNTER_INC(&pApic->StatTimerSetInitialCount);
1565 pApic->initial_count = u32NewInitialCount;
1566
1567 /*
1568 * Don't (re-)arm the timer if the it's masked or if it's
1569 * a zero length one-shot timer.
1570 */
1571 if ( !(pApic->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)
1572 && u32NewInitialCount > 0)
1573 {
1574 /*
1575 * Calculate the relative next time and perform a combined timer get/set
1576 * operation. This avoids racing the clock between get and set.
1577 */
1578 uint64_t cTicksNext = u32NewInitialCount;
1579 cTicksNext += 1;
1580 cTicksNext <<= pApic->count_shift;
1581 TMTimerSetRelative(pApic->CTX_SUFF(pTimer), cTicksNext, &pApic->initial_count_load_time);
1582 pApic->next_time = pApic->initial_count_load_time + cTicksNext;
1583 pApic->fTimerArmed = true;
1584 apicDoFrequencyHinting(pApic);
1585 STAM_COUNTER_INC(&pApic->StatTimerSetInitialCountArm);
1586 Log(("apicTimerSetInitialCount: cTicksNext=%'llu (%#llx) ic=%#x sh=%#x nxt=%#llx\n",
1587 cTicksNext, cTicksNext, u32NewInitialCount, pApic->count_shift, pApic->next_time));
1588 }
1589 else
1590 {
1591 /* Stop it if necessary and record the load time for unmasking. */
1592 if (pApic->fTimerArmed)
1593 {
1594 STAM_COUNTER_INC(&pApic->StatTimerSetInitialCountDisarm);
1595 TMTimerStop(pApic->CTX_SUFF(pTimer));
1596 pApic->fTimerArmed = false;
1597 pApic->uHintedCountShift = pApic->uHintedInitialCount = 0;
1598 }
1599 pApic->initial_count_load_time = TMTimerGet(pApic->CTX_SUFF(pTimer));
1600 Log(("apicTimerSetInitialCount: ic=%#x sh=%#x iclt=%#llx\n", u32NewInitialCount, pApic->count_shift, pApic->initial_count_load_time));
1601 }
1602}
1603
1604/**
1605 * Implementation of the 0320h access: change the LVT flags.
1606 *
1607 * @param pDev The device state.
1608 * @param pApic The APIC sub-device state to operate on.
1609 * @param fNew The new flags.
1610 */
1611static void apicTimerSetLvt(APICDeviceInfo *pDev, APICState *pApic, uint32_t fNew)
1612{
1613 STAM_COUNTER_INC(&pApic->StatTimerSetLvt);
1614
1615 /*
1616 * Make the flag change, saving the old ones so we can avoid
1617 * unnecessary work.
1618 */
1619 uint32_t const fOld = pApic->lvt[APIC_LVT_TIMER];
1620 pApic->lvt[APIC_LVT_TIMER] = fNew;
1621
1622 /* Only the masked and peridic bits are relevant (see apic_timer_update). */
1623 if ( (fOld & (APIC_LVT_MASKED | APIC_LVT_TIMER_PERIODIC))
1624 != (fNew & (APIC_LVT_MASKED | APIC_LVT_TIMER_PERIODIC)))
1625 {
1626 /*
1627 * If changed to one-shot from periodic, stop the timer if we're not
1628 * in the first period.
1629 */
1630 /** @todo check how clearing the periodic flag really should behave when not
1631 * in period 1. The current code just mirrors the behavior of the
1632 * original implementation. */
1633 if ( (fOld & APIC_LVT_TIMER_PERIODIC)
1634 && !(fNew & APIC_LVT_TIMER_PERIODIC))
1635 {
1636 STAM_COUNTER_INC(&pApic->StatTimerSetLvtClearPeriodic);
1637 uint64_t cTicks = (pApic->next_time - pApic->initial_count_load_time) >> pApic->count_shift;
1638 if (cTicks >= pApic->initial_count)
1639 {
1640 /* not first period, stop it. */
1641 TMTimerStop(pApic->CTX_SUFF(pTimer));
1642 pApic->fTimerArmed = false;
1643 pApic->uHintedCountShift = pApic->uHintedInitialCount = 0;
1644 }
1645 /* else: first period, let it fire normally. */
1646 }
1647
1648 /*
1649 * We postpone stopping the timer when it's masked, this way we can
1650 * avoid some timer work when the guest temporarily masks the timer.
1651 * (apicR3TimerCallback will stop it if still masked.)
1652 */
1653 if (fNew & APIC_LVT_MASKED)
1654 STAM_COUNTER_INC(&pApic->StatTimerSetLvtPostponed);
1655 else if (pApic->fTimerArmed)
1656 STAM_COUNTER_INC(&pApic->StatTimerSetLvtArmed);
1657 /*
1658 * If unmasked, not armed and with a valid initial count value (according
1659 * to our interpretation of the spec), we will have to rearm the timer so
1660 * it will fire at the end of the current period.
1661 *
1662 * N.B. This is code is currently RACING the virtual sync clock!
1663 */
1664 else if ( (fOld & APIC_LVT_MASKED)
1665 && pApic->initial_count > 0)
1666 {
1667 STAM_COUNTER_INC(&pApic->StatTimerSetLvtArm);
1668 for (unsigned cTries = 0; ; cTries++)
1669 {
1670 uint64_t NextTS;
1671 uint64_t cTicks = (TMTimerGet(pApic->CTX_SUFF(pTimer)) - pApic->initial_count_load_time) >> pApic->count_shift;
1672 if (fNew & APIC_LVT_TIMER_PERIODIC)
1673 NextTS = ((cTicks / ((uint64_t)pApic->initial_count + 1)) + 1) * ((uint64_t)pApic->initial_count + 1);
1674 else
1675 {
1676 if (cTicks >= pApic->initial_count)
1677 break;
1678 NextTS = (uint64_t)pApic->initial_count + 1;
1679 }
1680 NextTS <<= pApic->count_shift;
1681 NextTS += pApic->initial_count_load_time;
1682
1683 /* Try avoid the assertion in TM.cpp... this isn't perfect! */
1684 if ( NextTS > TMTimerGet(pApic->CTX_SUFF(pTimer))
1685 || cTries > 10)
1686 {
1687 TMTimerSet(pApic->CTX_SUFF(pTimer), NextTS);
1688 pApic->next_time = NextTS;
1689 pApic->fTimerArmed = true;
1690 apicDoFrequencyHinting(pApic);
1691 Log(("apicTimerSetLvt: ic=%#x sh=%#x nxt=%#llx\n", pApic->initial_count, pApic->count_shift, pApic->next_time));
1692 break;
1693 }
1694 STAM_COUNTER_INC(&pApic->StatTimerSetLvtArmRetries);
1695 }
1696 }
1697 }
1698 else
1699 STAM_COUNTER_INC(&pApic->StatTimerSetLvtNoRelevantChange);
1700}
1701
1702# ifdef IN_RING3
1703
1704/**
1705 * Timer callback function.
1706 *
1707 * @param pDevIns The device state.
1708 * @param pTimer The timer handle.
1709 * @param pvUser User argument pointing to the APIC instance.
1710 */
1711static DECLCALLBACK(void) apicR3TimerCallback(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
1712{
1713 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
1714 APICState *pApic = (APICState *)pvUser;
1715 Assert(pApic->pTimerR3 == pTimer);
1716 Assert(pApic->fTimerArmed);
1717 Assert(PDMCritSectIsOwner(pDev->pCritSectR3));
1718 Assert(TMTimerIsLockOwner(pTimer));
1719
1720 if (!(pApic->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) {
1721 LogFlow(("apic_timer: trigger irq\n"));
1722 apic_set_irq(pDev, pApic, pApic->lvt[APIC_LVT_TIMER] & 0xff, APIC_TRIGGER_EDGE,
1723 pDev->CTX_SUFF(pApicHlp)->pfnCalcIrqTag(pDevIns, PDM_IRQ_LEVEL_HIGH));
1724
1725 if ( (pApic->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC)
1726 && pApic->initial_count > 0) {
1727 /* new interval. */
1728 pApic->next_time += (((uint64_t)pApic->initial_count + 1) << pApic->count_shift);
1729 TMTimerSet(pApic->CTX_SUFF(pTimer), pApic->next_time);
1730 pApic->fTimerArmed = true;
1731 apicDoFrequencyHinting(pApic);
1732 Log2(("apicR3TimerCallback: ic=%#x sh=%#x nxt=%#llx\n", pApic->initial_count, pApic->count_shift, pApic->next_time));
1733 } else {
1734 /* single shot or disabled. */
1735 pApic->fTimerArmed = false;
1736 pApic->uHintedCountShift = pApic->uHintedInitialCount = 0;
1737 }
1738 } else {
1739 /* masked, do not rearm. */
1740 pApic->fTimerArmed = false;
1741 pApic->uHintedCountShift = pApic->uHintedInitialCount = 0;
1742 }
1743}
1744
1745
1746#ifdef APIC_FUZZY_SSM_COMPAT_TEST
1747/**
1748 * Helper for dumping per-VCPU APIC state to the release logger.
1749 *
1750 * This is primarily concerned about the APIC state relevant for saved-states.
1751 *
1752 * @param pApic The APIC state.
1753 * @param pszPrefix A caller supplied prefix before dumping the state.
1754 */
1755static void apic_dump_state(APICState *pApic, const char *pszPrefix)
1756{
1757 LogRel(("APIC%u: %s\n", pApic->phys_id, pszPrefix));
1758 LogRel(("APIC%u: uApicBaseMsr = %#RX32\n", pApic->phys_id, pApic->apicbase));
1759 LogRel(("APIC%u: uId = %#RX32\n", pApic->phys_id, pApic->id));
1760 LogRel(("APIC%u: uPhysId = %#RX32\n", pApic->phys_id, pApic->phys_id));
1761 LogRel(("APIC%u: uArbId = %#RX32\n", pApic->phys_id, pApic->arb_id));
1762 LogRel(("APIC%u: uTrp = %#RX32\n", pApic->phys_id, pApic->tpr));
1763 LogRel(("APIC%u: uSvr = %#RX32\n", pApic->phys_id, pApic->spurious_vec));
1764 LogRel(("APIC%u: uLdr = %#x\n", pApic->phys_id, pApic->log_dest));
1765 LogRel(("APIC%u: uDfr = %#x\n", pApic->phys_id, pApic->dest_mode));
1766
1767 for (size_t i = 0; i < 8; i++)
1768 {
1769 LogRel(("APIC%u: Isr[%u].u32Reg = %#RX32\n", pApic->phys_id, i, pApic->isr.au32Bitmap[i]));
1770 LogRel(("APIC%u: Tmr[%u].u32Reg = %#RX32\n", pApic->phys_id, i, pApic->tmr.au32Bitmap[i]));
1771 LogRel(("APIC%u: Irr[%u].u32Reg = %#RX32\n", pApic->phys_id, i, pApic->irr.au32Bitmap[i]));
1772 }
1773
1774 for (size_t i = 0; i < APIC_LVT_NB; i++)
1775 LogRel(("APIC%u: Lvt[%u].u32Reg = %#RX32\n", pApic->phys_id, i, pApic->lvt[i]));
1776
1777 LogRel(("APIC%u: uEsr = %#RX32\n", pApic->phys_id, pApic->esr));
1778 LogRel(("APIC%u: uIcr_Lo = %#RX32\n", pApic->phys_id, pApic->icr[0]));
1779 LogRel(("APIC%u: uIcr_Hi = %#RX32\n", pApic->phys_id, pApic->icr[1]));
1780 LogRel(("APIC%u: uTimerDcr = %#RX32\n", pApic->phys_id, pApic->divide_conf));
1781 LogRel(("APIC%u: uCountShift = %#RX32\n", pApic->phys_id, pApic->count_shift));
1782 LogRel(("APIC%u: uInitialCount = %#RX32\n", pApic->phys_id, pApic->initial_count));
1783 LogRel(("APIC%u: u64InitialCountLoadTime = %#RX64\n", pApic->phys_id, pApic->initial_count_load_time));
1784 LogRel(("APIC%u: u64NextTime / TimerCCR = %#RX64\n", pApic->phys_id, pApic->next_time));
1785}
1786
1787
1788/**
1789 * Fuzzies up the APIC state with completely random bits for testing &
1790 * validation purposes.
1791 *
1792 * @param pApic The APIC state.
1793 * @remarks Warning! This should ONLY be used for diagnostics, otherwise will
1794 * corrupt saved-states and may result in loss of data!
1795 */
1796static void apic_fuzz_state(APICState *pApic)
1797{
1798 pApic->apicbase = RTRandU32();
1799 pApic->id = RTRandU32();
1800 pApic->phys_id = RTRandU32();
1801 pApic->arb_id = RTRandU32();
1802 pApic->tpr = RTRandU32();
1803 pApic->spurious_vec = RTRandU32();
1804 pApic->log_dest = RTRandU32();
1805 pApic->dest_mode = RTRandU32();
1806
1807 for (size_t i = 0; i < 8; i++)
1808 {
1809 pApic->isr.au32Bitmap[i] = RTRandU32();
1810 pApic->tmr.au32Bitmap[i] = RTRandU32();
1811 pApic->irr.au32Bitmap[i] = RTRandU32();
1812 }
1813
1814 for (size_t i = 0; i < APIC_LVT_NB; i++)
1815 pApic->lvt[i] = RTRandU32();
1816
1817 pApic->esr = RTRandU32();
1818 pApic->icr[0] = RTRandU32();
1819 pApic->icr[1] = RTRandU32();
1820 pApic->divide_conf = RTRandU32();
1821
1822 int v = (pApic->divide_conf & 3) | ((pApic->divide_conf >> 1) & 4);
1823 pApic->count_shift = (v + 1) & 7;
1824
1825 pApic->initial_count = RTRandU32();
1826 pApic->initial_count_load_time = RTRandU64();
1827 pApic->next_time = pApic->initial_count_load_time;
1828}
1829#endif /* APIC_FUZZY_SSM_COMPAT_TEST */
1830
1831
1832static void apic_save(SSMHANDLE* f, void *opaque)
1833{
1834 APICState *pApic = (APICState*)opaque;
1835 int i;
1836
1837#ifdef APIC_FUZZY_SSM_COMPAT_TEST
1838#error "Fuzzying state is purely for testing. Remove this manually and proceed at your own risk!"
1839 APICState *pOriginal = pApic;
1840 APICState FuzzedApic;
1841 apic_fuzz_state(&FuzzedApic);
1842 pApic = &FuzzedApic;
1843 pApic->phys_id = pOriginal->phys_id;
1844#endif
1845
1846 SSMR3PutU32(f, pApic->apicbase);
1847 SSMR3PutU32(f, pApic->id);
1848 SSMR3PutU32(f, pApic->phys_id);
1849 SSMR3PutU32(f, pApic->arb_id);
1850 SSMR3PutU32(f, pApic->tpr);
1851 SSMR3PutU32(f, pApic->spurious_vec);
1852 SSMR3PutU8(f, pApic->log_dest);
1853 SSMR3PutU8(f, pApic->dest_mode);
1854 for (i = 0; i < 8; i++) {
1855 SSMR3PutU32(f, pApic->isr.au32Bitmap[i]);
1856 SSMR3PutU32(f, pApic->tmr.au32Bitmap[i]);
1857 SSMR3PutU32(f, pApic->irr.au32Bitmap[i]);
1858 }
1859 for (i = 0; i < APIC_LVT_NB; i++) {
1860 SSMR3PutU32(f, pApic->lvt[i]);
1861 }
1862 SSMR3PutU32(f, pApic->esr);
1863 SSMR3PutU32(f, pApic->icr[0]);
1864 SSMR3PutU32(f, pApic->icr[1]);
1865 SSMR3PutU32(f, pApic->divide_conf);
1866 SSMR3PutU32(f, pApic->count_shift);
1867 SSMR3PutU32(f, pApic->initial_count);
1868 SSMR3PutU64(f, pApic->initial_count_load_time);
1869 SSMR3PutU64(f, pApic->next_time);
1870
1871#ifdef APIC_FUZZY_SSM_COMPAT_TEST
1872 apic_dump_state(pApic, "Saved state:");
1873 pApic = pOriginal;
1874#endif
1875
1876 TMR3TimerSave(pApic->CTX_SUFF(pTimer), f);
1877}
1878
1879static int apic_load(SSMHANDLE *f, void *opaque, int version_id)
1880{
1881 APICState *pApic = (APICState*)opaque;
1882 int i;
1883
1884 /** @todo XXX: what if the base changes? (registered memory regions) */
1885 SSMR3GetU32(f, &pApic->apicbase);
1886
1887 switch (version_id)
1888 {
1889 case APIC_SAVED_STATE_VERSION_ANCIENT:
1890 {
1891 uint8_t val = 0;
1892 SSMR3GetU8(f, &val);
1893 pApic->id = val;
1894 /* UP only in old saved states */
1895 pApic->phys_id = 0;
1896 SSMR3GetU8(f, &val);
1897 pApic->arb_id = val;
1898 break;
1899 }
1900 case APIC_SAVED_STATE_VERSION:
1901 case APIC_SAVED_STATE_VERSION_VBOX_30:
1902 SSMR3GetU32(f, &pApic->id);
1903 SSMR3GetU32(f, &pApic->phys_id);
1904 SSMR3GetU32(f, &pApic->arb_id);
1905 break;
1906 default:
1907 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1908 }
1909 SSMR3GetU32(f, &pApic->tpr);
1910 SSMR3GetU32(f, &pApic->spurious_vec);
1911 SSMR3GetU8(f, &pApic->log_dest);
1912 SSMR3GetU8(f, &pApic->dest_mode);
1913 for (i = 0; i < 8; i++) {
1914 SSMR3GetU32(f, &pApic->isr.au32Bitmap[i]);
1915 SSMR3GetU32(f, &pApic->tmr.au32Bitmap[i]);
1916 SSMR3GetU32(f, &pApic->irr.au32Bitmap[i]);
1917 }
1918 for (i = 0; i < APIC_LVT_NB; i++) {
1919 SSMR3GetU32(f, &pApic->lvt[i]);
1920 }
1921 SSMR3GetU32(f, &pApic->esr);
1922 SSMR3GetU32(f, &pApic->icr[0]);
1923 SSMR3GetU32(f, &pApic->icr[1]);
1924 SSMR3GetU32(f, &pApic->divide_conf);
1925 SSMR3GetU32(f, (uint32_t *)&pApic->count_shift);
1926 SSMR3GetU32(f, (uint32_t *)&pApic->initial_count);
1927 SSMR3GetU64(f, (uint64_t *)&pApic->initial_count_load_time);
1928 SSMR3GetU64(f, (uint64_t *)&pApic->next_time);
1929
1930 int rc = TMR3TimerLoad(pApic->CTX_SUFF(pTimer), f);
1931 AssertRCReturn(rc, rc);
1932 pApic->uHintedCountShift = pApic->uHintedInitialCount = 0;
1933 pApic->fTimerArmed = TMTimerIsActive(pApic->CTX_SUFF(pTimer));
1934 if (pApic->fTimerArmed)
1935 apicDoFrequencyHinting(pApic);
1936
1937 return VINF_SUCCESS; /** @todo darn mess! */
1938}
1939
1940#endif /* IN_RING3 */
1941
1942/* LAPIC */
1943PDMBOTHCBDECL(int) apicMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
1944{
1945 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
1946 APICState *pApic = apicGetStateByCurEmt(pDev);
1947
1948 Assert(cb == 4);
1949
1950 /** @todo add LAPIC range validity checks (different LAPICs can
1951 * theoretically have different physical addresses, see @bugref{3092}) */
1952
1953 STAM_COUNTER_INC(&CTXSUFF(pDev->StatMMIORead));
1954#if 0 /* Note! experimental */
1955#ifndef IN_RING3
1956 uint32_t index = (GCPhysAddr >> 4) & 0xff;
1957
1958 if ( index == 0x08 /* TPR */
1959 && ++pApic->cTPRPatchAttempts < APIC_MAX_PATCH_ATTEMPTS)
1960 {
1961# ifdef IN_RC
1962 pDevIns->pDevHlpGC->pfnPATMSetMMIOPatchInfo(pDevIns, GCPhysAddr, &pApic->tpr);
1963# else
1964 RTGCPTR pDevInsGC = PDMINS2DATA_GCPTR(pDevIns);
1965 pDevIns->pHlpR0->pfnPATMSetMMIOPatchInfo(pDevIns, GCPhysAddr, pDevIns + RT_OFFSETOF(APICState, tpr));
1966# endif
1967 return VINF_PATM_HC_MMIO_PATCH_READ;
1968 }
1969#endif
1970#endif /* experimental */
1971
1972 /* Note! apicReadRegister does its own locking. */
1973 uint64_t u64Value = 0;
1974 int rc = apicReadRegister(pDev, pApic, (GCPhysAddr >> 4) & 0xff, &u64Value, VINF_IOM_R3_MMIO_READ, false /*fMsr*/);
1975 *(uint32_t *)pv = (uint32_t)u64Value;
1976 Log(("CPU%d: apicMMIORead at %RGp returns %#RX32\n", pApic->phys_id, GCPhysAddr, (uint32_t)u64Value));
1977 return rc;
1978}
1979
1980PDMBOTHCBDECL(int) apicMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb)
1981{
1982 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
1983 APICState *pApic = apicGetStateByCurEmt(pDev);
1984
1985 Log(("CPU%d: apicMMIOWrite at %RGp uValue=%#RX32\n", pApic->phys_id, GCPhysAddr, *(uint32_t const *)pv));
1986 Assert(cb == 4);
1987
1988 /** @todo add LAPIC range validity checks (multiple LAPICs can theoretically
1989 * have different physical addresses, see @bugref{3092}) */
1990
1991 STAM_COUNTER_INC(&CTXSUFF(pDev->StatMMIOWrite));
1992 /* Note! It does its own locking. */
1993 return apicWriteRegister(pDev, pApic, (GCPhysAddr >> 4) & 0xff, *(uint32_t const *)pv,
1994 VINF_IOM_R3_MMIO_WRITE, false /*fMsr*/);
1995}
1996
1997#ifdef IN_RING3
1998
1999/**
2000 * Wrapper around apicReadRegister.
2001 *
2002 * @returns 64-bit register value.
2003 * @param pDev The PDM device instance.
2004 * @param pApic The Local APIC in question.
2005 * @param iReg The APIC register index.
2006 */
2007static uint64_t apicR3InfoReadReg(APICDeviceInfo *pDev, APICState *pApic, uint32_t iReg)
2008{
2009 uint64_t u64Value;
2010 int rc = apicReadRegister(pDev, pApic, iReg, &u64Value, VINF_SUCCESS, true /*fMsr*/);
2011 AssertRCReturn(rc, UINT64_MAX);
2012 return u64Value;
2013}
2014
2015/**
2016 * Print an 8-DWORD Local APIC bit map (256 bits).
2017 *
2018 * @param pDev The PDM device instance.
2019 * @param pApic The Local APIC in question.
2020 * @param pHlp The output helper.
2021 * @param iStartReg The register to start at.
2022 */
2023static void apicR3DumpVec(APICDeviceInfo *pDev, APICState *pApic, PCDBGFINFOHLP pHlp, uint32_t iStartReg)
2024{
2025 for (int i = 7; i >= 0; --i)
2026 pHlp->pfnPrintf(pHlp, "%08x", apicR3InfoReadReg(pDev, pApic, iStartReg + i));
2027 pHlp->pfnPrintf(pHlp, "\n");
2028}
2029
2030/**
2031 * Print the set of pending interrupts in a 256-bit map.
2032 *
2033 * @param pDev The PDM device instance.
2034 * @param pApic The Local APIC in question.
2035 * @param pHlp The output helper.
2036 * @param iStartReg The register to start at.
2037 */
2038static void apicR3DumpPending(APICDeviceInfo *pDev, APICState *pApic, PCDBGFINFOHLP pHlp, PCAPIC256BITREG pReg)
2039{
2040 APIC256BITREG pending;
2041 int iMax;
2042 int cPending = 0;
2043
2044 pending = *pReg;
2045 pHlp->pfnPrintf(pHlp, " pending =");
2046
2047 while ((iMax = Apic256BitReg_FindLastSetBit(&pending, -1)) != -1)
2048 {
2049 pHlp->pfnPrintf(pHlp, " %02x", iMax);
2050 Apic256BitReg_ClearBit(&pending, iMax);
2051 ++cPending;
2052 }
2053 if (!cPending)
2054 pHlp->pfnPrintf(pHlp, " none");
2055 pHlp->pfnPrintf(pHlp, "\n");
2056}
2057
2058/**
2059 * Print basic Local APIC state.
2060 *
2061 * @param pDev The PDM device instance.
2062 * @param pApic The Local APIC in question.
2063 * @param pHlp The output helper.
2064 */
2065static void apicR3InfoBasic(APICDeviceInfo *pDev, APICState *pApic, PCDBGFINFOHLP pHlp)
2066{
2067 uint64_t u64;
2068
2069 pHlp->pfnPrintf(pHlp, "CPU%u: Local APIC at %08llx:\n", pApic->phys_id, pApic->apicbase);
2070 u64 = apicR3InfoReadReg(pDev, pApic, 0x2);
2071 pHlp->pfnPrintf(pHlp, " LAPIC ID : %08llx\n", u64);
2072 pHlp->pfnPrintf(pHlp, " APIC ID = %02llx\n", (u64 >> 24) & 0xff);
2073 u64 = apicR3InfoReadReg(pDev, pApic, 0x3);
2074 pHlp->pfnPrintf(pHlp, " APIC VER : %08llx\n", u64);
2075 pHlp->pfnPrintf(pHlp, " version = %02x\n", (int)RT_BYTE1(u64));
2076 pHlp->pfnPrintf(pHlp, " lvts = %d\n", (int)RT_BYTE3(u64) + 1);
2077 u64 = apicR3InfoReadReg(pDev, pApic, 0x8);
2078 pHlp->pfnPrintf(pHlp, " TPR : %08llx\n", u64);
2079 pHlp->pfnPrintf(pHlp, " task pri = %lld/%lld\n", (u64 >> 4) & 0xf, u64 & 0xf);
2080 u64 = apicR3InfoReadReg(pDev, pApic, 0xA);
2081 pHlp->pfnPrintf(pHlp, " PPR : %08llx\n", u64);
2082 pHlp->pfnPrintf(pHlp, " cpu pri = %lld/%lld\n", (u64 >> 4) & 0xf, u64 & 0xf);
2083 u64 = apicR3InfoReadReg(pDev, pApic, 0xD);
2084 pHlp->pfnPrintf(pHlp, " LDR : %08llx\n", u64);
2085 pHlp->pfnPrintf(pHlp, " log id = %02llx\n", (u64 >> 24) & 0xff);
2086 pHlp->pfnPrintf(pHlp, " DFR : %08llx\n", apicR3InfoReadReg(pDev, pApic, 0xE));
2087 u64 = apicR3InfoReadReg(pDev, pApic, 0xF);
2088 pHlp->pfnPrintf(pHlp, " SVR : %08llx\n", u64);
2089 pHlp->pfnPrintf(pHlp, " focus = %s\n", u64 & RT_BIT(9) ? "check off" : "check on");
2090 pHlp->pfnPrintf(pHlp, " lapic = %s\n", u64 & RT_BIT(8) ? "ENABLED" : "DISABLED");
2091 pHlp->pfnPrintf(pHlp, " vector = %02x\n", (unsigned)RT_BYTE1(u64));
2092 pHlp->pfnPrintf(pHlp, " ISR : ");
2093 apicR3DumpVec(pDev, pApic, pHlp, 0x10);
2094 apicR3DumpPending(pDev, pApic, pHlp, &pApic->isr);
2095 pHlp->pfnPrintf(pHlp, " IRR : ");
2096 apicR3DumpVec(pDev, pApic, pHlp, 0x20);
2097 apicR3DumpPending(pDev, pApic, pHlp, &pApic->irr);
2098}
2099
2100
2101/**
2102 * Print the more interesting Local APIC LVT entries.
2103 *
2104 * @param pDev The PDM device instance.
2105 * @param pApic The Local APIC in question.
2106 * @param pHlp The output helper.
2107 */
2108static void apicR3InfoLVT(APICDeviceInfo *pDev, APICState *pApic, PCDBGFINFOHLP pHlp)
2109{
2110 static const char * const s_apszDeliveryModes[] =
2111 {
2112 "Fixed ", "Reserved", "SMI", "Reserved", "NMI", "INIT", "Reserved", "ExtINT"
2113 };
2114 uint64_t u64;
2115
2116 u64 = apicR3InfoReadReg(pDev, pApic, 0x32);
2117 pHlp->pfnPrintf(pHlp, " LVT Timer : %08llx\n", u64);
2118 pHlp->pfnPrintf(pHlp, " mode = %s\n", u64 & RT_BIT(17) ? "periodic" : "one-shot");
2119 pHlp->pfnPrintf(pHlp, " mask = %llu\n", (u64 >> 16) & 1);
2120 pHlp->pfnPrintf(pHlp, " status = %s\n", u64 & RT_BIT(12) ? "pending" : "idle");
2121 pHlp->pfnPrintf(pHlp, " vector = %02llx\n", u64 & 0xff);
2122 u64 = apicR3InfoReadReg(pDev, pApic, 0x35);
2123 pHlp->pfnPrintf(pHlp, " LVT LINT0 : %08llx\n", u64);
2124 pHlp->pfnPrintf(pHlp, " mask = %llu\n", (u64 >> 16) & 1);
2125 pHlp->pfnPrintf(pHlp, " trigger = %s\n", u64 & RT_BIT(15) ? "level" : "edge");
2126 pHlp->pfnPrintf(pHlp, " rem irr = %llu\n", (u64 >> 14) & 1);
2127 pHlp->pfnPrintf(pHlp, " polarty = %llu\n", (u64 >> 13) & 1);
2128 pHlp->pfnPrintf(pHlp, " status = %s\n", u64 & RT_BIT(12) ? "pending" : "idle");
2129 pHlp->pfnPrintf(pHlp, " delivry = %s\n", s_apszDeliveryModes[(u64 >> 8) & 7]);
2130 pHlp->pfnPrintf(pHlp, " vector = %02llx\n", u64 & 0xff);
2131 u64 = apicR3InfoReadReg(pDev, pApic, 0x36);
2132 pHlp->pfnPrintf(pHlp, " LVT LINT1 : %08llx\n", u64);
2133 pHlp->pfnPrintf(pHlp, " mask = %llu\n", (u64 >> 16) & 1);
2134 pHlp->pfnPrintf(pHlp, " trigger = %s\n", u64 & RT_BIT(15) ? "level" : "edge");
2135 pHlp->pfnPrintf(pHlp, " rem irr = %lld\n", (u64 >> 14) & 1);
2136 pHlp->pfnPrintf(pHlp, " polarty = %lld\n", (u64 >> 13) & 1);
2137 pHlp->pfnPrintf(pHlp, " status = %s\n", u64 & RT_BIT(12) ? "pending" : "idle");
2138 pHlp->pfnPrintf(pHlp, " delivry = %s\n", s_apszDeliveryModes[(u64 >> 8) & 7]);
2139 pHlp->pfnPrintf(pHlp, " vector = %02llx\n", u64 & 0xff);
2140}
2141
2142
2143/**
2144 * Print LAPIC timer state.
2145 *
2146 * @param pDev The PDM device instance.
2147 * @param pApic The Local APIC in question.
2148 * @param pHlp The output helper.
2149 */
2150static void apicR3InfoTimer(APICDeviceInfo *pDev, APICState *pApic, PCDBGFINFOHLP pHlp)
2151{
2152 pHlp->pfnPrintf(pHlp, "Local APIC timer:\n");
2153 pHlp->pfnPrintf(pHlp, " Initial count : %08llx\n", apicR3InfoReadReg(pDev, pApic, 0x38));
2154 pHlp->pfnPrintf(pHlp, " Current count : %08llx\n", apicR3InfoReadReg(pDev, pApic, 0x39));
2155 uint64_t u64 = apicR3InfoReadReg(pDev, pApic, 0x3e);
2156 pHlp->pfnPrintf(pHlp, " Divide config : %08llx\n", u64);
2157 unsigned uDivider = ((u64 >> 1) & 0x04) | (u64 & 0x03);
2158 pHlp->pfnPrintf(pHlp, " divider = %u\n", uDivider == 7 ? 1 : 2 << uDivider);
2159}
2160
2161
2162/**
2163 * @callback_method_impl{FNDBGFHANDLERDEV,
2164 * Dumps the Local APIC state according to given argument.}
2165 */
2166static DECLCALLBACK(void) apicR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
2167{
2168 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2169 PVM pVM = PDMDevHlpGetVM(pDevIns);
2170 VMCPUID idCpu = VMMGetCpuId(pVM);
2171 if (idCpu == NIL_VMCPUID) /* Don't crash if we're not on EMT, just assume EMT0 for now. */
2172 idCpu = 0;
2173 APICState *pApic = apicGetStateById(pDev, idCpu);
2174
2175 if (pszArgs == NULL || !*pszArgs || !strcmp(pszArgs, "basic"))
2176 apicR3InfoBasic(pDev, pApic, pHlp);
2177 else if (!strcmp(pszArgs, "lvt"))
2178 apicR3InfoLVT(pDev, pApic, pHlp);
2179 else if (!strcmp(pszArgs, "timer"))
2180 apicR3InfoTimer(pDev, pApic, pHlp);
2181 else
2182 pHlp->pfnPrintf(pHlp, "Invalid argument. Recognized arguments are 'basic', 'lvt', 'timer'.\n");
2183}
2184
2185
2186/**
2187 * @copydoc FNSSMDEVLIVEEXEC
2188 */
2189static DECLCALLBACK(int) apicR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
2190{
2191 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2192
2193 SSMR3PutU32( pSSM, pDev->cCpus);
2194 SSMR3PutBool(pSSM, pDev->fIoApic);
2195 SSMR3PutU32( pSSM, pDev->enmMode);
2196 AssertCompile(PDMAPICMODE_APIC == 2);
2197
2198 return VINF_SSM_DONT_CALL_AGAIN;
2199}
2200
2201
2202/**
2203 * @copydoc FNSSMDEVSAVEEXEC
2204 */
2205static DECLCALLBACK(int) apicR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
2206{
2207 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2208
2209 /* config */
2210 apicR3LiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
2211
2212 /* save all APICs data */ /** @todo is it correct? */
2213 APIC_FOREACH_BEGIN(pDev);
2214 apic_save(pSSM, pCurApic);
2215 APIC_FOREACH_END();
2216
2217 return VINF_SUCCESS;
2218}
2219
2220/**
2221 * @copydoc FNSSMDEVLOADEXEC
2222 */
2223static DECLCALLBACK(int) apicR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
2224{
2225 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2226
2227 if ( uVersion != APIC_SAVED_STATE_VERSION
2228 && uVersion != APIC_SAVED_STATE_VERSION_VBOX_30
2229 && uVersion != APIC_SAVED_STATE_VERSION_ANCIENT)
2230 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
2231
2232 /* config */
2233 if (uVersion > APIC_SAVED_STATE_VERSION_VBOX_30)
2234 {
2235 uint32_t cCpus;
2236 int rc = SSMR3GetU32(pSSM, &cCpus); AssertRCReturn(rc, rc);
2237 if (cCpus != pDev->cCpus)
2238 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - cCpus: saved=%#x config=%#x"), cCpus, pDev->cCpus);
2239
2240 bool fIoApic;
2241 rc = SSMR3GetBool(pSSM, &fIoApic); AssertRCReturn(rc, rc);
2242 if (fIoApic != pDev->fIoApic)
2243 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - fIoApic: saved=%RTbool config=%RTbool"), fIoApic, pDev->fIoApic);
2244
2245 uint32_t uApicMode;
2246 rc = SSMR3GetU32(pSSM, &uApicMode); AssertRCReturn(rc, rc);
2247 if (uApicMode != (uint32_t)pDev->enmMode)
2248 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - uApicMode: saved=%#x config=%#x"), uApicMode, pDev->enmMode);
2249 }
2250
2251 if (uPass != SSM_PASS_FINAL)
2252 return VINF_SUCCESS;
2253
2254 /* load all APICs data */ /** @todo is it correct? */
2255 APIC_LOCK(pDev, VERR_INTERNAL_ERROR_3);
2256
2257 int rc = VINF_SUCCESS;
2258 APIC_FOREACH_BEGIN(pDev);
2259 rc = apic_load(pSSM, pCurApic, uVersion);
2260 if (RT_FAILURE(rc))
2261 break;
2262 APIC_FOREACH_END();
2263
2264 APIC_UNLOCK(pDev);
2265 return rc;
2266}
2267
2268/**
2269 * @copydoc FNPDMDEVRESET
2270 */
2271static DECLCALLBACK(void) apicR3Reset(PPDMDEVINS pDevIns)
2272{
2273 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2274 TMTimerLock(pDev->paLapicsR3[0].pTimerR3, VERR_IGNORED);
2275 APIC_LOCK_VOID(pDev, VERR_IGNORED);
2276
2277 /* Reset all APICs. */
2278 for (VMCPUID i = 0; i < pDev->cCpus; i++)
2279 {
2280 APICState *pApic = &pDev->CTX_SUFF(paLapics)[i];
2281 TMTimerStop(pApic->CTX_SUFF(pTimer));
2282
2283 /* Clear LAPIC state as if an INIT IPI was sent. */
2284 apicR3InitIpi(pDev, pApic);
2285
2286 /* The IDs are not touched by apicR3InitIpi() and must be reset now. */
2287 pApic->arb_id = pApic->id = i;
2288 Assert(pApic->id == pApic->phys_id); /* The two should match again. */
2289
2290 /* Reset should re-enable the APIC, see comment in msi.h */
2291 pApic->apicbase = VBOX_MSI_ADDR_BASE | MSR_IA32_APICBASE_ENABLE;
2292 if (pApic->phys_id == 0)
2293 pApic->apicbase |= MSR_IA32_APICBASE_BSP;
2294
2295 /* Clear any pending APIC interrupt action flag. */
2296 apicCpuClearInterrupt(pDev, pApic);
2297 }
2298
2299 LogRel(("APIC: Re-activating Local APIC\n"));
2300 CPUMSetGuestCpuIdPerCpuApicFeature(PDMDevHlpGetVMCPU(pDevIns), true);
2301
2302 APIC_UNLOCK(pDev);
2303 TMTimerUnlock(pDev->paLapicsR3[0].pTimerR3);
2304}
2305
2306
2307/**
2308 * @copydoc FNPDMDEVRELOCATE
2309 */
2310static DECLCALLBACK(void) apicR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
2311{
2312 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2313 pDev->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2314 pDev->pApicHlpRC = pDev->pApicHlpR3->pfnGetRCHelpers(pDevIns);
2315 pDev->paLapicsRC = MMHyperR3ToRC(PDMDevHlpGetVM(pDevIns), pDev->paLapicsR3);
2316 pDev->pCritSectRC = pDev->pApicHlpR3->pfnGetRCCritSect(pDevIns);
2317 for (uint32_t i = 0; i < pDev->cCpus; i++)
2318 pDev->paLapicsR3[i].pTimerRC = TMTimerRCPtr(pDev->paLapicsR3[i].pTimerR3);
2319}
2320
2321
2322/**
2323 * Initializes the state of one local APIC.
2324 *
2325 * @param pApic The Local APIC state to init.
2326 * @param id The Local APIC ID.
2327 */
2328static void apicR3StateInit(APICState *pApic, uint8_t id)
2329{
2330 memset(pApic, 0, sizeof(*pApic));
2331
2332 /* See comment in msi.h for LAPIC base info. */
2333 pApic->apicbase = VBOX_MSI_ADDR_BASE | MSR_IA32_APICBASE_ENABLE;
2334 if (id == 0) /* Mark first CPU as BSP. */
2335 pApic->apicbase |= MSR_IA32_APICBASE_BSP;
2336
2337 for (int i = 0; i < APIC_LVT_NB; i++)
2338 pApic->lvt[i] = RT_BIT_32(16); /* mask LVT */
2339
2340 pApic->spurious_vec = 0xff;
2341 pApic->phys_id = id;
2342 pApic->id = id;
2343}
2344
2345
2346/**
2347 * @copydoc FNPDMDEVCONSTRUCT
2348 */
2349static DECLCALLBACK(int) apicR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
2350{
2351 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2352 uint32_t i;
2353
2354 /*
2355 * Only single device instance.
2356 */
2357 Assert(iInstance == 0);
2358
2359 /*
2360 * Validate configuration.
2361 */
2362 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "IOAPIC|RZEnabled|NumCPUs", "");
2363
2364 bool fIoApic;
2365 int rc = CFGMR3QueryBoolDef(pCfg, "IOAPIC", &fIoApic, true);
2366 if (RT_FAILURE(rc))
2367 return PDMDEV_SET_ERROR(pDevIns, rc,
2368 N_("Configuration error: Failed to read \"IOAPIC\""));
2369
2370 bool fRZEnabled;
2371 rc = CFGMR3QueryBoolDef(pCfg, "RZEnabled", &fRZEnabled, true);
2372 if (RT_FAILURE(rc))
2373 return PDMDEV_SET_ERROR(pDevIns, rc,
2374 N_("Configuration error: Failed to query boolean value \"RZEnabled\""));
2375
2376 uint32_t cCpus;
2377 rc = CFGMR3QueryU32Def(pCfg, "NumCPUs", &cCpus, 1);
2378 if (RT_FAILURE(rc))
2379 return PDMDEV_SET_ERROR(pDevIns, rc,
2380 N_("Configuration error: Failed to query integer value \"NumCPUs\""));
2381
2382 Log(("APIC: cCpus=%d fRZEnabled=%RTbool fIoApic=%RTbool\n", cCpus, fRZEnabled, fIoApic));
2383 if (cCpus > 255)
2384 return PDMDEV_SET_ERROR(pDevIns, rc,
2385 N_("Configuration error: Invalid value for \"NumCPUs\""));
2386
2387 /*
2388 * Init the data.
2389 */
2390 pDev->pDevInsR3 = pDevIns;
2391 pDev->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
2392 pDev->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2393 pDev->cCpus = cCpus;
2394 pDev->fIoApic = fIoApic;
2395 /** @todo Finish X2APIC implementation. Must, among other things, set
2396 * PDMAPICMODE_X2APIC here when X2APIC is configured. */
2397 pDev->enmMode = PDMAPICMODE_APIC;
2398
2399 /* Disable locking in this device. */
2400 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
2401 AssertRCReturn(rc, rc);
2402
2403 PVM pVM = PDMDevHlpGetVM(pDevIns);
2404
2405 /*
2406 * We are not freeing this memory, as it's automatically released when guest exits.
2407 */
2408 rc = MMHyperAlloc(pVM, cCpus * sizeof(APICState), 1, MM_TAG_PDM_DEVICE_USER, (void **)&pDev->paLapicsR3);
2409 if (RT_FAILURE(rc))
2410 return VERR_NO_MEMORY;
2411 pDev->paLapicsR0 = MMHyperR3ToR0(pVM, pDev->paLapicsR3);
2412 pDev->paLapicsRC = MMHyperR3ToRC(pVM, pDev->paLapicsR3);
2413
2414 for (i = 0; i < cCpus; i++)
2415 apicR3StateInit(&pDev->paLapicsR3[i], i);
2416
2417 /*
2418 * Register the APIC.
2419 */
2420 PDMAPICREG ApicReg;
2421 ApicReg.u32Version = PDM_APICREG_VERSION;
2422 ApicReg.pfnGetInterruptR3 = apicGetInterrupt;
2423 ApicReg.pfnSetBaseMsrR3 = apicSetBase;
2424 ApicReg.pfnGetBaseMsrR3 = apicGetBase;
2425 ApicReg.pfnSetTprR3 = apicSetTPR;
2426 ApicReg.pfnGetTprR3 = apicGetTPR;
2427 ApicReg.pfnWriteMsrR3 = apicWriteMSR;
2428 ApicReg.pfnReadMsrR3 = apicReadMSR;
2429 ApicReg.pfnBusDeliverR3 = apicBusDeliverCallback;
2430 ApicReg.pfnLocalInterruptR3 = apicLocalInterrupt;
2431 ApicReg.pfnGetTimerFreqR3 = apicGetTimerFreq;
2432 if (fRZEnabled)
2433 {
2434 ApicReg.pszGetInterruptRC = "apicGetInterrupt";
2435 ApicReg.pszSetBaseMsrRC = "apicSetBase";
2436 ApicReg.pszGetBaseMsrRC = "apicGetBase";
2437 ApicReg.pszSetTprRC = "apicSetTPR";
2438 ApicReg.pszGetTprRC = "apicGetTPR";
2439 ApicReg.pszWriteMsrRC = "apicWriteMSR";
2440 ApicReg.pszReadMsrRC = "apicReadMSR";
2441 ApicReg.pszBusDeliverRC = "apicBusDeliverCallback";
2442 ApicReg.pszLocalInterruptRC = "apicLocalInterrupt";
2443 ApicReg.pszGetTimerFreqRC = "apicGetTimerFreq";
2444
2445 ApicReg.pszGetInterruptR0 = "apicGetInterrupt";
2446 ApicReg.pszSetBaseMsrR0 = "apicSetBase";
2447 ApicReg.pszGetBaseMsrR0 = "apicGetBase";
2448 ApicReg.pszSetTprR0 = "apicSetTPR";
2449 ApicReg.pszGetTprR0 = "apicGetTPR";
2450 ApicReg.pszWriteMsrR0 = "apicWriteMSR";
2451 ApicReg.pszReadMsrR0 = "apicReadMSR";
2452 ApicReg.pszBusDeliverR0 = "apicBusDeliverCallback";
2453 ApicReg.pszLocalInterruptR0 = "apicLocalInterrupt";
2454 ApicReg.pszGetTimerFreqR0 = "apicGetTimerFreq";
2455 }
2456 else
2457 {
2458 ApicReg.pszGetInterruptRC = NULL;
2459 ApicReg.pszSetBaseMsrRC = NULL;
2460 ApicReg.pszGetBaseMsrRC = NULL;
2461 ApicReg.pszSetTprRC = NULL;
2462 ApicReg.pszGetTprRC = NULL;
2463 ApicReg.pszWriteMsrRC = NULL;
2464 ApicReg.pszReadMsrRC = NULL;
2465 ApicReg.pszBusDeliverRC = NULL;
2466 ApicReg.pszLocalInterruptRC = NULL;
2467 ApicReg.pszGetTimerFreqRC = NULL;
2468
2469 ApicReg.pszGetInterruptR0 = NULL;
2470 ApicReg.pszSetBaseMsrR0 = NULL;
2471 ApicReg.pszGetBaseMsrR0 = NULL;
2472 ApicReg.pszSetTprR0 = NULL;
2473 ApicReg.pszGetTprR0 = NULL;
2474 ApicReg.pszWriteMsrR0 = NULL;
2475 ApicReg.pszReadMsrR0 = NULL;
2476 ApicReg.pszBusDeliverR0 = NULL;
2477 ApicReg.pszLocalInterruptR0 = NULL;
2478 ApicReg.pszGetTimerFreqR0 = NULL;
2479 }
2480
2481 rc = PDMDevHlpAPICRegister(pDevIns, &ApicReg, &pDev->pApicHlpR3);
2482 AssertLogRelRCReturn(rc, rc);
2483 pDev->pCritSectR3 = pDev->pApicHlpR3->pfnGetR3CritSect(pDevIns);
2484
2485 /*
2486 * The global CPUID feature bit(s).
2487 */
2488 LogRel(("APIC: Activating Local APIC\n"));
2489 pDev->pApicHlpR3->pfnSetFeatureLevel(pDevIns, pDev->enmMode);
2490
2491 /*
2492 * Register the MMIO range.
2493 */
2494 /** @todo shall reregister, if base changes. */
2495 uint32_t ApicBase = pDev->paLapicsR3[0].apicbase & ~0xfff;
2496 rc = PDMDevHlpMMIORegister(pDevIns, ApicBase, 0x1000, pDev,
2497 IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_DWORD_ZEROED,
2498 apicMMIOWrite, apicMMIORead, "APIC Memory");
2499 if (RT_FAILURE(rc))
2500 return rc;
2501
2502 if (fRZEnabled)
2503 {
2504 pDev->pApicHlpRC = pDev->pApicHlpR3->pfnGetRCHelpers(pDevIns);
2505 pDev->pCritSectRC = pDev->pApicHlpR3->pfnGetRCCritSect(pDevIns);
2506 rc = PDMDevHlpMMIORegisterRC(pDevIns, ApicBase, 0x1000, NIL_RTRCPTR /*pvUser*/, "apicMMIOWrite", "apicMMIORead");
2507 if (RT_FAILURE(rc))
2508 return rc;
2509
2510 pDev->pApicHlpR0 = pDev->pApicHlpR3->pfnGetR0Helpers(pDevIns);
2511 pDev->pCritSectR0 = pDev->pApicHlpR3->pfnGetR0CritSect(pDevIns);
2512 rc = PDMDevHlpMMIORegisterR0(pDevIns, ApicBase, 0x1000, NIL_RTR0PTR /*pvUser*/, "apicMMIOWrite", "apicMMIORead");
2513 if (RT_FAILURE(rc))
2514 return rc;
2515 }
2516
2517 /*
2518 * Create the APIC timers.
2519 */
2520 for (i = 0; i < cCpus; i++)
2521 {
2522 APICState *pApic = &pDev->paLapicsR3[i];
2523 pApic->pszDesc = MMR3HeapAPrintf(pVM, MM_TAG_PDM_DEVICE_USER, "APIC Timer #%u", i);
2524 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, apicR3TimerCallback, pApic,
2525 TMTIMER_FLAGS_NO_CRIT_SECT, pApic->pszDesc, &pApic->pTimerR3);
2526 if (RT_FAILURE(rc))
2527 return rc;
2528 pApic->pTimerR0 = TMTimerR0Ptr(pApic->pTimerR3);
2529 pApic->pTimerRC = TMTimerRCPtr(pApic->pTimerR3);
2530 TMR3TimerSetCritSect(pApic->pTimerR3, pDev->pCritSectR3);
2531 }
2532
2533 /*
2534 * Saved state.
2535 */
2536 rc = PDMDevHlpSSMRegister3(pDevIns, APIC_SAVED_STATE_VERSION, sizeof(*pDev),
2537 apicR3LiveExec, apicR3SaveExec, apicR3LoadExec);
2538 if (RT_FAILURE(rc))
2539 return rc;
2540
2541 /*
2542 * Register debugger info callback.
2543 */
2544 PDMDevHlpDBGFInfoRegister(pDevIns, "apic", "Display Local APIC state for current CPU. "
2545 "Recognizes 'basic', 'lvt', 'timer' as arguments, defaulting to 'basic'.", apicR3Info);
2546
2547#ifdef VBOX_WITH_STATISTICS
2548 /*
2549 * Statistics.
2550 */
2551 PDMDevHlpSTAMRegister(pDevIns, &pDev->StatMMIOReadGC, STAMTYPE_COUNTER, "/Devices/APIC/MMIOReadGC", STAMUNIT_OCCURENCES, "Number of APIC MMIO reads in GC.");
2552 PDMDevHlpSTAMRegister(pDevIns, &pDev->StatMMIOReadHC, STAMTYPE_COUNTER, "/Devices/APIC/MMIOReadHC", STAMUNIT_OCCURENCES, "Number of APIC MMIO reads in HC.");
2553 PDMDevHlpSTAMRegister(pDevIns, &pDev->StatMMIOWriteGC, STAMTYPE_COUNTER, "/Devices/APIC/MMIOWriteGC", STAMUNIT_OCCURENCES, "Number of APIC MMIO writes in GC.");
2554 PDMDevHlpSTAMRegister(pDevIns, &pDev->StatMMIOWriteHC, STAMTYPE_COUNTER, "/Devices/APIC/MMIOWriteHC", STAMUNIT_OCCURENCES, "Number of APIC MMIO writes in HC.");
2555 PDMDevHlpSTAMRegister(pDevIns, &pDev->StatClearedActiveIrq,STAMTYPE_COUNTER, "/Devices/APIC/MaskedActiveIRQ", STAMUNIT_OCCURENCES, "Number of cleared irqs.");
2556 for (i = 0; i < cCpus; i++)
2557 {
2558 APICState *pApic = &pDev->paLapicsR3[i];
2559 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetInitialCount, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Calls to apicTimerSetInitialCount.", "/Devices/APIC/%u/TimerSetInitialCount", i);
2560 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetInitialCountArm, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerSetRelative calls.", "/Devices/APIC/%u/TimerSetInitialCount/Arm", i);
2561 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetInitialCountDisarm, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerStop calls.", "/Devices/APIC/%u/TimerSetInitialCount/Disasm", i);
2562 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvt, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Calls to apicTimerSetLvt.", "/Devices/APIC/%u/TimerSetLvt", i);
2563 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtClearPeriodic, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Clearing APIC_LVT_TIMER_PERIODIC.", "/Devices/APIC/%u/TimerSetLvt/ClearPeriodic", i);
2564 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtPostponed, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerStop postponed.", "/Devices/APIC/%u/TimerSetLvt/Postponed", i);
2565 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtArmed, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerSet avoided.", "/Devices/APIC/%u/TimerSetLvt/Armed", i);
2566 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtArm, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerSet necessary.", "/Devices/APIC/%u/TimerSetLvt/Arm", i);
2567 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtArmRetries, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerSet retries.", "/Devices/APIC/%u/TimerSetLvt/ArmRetries", i);
2568 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtNoRelevantChange,STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "No relevant flags changed.", "/Devices/APIC/%u/TimerSetLvt/NoRelevantChange", i);
2569 }
2570#endif
2571
2572 return VINF_SUCCESS;
2573}
2574
2575
2576/**
2577 * APIC device registration structure.
2578 */
2579const PDMDEVREG g_DeviceAPIC =
2580{
2581 /* u32Version */
2582 PDM_DEVREG_VERSION,
2583 /* szName */
2584 "apic",
2585 /* szRCMod */
2586 "VBoxDD2RC.rc",
2587 /* szR0Mod */
2588 "VBoxDD2R0.r0",
2589 /* pszDescription */
2590 "Advanced Programmable Interrupt Controller (APIC) Device",
2591 /* fFlags */
2592 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,
2593 /* fClass */
2594 PDM_DEVREG_CLASS_PIC,
2595 /* cMaxInstances */
2596 1,
2597 /* cbInstance */
2598 sizeof(APICState),
2599 /* pfnConstruct */
2600 apicR3Construct,
2601 /* pfnDestruct */
2602 NULL,
2603 /* pfnRelocate */
2604 apicR3Relocate,
2605 /* pfnMemSetup */
2606 NULL,
2607 /* pfnPowerOn */
2608 NULL,
2609 /* pfnReset */
2610 apicR3Reset,
2611 /* pfnSuspend */
2612 NULL,
2613 /* pfnResume */
2614 NULL,
2615 /* pfnAttach */
2616 NULL,
2617 /* pfnDetach */
2618 NULL,
2619 /* pfnQueryInterface. */
2620 NULL,
2621 /* pfnInitComplete */
2622 NULL,
2623 /* pfnPowerOff */
2624 NULL,
2625 /* pfnSoftReset */
2626 NULL,
2627 /* u32VersionEnd */
2628 PDM_DEVREG_VERSION
2629};
2630
2631#endif /* IN_RING3 */
2632#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
2633
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette