VirtualBox

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

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

DevAPIC.cpp: Some cleanups.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 89.9 KB
Line 
1/* $Id: DevAPIC.cpp 44515 2013-02-01 14:52:32Z 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)
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 return true;
1242}
1243
1244static void apic_update_tpr(APICDeviceInfo *pDev, APICState *pApic, uint32_t val)
1245{
1246 bool fIrqIsActive = false;
1247 bool fIrqWasActive = false;
1248
1249 fIrqWasActive = apic_update_irq(pDev, pApic);
1250 pApic->tpr = val;
1251 fIrqIsActive = apic_update_irq(pDev, pApic);
1252
1253 /* If an interrupt is pending and now masked, then clear the FF flag. */
1254 if (fIrqWasActive && !fIrqIsActive)
1255 {
1256 Log(("apic_update_tpr: deactivate interrupt that was masked by the TPR update (%x)\n", val));
1257 STAM_COUNTER_INC(&pDev->StatClearedActiveIrq);
1258 apicCpuClearInterrupt(pDev, pApic);
1259 }
1260}
1261
1262static void apic_set_irq(APICDeviceInfo *pDev, APICState *pApic, int vector_num, int trigger_mode, uint32_t uTagSrc)
1263{
1264 LogFlow(("CPU%d: apic_set_irq vector=%x trigger_mode=%x uTagSrc=%#x\n", pApic->phys_id, vector_num, trigger_mode, uTagSrc));
1265
1266 Apic256BitReg_SetBit(&pApic->irr, vector_num);
1267 if (trigger_mode)
1268 Apic256BitReg_SetBit(&pApic->tmr, vector_num);
1269 else
1270 Apic256BitReg_ClearBit(&pApic->tmr, vector_num);
1271
1272 if (!pApic->auTags[vector_num])
1273 pApic->auTags[vector_num] = uTagSrc;
1274 else
1275 pApic->auTags[vector_num] |= RT_BIT_32(31);
1276
1277 apic_update_irq(pDev, pApic);
1278}
1279
1280static void apic_eoi(APICDeviceInfo *pDev, APICState *pApic)
1281{
1282 int isrv = Apic256BitReg_FindLastSetBit(&pApic->isr, -1);
1283 if (isrv < 0)
1284 return;
1285 Apic256BitReg_ClearBit(&pApic->isr, isrv);
1286 LogFlow(("CPU%d: apic_eoi isrv=%x\n", pApic->phys_id, isrv));
1287 /** @todo XXX: send the EOI packet to the APIC bus to allow the I/O APIC to
1288 * set the remote IRR bit for level triggered interrupts. */
1289 apic_update_irq(pDev, pApic);
1290}
1291
1292static PVMCPUSET apic_get_delivery_bitmask(APICDeviceInfo *pDev, uint8_t dest, uint8_t dest_mode, PVMCPUSET pDstSet)
1293{
1294 VMCPUSET_EMPTY(pDstSet);
1295
1296 if (dest_mode == 0)
1297 {
1298 if (dest == 0xff) /* The broadcast ID. */
1299 VMCPUSET_FILL(pDstSet);
1300 else
1301 VMCPUSET_ADD(pDstSet, dest);
1302 }
1303 else
1304 {
1305 /** @todo XXX: cluster mode */
1306 APIC_FOREACH_BEGIN(pDev);
1307 if (pCurApic->dest_mode == APIC_DESTMODE_FLAT)
1308 {
1309 if (dest & pCurApic->log_dest)
1310 VMCPUSET_ADD(pDstSet, iCurApic);
1311 }
1312 else if (pCurApic->dest_mode == APIC_DESTMODE_CLUSTER)
1313 {
1314 if ( (dest & 0xf0) == (pCurApic->log_dest & 0xf0)
1315 && (dest & pCurApic->log_dest & 0x0f))
1316 VMCPUSET_ADD(pDstSet, iCurApic);
1317 }
1318 APIC_FOREACH_END();
1319 }
1320
1321 return pDstSet;
1322}
1323
1324#ifdef IN_RING3
1325
1326static void apicR3InitIpi(APICDeviceInfo *pDev, APICState *pApic)
1327{
1328 int i;
1329
1330 for(i = 0; i < APIC_LVT_NB; i++)
1331 pApic->lvt[i] = 1 << 16; /* mask LVT */
1332 pApic->tpr = 0;
1333 pApic->spurious_vec = 0xff;
1334 pApic->log_dest = 0;
1335 pApic->dest_mode = 0xff; /** @todo 0xff???? */
1336 Apic256BitReg_Empty(&pApic->isr);
1337 Apic256BitReg_Empty(&pApic->tmr);
1338 Apic256BitReg_Empty(&pApic->irr);
1339 pApic->esr = 0;
1340 memset(pApic->icr, 0, sizeof(pApic->icr));
1341 pApic->divide_conf = 0;
1342 pApic->count_shift = 1;
1343 pApic->initial_count = 0;
1344 pApic->initial_count_load_time = 0;
1345 pApic->next_time = 0;
1346}
1347
1348
1349static void apicSendInitIpi(APICDeviceInfo *pDev, APICState *pApic)
1350{
1351 apicR3InitIpi(pDev, pApic);
1352 apicR3CpuSendInitIpi(pDev, pApic);
1353}
1354
1355/* send a SIPI message to the CPU to start it */
1356static void apicR3Startup(APICDeviceInfo *pDev, APICState *pApic, int vector_num)
1357{
1358 Log(("[SMP] apicR3Startup: %d on CPUs %d\n", vector_num, pApic->phys_id));
1359 apicR3CpuSendSipi(pDev, pApic, vector_num);
1360}
1361
1362#endif /* IN_RING3 */
1363
1364static int apic_deliver(APICDeviceInfo *pDev, APICState *pApic,
1365 uint8_t dest, uint8_t dest_mode,
1366 uint8_t delivery_mode, uint8_t vector_num,
1367 uint8_t polarity, uint8_t trigger_mode)
1368{
1369 int dest_shorthand = (pApic->icr[0] >> 18) & 3;
1370 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));
1371
1372 VMCPUSET DstSet;
1373 switch (dest_shorthand)
1374 {
1375 case 0:
1376 apic_get_delivery_bitmask(pDev, dest, dest_mode, &DstSet);
1377 break;
1378 case 1:
1379 VMCPUSET_EMPTY(&DstSet);
1380 VMCPUSET_ADD(&DstSet, pApic->id);
1381 break;
1382 case 2:
1383 VMCPUSET_FILL(&DstSet);
1384 break;
1385 case 3:
1386 VMCPUSET_FILL(&DstSet);
1387 VMCPUSET_DEL(&DstSet, pApic->id);
1388 break;
1389 }
1390
1391 switch (delivery_mode)
1392 {
1393 case APIC_DM_INIT:
1394 {
1395 uint32_t const trig_mode = (pApic->icr[0] >> 15) & 1;
1396 uint32_t const level = (pApic->icr[0] >> 14) & 1;
1397 if (level == 0 && trig_mode == 1)
1398 {
1399 APIC_FOREACH_IN_SET_BEGIN(pDev, &DstSet);
1400 pCurApic->arb_id = pCurApic->id;
1401 APIC_FOREACH_END();
1402 Log(("CPU%d: APIC_DM_INIT arbitration id(s) set\n", pApic->phys_id));
1403 return VINF_SUCCESS;
1404 }
1405 break;
1406 }
1407
1408 case APIC_DM_SIPI:
1409# ifdef IN_RING3
1410 APIC_FOREACH_IN_SET_BEGIN(pDev, &DstSet);
1411 apicR3Startup(pDev, pCurApic, vector_num);
1412 APIC_FOREACH_END();
1413 return VINF_SUCCESS;
1414# else
1415 /* We shall send SIPI only in R3, R0 calls should be
1416 rescheduled to R3 */
1417 return VINF_IOM_R3_MMIO_WRITE;
1418# endif
1419 }
1420
1421 return apic_bus_deliver(pDev, &DstSet, delivery_mode, vector_num,
1422 polarity, trigger_mode,
1423 pDev->CTX_SUFF(pApicHlp)->pfnCalcIrqTag(pDev->CTX_SUFF(pDevIns), PDM_IRQ_LEVEL_HIGH));
1424}
1425
1426
1427PDMBOTHCBDECL(int) apicGetInterrupt(PPDMDEVINS pDevIns, VMCPUID idCpu, uint32_t *puTagSrc)
1428{
1429 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
1430 /* if the APIC is not installed or enabled, we let the 8259 handle the IRQs */
1431 if (!pDev)
1432 {
1433 Log(("apic_get_interrupt: returns -1 (!pDev)\n"));
1434 return -1;
1435 }
1436
1437 Assert(PDMCritSectIsOwner(pDev->CTX_SUFF(pCritSect)));
1438
1439 APICState *pApic = apicGetStateById(pDev, idCpu);
1440
1441 if (!(pApic->spurious_vec & APIC_SV_ENABLE))
1442 {
1443 Log(("CPU%d: apic_get_interrupt: returns -1 (APIC_SV_ENABLE)\n", pApic->phys_id));
1444 return -1;
1445 }
1446
1447 /** @todo XXX: spurious IRQ handling */
1448 int intno = Apic256BitReg_FindLastSetBit(&pApic->irr, -1);
1449 if (intno < 0)
1450 {
1451 Log(("CPU%d: apic_get_interrupt: returns -1 (irr)\n", pApic->phys_id));
1452 return -1;
1453 }
1454
1455 if (pApic->tpr && (uint32_t)intno <= pApic->tpr)
1456 {
1457 *puTagSrc = 0;
1458 Log(("apic_get_interrupt: returns %d (sp)\n", pApic->spurious_vec & 0xff));
1459 return pApic->spurious_vec & 0xff;
1460 }
1461
1462 Apic256BitReg_ClearBit(&pApic->irr, intno);
1463 Apic256BitReg_SetBit(&pApic->isr, intno);
1464
1465 *puTagSrc = pApic->auTags[intno];
1466 pApic->auTags[intno] = 0;
1467
1468 apic_update_irq(pDev, pApic);
1469
1470 LogFlow(("CPU%d: apic_get_interrupt: returns %d / %#x\n", pApic->phys_id, intno, *puTagSrc));
1471 return intno;
1472}
1473
1474/**
1475 * @remarks Caller (apicReadRegister) takes both the TM and APIC locks before
1476 * calling this function.
1477 */
1478static uint32_t apic_get_current_count(APICDeviceInfo const *pDev, APICState const *pApic)
1479{
1480 int64_t d = (TMTimerGet(pApic->CTX_SUFF(pTimer)) - pApic->initial_count_load_time)
1481 >> pApic->count_shift;
1482
1483 uint32_t val;
1484 if (pApic->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC)
1485 /* periodic */
1486 val = pApic->initial_count - (d % ((uint64_t)pApic->initial_count + 1));
1487 else if (d >= pApic->initial_count)
1488 val = 0;
1489 else
1490 val = pApic->initial_count - d;
1491
1492 return val;
1493}
1494
1495/**
1496 * Does the frequency hinting and logging.
1497 *
1498 * @param pApic The device state.
1499 */
1500DECLINLINE(void) apicDoFrequencyHinting(APICState *pApic)
1501{
1502 if ( pApic->uHintedInitialCount != pApic->initial_count
1503 || pApic->uHintedCountShift != (uint32_t)pApic->count_shift)
1504 {
1505 pApic->uHintedInitialCount = pApic->initial_count;
1506 pApic->uHintedCountShift = pApic->count_shift;
1507
1508 uint32_t uHz;
1509 if (pApic->initial_count > 0)
1510 {
1511 Assert((unsigned)pApic->count_shift < 30);
1512 uint64_t cTickPerPeriod = ((uint64_t)pApic->initial_count + 1) << pApic->count_shift;
1513 uHz = TMTimerGetFreq(pApic->CTX_SUFF(pTimer)) / cTickPerPeriod;
1514 }
1515 else
1516 uHz = 0;
1517 TMTimerSetFrequencyHint(pApic->CTX_SUFF(pTimer), uHz);
1518 Log(("apic: %u Hz\n", uHz));
1519 }
1520}
1521
1522/**
1523 * Implementation of the 0380h access: Timer reset + new initial count.
1524 *
1525 * @param pDev The device state.
1526 * @param pApic The APIC sub-device state.
1527 * @param u32NewInitialCount The new initial count for the timer.
1528 */
1529static void apicTimerSetInitialCount(APICDeviceInfo *pDev, APICState *pApic, uint32_t u32NewInitialCount)
1530{
1531 STAM_COUNTER_INC(&pApic->StatTimerSetInitialCount);
1532 pApic->initial_count = u32NewInitialCount;
1533
1534 /*
1535 * Don't (re-)arm the timer if the it's masked or if it's
1536 * a zero length one-shot timer.
1537 */
1538 if ( !(pApic->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)
1539 && u32NewInitialCount > 0)
1540 {
1541 /*
1542 * Calculate the relative next time and perform a combined timer get/set
1543 * operation. This avoids racing the clock between get and set.
1544 */
1545 uint64_t cTicksNext = u32NewInitialCount;
1546 cTicksNext += 1;
1547 cTicksNext <<= pApic->count_shift;
1548 TMTimerSetRelative(pApic->CTX_SUFF(pTimer), cTicksNext, &pApic->initial_count_load_time);
1549 pApic->next_time = pApic->initial_count_load_time + cTicksNext;
1550 pApic->fTimerArmed = true;
1551 apicDoFrequencyHinting(pApic);
1552 STAM_COUNTER_INC(&pApic->StatTimerSetInitialCountArm);
1553 Log(("apicTimerSetInitialCount: cTicksNext=%'llu (%#llx) ic=%#x sh=%#x nxt=%#llx\n",
1554 cTicksNext, cTicksNext, u32NewInitialCount, pApic->count_shift, pApic->next_time));
1555 }
1556 else
1557 {
1558 /* Stop it if necessary and record the load time for unmasking. */
1559 if (pApic->fTimerArmed)
1560 {
1561 STAM_COUNTER_INC(&pApic->StatTimerSetInitialCountDisarm);
1562 TMTimerStop(pApic->CTX_SUFF(pTimer));
1563 pApic->fTimerArmed = false;
1564 pApic->uHintedCountShift = pApic->uHintedInitialCount = 0;
1565 }
1566 pApic->initial_count_load_time = TMTimerGet(pApic->CTX_SUFF(pTimer));
1567 Log(("apicTimerSetInitialCount: ic=%#x sh=%#x iclt=%#llx\n", u32NewInitialCount, pApic->count_shift, pApic->initial_count_load_time));
1568 }
1569}
1570
1571/**
1572 * Implementation of the 0320h access: change the LVT flags.
1573 *
1574 * @param pDev The device state.
1575 * @param pApic The APIC sub-device state to operate on.
1576 * @param fNew The new flags.
1577 */
1578static void apicTimerSetLvt(APICDeviceInfo *pDev, APICState *pApic, uint32_t fNew)
1579{
1580 STAM_COUNTER_INC(&pApic->StatTimerSetLvt);
1581
1582 /*
1583 * Make the flag change, saving the old ones so we can avoid
1584 * unnecessary work.
1585 */
1586 uint32_t const fOld = pApic->lvt[APIC_LVT_TIMER];
1587 pApic->lvt[APIC_LVT_TIMER] = fNew;
1588
1589 /* Only the masked and peridic bits are relevant (see apic_timer_update). */
1590 if ( (fOld & (APIC_LVT_MASKED | APIC_LVT_TIMER_PERIODIC))
1591 != (fNew & (APIC_LVT_MASKED | APIC_LVT_TIMER_PERIODIC)))
1592 {
1593 /*
1594 * If changed to one-shot from periodic, stop the timer if we're not
1595 * in the first period.
1596 */
1597 /** @todo check how clearing the periodic flag really should behave when not
1598 * in period 1. The current code just mirrors the behavior of the
1599 * original implementation. */
1600 if ( (fOld & APIC_LVT_TIMER_PERIODIC)
1601 && !(fNew & APIC_LVT_TIMER_PERIODIC))
1602 {
1603 STAM_COUNTER_INC(&pApic->StatTimerSetLvtClearPeriodic);
1604 uint64_t cTicks = (pApic->next_time - pApic->initial_count_load_time) >> pApic->count_shift;
1605 if (cTicks >= pApic->initial_count)
1606 {
1607 /* not first period, stop it. */
1608 TMTimerStop(pApic->CTX_SUFF(pTimer));
1609 pApic->fTimerArmed = false;
1610 pApic->uHintedCountShift = pApic->uHintedInitialCount = 0;
1611 }
1612 /* else: first period, let it fire normally. */
1613 }
1614
1615 /*
1616 * We postpone stopping the timer when it's masked, this way we can
1617 * avoid some timer work when the guest temporarily masks the timer.
1618 * (apicR3TimerCallback will stop it if still masked.)
1619 */
1620 if (fNew & APIC_LVT_MASKED)
1621 STAM_COUNTER_INC(&pApic->StatTimerSetLvtPostponed);
1622 else if (pApic->fTimerArmed)
1623 STAM_COUNTER_INC(&pApic->StatTimerSetLvtArmed);
1624 /*
1625 * If unmasked, not armed and with a valid initial count value (according
1626 * to our interpretation of the spec), we will have to rearm the timer so
1627 * it will fire at the end of the current period.
1628 *
1629 * N.B. This is code is currently RACING the virtual sync clock!
1630 */
1631 else if ( (fOld & APIC_LVT_MASKED)
1632 && pApic->initial_count > 0)
1633 {
1634 STAM_COUNTER_INC(&pApic->StatTimerSetLvtArm);
1635 for (unsigned cTries = 0; ; cTries++)
1636 {
1637 uint64_t NextTS;
1638 uint64_t cTicks = (TMTimerGet(pApic->CTX_SUFF(pTimer)) - pApic->initial_count_load_time) >> pApic->count_shift;
1639 if (fNew & APIC_LVT_TIMER_PERIODIC)
1640 NextTS = ((cTicks / ((uint64_t)pApic->initial_count + 1)) + 1) * ((uint64_t)pApic->initial_count + 1);
1641 else
1642 {
1643 if (cTicks >= pApic->initial_count)
1644 break;
1645 NextTS = (uint64_t)pApic->initial_count + 1;
1646 }
1647 NextTS <<= pApic->count_shift;
1648 NextTS += pApic->initial_count_load_time;
1649
1650 /* Try avoid the assertion in TM.cpp... this isn't perfect! */
1651 if ( NextTS > TMTimerGet(pApic->CTX_SUFF(pTimer))
1652 || cTries > 10)
1653 {
1654 TMTimerSet(pApic->CTX_SUFF(pTimer), NextTS);
1655 pApic->next_time = NextTS;
1656 pApic->fTimerArmed = true;
1657 apicDoFrequencyHinting(pApic);
1658 Log(("apicTimerSetLvt: ic=%#x sh=%#x nxt=%#llx\n", pApic->initial_count, pApic->count_shift, pApic->next_time));
1659 break;
1660 }
1661 STAM_COUNTER_INC(&pApic->StatTimerSetLvtArmRetries);
1662 }
1663 }
1664 }
1665 else
1666 STAM_COUNTER_INC(&pApic->StatTimerSetLvtNoRelevantChange);
1667}
1668
1669# ifdef IN_RING3
1670
1671/**
1672 * Timer callback function.
1673 *
1674 * @param pDevIns The device state.
1675 * @param pTimer The timer handle.
1676 * @param pvUser User argument pointing to the APIC instance.
1677 */
1678static DECLCALLBACK(void) apicR3TimerCallback(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
1679{
1680 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
1681 APICState *pApic = (APICState *)pvUser;
1682 Assert(pApic->pTimerR3 == pTimer);
1683 Assert(pApic->fTimerArmed);
1684 Assert(PDMCritSectIsOwner(pDev->pCritSectR3));
1685 Assert(TMTimerIsLockOwner(pTimer));
1686
1687 if (!(pApic->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) {
1688 LogFlow(("apic_timer: trigger irq\n"));
1689 apic_set_irq(pDev, pApic, pApic->lvt[APIC_LVT_TIMER] & 0xff, APIC_TRIGGER_EDGE,
1690 pDev->CTX_SUFF(pApicHlp)->pfnCalcIrqTag(pDevIns, PDM_IRQ_LEVEL_HIGH));
1691
1692 if ( (pApic->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC)
1693 && pApic->initial_count > 0) {
1694 /* new interval. */
1695 pApic->next_time += (((uint64_t)pApic->initial_count + 1) << pApic->count_shift);
1696 TMTimerSet(pApic->CTX_SUFF(pTimer), pApic->next_time);
1697 pApic->fTimerArmed = true;
1698 apicDoFrequencyHinting(pApic);
1699 Log2(("apicR3TimerCallback: ic=%#x sh=%#x nxt=%#llx\n", pApic->initial_count, pApic->count_shift, pApic->next_time));
1700 } else {
1701 /* single shot or disabled. */
1702 pApic->fTimerArmed = false;
1703 pApic->uHintedCountShift = pApic->uHintedInitialCount = 0;
1704 }
1705 } else {
1706 /* masked, do not rearm. */
1707 pApic->fTimerArmed = false;
1708 pApic->uHintedCountShift = pApic->uHintedInitialCount = 0;
1709 }
1710}
1711
1712static void apic_save(SSMHANDLE* f, void *opaque)
1713{
1714 APICState *pApic = (APICState*)opaque;
1715 int i;
1716
1717 SSMR3PutU32(f, pApic->apicbase);
1718 SSMR3PutU32(f, pApic->id);
1719 SSMR3PutU32(f, pApic->phys_id);
1720 SSMR3PutU32(f, pApic->arb_id);
1721 SSMR3PutU32(f, pApic->tpr);
1722 SSMR3PutU32(f, pApic->spurious_vec);
1723 SSMR3PutU8(f, pApic->log_dest);
1724 SSMR3PutU8(f, pApic->dest_mode);
1725 for (i = 0; i < 8; i++) {
1726 SSMR3PutU32(f, pApic->isr.au32Bitmap[i]);
1727 SSMR3PutU32(f, pApic->tmr.au32Bitmap[i]);
1728 SSMR3PutU32(f, pApic->irr.au32Bitmap[i]);
1729 }
1730 for (i = 0; i < APIC_LVT_NB; i++) {
1731 SSMR3PutU32(f, pApic->lvt[i]);
1732 }
1733 SSMR3PutU32(f, pApic->esr);
1734 SSMR3PutU32(f, pApic->icr[0]);
1735 SSMR3PutU32(f, pApic->icr[1]);
1736 SSMR3PutU32(f, pApic->divide_conf);
1737 SSMR3PutU32(f, pApic->count_shift);
1738 SSMR3PutU32(f, pApic->initial_count);
1739 SSMR3PutU64(f, pApic->initial_count_load_time);
1740 SSMR3PutU64(f, pApic->next_time);
1741
1742 TMR3TimerSave(pApic->CTX_SUFF(pTimer), f);
1743}
1744
1745static int apic_load(SSMHANDLE *f, void *opaque, int version_id)
1746{
1747 APICState *pApic = (APICState*)opaque;
1748 int i;
1749
1750 /** @todo XXX: what if the base changes? (registered memory regions) */
1751 SSMR3GetU32(f, &pApic->apicbase);
1752
1753 switch (version_id)
1754 {
1755 case APIC_SAVED_STATE_VERSION_ANCIENT:
1756 {
1757 uint8_t val = 0;
1758 SSMR3GetU8(f, &val);
1759 pApic->id = val;
1760 /* UP only in old saved states */
1761 pApic->phys_id = 0;
1762 SSMR3GetU8(f, &val);
1763 pApic->arb_id = val;
1764 break;
1765 }
1766 case APIC_SAVED_STATE_VERSION:
1767 case APIC_SAVED_STATE_VERSION_VBOX_30:
1768 SSMR3GetU32(f, &pApic->id);
1769 SSMR3GetU32(f, &pApic->phys_id);
1770 SSMR3GetU32(f, &pApic->arb_id);
1771 break;
1772 default:
1773 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1774 }
1775 SSMR3GetU32(f, &pApic->tpr);
1776 SSMR3GetU32(f, &pApic->spurious_vec);
1777 SSMR3GetU8(f, &pApic->log_dest);
1778 SSMR3GetU8(f, &pApic->dest_mode);
1779 for (i = 0; i < 8; i++) {
1780 SSMR3GetU32(f, &pApic->isr.au32Bitmap[i]);
1781 SSMR3GetU32(f, &pApic->tmr.au32Bitmap[i]);
1782 SSMR3GetU32(f, &pApic->irr.au32Bitmap[i]);
1783 }
1784 for (i = 0; i < APIC_LVT_NB; i++) {
1785 SSMR3GetU32(f, &pApic->lvt[i]);
1786 }
1787 SSMR3GetU32(f, &pApic->esr);
1788 SSMR3GetU32(f, &pApic->icr[0]);
1789 SSMR3GetU32(f, &pApic->icr[1]);
1790 SSMR3GetU32(f, &pApic->divide_conf);
1791 SSMR3GetU32(f, (uint32_t *)&pApic->count_shift);
1792 SSMR3GetU32(f, (uint32_t *)&pApic->initial_count);
1793 SSMR3GetU64(f, (uint64_t *)&pApic->initial_count_load_time);
1794 SSMR3GetU64(f, (uint64_t *)&pApic->next_time);
1795
1796 int rc = TMR3TimerLoad(pApic->CTX_SUFF(pTimer), f);
1797 AssertRCReturn(rc, rc);
1798 pApic->uHintedCountShift = pApic->uHintedInitialCount = 0;
1799 pApic->fTimerArmed = TMTimerIsActive(pApic->CTX_SUFF(pTimer));
1800 if (pApic->fTimerArmed)
1801 apicDoFrequencyHinting(pApic);
1802
1803 return VINF_SUCCESS; /** @todo darn mess! */
1804}
1805
1806#endif /* IN_RING3 */
1807
1808/* LAPIC */
1809PDMBOTHCBDECL(int) apicMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
1810{
1811 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
1812 APICState *pApic = apicGetStateByCurEmt(pDev);
1813
1814 Log(("CPU%d: apicMMIORead at %llx\n", pApic->phys_id, (uint64_t)GCPhysAddr));
1815
1816 /** @todo add LAPIC range validity checks (different LAPICs can
1817 * theoretically have different physical addresses, see @bugref{3092}) */
1818
1819 STAM_COUNTER_INC(&CTXSUFF(pDev->StatMMIORead));
1820 switch (cb)
1821 {
1822 case 1:
1823 /** @todo this is not how recent APIC behave! We will fix
1824 * this via the IOM. */
1825 *(uint8_t *)pv = 0;
1826 break;
1827
1828 case 2:
1829 /** @todo this is not how recent APIC behave! */
1830 *(uint16_t *)pv = 0;
1831 break;
1832
1833 case 4:
1834 {
1835#if 0 /* Note! experimental */
1836#ifndef IN_RING3
1837 uint32_t index = (GCPhysAddr >> 4) & 0xff;
1838
1839 if ( index == 0x08 /* TPR */
1840 && ++pApic->cTPRPatchAttempts < APIC_MAX_PATCH_ATTEMPTS)
1841 {
1842#ifdef IN_RC
1843 pDevIns->pDevHlpGC->pfnPATMSetMMIOPatchInfo(pDevIns, GCPhysAddr, &pApic->tpr);
1844#else
1845 RTGCPTR pDevInsGC = PDMINS2DATA_GCPTR(pDevIns);
1846 pDevIns->pHlpR0->pfnPATMSetMMIOPatchInfo(pDevIns, GCPhysAddr, pDevIns + RT_OFFSETOF(APICState, tpr));
1847#endif
1848 return VINF_PATM_HC_MMIO_PATCH_READ;
1849 }
1850#endif
1851#endif /* experimental */
1852
1853 /* It does its own locking. */
1854 uint64_t u64Value = 0;
1855 int rc = apicReadRegister(pDev, pApic, (GCPhysAddr >> 4) & 0xff, &u64Value,
1856 VINF_IOM_R3_MMIO_READ, false /*fMsr*/);
1857 *(uint32_t *)pv = (uint32_t)u64Value;
1858 return rc;
1859 }
1860
1861 default:
1862 AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */
1863 return VERR_INTERNAL_ERROR;
1864 }
1865 return VINF_SUCCESS;
1866}
1867
1868PDMBOTHCBDECL(int) apicMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb)
1869{
1870 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
1871 APICState *pApic = apicGetStateByCurEmt(pDev);
1872
1873 Log(("CPU%d: apicMMIOWrite at %llx\n", pApic->phys_id, (uint64_t)GCPhysAddr));
1874
1875 /** @todo: add LAPIC range validity checks (multiple LAPICs can theoretically have
1876 * different physical addresses, see @bugref{3092}) */
1877
1878 STAM_COUNTER_INC(&CTXSUFF(pDev->StatMMIOWrite));
1879 switch (cb)
1880 {
1881 case 1:
1882 case 2:
1883 /* ignore */
1884 break;
1885
1886 case 4:
1887 /* It does its own locking. */
1888 return apicWriteRegister(pDev, pApic, (GCPhysAddr >> 4) & 0xff, *(uint32_t const *)pv,
1889 VINF_IOM_R3_MMIO_WRITE, false /*fMsr*/);
1890
1891 default:
1892 AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */
1893 return VERR_INTERNAL_ERROR;
1894 }
1895 return VINF_SUCCESS;
1896}
1897
1898#ifdef IN_RING3
1899
1900/**
1901 * Wrapper around apicReadRegister.
1902 *
1903 * @returns 64-bit register value.
1904 * @param pDev The PDM device instance.
1905 * @param pApic The Local APIC in question.
1906 * @param iReg The APIC register index.
1907 */
1908static uint64_t apicR3InfoReadReg(APICDeviceInfo *pDev, APICState *pApic, uint32_t iReg)
1909{
1910 uint64_t u64Value;
1911 int rc = apicReadRegister(pDev, pApic, iReg, &u64Value, VINF_SUCCESS, true /*fMsr*/);
1912 AssertRCReturn(rc, UINT64_MAX);
1913 return u64Value;
1914}
1915
1916
1917/**
1918 * Print a 8-DWORD Local APIC bit map (256 bits).
1919 *
1920 * @param pDev The PDM device instance.
1921 * @param pApic The Local APIC in question.
1922 * @param pHlp The output helper.
1923 * @param iStartReg The register to start at.
1924 */
1925static void apicR3DumpVec(APICDeviceInfo *pDev, APICState *pApic, PCDBGFINFOHLP pHlp, uint32_t iStartReg)
1926{
1927 for (uint32_t i = 0; i < 8; i++)
1928 pHlp->pfnPrintf(pHlp, "%08x", apicR3InfoReadReg(pDev, pApic, iStartReg + i));
1929 pHlp->pfnPrintf(pHlp, "\n");
1930}
1931
1932/**
1933 * Print basic Local APIC state.
1934 *
1935 * @param pDev The PDM device instance.
1936 * @param pApic The Local APIC in question.
1937 * @param pHlp The output helper.
1938 */
1939static void apicR3InfoBasic(APICDeviceInfo *pDev, APICState *pApic, PCDBGFINFOHLP pHlp)
1940{
1941 uint64_t u64;
1942
1943 pHlp->pfnPrintf(pHlp, "Local APIC at %08llx:\n", pApic->apicbase);
1944 u64 = apicR3InfoReadReg(pDev, pApic, 0x2);
1945 pHlp->pfnPrintf(pHlp, " LAPIC ID : %08llx\n", u64);
1946 pHlp->pfnPrintf(pHlp, " APIC ID = %02llx\n", (u64 >> 24) & 0xff);
1947 u64 = apicR3InfoReadReg(pDev, pApic, 0x3);
1948 pHlp->pfnPrintf(pHlp, " APIC VER : %08llx\n", u64);
1949 pHlp->pfnPrintf(pHlp, " version = %02x\n", (int)RT_BYTE1(u64));
1950 pHlp->pfnPrintf(pHlp, " lvts = %d\n", (int)RT_BYTE3(u64) + 1);
1951 u64 = apicR3InfoReadReg(pDev, pApic, 0x8);
1952 pHlp->pfnPrintf(pHlp, " TPR : %08llx\n", u64);
1953 pHlp->pfnPrintf(pHlp, " task pri = %lld/%lld\n", (u64 >> 4) & 0xf, u64 & 0xf);
1954 u64 = apicR3InfoReadReg(pDev, pApic, 0xA);
1955 pHlp->pfnPrintf(pHlp, " PPR : %08llx\n", u64);
1956 pHlp->pfnPrintf(pHlp, " cpu pri = %lld/%lld\n", (u64 >> 4) & 0xf, u64 & 0xf);
1957 u64 = apicR3InfoReadReg(pDev, pApic, 0xD);
1958 pHlp->pfnPrintf(pHlp, " LDR : %08llx\n", u64);
1959 pHlp->pfnPrintf(pHlp, " log id = %02llx\n", (u64 >> 24) & 0xff);
1960 pHlp->pfnPrintf(pHlp, " DFR : %08llx\n", apicR3InfoReadReg(pDev, pApic, 0xE));
1961 u64 = apicR3InfoReadReg(pDev, pApic, 0xF);
1962 pHlp->pfnPrintf(pHlp, " SVR : %08llx\n", u64);
1963 pHlp->pfnPrintf(pHlp, " focus = %s\n", u64 & RT_BIT(9) ? "check off" : "check on");
1964 pHlp->pfnPrintf(pHlp, " lapic = %s\n", u64 & RT_BIT(8) ? "ENABLED" : "DISABLED");
1965 pHlp->pfnPrintf(pHlp, " vector = %02x\n", (unsigned)RT_BYTE1(u64));
1966 pHlp->pfnPrintf(pHlp, " ISR : ");
1967 apicR3DumpVec(pDev, pApic, pHlp, 0x10);
1968 int iMax = Apic256BitReg_FindLastSetBit(&pApic->isr, -1);
1969 pHlp->pfnPrintf(pHlp, " highest = %02x\n", iMax == -1 ? 0 : iMax);
1970 pHlp->pfnPrintf(pHlp, " IRR : ");
1971 apicR3DumpVec(pDev, pApic, pHlp, 0x20);
1972 iMax = Apic256BitReg_FindLastSetBit(&pApic->irr, -1);
1973 pHlp->pfnPrintf(pHlp, " highest = %02X\n", iMax == -1 ? 0 : iMax);
1974}
1975
1976
1977/**
1978 * Print the more interesting Local APIC LVT entries.
1979 *
1980 * @param pDev The PDM device instance.
1981 * @param pApic The Local APIC in question.
1982 * @param pHlp The output helper.
1983 */
1984static void apicR3InfoLVT(APICDeviceInfo *pDev, APICState *pApic, PCDBGFINFOHLP pHlp)
1985{
1986 static const char * const s_apszDeliveryModes[] =
1987 {
1988 "Fixed ", "Reserved", "SMI", "Reserved", "NMI", "INIT", "Reserved", "ExtINT"
1989 };
1990 uint64_t u64;
1991
1992 u64 = apicR3InfoReadReg(pDev, pApic, 0x32);
1993 pHlp->pfnPrintf(pHlp, " LVT Timer : %08llx\n", u64);
1994 pHlp->pfnPrintf(pHlp, " mode = %s\n", u64 & RT_BIT(17) ? "periodic" : "one-shot");
1995 pHlp->pfnPrintf(pHlp, " mask = %llu\n", (u64 >> 16) & 1);
1996 pHlp->pfnPrintf(pHlp, " status = %s\n", u64 & RT_BIT(12) ? "pending" : "idle");
1997 pHlp->pfnPrintf(pHlp, " vector = %02llx\n", u64 & 0xff);
1998 u64 = apicR3InfoReadReg(pDev, pApic, 0x35);
1999 pHlp->pfnPrintf(pHlp, " LVT LINT0 : %08llx\n", u64);
2000 pHlp->pfnPrintf(pHlp, " mask = %llu\n", (u64 >> 16) & 1);
2001 pHlp->pfnPrintf(pHlp, " trigger = %s\n", u64 & RT_BIT(15) ? "level" : "edge");
2002 pHlp->pfnPrintf(pHlp, " rem irr = %llu\n", (u64 >> 14) & 1);
2003 pHlp->pfnPrintf(pHlp, " polarty = %llu\n", (u64 >> 13) & 1);
2004 pHlp->pfnPrintf(pHlp, " status = %s\n", u64 & RT_BIT(12) ? "pending" : "idle");
2005 pHlp->pfnPrintf(pHlp, " delivry = %s\n", s_apszDeliveryModes[(u64 >> 8) & 7]);
2006 pHlp->pfnPrintf(pHlp, " vector = %02llx\n", u64 & 0xff);
2007 u64 = apicR3InfoReadReg(pDev, pApic, 0x36);
2008 pHlp->pfnPrintf(pHlp, " LVT LINT1 : %08llx\n", u64);
2009 pHlp->pfnPrintf(pHlp, " mask = %llu\n", (u64 >> 16) & 1);
2010 pHlp->pfnPrintf(pHlp, " trigger = %s\n", u64 & RT_BIT(15) ? "level" : "edge");
2011 pHlp->pfnPrintf(pHlp, " rem irr = %lld\n", (u64 >> 14) & 1);
2012 pHlp->pfnPrintf(pHlp, " polarty = %lld\n", (u64 >> 13) & 1);
2013 pHlp->pfnPrintf(pHlp, " status = %s\n", u64 & RT_BIT(12) ? "pending" : "idle");
2014 pHlp->pfnPrintf(pHlp, " delivry = %s\n", s_apszDeliveryModes[(u64 >> 8) & 7]);
2015 pHlp->pfnPrintf(pHlp, " vector = %02llx\n", u64 & 0xff);
2016}
2017
2018
2019/**
2020 * Print LAPIC timer state.
2021 *
2022 * @param pDev The PDM device instance.
2023 * @param pApic The Local APIC in question.
2024 * @param pHlp The output helper.
2025 */
2026static void apicR3InfoTimer(APICDeviceInfo *pDev, APICState *pApic, PCDBGFINFOHLP pHlp)
2027{
2028 pHlp->pfnPrintf(pHlp, "Local APIC timer:\n");
2029 pHlp->pfnPrintf(pHlp, " Initial count : %08llx\n", apicR3InfoReadReg(pDev, pApic, 0x38));
2030 pHlp->pfnPrintf(pHlp, " Current count : %08llx\n", apicR3InfoReadReg(pDev, pApic, 0x39));
2031 uint64_t u64 = apicR3InfoReadReg(pDev, pApic, 0x3e);
2032 pHlp->pfnPrintf(pHlp, " Divide config : %08llx\n", u64);
2033 unsigned uDivider = ((u64 >> 1) & 0x04) | (u64 & 0x03);
2034 pHlp->pfnPrintf(pHlp, " divider = %u\n", uDivider == 7 ? 1 : 2 << uDivider);
2035}
2036
2037
2038/**
2039 * @callback_method_impl{FNDBGFHANDLERDEV,
2040 * Dumps the Local APIC state according to given argument.}
2041 */
2042static DECLCALLBACK(void) apicR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
2043{
2044 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2045 APICState *pApic = apicGetStateByCurEmt(pDev);
2046
2047 if (pszArgs == NULL || !*pszArgs || !strcmp(pszArgs, "basic"))
2048 apicR3InfoBasic(pDev, pApic, pHlp);
2049 else if (!strcmp(pszArgs, "lvt"))
2050 apicR3InfoLVT(pDev, pApic, pHlp);
2051 else if (!strcmp(pszArgs, "timer"))
2052 apicR3InfoTimer(pDev, pApic, pHlp);
2053 else
2054 pHlp->pfnPrintf(pHlp, "Invalid argument. Recognized arguments are 'basic', 'lvt', 'timer'.\n");
2055}
2056
2057
2058/**
2059 * @copydoc FNSSMDEVLIVEEXEC
2060 */
2061static DECLCALLBACK(int) apicR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
2062{
2063 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2064
2065 SSMR3PutU32( pSSM, pDev->cCpus);
2066 SSMR3PutBool(pSSM, pDev->fIoApic);
2067 SSMR3PutU32( pSSM, pDev->enmVersion);
2068 AssertCompile(PDMAPICVERSION_APIC == 2);
2069
2070 return VINF_SSM_DONT_CALL_AGAIN;
2071}
2072
2073
2074/**
2075 * @copydoc FNSSMDEVSAVEEXEC
2076 */
2077static DECLCALLBACK(int) apicR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
2078{
2079 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2080
2081 /* config */
2082 apicR3LiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
2083
2084 /* save all APICs data */ /** @todo: is it correct? */
2085 APIC_FOREACH_BEGIN(pDev);
2086 apic_save(pSSM, pCurApic);
2087 APIC_FOREACH_END();
2088
2089 return VINF_SUCCESS;
2090}
2091
2092/**
2093 * @copydoc FNSSMDEVLOADEXEC
2094 */
2095static DECLCALLBACK(int) apicR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
2096{
2097 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2098
2099 if ( uVersion != APIC_SAVED_STATE_VERSION
2100 && uVersion != APIC_SAVED_STATE_VERSION_VBOX_30
2101 && uVersion != APIC_SAVED_STATE_VERSION_ANCIENT)
2102 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
2103
2104 /* config */
2105 if (uVersion > APIC_SAVED_STATE_VERSION_VBOX_30)
2106 {
2107 uint32_t cCpus;
2108 int rc = SSMR3GetU32(pSSM, &cCpus); AssertRCReturn(rc, rc);
2109 if (cCpus != pDev->cCpus)
2110 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - cCpus: saved=%#x config=%#x"), cCpus, pDev->cCpus);
2111
2112 bool fIoApic;
2113 rc = SSMR3GetBool(pSSM, &fIoApic); AssertRCReturn(rc, rc);
2114 if (fIoApic != pDev->fIoApic)
2115 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - fIoApic: saved=%RTbool config=%RTbool"), fIoApic, pDev->fIoApic);
2116
2117 uint32_t uApicVersion;
2118 rc = SSMR3GetU32(pSSM, &uApicVersion); AssertRCReturn(rc, rc);
2119 if (uApicVersion != (uint32_t)pDev->enmVersion)
2120 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - uApicVersion: saved=%#x config=%#x"), uApicVersion, pDev->enmVersion);
2121 }
2122
2123 if (uPass != SSM_PASS_FINAL)
2124 return VINF_SUCCESS;
2125
2126 /* load all APICs data */ /** @todo: is it correct? */
2127 APIC_LOCK(pDev, VERR_INTERNAL_ERROR_3);
2128
2129 int rc = VINF_SUCCESS;
2130 APIC_FOREACH_BEGIN(pDev);
2131 rc = apic_load(pSSM, pCurApic, uVersion);
2132 if (RT_FAILURE(rc))
2133 break;
2134 APIC_FOREACH_END();
2135
2136 APIC_UNLOCK(pDev);
2137 return rc;
2138}
2139
2140/**
2141 * @copydoc FNPDMDEVRESET
2142 */
2143static DECLCALLBACK(void) apicR3Reset(PPDMDEVINS pDevIns)
2144{
2145 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2146 TMTimerLock(pDev->paLapicsR3[0].pTimerR3, VERR_IGNORED);
2147 APIC_LOCK_VOID(pDev, VERR_IGNORED);
2148
2149 /* Reset all APICs. */
2150 for (VMCPUID i = 0; i < pDev->cCpus; i++)
2151 {
2152 APICState *pApic = &pDev->CTX_SUFF(paLapics)[i];
2153 TMTimerStop(pApic->CTX_SUFF(pTimer));
2154
2155 /* Clear LAPIC state as if an INIT IPI was sent. */
2156 apicR3InitIpi(pDev, pApic);
2157
2158 /* The IDs are not touched by apicR3InitIpi() and must be reset now. */
2159 pApic->arb_id = pApic->id = i;
2160 Assert(pApic->id == pApic->phys_id); /* The two should match again. */
2161
2162 /* Reset should re-enable the APIC, see comment in msi.h */
2163 pApic->apicbase = VBOX_MSI_ADDR_BASE | MSR_IA32_APICBASE_ENABLE;
2164 if (pApic->phys_id == 0)
2165 pApic->apicbase |= MSR_IA32_APICBASE_BSP;
2166
2167 /* Clear any pending APIC interrupt action flag. */
2168 apicCpuClearInterrupt(pDev, pApic);
2169 }
2170 /** @todo r=bird: Why is this done everytime, while the constructor first
2171 * checks the CPUID? Who is right? */
2172 pDev->pApicHlpR3->pfnChangeFeature(pDev->pDevInsR3, pDev->enmVersion);
2173
2174 APIC_UNLOCK(pDev);
2175 TMTimerUnlock(pDev->paLapicsR3[0].pTimerR3);
2176}
2177
2178
2179/**
2180 * @copydoc FNPDMDEVRELOCATE
2181 */
2182static DECLCALLBACK(void) apicR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
2183{
2184 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2185 pDev->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2186 pDev->pApicHlpRC = pDev->pApicHlpR3->pfnGetRCHelpers(pDevIns);
2187 pDev->paLapicsRC = MMHyperR3ToRC(PDMDevHlpGetVM(pDevIns), pDev->paLapicsR3);
2188 pDev->pCritSectRC = pDev->pApicHlpR3->pfnGetRCCritSect(pDevIns);
2189 for (uint32_t i = 0; i < pDev->cCpus; i++)
2190 pDev->paLapicsR3[i].pTimerRC = TMTimerRCPtr(pDev->paLapicsR3[i].pTimerR3);
2191}
2192
2193
2194/**
2195 * Initializes the state of one local APIC.
2196 *
2197 * @param pApic The Local APIC state to init.
2198 * @param id The Local APIC ID.
2199 */
2200static void apicR3StateInit(APICState *pApic, uint8_t id)
2201{
2202 memset(pApic, 0, sizeof(*pApic));
2203
2204 /* See comment in msi.h for LAPIC base info. */
2205 pApic->apicbase = VBOX_MSI_ADDR_BASE | MSR_IA32_APICBASE_ENABLE;
2206 if (id == 0) /* Mark first CPU as BSP. */
2207 pApic->apicbase |= MSR_IA32_APICBASE_BSP;
2208
2209 for (int i = 0; i < APIC_LVT_NB; i++)
2210 pApic->lvt[i] = RT_BIT_32(16); /* mask LVT */
2211
2212 pApic->spurious_vec = 0xff;
2213 pApic->phys_id = id;
2214 pApic->id = id;
2215}
2216
2217
2218/**
2219 * @copydoc FNPDMDEVCONSTRUCT
2220 */
2221static DECLCALLBACK(int) apicR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
2222{
2223 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2224 uint32_t i;
2225
2226 /*
2227 * Only single device instance.
2228 */
2229 Assert(iInstance == 0);
2230
2231 /*
2232 * Validate configuration.
2233 */
2234 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "IOAPIC|RZEnabled|NumCPUs", "");
2235
2236 bool fIoApic;
2237 int rc = CFGMR3QueryBoolDef(pCfg, "IOAPIC", &fIoApic, true);
2238 if (RT_FAILURE(rc))
2239 return PDMDEV_SET_ERROR(pDevIns, rc,
2240 N_("Configuration error: Failed to read \"IOAPIC\""));
2241
2242 bool fRZEnabled;
2243 rc = CFGMR3QueryBoolDef(pCfg, "RZEnabled", &fRZEnabled, true);
2244 if (RT_FAILURE(rc))
2245 return PDMDEV_SET_ERROR(pDevIns, rc,
2246 N_("Configuration error: Failed to query boolean value \"RZEnabled\""));
2247
2248 uint32_t cCpus;
2249 rc = CFGMR3QueryU32Def(pCfg, "NumCPUs", &cCpus, 1);
2250 if (RT_FAILURE(rc))
2251 return PDMDEV_SET_ERROR(pDevIns, rc,
2252 N_("Configuration error: Failed to query integer value \"NumCPUs\""));
2253
2254 Log(("APIC: cCpus=%d fRZEnabled=%RTbool fIoApic=%RTbool\n", cCpus, fRZEnabled, fIoApic));
2255 if (cCpus > 255)
2256 return PDMDEV_SET_ERROR(pDevIns, rc,
2257 N_("Configuration error: Invalid value for \"NumCPUs\""));
2258
2259 /*
2260 * Init the data.
2261 */
2262 pDev->pDevInsR3 = pDevIns;
2263 pDev->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
2264 pDev->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2265 pDev->cCpus = cCpus;
2266 pDev->fIoApic = fIoApic;
2267 /* Use PDMAPICVERSION_X2APIC to activate x2APIC mode */
2268 pDev->enmVersion = PDMAPICVERSION_APIC;
2269
2270 /* Disable locking in this device. */
2271 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
2272 AssertRCReturn(rc, rc);
2273
2274 PVM pVM = PDMDevHlpGetVM(pDevIns);
2275
2276 /*
2277 * We are not freeing this memory, as it's automatically released when guest exits.
2278 */
2279 rc = MMHyperAlloc(pVM, cCpus * sizeof(APICState), 1, MM_TAG_PDM_DEVICE_USER, (void **)&pDev->paLapicsR3);
2280 if (RT_FAILURE(rc))
2281 return VERR_NO_MEMORY;
2282 pDev->paLapicsR0 = MMHyperR3ToR0(pVM, pDev->paLapicsR3);
2283 pDev->paLapicsRC = MMHyperR3ToRC(pVM, pDev->paLapicsR3);
2284
2285 for (i = 0; i < cCpus; i++)
2286 apicR3StateInit(&pDev->paLapicsR3[i], i);
2287
2288 /*
2289 * Register the APIC.
2290 */
2291 PDMAPICREG ApicReg;
2292 ApicReg.u32Version = PDM_APICREG_VERSION;
2293 ApicReg.pfnGetInterruptR3 = apicGetInterrupt;
2294 ApicReg.pfnHasPendingIrqR3 = apicHasPendingIrq;
2295 ApicReg.pfnSetBaseR3 = apicSetBase;
2296 ApicReg.pfnGetBaseR3 = apicGetBase;
2297 ApicReg.pfnSetTPRR3 = apicSetTPR;
2298 ApicReg.pfnGetTPRR3 = apicGetTPR;
2299 ApicReg.pfnWriteMSRR3 = apicWriteMSR;
2300 ApicReg.pfnReadMSRR3 = apicReadMSR;
2301 ApicReg.pfnBusDeliverR3 = apicBusDeliverCallback;
2302 ApicReg.pfnLocalInterruptR3 = apicLocalInterrupt;
2303 if (fRZEnabled)
2304 {
2305 ApicReg.pszGetInterruptRC = "apicGetInterrupt";
2306 ApicReg.pszHasPendingIrqRC = "apicHasPendingIrq";
2307 ApicReg.pszSetBaseRC = "apicSetBase";
2308 ApicReg.pszGetBaseRC = "apicGetBase";
2309 ApicReg.pszSetTPRRC = "apicSetTPR";
2310 ApicReg.pszGetTPRRC = "apicGetTPR";
2311 ApicReg.pszWriteMSRRC = "apicWriteMSR";
2312 ApicReg.pszReadMSRRC = "apicReadMSR";
2313 ApicReg.pszBusDeliverRC = "apicBusDeliverCallback";
2314 ApicReg.pszLocalInterruptRC = "apicLocalInterrupt";
2315
2316 ApicReg.pszGetInterruptR0 = "apicGetInterrupt";
2317 ApicReg.pszHasPendingIrqR0 = "apicHasPendingIrq";
2318 ApicReg.pszSetBaseR0 = "apicSetBase";
2319 ApicReg.pszGetBaseR0 = "apicGetBase";
2320 ApicReg.pszSetTPRR0 = "apicSetTPR";
2321 ApicReg.pszGetTPRR0 = "apicGetTPR";
2322 ApicReg.pszWriteMSRR0 = "apicWriteMSR";
2323 ApicReg.pszReadMSRR0 = "apicReadMSR";
2324 ApicReg.pszBusDeliverR0 = "apicBusDeliverCallback";
2325 ApicReg.pszLocalInterruptR0 = "apicLocalInterrupt";
2326 }
2327 else
2328 {
2329 ApicReg.pszGetInterruptRC = NULL;
2330 ApicReg.pszHasPendingIrqRC = NULL;
2331 ApicReg.pszSetBaseRC = NULL;
2332 ApicReg.pszGetBaseRC = NULL;
2333 ApicReg.pszSetTPRRC = NULL;
2334 ApicReg.pszGetTPRRC = NULL;
2335 ApicReg.pszWriteMSRRC = NULL;
2336 ApicReg.pszReadMSRRC = NULL;
2337 ApicReg.pszBusDeliverRC = NULL;
2338 ApicReg.pszLocalInterruptRC = NULL;
2339
2340 ApicReg.pszGetInterruptR0 = NULL;
2341 ApicReg.pszHasPendingIrqR0 = NULL;
2342 ApicReg.pszSetBaseR0 = NULL;
2343 ApicReg.pszGetBaseR0 = NULL;
2344 ApicReg.pszSetTPRR0 = NULL;
2345 ApicReg.pszGetTPRR0 = NULL;
2346 ApicReg.pszWriteMSRR0 = NULL;
2347 ApicReg.pszReadMSRR0 = NULL;
2348 ApicReg.pszBusDeliverR0 = NULL;
2349 ApicReg.pszLocalInterruptR0 = NULL;
2350 }
2351
2352 rc = PDMDevHlpAPICRegister(pDevIns, &ApicReg, &pDev->pApicHlpR3);
2353 AssertLogRelRCReturn(rc, rc);
2354 pDev->pCritSectR3 = pDev->pApicHlpR3->pfnGetR3CritSect(pDevIns);
2355
2356 /*
2357 * The CPUID feature bit.
2358 */
2359 /** @todo r=bird: See remark in the apicR3Reset. */
2360 uint32_t u32Eax, u32Ebx, u32Ecx, u32Edx;
2361 PDMDevHlpGetCpuId(pDevIns, 0, &u32Eax, &u32Ebx, &u32Ecx, &u32Edx);
2362 if (u32Eax >= 1)
2363 {
2364 if ( fIoApic /* If IOAPIC is enabled, enable Local APIC in any case */
2365 || ( u32Ebx == X86_CPUID_VENDOR_INTEL_EBX
2366 && u32Ecx == X86_CPUID_VENDOR_INTEL_ECX
2367 && u32Edx == X86_CPUID_VENDOR_INTEL_EDX /* GenuineIntel */)
2368 || ( u32Ebx == X86_CPUID_VENDOR_AMD_EBX
2369 && u32Ecx == X86_CPUID_VENDOR_AMD_ECX
2370 && u32Edx == X86_CPUID_VENDOR_AMD_EDX /* AuthenticAMD */))
2371 {
2372 LogRel(("Activating Local APIC\n"));
2373 pDev->pApicHlpR3->pfnChangeFeature(pDevIns, pDev->enmVersion);
2374 }
2375 }
2376
2377 /*
2378 * Register the MMIO range.
2379 */
2380 /** @todo: shall reregister, if base changes. */
2381 uint32_t ApicBase = pDev->paLapicsR3[0].apicbase & ~0xfff;
2382 rc = PDMDevHlpMMIORegister(pDevIns, ApicBase, 0x1000, pDev,
2383 IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
2384 apicMMIOWrite, apicMMIORead, "APIC Memory");
2385 if (RT_FAILURE(rc))
2386 return rc;
2387
2388 if (fRZEnabled)
2389 {
2390 pDev->pApicHlpRC = pDev->pApicHlpR3->pfnGetRCHelpers(pDevIns);
2391 pDev->pCritSectRC = pDev->pApicHlpR3->pfnGetRCCritSect(pDevIns);
2392 rc = PDMDevHlpMMIORegisterRC(pDevIns, ApicBase, 0x1000, NIL_RTRCPTR /*pvUser*/, "apicMMIOWrite", "apicMMIORead");
2393 if (RT_FAILURE(rc))
2394 return rc;
2395
2396 pDev->pApicHlpR0 = pDev->pApicHlpR3->pfnGetR0Helpers(pDevIns);
2397 pDev->pCritSectR0 = pDev->pApicHlpR3->pfnGetR0CritSect(pDevIns);
2398 rc = PDMDevHlpMMIORegisterR0(pDevIns, ApicBase, 0x1000, NIL_RTR0PTR /*pvUser*/, "apicMMIOWrite", "apicMMIORead");
2399 if (RT_FAILURE(rc))
2400 return rc;
2401 }
2402
2403 /*
2404 * Create the APIC timers.
2405 */
2406 for (i = 0; i < cCpus; i++)
2407 {
2408 APICState *pApic = &pDev->paLapicsR3[i];
2409 pApic->pszDesc = MMR3HeapAPrintf(pVM, MM_TAG_PDM_DEVICE_USER, "APIC Timer #%u", i);
2410 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, apicR3TimerCallback, pApic,
2411 TMTIMER_FLAGS_NO_CRIT_SECT, pApic->pszDesc, &pApic->pTimerR3);
2412 if (RT_FAILURE(rc))
2413 return rc;
2414 pApic->pTimerR0 = TMTimerR0Ptr(pApic->pTimerR3);
2415 pApic->pTimerRC = TMTimerRCPtr(pApic->pTimerR3);
2416 TMR3TimerSetCritSect(pApic->pTimerR3, pDev->pCritSectR3);
2417 }
2418
2419 /*
2420 * Saved state.
2421 */
2422 rc = PDMDevHlpSSMRegister3(pDevIns, APIC_SAVED_STATE_VERSION, sizeof(*pDev),
2423 apicR3LiveExec, apicR3SaveExec, apicR3LoadExec);
2424 if (RT_FAILURE(rc))
2425 return rc;
2426
2427 /*
2428 * Register debugger info callback.
2429 */
2430 PDMDevHlpDBGFInfoRegister(pDevIns, "apic", "Display Local APIC state for current CPU. "
2431 "Recognizes 'basic', 'lvt', 'timer' as arguments, defaulting to 'basic'.", apicR3Info);
2432
2433#ifdef VBOX_WITH_STATISTICS
2434 /*
2435 * Statistics.
2436 */
2437 PDMDevHlpSTAMRegister(pDevIns, &pDev->StatMMIOReadGC, STAMTYPE_COUNTER, "/Devices/APIC/MMIOReadGC", STAMUNIT_OCCURENCES, "Number of APIC MMIO reads in GC.");
2438 PDMDevHlpSTAMRegister(pDevIns, &pDev->StatMMIOReadHC, STAMTYPE_COUNTER, "/Devices/APIC/MMIOReadHC", STAMUNIT_OCCURENCES, "Number of APIC MMIO reads in HC.");
2439 PDMDevHlpSTAMRegister(pDevIns, &pDev->StatMMIOWriteGC, STAMTYPE_COUNTER, "/Devices/APIC/MMIOWriteGC", STAMUNIT_OCCURENCES, "Number of APIC MMIO writes in GC.");
2440 PDMDevHlpSTAMRegister(pDevIns, &pDev->StatMMIOWriteHC, STAMTYPE_COUNTER, "/Devices/APIC/MMIOWriteHC", STAMUNIT_OCCURENCES, "Number of APIC MMIO writes in HC.");
2441 PDMDevHlpSTAMRegister(pDevIns, &pDev->StatClearedActiveIrq,STAMTYPE_COUNTER, "/Devices/APIC/MaskedActiveIRQ", STAMUNIT_OCCURENCES, "Number of cleared irqs.");
2442 for (i = 0; i < cCpus; i++)
2443 {
2444 APICState *pApic = &pDev->paLapicsR3[i];
2445 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetInitialCount, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Calls to apicTimerSetInitialCount.", "/Devices/APIC/%u/TimerSetInitialCount", i);
2446 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetInitialCountArm, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerSetRelative calls.", "/Devices/APIC/%u/TimerSetInitialCount/Arm", i);
2447 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetInitialCountDisarm, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerStop calls.", "/Devices/APIC/%u/TimerSetInitialCount/Disasm", i);
2448 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvt, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Calls to apicTimerSetLvt.", "/Devices/APIC/%u/TimerSetLvt", i);
2449 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtClearPeriodic, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Clearing APIC_LVT_TIMER_PERIODIC.", "/Devices/APIC/%u/TimerSetLvt/ClearPeriodic", i);
2450 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtPostponed, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerStop postponed.", "/Devices/APIC/%u/TimerSetLvt/Postponed", i);
2451 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtArmed, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerSet avoided.", "/Devices/APIC/%u/TimerSetLvt/Armed", i);
2452 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtArm, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerSet necessary.", "/Devices/APIC/%u/TimerSetLvt/Arm", i);
2453 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtArmRetries, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerSet retries.", "/Devices/APIC/%u/TimerSetLvt/ArmRetries", i);
2454 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtNoRelevantChange,STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "No relevant flags changed.", "/Devices/APIC/%u/TimerSetLvt/NoRelevantChange", i);
2455 }
2456#endif
2457
2458 return VINF_SUCCESS;
2459}
2460
2461
2462/**
2463 * APIC device registration structure.
2464 */
2465const PDMDEVREG g_DeviceAPIC =
2466{
2467 /* u32Version */
2468 PDM_DEVREG_VERSION,
2469 /* szName */
2470 "apic",
2471 /* szRCMod */
2472 "VBoxDD2GC.gc",
2473 /* szR0Mod */
2474 "VBoxDD2R0.r0",
2475 /* pszDescription */
2476 "Advanced Programmable Interrupt Controller (APIC) Device",
2477 /* fFlags */
2478 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,
2479 /* fClass */
2480 PDM_DEVREG_CLASS_PIC,
2481 /* cMaxInstances */
2482 1,
2483 /* cbInstance */
2484 sizeof(APICState),
2485 /* pfnConstruct */
2486 apicR3Construct,
2487 /* pfnDestruct */
2488 NULL,
2489 /* pfnRelocate */
2490 apicR3Relocate,
2491 /* pfnIOCtl */
2492 NULL,
2493 /* pfnPowerOn */
2494 NULL,
2495 /* pfnReset */
2496 apicR3Reset,
2497 /* pfnSuspend */
2498 NULL,
2499 /* pfnResume */
2500 NULL,
2501 /* pfnAttach */
2502 NULL,
2503 /* pfnDetach */
2504 NULL,
2505 /* pfnQueryInterface. */
2506 NULL,
2507 /* pfnInitComplete */
2508 NULL,
2509 /* pfnPowerOff */
2510 NULL,
2511 /* pfnSoftReset */
2512 NULL,
2513 /* u32VersionEnd */
2514 PDM_DEVREG_VERSION
2515};
2516
2517#endif /* IN_RING3 */
2518#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
2519
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