VirtualBox

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

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

VMM: Facility for getting the highest-priority pending interrupt from the APIC device.

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