VirtualBox

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

Last change on this file since 44509 was 44509, checked in by vboxsync, 12 years ago

Document PIC and APIC callback method locking rules.

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