VirtualBox

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

Last change on this file since 60422 was 60307, checked in by vboxsync, 9 years ago

VMM: APIC rewrite. Initial commit, work in progress.

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