VirtualBox

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

Last change on this file since 63942 was 62509, checked in by vboxsync, 8 years ago

(C) 2016

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 95.3 KB
Line 
1/* $Id: DevAPIC.cpp 62509 2016-07-22 19:12:22Z 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-2016 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 * "Mode" is ignored (used by newer APIC code).
2362 */
2363 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "IOAPIC|RZEnabled|NumCPUs|Mode", "");
2364
2365 bool fIoApic;
2366 int rc = CFGMR3QueryBoolDef(pCfg, "IOAPIC", &fIoApic, true);
2367 if (RT_FAILURE(rc))
2368 return PDMDEV_SET_ERROR(pDevIns, rc,
2369 N_("Configuration error: Failed to read \"IOAPIC\""));
2370
2371 bool fRZEnabled;
2372 rc = CFGMR3QueryBoolDef(pCfg, "RZEnabled", &fRZEnabled, true);
2373 if (RT_FAILURE(rc))
2374 return PDMDEV_SET_ERROR(pDevIns, rc,
2375 N_("Configuration error: Failed to query boolean value \"RZEnabled\""));
2376
2377 uint32_t cCpus;
2378 rc = CFGMR3QueryU32Def(pCfg, "NumCPUs", &cCpus, 1);
2379 if (RT_FAILURE(rc))
2380 return PDMDEV_SET_ERROR(pDevIns, rc,
2381 N_("Configuration error: Failed to query integer value \"NumCPUs\""));
2382
2383 Log(("APIC: cCpus=%d fRZEnabled=%RTbool fIoApic=%RTbool\n", cCpus, fRZEnabled, fIoApic));
2384 if (cCpus > 255)
2385 return PDMDEV_SET_ERROR(pDevIns, rc,
2386 N_("Configuration error: Invalid value for \"NumCPUs\""));
2387
2388 /*
2389 * Init the data.
2390 */
2391 pDev->pDevInsR3 = pDevIns;
2392 pDev->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
2393 pDev->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2394 pDev->cCpus = cCpus;
2395 pDev->fIoApic = fIoApic;
2396 /** @todo Finish X2APIC implementation. Must, among other things, set
2397 * PDMAPICMODE_X2APIC here when X2APIC is configured. */
2398 pDev->enmMode = PDMAPICMODE_APIC;
2399
2400 /* Disable locking in this device. */
2401 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
2402 AssertRCReturn(rc, rc);
2403
2404 PVM pVM = PDMDevHlpGetVM(pDevIns);
2405
2406 /*
2407 * We are not freeing this memory, as it's automatically released when guest exits.
2408 */
2409 rc = MMHyperAlloc(pVM, cCpus * sizeof(APICState), 1, MM_TAG_PDM_DEVICE_USER, (void **)&pDev->paLapicsR3);
2410 if (RT_FAILURE(rc))
2411 return VERR_NO_MEMORY;
2412 pDev->paLapicsR0 = MMHyperR3ToR0(pVM, pDev->paLapicsR3);
2413 pDev->paLapicsRC = MMHyperR3ToRC(pVM, pDev->paLapicsR3);
2414
2415 for (i = 0; i < cCpus; i++)
2416 apicR3StateInit(&pDev->paLapicsR3[i], i);
2417
2418 /*
2419 * Register the APIC.
2420 */
2421 PDMAPICREG ApicReg;
2422 ApicReg.u32Version = PDM_APICREG_VERSION;
2423 ApicReg.pfnGetInterruptR3 = apicGetInterrupt;
2424 ApicReg.pfnSetBaseMsrR3 = apicSetBase;
2425 ApicReg.pfnGetBaseMsrR3 = apicGetBase;
2426 ApicReg.pfnSetTprR3 = apicSetTPR;
2427 ApicReg.pfnGetTprR3 = apicGetTPR;
2428 ApicReg.pfnWriteMsrR3 = apicWriteMSR;
2429 ApicReg.pfnReadMsrR3 = apicReadMSR;
2430 ApicReg.pfnBusDeliverR3 = apicBusDeliverCallback;
2431 ApicReg.pfnLocalInterruptR3 = apicLocalInterrupt;
2432 ApicReg.pfnGetTimerFreqR3 = apicGetTimerFreq;
2433 if (fRZEnabled)
2434 {
2435 ApicReg.pszGetInterruptRC = "apicGetInterrupt";
2436 ApicReg.pszSetBaseMsrRC = "apicSetBase";
2437 ApicReg.pszGetBaseMsrRC = "apicGetBase";
2438 ApicReg.pszSetTprRC = "apicSetTPR";
2439 ApicReg.pszGetTprRC = "apicGetTPR";
2440 ApicReg.pszWriteMsrRC = "apicWriteMSR";
2441 ApicReg.pszReadMsrRC = "apicReadMSR";
2442 ApicReg.pszBusDeliverRC = "apicBusDeliverCallback";
2443 ApicReg.pszLocalInterruptRC = "apicLocalInterrupt";
2444 ApicReg.pszGetTimerFreqRC = "apicGetTimerFreq";
2445
2446 ApicReg.pszGetInterruptR0 = "apicGetInterrupt";
2447 ApicReg.pszSetBaseMsrR0 = "apicSetBase";
2448 ApicReg.pszGetBaseMsrR0 = "apicGetBase";
2449 ApicReg.pszSetTprR0 = "apicSetTPR";
2450 ApicReg.pszGetTprR0 = "apicGetTPR";
2451 ApicReg.pszWriteMsrR0 = "apicWriteMSR";
2452 ApicReg.pszReadMsrR0 = "apicReadMSR";
2453 ApicReg.pszBusDeliverR0 = "apicBusDeliverCallback";
2454 ApicReg.pszLocalInterruptR0 = "apicLocalInterrupt";
2455 ApicReg.pszGetTimerFreqR0 = "apicGetTimerFreq";
2456 }
2457 else
2458 {
2459 ApicReg.pszGetInterruptRC = NULL;
2460 ApicReg.pszSetBaseMsrRC = NULL;
2461 ApicReg.pszGetBaseMsrRC = NULL;
2462 ApicReg.pszSetTprRC = NULL;
2463 ApicReg.pszGetTprRC = NULL;
2464 ApicReg.pszWriteMsrRC = NULL;
2465 ApicReg.pszReadMsrRC = NULL;
2466 ApicReg.pszBusDeliverRC = NULL;
2467 ApicReg.pszLocalInterruptRC = NULL;
2468 ApicReg.pszGetTimerFreqRC = NULL;
2469
2470 ApicReg.pszGetInterruptR0 = NULL;
2471 ApicReg.pszSetBaseMsrR0 = NULL;
2472 ApicReg.pszGetBaseMsrR0 = NULL;
2473 ApicReg.pszSetTprR0 = NULL;
2474 ApicReg.pszGetTprR0 = NULL;
2475 ApicReg.pszWriteMsrR0 = NULL;
2476 ApicReg.pszReadMsrR0 = NULL;
2477 ApicReg.pszBusDeliverR0 = NULL;
2478 ApicReg.pszLocalInterruptR0 = NULL;
2479 ApicReg.pszGetTimerFreqR0 = NULL;
2480 }
2481
2482 rc = PDMDevHlpAPICRegister(pDevIns, &ApicReg, &pDev->pApicHlpR3);
2483 AssertLogRelRCReturn(rc, rc);
2484 pDev->pCritSectR3 = pDev->pApicHlpR3->pfnGetR3CritSect(pDevIns);
2485
2486 /*
2487 * The global CPUID feature bit(s).
2488 */
2489 LogRel(("APIC: Activating Local APIC\n"));
2490 pDev->pApicHlpR3->pfnSetFeatureLevel(pDevIns, pDev->enmMode);
2491
2492 /*
2493 * Register the MMIO range.
2494 */
2495 /** @todo shall reregister, if base changes. */
2496 uint32_t ApicBase = pDev->paLapicsR3[0].apicbase & ~0xfff;
2497 rc = PDMDevHlpMMIORegister(pDevIns, ApicBase, 0x1000, pDev,
2498 IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_DWORD_ZEROED,
2499 apicMMIOWrite, apicMMIORead, "APIC Memory");
2500 if (RT_FAILURE(rc))
2501 return rc;
2502
2503 if (fRZEnabled)
2504 {
2505 pDev->pApicHlpRC = pDev->pApicHlpR3->pfnGetRCHelpers(pDevIns);
2506 pDev->pCritSectRC = pDev->pApicHlpR3->pfnGetRCCritSect(pDevIns);
2507 rc = PDMDevHlpMMIORegisterRC(pDevIns, ApicBase, 0x1000, NIL_RTRCPTR /*pvUser*/, "apicMMIOWrite", "apicMMIORead");
2508 if (RT_FAILURE(rc))
2509 return rc;
2510
2511 pDev->pApicHlpR0 = pDev->pApicHlpR3->pfnGetR0Helpers(pDevIns);
2512 pDev->pCritSectR0 = pDev->pApicHlpR3->pfnGetR0CritSect(pDevIns);
2513 rc = PDMDevHlpMMIORegisterR0(pDevIns, ApicBase, 0x1000, NIL_RTR0PTR /*pvUser*/, "apicMMIOWrite", "apicMMIORead");
2514 if (RT_FAILURE(rc))
2515 return rc;
2516 }
2517
2518 /*
2519 * Create the APIC timers.
2520 */
2521 for (i = 0; i < cCpus; i++)
2522 {
2523 APICState *pApic = &pDev->paLapicsR3[i];
2524 pApic->pszDesc = MMR3HeapAPrintf(pVM, MM_TAG_PDM_DEVICE_USER, "APIC Timer #%u", i);
2525 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, apicR3TimerCallback, pApic,
2526 TMTIMER_FLAGS_NO_CRIT_SECT, pApic->pszDesc, &pApic->pTimerR3);
2527 if (RT_FAILURE(rc))
2528 return rc;
2529 pApic->pTimerR0 = TMTimerR0Ptr(pApic->pTimerR3);
2530 pApic->pTimerRC = TMTimerRCPtr(pApic->pTimerR3);
2531 TMR3TimerSetCritSect(pApic->pTimerR3, pDev->pCritSectR3);
2532 }
2533
2534 /*
2535 * Saved state.
2536 */
2537 rc = PDMDevHlpSSMRegister3(pDevIns, APIC_SAVED_STATE_VERSION, sizeof(*pDev),
2538 apicR3LiveExec, apicR3SaveExec, apicR3LoadExec);
2539 if (RT_FAILURE(rc))
2540 return rc;
2541
2542 /*
2543 * Register debugger info callback.
2544 */
2545 PDMDevHlpDBGFInfoRegister(pDevIns, "apic", "Display Local APIC state for current CPU. "
2546 "Recognizes 'basic', 'lvt', 'timer' as arguments, defaulting to 'basic'.", apicR3Info);
2547
2548#ifdef VBOX_WITH_STATISTICS
2549 /*
2550 * Statistics.
2551 */
2552 PDMDevHlpSTAMRegister(pDevIns, &pDev->StatMMIOReadGC, STAMTYPE_COUNTER, "/Devices/APIC/MMIOReadGC", STAMUNIT_OCCURENCES, "Number of APIC MMIO reads in GC.");
2553 PDMDevHlpSTAMRegister(pDevIns, &pDev->StatMMIOReadHC, STAMTYPE_COUNTER, "/Devices/APIC/MMIOReadHC", STAMUNIT_OCCURENCES, "Number of APIC MMIO reads in HC.");
2554 PDMDevHlpSTAMRegister(pDevIns, &pDev->StatMMIOWriteGC, STAMTYPE_COUNTER, "/Devices/APIC/MMIOWriteGC", STAMUNIT_OCCURENCES, "Number of APIC MMIO writes in GC.");
2555 PDMDevHlpSTAMRegister(pDevIns, &pDev->StatMMIOWriteHC, STAMTYPE_COUNTER, "/Devices/APIC/MMIOWriteHC", STAMUNIT_OCCURENCES, "Number of APIC MMIO writes in HC.");
2556 PDMDevHlpSTAMRegister(pDevIns, &pDev->StatClearedActiveIrq,STAMTYPE_COUNTER, "/Devices/APIC/MaskedActiveIRQ", STAMUNIT_OCCURENCES, "Number of cleared irqs.");
2557 for (i = 0; i < cCpus; i++)
2558 {
2559 APICState *pApic = &pDev->paLapicsR3[i];
2560 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetInitialCount, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Calls to apicTimerSetInitialCount.", "/Devices/APIC/%u/TimerSetInitialCount", i);
2561 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetInitialCountArm, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerSetRelative calls.", "/Devices/APIC/%u/TimerSetInitialCount/Arm", i);
2562 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetInitialCountDisarm, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerStop calls.", "/Devices/APIC/%u/TimerSetInitialCount/Disasm", i);
2563 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvt, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Calls to apicTimerSetLvt.", "/Devices/APIC/%u/TimerSetLvt", i);
2564 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtClearPeriodic, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Clearing APIC_LVT_TIMER_PERIODIC.", "/Devices/APIC/%u/TimerSetLvt/ClearPeriodic", i);
2565 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtPostponed, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerStop postponed.", "/Devices/APIC/%u/TimerSetLvt/Postponed", i);
2566 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtArmed, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerSet avoided.", "/Devices/APIC/%u/TimerSetLvt/Armed", i);
2567 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtArm, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerSet necessary.", "/Devices/APIC/%u/TimerSetLvt/Arm", i);
2568 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtArmRetries, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerSet retries.", "/Devices/APIC/%u/TimerSetLvt/ArmRetries", i);
2569 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtNoRelevantChange,STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "No relevant flags changed.", "/Devices/APIC/%u/TimerSetLvt/NoRelevantChange", i);
2570 }
2571#endif
2572
2573 return VINF_SUCCESS;
2574}
2575
2576
2577/**
2578 * APIC device registration structure.
2579 */
2580const PDMDEVREG g_DeviceAPIC =
2581{
2582 /* u32Version */
2583 PDM_DEVREG_VERSION,
2584 /* szName */
2585 "apic",
2586 /* szRCMod */
2587 "VBoxDD2RC.rc",
2588 /* szR0Mod */
2589 "VBoxDD2R0.r0",
2590 /* pszDescription */
2591 "Advanced Programmable Interrupt Controller (APIC) Device",
2592 /* fFlags */
2593 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,
2594 /* fClass */
2595 PDM_DEVREG_CLASS_PIC,
2596 /* cMaxInstances */
2597 1,
2598 /* cbInstance */
2599 sizeof(APICState),
2600 /* pfnConstruct */
2601 apicR3Construct,
2602 /* pfnDestruct */
2603 NULL,
2604 /* pfnRelocate */
2605 apicR3Relocate,
2606 /* pfnMemSetup */
2607 NULL,
2608 /* pfnPowerOn */
2609 NULL,
2610 /* pfnReset */
2611 apicR3Reset,
2612 /* pfnSuspend */
2613 NULL,
2614 /* pfnResume */
2615 NULL,
2616 /* pfnAttach */
2617 NULL,
2618 /* pfnDetach */
2619 NULL,
2620 /* pfnQueryInterface. */
2621 NULL,
2622 /* pfnInitComplete */
2623 NULL,
2624 /* pfnPowerOff */
2625 NULL,
2626 /* pfnSoftReset */
2627 NULL,
2628 /* u32VersionEnd */
2629 PDM_DEVREG_VERSION
2630};
2631
2632#endif /* IN_RING3 */
2633#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
2634
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