VirtualBox

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

Last change on this file since 57064 was 56832, checked in by vboxsync, 9 years ago

DevAPIC: LogRel consistency.

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