VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/APIC.cpp@ 61574

Last change on this file since 61574 was 61566, checked in by vboxsync, 9 years ago

VMM/APIC: Fix DBGF info callbacks to run on EMT and use separate callbacks rather than arguments so
we can dump them in an automated fashion while collecting crash diagnostics.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 72.4 KB
Line 
1/* $Id: APIC.cpp 61566 2016-06-08 09:39:35Z vboxsync $ */
2/** @file
3 * APIC - Advanced Programmable Interrupt Controller.
4 */
5
6/*
7 * Copyright (C) 2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_DEV_APIC
23#include <VBox/log.h>
24#include "APICInternal.h"
25#include <VBox/vmm/cpum.h>
26#include <VBox/vmm/hm.h>
27#include <VBox/vmm/mm.h>
28#include <VBox/vmm/pdmdev.h>
29#include <VBox/vmm/ssm.h>
30#include <VBox/vmm/vm.h>
31
32
33#ifndef VBOX_DEVICE_STRUCT_TESTCASE
34/*********************************************************************************************************************************
35* Defined Constants And Macros *
36*********************************************************************************************************************************/
37/** The current APIC saved state version. */
38#define APIC_SAVED_STATE_VERSION 4
39/** The saved state version used by VirtualBox 5.0 and
40 * earlier. */
41#define APIC_SAVED_STATE_VERSION_VBOX_50 3
42/** The saved state version used by VirtualBox v3 and earlier.
43 * This does not include the config. */
44#define APIC_SAVED_STATE_VERSION_VBOX_30 2
45/** Some ancient version... */
46#define APIC_SAVED_STATE_VERSION_ANCIENT 1
47
48
49/*********************************************************************************************************************************
50* Global Variables *
51*********************************************************************************************************************************/
52/** Saved state field descriptors for XAPICPAGE. */
53static const SSMFIELD g_aXApicPageFields[] =
54{
55 SSMFIELD_ENTRY( XAPICPAGE, id.u8ApicId),
56 SSMFIELD_ENTRY( XAPICPAGE, version.all.u32Version),
57 SSMFIELD_ENTRY( XAPICPAGE, tpr.u8Tpr),
58 SSMFIELD_ENTRY( XAPICPAGE, apr.u8Apr),
59 SSMFIELD_ENTRY( XAPICPAGE, ppr.u8Ppr),
60 SSMFIELD_ENTRY( XAPICPAGE, ldr.all.u32Ldr),
61 SSMFIELD_ENTRY( XAPICPAGE, dfr.all.u32Dfr),
62 SSMFIELD_ENTRY( XAPICPAGE, svr.all.u32Svr),
63 SSMFIELD_ENTRY( XAPICPAGE, isr.u[0].u32Reg),
64 SSMFIELD_ENTRY( XAPICPAGE, isr.u[1].u32Reg),
65 SSMFIELD_ENTRY( XAPICPAGE, isr.u[2].u32Reg),
66 SSMFIELD_ENTRY( XAPICPAGE, isr.u[3].u32Reg),
67 SSMFIELD_ENTRY( XAPICPAGE, isr.u[4].u32Reg),
68 SSMFIELD_ENTRY( XAPICPAGE, isr.u[5].u32Reg),
69 SSMFIELD_ENTRY( XAPICPAGE, isr.u[6].u32Reg),
70 SSMFIELD_ENTRY( XAPICPAGE, isr.u[7].u32Reg),
71 SSMFIELD_ENTRY( XAPICPAGE, tmr.u[0].u32Reg),
72 SSMFIELD_ENTRY( XAPICPAGE, tmr.u[1].u32Reg),
73 SSMFIELD_ENTRY( XAPICPAGE, tmr.u[2].u32Reg),
74 SSMFIELD_ENTRY( XAPICPAGE, tmr.u[3].u32Reg),
75 SSMFIELD_ENTRY( XAPICPAGE, tmr.u[4].u32Reg),
76 SSMFIELD_ENTRY( XAPICPAGE, tmr.u[5].u32Reg),
77 SSMFIELD_ENTRY( XAPICPAGE, tmr.u[6].u32Reg),
78 SSMFIELD_ENTRY( XAPICPAGE, tmr.u[7].u32Reg),
79 SSMFIELD_ENTRY( XAPICPAGE, irr.u[0].u32Reg),
80 SSMFIELD_ENTRY( XAPICPAGE, irr.u[1].u32Reg),
81 SSMFIELD_ENTRY( XAPICPAGE, irr.u[2].u32Reg),
82 SSMFIELD_ENTRY( XAPICPAGE, irr.u[3].u32Reg),
83 SSMFIELD_ENTRY( XAPICPAGE, irr.u[4].u32Reg),
84 SSMFIELD_ENTRY( XAPICPAGE, irr.u[5].u32Reg),
85 SSMFIELD_ENTRY( XAPICPAGE, irr.u[6].u32Reg),
86 SSMFIELD_ENTRY( XAPICPAGE, irr.u[7].u32Reg),
87 SSMFIELD_ENTRY( XAPICPAGE, esr.all.u32Errors),
88 SSMFIELD_ENTRY( XAPICPAGE, icr_lo.all.u32IcrLo),
89 SSMFIELD_ENTRY( XAPICPAGE, icr_hi.all.u32IcrHi),
90 SSMFIELD_ENTRY( XAPICPAGE, lvt_timer.all.u32LvtTimer),
91 SSMFIELD_ENTRY( XAPICPAGE, lvt_thermal.all.u32LvtThermal),
92 SSMFIELD_ENTRY( XAPICPAGE, lvt_perf.all.u32LvtPerf),
93 SSMFIELD_ENTRY( XAPICPAGE, lvt_lint0.all.u32LvtLint0),
94 SSMFIELD_ENTRY( XAPICPAGE, lvt_lint1.all.u32LvtLint1),
95 SSMFIELD_ENTRY( XAPICPAGE, lvt_error.all.u32LvtError),
96 SSMFIELD_ENTRY( XAPICPAGE, timer_icr.u32InitialCount),
97 SSMFIELD_ENTRY( XAPICPAGE, timer_ccr.u32CurrentCount),
98 SSMFIELD_ENTRY( XAPICPAGE, timer_dcr.all.u32DivideValue),
99 SSMFIELD_ENTRY_TERM()
100};
101
102/** Saved state field descriptors for X2APICPAGE. */
103static const SSMFIELD g_aX2ApicPageFields[] =
104{
105 SSMFIELD_ENTRY(X2APICPAGE, id.u32ApicId),
106 SSMFIELD_ENTRY(X2APICPAGE, version.all.u32Version),
107 SSMFIELD_ENTRY(X2APICPAGE, tpr.u8Tpr),
108 SSMFIELD_ENTRY(X2APICPAGE, ppr.u8Ppr),
109 SSMFIELD_ENTRY(X2APICPAGE, ldr.u32LogicalApicId),
110 SSMFIELD_ENTRY(X2APICPAGE, svr.all.u32Svr),
111 SSMFIELD_ENTRY(X2APICPAGE, isr.u[0].u32Reg),
112 SSMFIELD_ENTRY(X2APICPAGE, isr.u[1].u32Reg),
113 SSMFIELD_ENTRY(X2APICPAGE, isr.u[2].u32Reg),
114 SSMFIELD_ENTRY(X2APICPAGE, isr.u[3].u32Reg),
115 SSMFIELD_ENTRY(X2APICPAGE, isr.u[4].u32Reg),
116 SSMFIELD_ENTRY(X2APICPAGE, isr.u[5].u32Reg),
117 SSMFIELD_ENTRY(X2APICPAGE, isr.u[6].u32Reg),
118 SSMFIELD_ENTRY(X2APICPAGE, isr.u[7].u32Reg),
119 SSMFIELD_ENTRY(X2APICPAGE, tmr.u[0].u32Reg),
120 SSMFIELD_ENTRY(X2APICPAGE, tmr.u[1].u32Reg),
121 SSMFIELD_ENTRY(X2APICPAGE, tmr.u[2].u32Reg),
122 SSMFIELD_ENTRY(X2APICPAGE, tmr.u[3].u32Reg),
123 SSMFIELD_ENTRY(X2APICPAGE, tmr.u[4].u32Reg),
124 SSMFIELD_ENTRY(X2APICPAGE, tmr.u[5].u32Reg),
125 SSMFIELD_ENTRY(X2APICPAGE, tmr.u[6].u32Reg),
126 SSMFIELD_ENTRY(X2APICPAGE, tmr.u[7].u32Reg),
127 SSMFIELD_ENTRY(X2APICPAGE, irr.u[0].u32Reg),
128 SSMFIELD_ENTRY(X2APICPAGE, irr.u[1].u32Reg),
129 SSMFIELD_ENTRY(X2APICPAGE, irr.u[2].u32Reg),
130 SSMFIELD_ENTRY(X2APICPAGE, irr.u[3].u32Reg),
131 SSMFIELD_ENTRY(X2APICPAGE, irr.u[4].u32Reg),
132 SSMFIELD_ENTRY(X2APICPAGE, irr.u[5].u32Reg),
133 SSMFIELD_ENTRY(X2APICPAGE, irr.u[6].u32Reg),
134 SSMFIELD_ENTRY(X2APICPAGE, irr.u[7].u32Reg),
135 SSMFIELD_ENTRY(X2APICPAGE, esr.all.u32Errors),
136 SSMFIELD_ENTRY(X2APICPAGE, icr_lo.all.u32IcrLo),
137 SSMFIELD_ENTRY(X2APICPAGE, icr_hi.u32IcrHi),
138 SSMFIELD_ENTRY(X2APICPAGE, lvt_timer.all.u32LvtTimer),
139 SSMFIELD_ENTRY(X2APICPAGE, lvt_thermal.all.u32LvtThermal),
140 SSMFIELD_ENTRY(X2APICPAGE, lvt_perf.all.u32LvtPerf),
141 SSMFIELD_ENTRY(X2APICPAGE, lvt_lint0.all.u32LvtLint0),
142 SSMFIELD_ENTRY(X2APICPAGE, lvt_lint1.all.u32LvtLint1),
143 SSMFIELD_ENTRY(X2APICPAGE, lvt_error.all.u32LvtError),
144 SSMFIELD_ENTRY(X2APICPAGE, timer_icr.u32InitialCount),
145 SSMFIELD_ENTRY(X2APICPAGE, timer_ccr.u32CurrentCount),
146 SSMFIELD_ENTRY(X2APICPAGE, timer_dcr.all.u32DivideValue),
147 SSMFIELD_ENTRY_TERM()
148};
149
150
151/**
152 * Initializes per-VCPU APIC to the state following an INIT reset
153 * ("Wait-for-SIPI" state).
154 *
155 * @param pVCpu The cross context virtual CPU structure.
156 */
157static void apicR3InitIpi(PVMCPU pVCpu)
158{
159 VMCPU_ASSERT_EMT_OR_NOT_RUNNING(pVCpu);
160 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
161
162 /*
163 * See Intel spec. 10.4.7.3 "Local APIC State After an INIT Reset (Wait-for-SIPI State)"
164 * and AMD spec 16.3.2 "APIC Registers".
165 *
166 * The reason we don't simply zero out the entire APIC page and only set the non-zero members
167 * is because there are some registers that are not touched by the INIT IPI (e.g. version)
168 * operation and this function is only a subset of the reset operation.
169 */
170 RT_ZERO(pXApicPage->irr);
171 RT_ZERO(pXApicPage->irr);
172 RT_ZERO(pXApicPage->isr);
173 RT_ZERO(pXApicPage->tmr);
174 RT_ZERO(pXApicPage->icr_hi);
175 RT_ZERO(pXApicPage->icr_lo);
176 RT_ZERO(pXApicPage->ldr);
177 RT_ZERO(pXApicPage->tpr);
178 RT_ZERO(pXApicPage->ppr);
179 RT_ZERO(pXApicPage->timer_icr);
180 RT_ZERO(pXApicPage->timer_ccr);
181 RT_ZERO(pXApicPage->timer_dcr);
182
183 pXApicPage->dfr.u.u4Model = XAPICDESTFORMAT_FLAT;
184 pXApicPage->dfr.u.u28ReservedMb1 = UINT32_C(0xfffffff);
185
186 /** @todo CMCI. */
187
188 RT_ZERO(pXApicPage->lvt_timer);
189 pXApicPage->lvt_timer.u.u1Mask = 1;
190
191#if XAPIC_HARDWARE_VERSION == XAPIC_HARDWARE_VERSION_P4
192 RT_ZERO(pXApicPage->lvt_thermal);
193 pXApicPage->lvt_thermal.u.u1Mask = 1;
194#endif
195
196 RT_ZERO(pXApicPage->lvt_perf);
197 pXApicPage->lvt_perf.u.u1Mask = 1;
198
199 RT_ZERO(pXApicPage->lvt_lint0);
200 pXApicPage->lvt_lint0.u.u1Mask = 1;
201
202 RT_ZERO(pXApicPage->lvt_lint1);
203 pXApicPage->lvt_lint1.u.u1Mask = 1;
204
205 RT_ZERO(pXApicPage->lvt_error);
206 pXApicPage->lvt_error.u.u1Mask = 1;
207
208 RT_ZERO(pXApicPage->svr);
209 pXApicPage->svr.u.u8SpuriousVector = 0xff;
210
211 /* The self-IPI register is reset to 0. See Intel spec. 10.12.5.1 "x2APIC States" */
212 PX2APICPAGE pX2ApicPage = VMCPU_TO_X2APICPAGE(pVCpu);
213 RT_ZERO(pX2ApicPage->self_ipi);
214
215 /* Clear the pending-interrupt bitmaps. */
216 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
217 RT_BZERO(&pApicCpu->ApicPibLevel, sizeof(APICPIB));
218 RT_BZERO(pApicCpu->pvApicPibR3, sizeof(APICPIB));
219}
220
221
222/**
223 * Resets the APIC base MSR.
224 *
225 * @param pVCpu The cross context virtual CPU structure.
226 */
227static void apicR3ResetBaseMsr(PVMCPU pVCpu)
228{
229 /*
230 * Initialize the APIC base MSR. The APIC enable-bit is set upon power-up or reset[1].
231 *
232 * A Reset (in xAPIC and x2APIC mode) brings up the local APIC in xAPIC mode.
233 * An INIT IPI does -not- cause a transition between xAPIC and x2APIC mode[2].
234 *
235 * [1] See AMD spec. 14.1.3 "Processor Initialization State"
236 * [2] See Intel spec. 10.12.5.1 "x2APIC States".
237 */
238 VMCPU_ASSERT_EMT_OR_NOT_RUNNING(pVCpu);
239
240 /* Construct. */
241 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
242 PAPIC pApic = VM_TO_APIC(pVCpu->CTX_SUFF(pVM));
243 uint64_t uApicBaseMsr = MSR_IA32_APICBASE_ADDR;;
244 if (pVCpu->idCpu == 0)
245 uApicBaseMsr |= MSR_IA32_APICBASE_BSP;
246
247 /* If the VM was configured with disabled mode, don't enable xAPIC mode. */
248 if (pApic->enmOriginalMode != APICMODE_DISABLED)
249 {
250 uApicBaseMsr |= MSR_IA32_APICBASE_EN;
251
252 /** @todo CPUID bits needs to be done on a per-VCPU basis! */
253 CPUMSetGuestCpuIdFeature(pVCpu->CTX_SUFF(pVM), CPUMCPUIDFEATURE_APIC);
254 LogRel(("APIC%u: Switched mode to xAPIC\n", pVCpu->idCpu));
255 }
256
257 /* Commit. */
258 ASMAtomicWriteU64(&pApicCpu->uApicBaseMsr, uApicBaseMsr);
259}
260
261
262/**
263 * Initializes per-VCPU APIC to the state following a power-up or hardware
264 * reset.
265 *
266 * @param pVCpu The cross context virtual CPU structure.
267 * @param fResetApicBaseMsr Whether to reset the APIC base MSR.
268 */
269VMMR3_INT_DECL(void) APICR3Reset(PVMCPU pVCpu, bool fResetApicBaseMsr)
270{
271 VMCPU_ASSERT_EMT_OR_NOT_RUNNING(pVCpu);
272
273 LogFlow(("APIC%u: APICR3Reset: fResetApicBaseMsr=%RTbool\n", pVCpu->idCpu, fResetApicBaseMsr));
274
275#ifdef VBOX_STRICT
276 /* Verify that the initial APIC ID reported via CPUID matches our VMCPU ID assumption. */
277 uint32_t uEax, uEbx, uEcx, uEdx;
278 uEax = uEbx = uEcx = uEdx = UINT32_MAX;
279 CPUMGetGuestCpuId(pVCpu, 1, 0, &uEax, &uEbx, &uEcx, &uEdx);
280 Assert(((uEbx >> 24) & 0xff) == pVCpu->idCpu);
281#endif
282
283 /*
284 * The state following a power-up or reset is a superset of the INIT state.
285 * See Intel spec. 10.4.7.3 "Local APIC State After an INIT Reset ('Wait-for-SIPI' State)"
286 */
287 apicR3InitIpi(pVCpu);
288
289 /*
290 * The APIC version register is read-only, so just initialize it here.
291 * It is not clear from the specs, where exactly it is initialized.
292 * The version determines the number of LVT entries and size of the APIC ID (8 bits for P4).
293 */
294 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
295#if XAPIC_HARDWARE_VERSION == XAPIC_HARDWARE_VERSION_P4
296 pXApicPage->version.u.u8MaxLvtEntry = XAPIC_MAX_LVT_ENTRIES_P4 - 1;
297 pXApicPage->version.u.u8Version = XAPIC_HARDWARE_VERSION_P4;
298 AssertCompile(sizeof(pXApicPage->id.u8ApicId) >= XAPIC_APIC_ID_BIT_COUNT_P4 / 8);
299#else
300# error "Implement Pentium and P6 family APIC architectures"
301#endif
302
303 /** @todo It isn't clear in the spec. where exactly the default base address
304 * is (re)initialized, atm we do it here in Reset. */
305 if (fResetApicBaseMsr)
306 apicR3ResetBaseMsr(pVCpu);
307
308 /*
309 * Initialize the APIC ID register to xAPIC format.
310 */
311 ASMMemZero32(&pXApicPage->id, sizeof(pXApicPage->id));
312 pXApicPage->id.u8ApicId = pVCpu->idCpu;
313}
314
315
316/**
317 * Receives an INIT IPI.
318 *
319 * @param pVCpu The cross context virtual CPU structure.
320 */
321VMMR3_INT_DECL(void) APICR3InitIpi(PVMCPU pVCpu)
322{
323 VMCPU_ASSERT_EMT(pVCpu);
324 LogFlow(("APIC%u: APICR3InitIpi\n", pVCpu->idCpu));
325 apicR3InitIpi(pVCpu);
326}
327
328
329/**
330 * Helper for dumping an APIC 256-bit sparse register.
331 *
332 * @param pApicReg The APIC 256-bit spare register.
333 * @param pHlp The debug output helper.
334 */
335static void apicR3DbgInfo256BitReg(volatile const XAPIC256BITREG *pApicReg, PCDBGFINFOHLP pHlp)
336{
337 ssize_t const cFragments = RT_ELEMENTS(pApicReg->u);
338 unsigned const cBitsPerFragment = sizeof(pApicReg->u[0].u32Reg) * 8;
339 XAPIC256BITREG ApicReg;
340 RT_ZERO(ApicReg);
341
342 pHlp->pfnPrintf(pHlp, " ");
343 for (ssize_t i = cFragments - 1; i >= 0; i--)
344 {
345 uint32_t const uFragment = pApicReg->u[i].u32Reg;
346 ApicReg.u[i].u32Reg = uFragment;
347 pHlp->pfnPrintf(pHlp, "%08x", uFragment);
348 }
349 pHlp->pfnPrintf(pHlp, "\n");
350
351 uint32_t cPending = 0;
352 pHlp->pfnPrintf(pHlp, " Pending:");
353 for (ssize_t i = cFragments - 1; i >= 0; i--)
354 {
355 uint32_t uFragment = ApicReg.u[i].u32Reg;
356 if (uFragment)
357 {
358 do
359 {
360 unsigned idxSetBit = ASMBitLastSetU32(uFragment);
361 --idxSetBit;
362 ASMBitClear(&uFragment, idxSetBit);
363
364 idxSetBit += (i * cBitsPerFragment);
365 pHlp->pfnPrintf(pHlp, " %#02x", idxSetBit);
366 ++cPending;
367 } while (uFragment);
368 }
369 }
370 if (!cPending)
371 pHlp->pfnPrintf(pHlp, " None");
372 pHlp->pfnPrintf(pHlp, "\n");
373}
374
375
376/**
377 * Helper for dumping an APIC pending-interrupt bitmap.
378 *
379 * @param pApicPib The pending-interrupt bitmap.
380 * @param pHlp The debug output helper.
381 */
382static void apicR3DbgInfoPib(PCAPICPIB pApicPib, PCDBGFINFOHLP pHlp)
383{
384 /* Copy the pending-interrupt bitmap as an APIC 256-bit sparse register. */
385 XAPIC256BITREG ApicReg;
386 RT_ZERO(ApicReg);
387 ssize_t const cFragmentsDst = RT_ELEMENTS(ApicReg.u);
388 ssize_t const cFragmentsSrc = RT_ELEMENTS(pApicPib->aVectorBitmap);
389 AssertCompile(RT_ELEMENTS(ApicReg.u) == 2 * RT_ELEMENTS(pApicPib->aVectorBitmap));
390 for (ssize_t idxPib = cFragmentsSrc - 1, idxReg = cFragmentsDst - 1; idxPib >= 0; idxPib--, idxReg -= 2)
391 {
392 uint64_t const uFragment = pApicPib->aVectorBitmap[idxPib];
393 uint32_t const uFragmentLo = RT_LO_U32(uFragment);
394 uint32_t const uFragmentHi = RT_HI_U32(uFragment);
395 ApicReg.u[idxReg].u32Reg = uFragmentHi;
396 ApicReg.u[idxReg - 1].u32Reg = uFragmentLo;
397 }
398
399 /* Dump it. */
400 apicR3DbgInfo256BitReg(&ApicReg, pHlp);
401}
402
403
404/**
405 * Dumps basic APIC state.
406 *
407 * @param pVCpu The cross context virtual CPU structure.
408 * @param pHlp The info helpers.
409 * @param pszArgs Arguments, ignored.
410 */
411static DECLCALLBACK(void) apicR3Info(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
412{
413 NOREF(pszArgs);
414 PVMCPU pVCpu = VMMGetCpu(pVM); AssertFatalMsg(pVCpu, ("Invalid EMT thread. pVCpu=%p\n", pVCpu));
415 PCAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
416 PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
417 PCX2APICPAGE pX2ApicPage = VMCPU_TO_CX2APICPAGE(pVCpu);
418
419 uint64_t const uBaseMsr = pApicCpu->uApicBaseMsr;
420 APICMODE const enmMode = apicGetMode(uBaseMsr);
421 bool const fX2ApicMode = XAPIC_IN_X2APIC_MODE(pVCpu);
422
423 pHlp->pfnPrintf(pHlp, "VCPU[%u] APIC:\n", pVCpu->idCpu);
424 pHlp->pfnPrintf(pHlp, " APIC Base MSR = %#RX64 (Addr=%#RX64)\n", uBaseMsr,
425 MSR_IA32_APICBASE_GET_ADDR(uBaseMsr));
426 pHlp->pfnPrintf(pHlp, " Mode = %#x (%s)\n", enmMode, apicGetModeName(enmMode));
427 if (fX2ApicMode)
428 {
429 pHlp->pfnPrintf(pHlp, " APIC ID = %u (%#x)\n", pX2ApicPage->id.u32ApicId,
430 pX2ApicPage->id.u32ApicId);
431 }
432 else
433 pHlp->pfnPrintf(pHlp, " APIC ID = %u (%#x)\n", pXApicPage->id.u8ApicId, pXApicPage->id.u8ApicId);
434 pHlp->pfnPrintf(pHlp, " Version = %#x\n", pXApicPage->version.all.u32Version);
435 pHlp->pfnPrintf(pHlp, " APIC Version = %#x\n", pXApicPage->version.u.u8Version);
436 pHlp->pfnPrintf(pHlp, " Max LVT entry index (0..N) = %u\n", pXApicPage->version.u.u8MaxLvtEntry);
437 pHlp->pfnPrintf(pHlp, " EOI Broadcast supression = %RTbool\n", pXApicPage->version.u.fEoiBroadcastSupression);
438 if (!fX2ApicMode)
439 pHlp->pfnPrintf(pHlp, " APR = %u (%#x)\n", pXApicPage->apr.u8Apr, pXApicPage->apr.u8Apr);
440 pHlp->pfnPrintf(pHlp, " TPR = %u (%#x)\n", pXApicPage->tpr.u8Tpr, pXApicPage->tpr.u8Tpr);
441 pHlp->pfnPrintf(pHlp, " Task-priority class = %#x\n", XAPIC_TPR_GET_TP(pXApicPage->tpr.u8Tpr));
442 pHlp->pfnPrintf(pHlp, " Task-priority subclass = %#x\n", XAPIC_TPR_GET_TP_SUBCLASS(pXApicPage->tpr.u8Tpr));
443 pHlp->pfnPrintf(pHlp, " PPR = %u (%#x)\n", pXApicPage->ppr.u8Ppr, pXApicPage->ppr.u8Ppr);
444 pHlp->pfnPrintf(pHlp, " Processor-priority class = %#x\n", XAPIC_PPR_GET_PP(pXApicPage->ppr.u8Ppr));
445 pHlp->pfnPrintf(pHlp, " Processor-priority subclass = %#x\n", XAPIC_PPR_GET_PP_SUBCLASS(pXApicPage->ppr.u8Ppr));
446 if (!fX2ApicMode)
447 pHlp->pfnPrintf(pHlp, " RRD = %u (%#x)\n", pXApicPage->rrd.u32Rrd, pXApicPage->rrd.u32Rrd);
448 pHlp->pfnPrintf(pHlp, " LDR = %#x\n", pXApicPage->ldr.all.u32Ldr);
449 pHlp->pfnPrintf(pHlp, " Logical APIC ID = %#x\n", fX2ApicMode ? pX2ApicPage->ldr.u32LogicalApicId
450 : pXApicPage->ldr.u.u8LogicalApicId);
451 if (!fX2ApicMode)
452 {
453 pHlp->pfnPrintf(pHlp, " DFR = %#x\n", pXApicPage->dfr.all.u32Dfr);
454 pHlp->pfnPrintf(pHlp, " Model = %#x (%s)\n", pXApicPage->dfr.u.u4Model,
455 apicGetDestFormatName((XAPICDESTFORMAT)pXApicPage->dfr.u.u4Model));
456 }
457 pHlp->pfnPrintf(pHlp, " SVR\n");
458 pHlp->pfnPrintf(pHlp, " Vector = %u (%#x)\n", pXApicPage->svr.u.u8SpuriousVector,
459 pXApicPage->svr.u.u8SpuriousVector);
460 pHlp->pfnPrintf(pHlp, " Software Enabled = %RTbool\n", RT_BOOL(pXApicPage->svr.u.fApicSoftwareEnable));
461 pHlp->pfnPrintf(pHlp, " Supress EOI broadcast = %RTbool\n", RT_BOOL(pXApicPage->svr.u.fSupressEoiBroadcast));
462 pHlp->pfnPrintf(pHlp, " ISR\n");
463 apicR3DbgInfo256BitReg(&pXApicPage->isr, pHlp);
464 pHlp->pfnPrintf(pHlp, " TMR\n");
465 apicR3DbgInfo256BitReg(&pXApicPage->tmr, pHlp);
466 pHlp->pfnPrintf(pHlp, " IRR\n");
467 apicR3DbgInfo256BitReg(&pXApicPage->irr, pHlp);
468 pHlp->pfnPrintf(pHlp, " PIB\n");
469 apicR3DbgInfoPib((PCAPICPIB)pApicCpu->pvApicPibR3, pHlp);
470 pHlp->pfnPrintf(pHlp, " Level PIB\n");
471 apicR3DbgInfoPib(&pApicCpu->ApicPibLevel, pHlp);
472 pHlp->pfnPrintf(pHlp, " ESR Internal = %#x\n", pApicCpu->uEsrInternal);
473 pHlp->pfnPrintf(pHlp, " ESR = %#x\n", pXApicPage->esr.all.u32Errors);
474 pHlp->pfnPrintf(pHlp, " Redirectable IPI = %RTbool\n", pXApicPage->esr.u.fRedirectableIpi);
475 pHlp->pfnPrintf(pHlp, " Send Illegal Vector = %RTbool\n", pXApicPage->esr.u.fSendIllegalVector);
476 pHlp->pfnPrintf(pHlp, " Recv Illegal Vector = %RTbool\n", pXApicPage->esr.u.fRcvdIllegalVector);
477 pHlp->pfnPrintf(pHlp, " Illegal Register Address = %RTbool\n", pXApicPage->esr.u.fIllegalRegAddr);
478 pHlp->pfnPrintf(pHlp, " ICR Low = %#x\n", pXApicPage->icr_lo.all.u32IcrLo);
479 pHlp->pfnPrintf(pHlp, " Vector = %u (%#x)\n", pXApicPage->icr_lo.u.u8Vector,
480 pXApicPage->icr_lo.u.u8Vector);
481 pHlp->pfnPrintf(pHlp, " Delivery Mode = %#x (%s)\n", pXApicPage->icr_lo.u.u3DeliveryMode,
482 apicGetDeliveryModeName((XAPICDELIVERYMODE)pXApicPage->icr_lo.u.u3DeliveryMode));
483 pHlp->pfnPrintf(pHlp, " Destination Mode = %#x (%s)\n", pXApicPage->icr_lo.u.u1DestMode,
484 apicGetDestModeName((XAPICDESTMODE)pXApicPage->icr_lo.u.u1DestMode));
485 if (!fX2ApicMode)
486 pHlp->pfnPrintf(pHlp, " Delivery Status = %u\n", pXApicPage->icr_lo.u.u1DeliveryStatus);
487 pHlp->pfnPrintf(pHlp, " Level = %u\n", pXApicPage->icr_lo.u.u1Level);
488 pHlp->pfnPrintf(pHlp, " Trigger Mode = %u (%s)\n", pXApicPage->icr_lo.u.u1TriggerMode,
489 apicGetTriggerModeName((XAPICTRIGGERMODE)pXApicPage->icr_lo.u.u1TriggerMode));
490 pHlp->pfnPrintf(pHlp, " Destination shorthand = %#x (%s)\n", pXApicPage->icr_lo.u.u2DestShorthand,
491 apicGetDestShorthandName((XAPICDESTSHORTHAND)pXApicPage->icr_lo.u.u2DestShorthand));
492 pHlp->pfnPrintf(pHlp, " ICR High = %#x\n", pXApicPage->icr_hi.all.u32IcrHi);
493 pHlp->pfnPrintf(pHlp, " Destination field/mask = %#x\n", fX2ApicMode ? pX2ApicPage->icr_hi.u32IcrHi
494 : pXApicPage->icr_hi.u.u8Dest);
495}
496
497
498/**
499 * Helper for dumping the LVT timer.
500 *
501 * @param pVCpu The cross context virtual CPU structure.
502 * @param pHlp The debug output helper.
503 */
504static void apicR3InfoLvtTimer(PVMCPU pVCpu, PCDBGFINFOHLP pHlp)
505{
506 PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
507 uint32_t const uLvtTimer = pXApicPage->lvt_timer.all.u32LvtTimer;
508 pHlp->pfnPrintf(pHlp, "LVT Timer = %#RX32\n", uLvtTimer);
509 pHlp->pfnPrintf(pHlp, " Vector = %u (%#x)\n", pXApicPage->lvt_timer.u.u8Vector, pXApicPage->lvt_timer.u.u8Vector);
510 pHlp->pfnPrintf(pHlp, " Delivery status = %u\n", pXApicPage->lvt_timer.u.u1DeliveryStatus);
511 pHlp->pfnPrintf(pHlp, " Masked = %RTbool\n", XAPIC_LVT_IS_MASKED(uLvtTimer));
512 pHlp->pfnPrintf(pHlp, " Timer Mode = %#x (%s)\n", pXApicPage->lvt_timer.u.u2TimerMode,
513 apicGetTimerModeName((XAPICTIMERMODE)pXApicPage->lvt_timer.u.u2TimerMode));
514 pHlp->pfnPrintf(pHlp, "\n");
515}
516
517
518/**
519 * Dumps APIC Local Vector Table (LVT) information.
520 *
521 * @param pVCpu The cross context virtual CPU structure.
522 * @param pHlp The info helpers.
523 * @param pszArgs Arguments, ignored.
524 */
525static DECLCALLBACK(void) apicR3InfoLvt(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
526{
527 NOREF(pszArgs);
528 PVMCPU pVCpu = VMMGetCpu(pVM); AssertFatalMsg(pVCpu, ("Invalid EMT thread. pVCpu=%p\n", pVCpu));
529 PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
530
531 apicR3InfoLvtTimer(pVCpu, pHlp);
532
533#if XAPIC_HARDWARE_VERSION == XAPIC_HARDWARE_VERSION_P4
534 uint32_t const uLvtThermal = pXApicPage->lvt_thermal.all.u32LvtThermal;
535 pHlp->pfnPrintf(pHlp, "LVT Thermal = %#RX32)\n", uLvtThermal);
536 pHlp->pfnPrintf(pHlp, " Vector = %u (%#x)\n", pXApicPage->lvt_thermal.u.u8Vector,
537 pXApicPage->lvt_thermal.u.u8Vector);
538 pHlp->pfnPrintf(pHlp, " Delivery Mode = %#x (%s)\n", pXApicPage->lvt_thermal.u.u3DeliveryMode,
539 apicGetDeliveryModeName((XAPICDELIVERYMODE)pXApicPage->lvt_thermal.u.u3DeliveryMode));
540 pHlp->pfnPrintf(pHlp, " Delivery status = %u\n", pXApicPage->lvt_thermal.u.u1DeliveryStatus);
541 pHlp->pfnPrintf(pHlp, " Masked = %RTbool\n", XAPIC_LVT_IS_MASKED(uLvtThermal));
542 pHlp->pfnPrintf(pHlp, "\n");
543#endif
544
545 uint32_t const uLvtPerf = pXApicPage->lvt_perf.all.u32LvtPerf;
546 pHlp->pfnPrintf(pHlp, "LVT Perf = %#RX32\n", uLvtPerf);
547 pHlp->pfnPrintf(pHlp, " Vector = %u (%#x)\n", pXApicPage->lvt_perf.u.u8Vector, pXApicPage->lvt_perf.u.u8Vector);
548 pHlp->pfnPrintf(pHlp, " Delivery Mode = %#x (%s)\n", pXApicPage->lvt_perf.u.u3DeliveryMode,
549 apicGetDeliveryModeName((XAPICDELIVERYMODE)pXApicPage->lvt_perf.u.u3DeliveryMode));
550 pHlp->pfnPrintf(pHlp, " Delivery status = %u\n", pXApicPage->lvt_perf.u.u1DeliveryStatus);
551 pHlp->pfnPrintf(pHlp, " Masked = %RTbool\n", XAPIC_LVT_IS_MASKED(uLvtPerf));
552 pHlp->pfnPrintf(pHlp, "\n");
553
554 uint32_t const uLvtLint0 = pXApicPage->lvt_lint0.all.u32LvtLint0;
555 pHlp->pfnPrintf(pHlp, "LVT LINT0 = %#RX32\n", uLvtLint0);
556 pHlp->pfnPrintf(pHlp, " Vector = %u (%#x)\n", pXApicPage->lvt_lint0.u.u8Vector, pXApicPage->lvt_lint0.u.u8Vector);
557 pHlp->pfnPrintf(pHlp, " Delivery Mode = %#x (%s)\n", pXApicPage->lvt_lint0.u.u3DeliveryMode,
558 apicGetDeliveryModeName((XAPICDELIVERYMODE)pXApicPage->lvt_lint0.u.u3DeliveryMode));
559 pHlp->pfnPrintf(pHlp, " Delivery status = %u\n", pXApicPage->lvt_lint0.u.u1DeliveryStatus);
560 pHlp->pfnPrintf(pHlp, " Pin polarity = %u\n", pXApicPage->lvt_lint0.u.u1IntrPolarity);
561 pHlp->pfnPrintf(pHlp, " Remote IRR = %u\n", pXApicPage->lvt_lint0.u.u1RemoteIrr);
562 pHlp->pfnPrintf(pHlp, " Trigger Mode = %u (%s)\n", pXApicPage->lvt_lint0.u.u1TriggerMode,
563 apicGetTriggerModeName((XAPICTRIGGERMODE)pXApicPage->lvt_lint0.u.u1TriggerMode));
564 pHlp->pfnPrintf(pHlp, " Masked = %RTbool\n", XAPIC_LVT_IS_MASKED(uLvtLint0));
565 pHlp->pfnPrintf(pHlp, "\n");
566
567 uint32_t const uLvtLint1 = pXApicPage->lvt_lint1.all.u32LvtLint1;
568 pHlp->pfnPrintf(pHlp, "LVT LINT1 = %#RX32\n", uLvtLint1);
569 pHlp->pfnPrintf(pHlp, " Vector = %u (%#x)\n", pXApicPage->lvt_lint1.u.u8Vector, pXApicPage->lvt_lint1.u.u8Vector);
570 pHlp->pfnPrintf(pHlp, " Delivery Mode = %#x (%s)\n", pXApicPage->lvt_lint1.u.u3DeliveryMode,
571 apicGetDeliveryModeName((XAPICDELIVERYMODE)pXApicPage->lvt_lint1.u.u3DeliveryMode));
572 pHlp->pfnPrintf(pHlp, " Delivery status = %u\n", pXApicPage->lvt_lint1.u.u1DeliveryStatus);
573 pHlp->pfnPrintf(pHlp, " Pin polarity = %u\n", pXApicPage->lvt_lint1.u.u1IntrPolarity);
574 pHlp->pfnPrintf(pHlp, " Remote IRR = %u\n", pXApicPage->lvt_lint1.u.u1RemoteIrr);
575 pHlp->pfnPrintf(pHlp, " Trigger Mode = %u (%s)\n", pXApicPage->lvt_lint1.u.u1TriggerMode,
576 apicGetTriggerModeName((XAPICTRIGGERMODE)pXApicPage->lvt_lint1.u.u1TriggerMode));
577 pHlp->pfnPrintf(pHlp, " Masked = %RTbool\n", XAPIC_LVT_IS_MASKED(uLvtLint1));
578 pHlp->pfnPrintf(pHlp, "\n");
579
580 uint32_t const uLvtError = pXApicPage->lvt_error.all.u32LvtError;
581 pHlp->pfnPrintf(pHlp, "LVT Error = %#RX32\n", uLvtError);
582 pHlp->pfnPrintf(pHlp, " Vector = %u (%#x)\n", pXApicPage->lvt_error.u.u8Vector, pXApicPage->lvt_error.u.u8Vector);
583 pHlp->pfnPrintf(pHlp, " Delivery status = %u\n", pXApicPage->lvt_error.u.u1DeliveryStatus);
584 pHlp->pfnPrintf(pHlp, " Masked = %RTbool\n", XAPIC_LVT_IS_MASKED(uLvtError));
585 pHlp->pfnPrintf(pHlp, "\n");
586}
587
588
589/**
590 * Dumps the APIC timer information.
591 *
592 * @param pVCpu The cross context virtual CPU structure.
593 * @param pHlp The info helpers.
594 * @param pszArgs Arguments, ignored.
595 */
596static DECLCALLBACK(void) apicR3InfoTimer(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
597{
598 NOREF(pszArgs);
599 PVMCPU pVCpu = VMMGetCpu(pVM); AssertFatalMsg(pVCpu, ("Invalid EMT thread. pVCpu=%p\n", pVCpu));
600 PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
601 PCAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
602
603 pHlp->pfnPrintf(pHlp, "Local APIC timer:\n");
604 pHlp->pfnPrintf(pHlp, " ICR = %#RX32\n", pXApicPage->timer_icr.u32InitialCount);
605 pHlp->pfnPrintf(pHlp, " CCR = %#RX32\n", pXApicPage->timer_ccr.u32CurrentCount);
606 pHlp->pfnPrintf(pHlp, " DCR = %#RX32\n", pXApicPage->timer_dcr.all.u32DivideValue);
607 pHlp->pfnPrintf(pHlp, " Timer shift = %#x\n", apicGetTimerShift(pXApicPage));
608 pHlp->pfnPrintf(pHlp, " Timer initial TS = %#RU64\n", pApicCpu->u64TimerInitial);
609 pHlp->pfnPrintf(pHlp, "\n");
610
611 apicR3InfoLvtTimer(pVCpu, pHlp);
612}
613
614
615/**
616 * Converts legacy PDMAPICMODE to the new APICMODE enum.
617 *
618 * @returns The new APIC mode.
619 * @param enmLegacyMode The legacy mode to convert.
620 */
621static APICMODE apicR3ConvertFromLegacyApicMode(PDMAPICMODE enmLegacyMode)
622{
623 switch (enmLegacyMode)
624 {
625 case PDMAPICMODE_NONE: return APICMODE_DISABLED;
626 case PDMAPICMODE_APIC: return APICMODE_XAPIC;
627 case PDMAPICMODE_X2APIC: return APICMODE_X2APIC;
628 case PDMAPICMODE_INVALID: return APICMODE_INVALID;
629 default: break;
630 }
631 return (APICMODE)enmLegacyMode;
632}
633
634
635/**
636 * Converts the new APICMODE enum to the legacy PDMAPICMODE enum.
637 *
638 * @returns The legacy APIC mode.
639 * @param enmMode The APIC mode to convert.
640 */
641static PDMAPICMODE apicR3ConvertToLegacyApicMode(APICMODE enmMode)
642{
643 switch (enmMode)
644 {
645 case APICMODE_DISABLED: return PDMAPICMODE_NONE;
646 case APICMODE_XAPIC: return PDMAPICMODE_APIC;
647 case APICMODE_X2APIC: return PDMAPICMODE_X2APIC;
648 case APICMODE_INVALID: return PDMAPICMODE_INVALID;
649 default: break;
650 }
651 return (PDMAPICMODE)enmMode;
652}
653
654
655#ifdef APIC_FUZZY_SSM_COMPAT_TEST
656/**
657 * Reads a 32-bit register at a specified offset.
658 *
659 * @returns The value at the specified offset.
660 * @param pXApicPage The xAPIC page.
661 * @param offReg The offset of the register being read.
662 *
663 * @remarks Duplicate of apicReadRaw32()!
664 */
665static uint32_t apicR3ReadRawR32(PCXAPICPAGE pXApicPage, uint16_t offReg)
666{
667 Assert(offReg < sizeof(*pXApicPage) - sizeof(uint32_t));
668 uint8_t const *pbXApic = (const uint8_t *)pXApicPage;
669 uint32_t const uValue = *(const uint32_t *)(pbXApic + offReg);
670 return uValue;
671}
672
673
674/**
675 * Helper for dumping per-VCPU APIC state to the release logger.
676 *
677 * This is primarily concerned about the APIC state relevant for saved-states.
678 *
679 * @param pVCpu The cross context virtual CPU structure.
680 * @param pszPrefix A caller supplied prefix before dumping the state.
681 * @param uVersion Data layout version.
682 */
683static void apicR3DumpState(PVMCPU pVCpu, const char *pszPrefix, uint32_t uVersion)
684{
685 PCAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
686
687 LogRel(("APIC%u: %s (version %u):\n", pVCpu->idCpu, pszPrefix, uVersion));
688
689 switch (uVersion)
690 {
691 case APIC_SAVED_STATE_VERSION:
692 {
693 /* The auxiliary state. */
694 LogRel(("APIC%u: uApicBaseMsr = %#RX64\n", pVCpu->idCpu, pApicCpu->uApicBaseMsr));
695 LogRel(("APIC%u: uEsrInternal = %#RX64\n", pVCpu->idCpu, pApicCpu->uEsrInternal));
696
697 /* The timer. */
698 LogRel(("APIC%u: u64TimerInitial = %#RU64\n", pVCpu->idCpu, pApicCpu->u64TimerInitial));
699 LogRel(("APIC%u: uHintedTimerInitialCount = %#RU64\n", pVCpu->idCpu, pApicCpu->uHintedTimerInitialCount));
700 LogRel(("APIC%u: uHintedTimerShift = %#RU64\n", pVCpu->idCpu, pApicCpu->uHintedTimerShift));
701
702 PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
703 LogRel(("APIC%u: uTimerICR = %#RX32\n", pVCpu->idCpu, pXApicPage->timer_icr.u32InitialCount));
704 LogRel(("APIC%u: uTimerCCR = %#RX32\n", pVCpu->idCpu, pXApicPage->timer_ccr.u32CurrentCount));
705
706 /* The PIBs. */
707 LogRel(("APIC%u: Edge PIB : %.*Rhxs\n", pVCpu->idCpu, sizeof(APICPIB), pApicCpu->pvApicPibR3));
708 LogRel(("APIC%u: Level PIB: %.*Rhxs\n", pVCpu->idCpu, sizeof(APICPIB), &pApicCpu->ApicPibLevel));
709
710 /* The APIC page. */
711 LogRel(("APIC%u: APIC page: %.*Rhxs\n", pVCpu->idCpu, sizeof(XAPICPAGE), pApicCpu->pvApicPageR3));
712 break;
713 }
714
715 case APIC_SAVED_STATE_VERSION_VBOX_50:
716 case APIC_SAVED_STATE_VERSION_VBOX_30:
717 case APIC_SAVED_STATE_VERSION_ANCIENT:
718 {
719 PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
720 LogRel(("APIC%u: uApicBaseMsr = %#RX32\n", pVCpu->idCpu, RT_LO_U32(pApicCpu->uApicBaseMsr)));
721 LogRel(("APIC%u: uId = %#RX32\n", pVCpu->idCpu, pXApicPage->id.u8ApicId));
722 LogRel(("APIC%u: uPhysId = N/A\n", pVCpu->idCpu));
723 LogRel(("APIC%u: uArbId = N/A\n", pVCpu->idCpu));
724 LogRel(("APIC%u: uTpr = %#RX32\n", pVCpu->idCpu, pXApicPage->tpr.u8Tpr));
725 LogRel(("APIC%u: uSvr = %#RX32\n", pVCpu->idCpu, pXApicPage->svr.all.u32Svr));
726 LogRel(("APIC%u: uLdr = %#x\n", pVCpu->idCpu, pXApicPage->ldr.all.u32Ldr));
727 LogRel(("APIC%u: uDfr = %#x\n", pVCpu->idCpu, pXApicPage->dfr.all.u32Dfr));
728
729 for (size_t i = 0; i < 8; i++)
730 {
731 LogRel(("APIC%u: Isr[%u].u32Reg = %#RX32\n", pVCpu->idCpu, i, pXApicPage->isr.u[i].u32Reg));
732 LogRel(("APIC%u: Tmr[%u].u32Reg = %#RX32\n", pVCpu->idCpu, i, pXApicPage->tmr.u[i].u32Reg));
733 LogRel(("APIC%u: Irr[%u].u32Reg = %#RX32\n", pVCpu->idCpu, i, pXApicPage->irr.u[i].u32Reg));
734 }
735
736 for (size_t i = 0; i < XAPIC_MAX_LVT_ENTRIES_P4; i++)
737 {
738 uint16_t const offReg = XAPIC_OFF_LVT_START + (i << 4);
739 LogRel(("APIC%u: Lvt[%u].u32Reg = %#RX32\n", pVCpu->idCpu, i, apicR3ReadRawR32(pXApicPage, offReg)));
740 }
741
742 LogRel(("APIC%u: uEsr = %#RX32\n", pVCpu->idCpu, pXApicPage->esr.all.u32Errors));
743 LogRel(("APIC%u: uIcr_Lo = %#RX32\n", pVCpu->idCpu, pXApicPage->icr_lo.all.u32IcrLo));
744 LogRel(("APIC%u: uIcr_Hi = %#RX32\n", pVCpu->idCpu, pXApicPage->icr_hi.all.u32IcrHi));
745 LogRel(("APIC%u: uTimerDcr = %#RX32\n", pVCpu->idCpu, pXApicPage->timer_dcr.all.u32DivideValue));
746 LogRel(("APIC%u: uCountShift = %#RX32\n", pVCpu->idCpu, apicGetTimerShift(pXApicPage)));
747 LogRel(("APIC%u: uInitialCount = %#RX32\n", pVCpu->idCpu, pXApicPage->timer_icr.u32InitialCount));
748 LogRel(("APIC%u: u64InitialCountLoadTime = %#RX64\n", pVCpu->idCpu, pApicCpu->u64TimerInitial));
749 LogRel(("APIC%u: u64NextTime / TimerCCR = %#RX64\n", pVCpu->idCpu, pXApicPage->timer_ccr.u32CurrentCount));
750 break;
751 }
752
753 default:
754 {
755 LogRel(("APIC: apicR3DumpState: Invalid/unrecognized saved-state version %u (%#x)\n", uVersion, uVersion));
756 break;
757 }
758 }
759}
760#endif /* APIC_FUZZY_SSM_COMPAT_TEST */
761
762
763/**
764 * Worker for saving per-VM APIC data.
765 *
766 * @returns VBox status code.
767 * @param pVM The cross context VM structure.
768 * @param pSSM The SSM handle.
769 */
770static int apicR3SaveVMData(PVM pVM, PSSMHANDLE pSSM)
771{
772 PAPIC pApic = VM_TO_APIC(pVM);
773 SSMR3PutU32(pSSM, pVM->cCpus);
774 SSMR3PutBool(pSSM, pApic->fIoApicPresent);
775 return SSMR3PutU32(pSSM, apicR3ConvertToLegacyApicMode(pApic->enmOriginalMode));
776}
777
778
779/**
780 * Worker for loading per-VM APIC data.
781 *
782 * @returns VBox status code.
783 * @param pVM The cross context VM structure.
784 * @param pSSM The SSM handle.
785 */
786static int apicR3LoadVMData(PVM pVM, PSSMHANDLE pSSM)
787{
788 PAPIC pApic = VM_TO_APIC(pVM);
789
790 /* Load and verify number of CPUs. */
791 uint32_t cCpus;
792 int rc = SSMR3GetU32(pSSM, &cCpus);
793 AssertRCReturn(rc, rc);
794 if (cCpus != pVM->cCpus)
795 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - cCpus: saved=%u config=%u"), cCpus, pVM->cCpus);
796
797 /* Load and verify I/O APIC presence. */
798 bool fIoApicPresent;
799 rc = SSMR3GetBool(pSSM, &fIoApicPresent);
800 AssertRCReturn(rc, rc);
801 if (fIoApicPresent != pApic->fIoApicPresent)
802 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - fIoApicPresent: saved=%RTbool config=%RTbool"),
803 fIoApicPresent, pApic->fIoApicPresent);
804
805 /* Load and verify configured APIC mode. */
806 uint32_t uLegacyApicMode;
807 rc = SSMR3GetU32(pSSM, &uLegacyApicMode);
808 AssertRCReturn(rc, rc);
809 APICMODE const enmApicMode = apicR3ConvertFromLegacyApicMode((PDMAPICMODE)uLegacyApicMode);
810 if (enmApicMode != pApic->enmOriginalMode)
811 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - uApicMode: saved=%u (%u) config=%u (%u)"),
812 uLegacyApicMode, enmApicMode, apicR3ConvertToLegacyApicMode(pApic->enmOriginalMode),
813 pApic->enmOriginalMode);
814 return VINF_SUCCESS;
815}
816
817
818/**
819 * Worker for loading per-VCPU APIC data for legacy (old) saved-states.
820 *
821 * @returns VBox status code.
822 * @param pVM The cross context VM structure.
823 * @param pVCpu The cross context virtual CPU structure.
824 * @param pSSM The SSM handle.
825 * @param uVersion Data layout version.
826 */
827static int apicR3LoadLegacyVCpuData(PVM pVM, PVMCPU pVCpu, PSSMHANDLE pSSM, uint32_t uVersion)
828{
829 AssertReturn(uVersion <= APIC_SAVED_STATE_VERSION_VBOX_50, VERR_NOT_SUPPORTED);
830
831 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
832 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
833
834 uint32_t uApicBaseLo;
835 int rc = SSMR3GetU32(pSSM, &uApicBaseLo);
836 AssertRCReturn(rc, rc);
837 pApicCpu->uApicBaseMsr = uApicBaseLo;
838 Log2(("APIC%u: apicR3LoadLegacyVCpuData: uApicBaseMsr=%#RX64\n", pVCpu->idCpu, pApicCpu->uApicBaseMsr));
839
840 switch (uVersion)
841 {
842 case APIC_SAVED_STATE_VERSION_VBOX_50:
843 case APIC_SAVED_STATE_VERSION_VBOX_30:
844 {
845 uint32_t uApicId, uPhysApicId, uArbId;
846 SSMR3GetU32(pSSM, &uApicId); pXApicPage->id.u8ApicId = uApicId;
847 SSMR3GetU32(pSSM, &uPhysApicId); NOREF(uPhysApicId); /* PhysId == pVCpu->idCpu */
848 SSMR3GetU32(pSSM, &uArbId); NOREF(uArbId); /* ArbID is & was unused. */
849 break;
850 }
851
852 case APIC_SAVED_STATE_VERSION_ANCIENT:
853 {
854 uint8_t uPhysApicId;
855 SSMR3GetU8(pSSM, &pXApicPage->id.u8ApicId);
856 SSMR3GetU8(pSSM, &uPhysApicId); NOREF(uPhysApicId); /* PhysId == pVCpu->idCpu */
857 break;
858 }
859
860 default:
861 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
862 }
863
864 uint32_t u32Tpr;
865 SSMR3GetU32(pSSM, &u32Tpr);
866 pXApicPage->tpr.u8Tpr = u32Tpr & XAPIC_TPR_VALID;
867
868 SSMR3GetU32(pSSM, &pXApicPage->svr.all.u32Svr);
869 SSMR3GetU8(pSSM, &pXApicPage->ldr.u.u8LogicalApicId);
870
871 uint8_t uDfr;
872 SSMR3GetU8(pSSM, &uDfr);
873 pXApicPage->dfr.u.u4Model = uDfr >> 4;
874
875 AssertCompile(RT_ELEMENTS(pXApicPage->isr.u) == 8);
876 AssertCompile(RT_ELEMENTS(pXApicPage->tmr.u) == 8);
877 AssertCompile(RT_ELEMENTS(pXApicPage->irr.u) == 8);
878 for (size_t i = 0; i < 8; i++)
879 {
880 SSMR3GetU32(pSSM, &pXApicPage->isr.u[i].u32Reg);
881 SSMR3GetU32(pSSM, &pXApicPage->tmr.u[i].u32Reg);
882 SSMR3GetU32(pSSM, &pXApicPage->irr.u[i].u32Reg);
883 }
884
885 SSMR3GetU32(pSSM, &pXApicPage->lvt_timer.all.u32LvtTimer);
886 SSMR3GetU32(pSSM, &pXApicPage->lvt_thermal.all.u32LvtThermal);
887 SSMR3GetU32(pSSM, &pXApicPage->lvt_perf.all.u32LvtPerf);
888 SSMR3GetU32(pSSM, &pXApicPage->lvt_lint0.all.u32LvtLint0);
889 SSMR3GetU32(pSSM, &pXApicPage->lvt_lint1.all.u32LvtLint1);
890 SSMR3GetU32(pSSM, &pXApicPage->lvt_error.all.u32LvtError);
891
892 SSMR3GetU32(pSSM, &pXApicPage->esr.all.u32Errors);
893 SSMR3GetU32(pSSM, &pXApicPage->icr_lo.all.u32IcrLo);
894 SSMR3GetU32(pSSM, &pXApicPage->icr_hi.all.u32IcrHi);
895
896 uint32_t u32TimerShift;
897 SSMR3GetU32(pSSM, &pXApicPage->timer_dcr.all.u32DivideValue);
898 SSMR3GetU32(pSSM, &u32TimerShift);
899 /*
900 * Old implementation may have left the timer shift uninitialized until
901 * the timer configuration register was written. Unfortunately zero is
902 * also a valid timer shift value, so we're just going to ignore it
903 * completely. The shift count can always be derived from the DCR.
904 * See @bugref{8245#c98}.
905 */
906 uint8_t const uTimerShift = apicGetTimerShift(pXApicPage);
907
908 SSMR3GetU32(pSSM, &pXApicPage->timer_icr.u32InitialCount);
909 SSMR3GetU64(pSSM, &pApicCpu->u64TimerInitial);
910 uint64_t uNextTS;
911 rc = SSMR3GetU64(pSSM, &uNextTS); AssertRCReturn(rc, rc);
912 if (uNextTS >= pApicCpu->u64TimerInitial + ((pXApicPage->timer_icr.u32InitialCount + 1) << uTimerShift))
913 pXApicPage->timer_ccr.u32CurrentCount = pXApicPage->timer_icr.u32InitialCount;
914
915 rc = TMR3TimerLoad(pApicCpu->pTimerR3, pSSM);
916 AssertRCReturn(rc, rc);
917 Assert(pApicCpu->uHintedTimerInitialCount == 0);
918 Assert(pApicCpu->uHintedTimerShift == 0);
919 if (TMTimerIsActive(pApicCpu->pTimerR3))
920 {
921 uint32_t const uInitialCount = pXApicPage->timer_icr.u32InitialCount;
922 apicHintTimerFreq(pApicCpu, uInitialCount, uTimerShift);
923 }
924
925 return rc;
926}
927
928
929/**
930 * @copydoc FNSSMDEVLIVEEXEC
931 */
932static DECLCALLBACK(int) apicR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
933{
934 PAPICDEV pApicDev = PDMINS_2_DATA(pDevIns, PAPICDEV);
935 PVM pVM = PDMDevHlpGetVM(pApicDev->pDevInsR3);
936
937 LogFlow(("APIC: apicR3LiveExec: uPass=%u\n", uPass));
938
939 int rc = apicR3SaveVMData(pVM, pSSM);
940 AssertRCReturn(rc, rc);
941 return VINF_SSM_DONT_CALL_AGAIN;
942}
943
944
945/**
946 * @copydoc FNSSMDEVSAVEEXEC
947 */
948static DECLCALLBACK(int) apicR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
949{
950 PAPICDEV pApicDev = PDMINS_2_DATA(pDevIns, PAPICDEV);
951 PVM pVM = PDMDevHlpGetVM(pDevIns);
952 PAPIC pApic = VM_TO_APIC(pVM);
953 AssertReturn(pVM, VERR_INVALID_VM_HANDLE);
954
955 LogFlow(("APIC: apicR3SaveExec\n"));
956
957 /* Save per-VM data. */
958 int rc = apicR3SaveVMData(pVM, pSSM);
959 AssertRCReturn(rc, rc);
960
961 /* Save per-VCPU data.*/
962 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
963 {
964 PVMCPU pVCpu = &pVM->aCpus[idCpu];
965 PCAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
966
967 /* Update interrupts from the pending-interrupts bitmaps to the IRR. */
968 APICUpdatePendingInterrupts(pVCpu);
969
970 /* Save the auxiliary data. */
971 SSMR3PutU64(pSSM, pApicCpu->uApicBaseMsr);
972 SSMR3PutU32(pSSM, pApicCpu->uEsrInternal);
973
974 /* Save the APIC page. */
975 if (XAPIC_IN_X2APIC_MODE(pVCpu))
976 SSMR3PutStruct(pSSM, (const void *)pApicCpu->pvApicPageR3, &g_aX2ApicPageFields[0]);
977 else
978 SSMR3PutStruct(pSSM, (const void *)pApicCpu->pvApicPageR3, &g_aXApicPageFields[0]);
979
980 /* Save the timer. */
981 SSMR3PutU64(pSSM, pApicCpu->u64TimerInitial);
982 TMR3TimerSave(pApicCpu->pTimerR3, pSSM);
983
984#if defined(APIC_FUZZY_SSM_COMPAT_TEST) || defined(DEBUG_ramshankar)
985 apicR3DumpState(pVCpu, "Saved state", APIC_SAVED_STATE_VERSION);
986#endif
987 }
988
989#ifdef APIC_FUZZY_SSM_COMPAT_TEST
990 /* The state is fuzzy, don't even bother trying to load the guest. */
991 return VERR_INVALID_STATE;
992#else
993 return rc;
994#endif
995}
996
997
998/**
999 * @copydoc FNSSMDEVLOADEXEC
1000 */
1001static DECLCALLBACK(int) apicR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1002{
1003 PAPICDEV pApicDev = PDMINS_2_DATA(pDevIns, PAPICDEV);
1004 PVM pVM = PDMDevHlpGetVM(pDevIns);
1005 PAPIC pApic = VM_TO_APIC(pVM);
1006
1007 AssertReturn(pVM, VERR_INVALID_VM_HANDLE);
1008 AssertReturn(uPass == SSM_PASS_FINAL, VERR_WRONG_ORDER);
1009
1010 LogFlow(("APIC: apicR3LoadExec: uVersion=%u uPass=%#x\n", uVersion, uPass));
1011
1012 /* Weed out invalid versions. */
1013 if ( uVersion != APIC_SAVED_STATE_VERSION
1014 && uVersion != APIC_SAVED_STATE_VERSION_VBOX_50
1015 && uVersion != APIC_SAVED_STATE_VERSION_VBOX_30
1016 && uVersion != APIC_SAVED_STATE_VERSION_ANCIENT)
1017 {
1018 LogRel(("APIC: apicR3LoadExec: Invalid/unrecognized saved-state version %u (%#x)\n", uVersion, uVersion));
1019 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1020 }
1021
1022 int rc = VINF_SUCCESS;
1023 if (uVersion > APIC_SAVED_STATE_VERSION_VBOX_30)
1024 {
1025 rc = apicR3LoadVMData(pVM, pSSM);
1026 AssertRCReturn(rc, rc);
1027
1028 if (uVersion == APIC_SAVED_STATE_VERSION)
1029 { /* Load any new additional per-VM data. */ }
1030 }
1031
1032 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1033 {
1034 PVMCPU pVCpu = &pVM->aCpus[idCpu];
1035 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
1036
1037 if (uVersion == APIC_SAVED_STATE_VERSION)
1038 {
1039 /* Load the auxiliary data. */
1040 SSMR3GetU64(pSSM, (uint64_t *)&pApicCpu->uApicBaseMsr);
1041 SSMR3GetU32(pSSM, &pApicCpu->uEsrInternal);
1042
1043 /* Load the APIC page. */
1044 if (XAPIC_IN_X2APIC_MODE(pVCpu))
1045 SSMR3GetStruct(pSSM, pApicCpu->pvApicPageR3, &g_aX2ApicPageFields[0]);
1046 else
1047 SSMR3GetStruct(pSSM, pApicCpu->pvApicPageR3, &g_aXApicPageFields[0]);
1048
1049 /* Load the timer. */
1050 rc = SSMR3GetU64(pSSM, &pApicCpu->u64TimerInitial); AssertRCReturn(rc, rc);
1051 rc = TMR3TimerLoad(pApicCpu->pTimerR3, pSSM); AssertRCReturn(rc, rc);
1052 Assert(pApicCpu->uHintedTimerShift == 0);
1053 Assert(pApicCpu->uHintedTimerInitialCount == 0);
1054 if (TMTimerIsActive(pApicCpu->pTimerR3))
1055 {
1056 PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
1057 uint32_t const uInitialCount = pXApicPage->timer_icr.u32InitialCount;
1058 uint8_t const uTimerShift = apicGetTimerShift(pXApicPage);
1059 apicHintTimerFreq(pApicCpu, uInitialCount, uTimerShift);
1060 }
1061 }
1062 else
1063 {
1064 rc = apicR3LoadLegacyVCpuData(pVM, pVCpu, pSSM, uVersion);
1065 AssertRCReturn(rc, rc);
1066 }
1067
1068#if defined(APIC_FUZZY_SSM_COMPAT_TEST) || defined(DEBUG_ramshankar)
1069 apicR3DumpState(pVCpu, "Loaded state", uVersion);
1070#endif
1071 }
1072
1073 return rc;
1074}
1075
1076
1077/**
1078 * The timer callback.
1079 *
1080 * @param pDevIns The device instance.
1081 * @param pTimer The timer handle.
1082 * @param pvUser Opaque pointer to the VMCPU.
1083 *
1084 * @thread Any.
1085 * @remarks Currently this function is invoked on the last EMT, see @c
1086 * idTimerCpu in tmR3TimerCallback(). However, the code does -not-
1087 * rely on this and is designed to work with being invoked on any
1088 * thread.
1089 */
1090static DECLCALLBACK(void) apicR3TimerCallback(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
1091{
1092 PVMCPU pVCpu = (PVMCPU)pvUser;
1093 Assert(TMTimerIsLockOwner(pTimer));
1094 Assert(pVCpu);
1095 LogFlow(("APIC%u: apicR3TimerCallback\n", pVCpu->idCpu));
1096
1097 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
1098 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
1099 uint32_t const uLvtTimer = pXApicPage->lvt_timer.all.u32LvtTimer;
1100 STAM_COUNTER_INC(&pApicCpu->StatTimerCallback);
1101 if (!XAPIC_LVT_IS_MASKED(uLvtTimer))
1102 {
1103 uint8_t uVector = XAPIC_LVT_GET_VECTOR(uLvtTimer);
1104 Log2(("APIC%u: apicR3TimerCallback: Raising timer interrupt. uVector=%#x\n", pVCpu->idCpu, uVector));
1105 APICPostInterrupt(pVCpu, uVector, XAPICTRIGGERMODE_EDGE);
1106 }
1107
1108 XAPICTIMERMODE enmTimerMode = XAPIC_LVT_GET_TIMER_MODE(uLvtTimer);
1109 switch (enmTimerMode)
1110 {
1111 case XAPICTIMERMODE_PERIODIC:
1112 {
1113 /* The initial-count register determines if the periodic timer is re-armed. */
1114 uint32_t const uInitialCount = pXApicPage->timer_icr.u32InitialCount;
1115 pXApicPage->timer_ccr.u32CurrentCount = uInitialCount;
1116 if (uInitialCount)
1117 {
1118 Log2(("APIC%u: apicR3TimerCallback: Re-arming timer. uInitialCount=%#RX32\n", pVCpu->idCpu, uInitialCount));
1119 APICStartTimer(pVCpu, uInitialCount);
1120 }
1121 break;
1122 }
1123
1124 case XAPICTIMERMODE_ONESHOT:
1125 {
1126 pXApicPage->timer_ccr.u32CurrentCount = 0;
1127 break;
1128 }
1129
1130 case XAPICTIMERMODE_TSC_DEADLINE:
1131 {
1132 /** @todo implement TSC deadline. */
1133 AssertMsgFailed(("APIC: TSC deadline mode unimplemented\n"));
1134 break;
1135 }
1136 }
1137}
1138
1139
1140/**
1141 * @interface_method_impl{PDMDEVREG,pfnReset}
1142 */
1143static DECLCALLBACK(void) apicR3Reset(PPDMDEVINS pDevIns)
1144{
1145 PAPICDEV pApicDev = PDMINS_2_DATA(pDevIns, PAPICDEV);
1146 PVM pVM = PDMDevHlpGetVM(pDevIns);
1147 VM_ASSERT_EMT0(pVM);
1148 VM_ASSERT_IS_NOT_RUNNING(pVM);
1149
1150 LogFlow(("APIC: apicR3Reset\n"));
1151
1152 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1153 {
1154 PVMCPU pVCpuDest = &pVM->aCpus[idCpu];
1155 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpuDest);
1156
1157 if (TMTimerIsActive(pApicCpu->pTimerR3))
1158 TMTimerStop(pApicCpu->pTimerR3);
1159
1160 APICR3Reset(pVCpuDest, true /* fResetApicBaseMsr */);
1161
1162 /* Clear the interrupt pending force flag. */
1163 APICClearInterruptFF(pVCpuDest, PDMAPICIRQ_HARDWARE);
1164 }
1165}
1166
1167
1168/**
1169 * @interface_method_impl{PDMDEVREG,pfnRelocate}
1170 */
1171static DECLCALLBACK(void) apicR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
1172{
1173 PVM pVM = PDMDevHlpGetVM(pDevIns);
1174 PAPIC pApic = VM_TO_APIC(pVM);
1175 PAPICDEV pApicDev = PDMINS_2_DATA(pDevIns, PAPICDEV);
1176
1177 LogFlow(("APIC: apicR3Relocate: pVM=%p pDevIns=%p offDelta=%RGi\n", pVM, pDevIns, offDelta));
1178
1179 pApicDev->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1180 pApicDev->pApicHlpRC = pApicDev->pApicHlpR3->pfnGetRCHelpers(pDevIns);
1181 pApicDev->pCritSectRC = pApicDev->pApicHlpR3->pfnGetRCCritSect(pDevIns);
1182
1183 pApic->pApicDevRC = PDMINS_2_DATA_RCPTR(pDevIns);
1184 pApic->pvApicPibRC += offDelta;
1185
1186 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1187 {
1188 PVMCPU pVCpu = &pVM->aCpus[idCpu];
1189 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
1190 pApicCpu->pTimerRC = TMTimerRCPtr(pApicCpu->pTimerR3);
1191
1192 pApicCpu->pvApicPageRC += offDelta;
1193 pApicCpu->pvApicPibRC += offDelta;
1194 Log2(("APIC%u: apicR3Relocate: APIC PIB at %RGv\n", pVCpu->idCpu, pApicCpu->pvApicPibRC));
1195 }
1196}
1197
1198
1199/**
1200 * Terminates the APIC state.
1201 *
1202 * @param pVM The cross context VM structure.
1203 */
1204static void apicR3TermState(PVM pVM)
1205{
1206 PAPIC pApic = VM_TO_APIC(pVM);
1207 LogFlow(("APIC: apicR3TermState: pVM=%p\n", pVM));
1208
1209 /* Unmap and free the PIB. */
1210 if (pApic->pvApicPibR3 != NIL_RTR3PTR)
1211 {
1212 size_t const cPages = pApic->cbApicPib >> PAGE_SHIFT;
1213 if (cPages == 1)
1214 SUPR3PageFreeEx(pApic->pvApicPibR3, cPages);
1215 else
1216 SUPR3ContFree(pApic->pvApicPibR3, cPages);
1217 pApic->pvApicPibR3 = NIL_RTR3PTR;
1218 pApic->pvApicPibR0 = NIL_RTR0PTR;
1219 pApic->pvApicPibRC = NIL_RTRCPTR;
1220 }
1221
1222 /* Unmap and free the virtual-APIC pages. */
1223 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1224 {
1225 PVMCPU pVCpu = &pVM->aCpus[idCpu];
1226 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
1227
1228 pApicCpu->pvApicPibR3 = NIL_RTR3PTR;
1229 pApicCpu->pvApicPibR0 = NIL_RTR0PTR;
1230 pApicCpu->pvApicPibRC = NIL_RTRCPTR;
1231
1232 if (pApicCpu->pvApicPageR3 != NIL_RTR3PTR)
1233 {
1234 SUPR3PageFreeEx(pApicCpu->pvApicPageR3, 1 /* cPages */);
1235 pApicCpu->pvApicPageR3 = NIL_RTR3PTR;
1236 pApicCpu->pvApicPageR0 = NIL_RTR0PTR;
1237 pApicCpu->pvApicPageRC = NIL_RTRCPTR;
1238 }
1239 }
1240}
1241
1242
1243/**
1244 * Initializes the APIC state.
1245 *
1246 * @returns VBox status code.
1247 * @param pVM The cross context VM structure.
1248 */
1249static int apicR3InitState(PVM pVM)
1250{
1251 PAPIC pApic = VM_TO_APIC(pVM);
1252 LogFlow(("APIC: apicR3InitState: pVM=%p\n", pVM));
1253
1254 /* With hardware virtualization, we don't need to map the APIC in GC. */
1255 bool const fNeedsGCMapping = !HMIsEnabled(pVM);
1256
1257 /*
1258 * Allocate and map the pending-interrupt bitmap (PIB).
1259 *
1260 * We allocate all the VCPUs' PIBs contiguously in order to save space as
1261 * physically contiguous allocations are rounded to a multiple of page size.
1262 */
1263 Assert(pApic->pvApicPibR3 == NIL_RTR3PTR);
1264 Assert(pApic->pvApicPibR0 == NIL_RTR0PTR);
1265 Assert(pApic->pvApicPibRC == NIL_RTRCPTR);
1266 pApic->cbApicPib = RT_ALIGN_Z(pVM->cCpus * sizeof(APICPIB), PAGE_SIZE);
1267 size_t const cPages = pApic->cbApicPib >> PAGE_SHIFT;
1268 if (cPages == 1)
1269 {
1270 SUPPAGE SupApicPib;
1271 RT_ZERO(SupApicPib);
1272 SupApicPib.Phys = NIL_RTHCPHYS;
1273 int rc = SUPR3PageAllocEx(1 /* cPages */, 0 /* fFlags */, &pApic->pvApicPibR3, &pApic->pvApicPibR0, &SupApicPib);
1274 if (RT_SUCCESS(rc))
1275 {
1276 pApic->HCPhysApicPib = SupApicPib.Phys;
1277 AssertLogRelReturn(pApic->pvApicPibR3, VERR_INTERNAL_ERROR);
1278 }
1279 else
1280 {
1281 LogRel(("APIC: Failed to allocate %u bytes for the pending-interrupt bitmap, rc=%Rrc\n", pApic->cbApicPib, rc));
1282 return rc;
1283 }
1284 }
1285 else
1286 pApic->pvApicPibR3 = SUPR3ContAlloc(cPages, &pApic->pvApicPibR0, &pApic->HCPhysApicPib);
1287
1288 if (pApic->pvApicPibR3)
1289 {
1290 AssertLogRelReturn(pApic->pvApicPibR0 != NIL_RTR0PTR, VERR_INTERNAL_ERROR);
1291 AssertLogRelReturn(pApic->HCPhysApicPib != NIL_RTHCPHYS, VERR_INTERNAL_ERROR);
1292
1293 /* Initialize the PIB. */
1294 RT_BZERO(pApic->pvApicPibR3, pApic->cbApicPib);
1295
1296 /* Map the PIB into GC. */
1297 if (fNeedsGCMapping)
1298 {
1299 pApic->pvApicPibRC = NIL_RTRCPTR;
1300 int rc = MMR3HyperMapHCPhys(pVM, pApic->pvApicPibR3, NIL_RTR0PTR, pApic->HCPhysApicPib, pApic->cbApicPib,
1301 "APIC PIB", (PRTGCPTR)&pApic->pvApicPibRC);
1302 if (RT_FAILURE(rc))
1303 {
1304 LogRel(("APIC: Failed to map %u bytes for the pending-interrupt bitmap into GC, rc=%Rrc\n", pApic->cbApicPib,
1305 rc));
1306 apicR3TermState(pVM);
1307 return rc;
1308 }
1309
1310 AssertLogRelReturn(pApic->pvApicPibRC != NIL_RTRCPTR, VERR_INTERNAL_ERROR);
1311 }
1312
1313 /*
1314 * Allocate the map the virtual-APIC pages.
1315 */
1316 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1317 {
1318 PVMCPU pVCpu = &pVM->aCpus[idCpu];
1319 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
1320
1321 SUPPAGE SupApicPage;
1322 RT_ZERO(SupApicPage);
1323 SupApicPage.Phys = NIL_RTHCPHYS;
1324
1325 Assert(pVCpu->idCpu == idCpu);
1326 Assert(pApicCpu->pvApicPageR3 == NIL_RTR0PTR);
1327 Assert(pApicCpu->pvApicPageR0 == NIL_RTR0PTR);
1328 Assert(pApicCpu->pvApicPageRC == NIL_RTRCPTR);
1329 AssertCompile(sizeof(XAPICPAGE) == PAGE_SIZE);
1330 pApicCpu->cbApicPage = sizeof(XAPICPAGE);
1331 int rc = SUPR3PageAllocEx(1 /* cPages */, 0 /* fFlags */, &pApicCpu->pvApicPageR3, &pApicCpu->pvApicPageR0,
1332 &SupApicPage);
1333 if (RT_SUCCESS(rc))
1334 {
1335 AssertLogRelReturn(pApicCpu->pvApicPageR3 != NIL_RTR3PTR, VERR_INTERNAL_ERROR);
1336 AssertLogRelReturn(pApicCpu->HCPhysApicPage != NIL_RTHCPHYS, VERR_INTERNAL_ERROR);
1337 pApicCpu->HCPhysApicPage = SupApicPage.Phys;
1338
1339 /* Map the virtual-APIC page into GC. */
1340 if (fNeedsGCMapping)
1341 {
1342 rc = MMR3HyperMapHCPhys(pVM, pApicCpu->pvApicPageR3, NIL_RTR0PTR, pApicCpu->HCPhysApicPage,
1343 pApicCpu->cbApicPage, "APIC", (PRTGCPTR)&pApicCpu->pvApicPageRC);
1344 if (RT_FAILURE(rc))
1345 {
1346 LogRel(("APIC%u: Failed to map %u bytes for the virtual-APIC page into GC, rc=%Rrc", idCpu,
1347 pApicCpu->cbApicPage, rc));
1348 apicR3TermState(pVM);
1349 return rc;
1350 }
1351
1352 AssertLogRelReturn(pApicCpu->pvApicPageRC != NIL_RTRCPTR, VERR_INTERNAL_ERROR);
1353 }
1354
1355 /* Associate the per-VCPU PIB pointers to the per-VM PIB mapping. */
1356 uint32_t const offApicPib = idCpu * sizeof(APICPIB);
1357 pApicCpu->pvApicPibR0 = (RTR0PTR)((RTR0UINTPTR)pApic->pvApicPibR0 + offApicPib);
1358 pApicCpu->pvApicPibR3 = (RTR3PTR)((RTR3UINTPTR)pApic->pvApicPibR3 + offApicPib);
1359 if (fNeedsGCMapping)
1360 pApicCpu->pvApicPibRC = (RTRCPTR)((RTRCUINTPTR)pApic->pvApicPibRC + offApicPib);
1361
1362 /* Initialize the virtual-APIC state. */
1363 RT_BZERO(pApicCpu->pvApicPageR3, pApicCpu->cbApicPage);
1364 APICR3Reset(pVCpu, true /* fResetApicBaseMsr */);
1365
1366#ifdef DEBUG_ramshankar
1367 Assert(pApicCpu->pvApicPibR3 != NIL_RTR3PTR);
1368 Assert(pApicCpu->pvApicPibR0 != NIL_RTR0PTR);
1369 Assert(!fNeedsGCMapping || pApicCpu->pvApicPibRC != NIL_RTRCPTR);
1370 Assert(pApicCpu->pvApicPageR3 != NIL_RTR3PTR);
1371 Assert(pApicCpu->pvApicPageR0 != NIL_RTR0PTR);
1372 Assert(!fNeedsGCMapping || pApicCpu->pvApicPageRC != NIL_RTRCPTR);
1373 Assert(!fNeedsGCMapping || pApic->pvApicPibRC == pVM->aCpus[0].apic.s.pvApicPibRC);
1374#endif
1375 }
1376 else
1377 {
1378 LogRel(("APIC%u: Failed to allocate %u bytes for the virtual-APIC page, rc=%Rrc\n", idCpu, pApicCpu->cbApicPage, rc));
1379 apicR3TermState(pVM);
1380 return rc;
1381 }
1382 }
1383
1384#ifdef DEBUG_ramshankar
1385 Assert(pApic->pvApicPibR3 != NIL_RTR3PTR);
1386 Assert(pApic->pvApicPibR0 != NIL_RTR0PTR);
1387 Assert(!fNeedsGCMapping || pApic->pvApicPibRC != NIL_RTRCPTR);
1388#endif
1389 return VINF_SUCCESS;
1390 }
1391
1392 LogRel(("APIC: Failed to allocate %u bytes of physically contiguous memory for the pending-interrupt bitmap\n",
1393 pApic->cbApicPib));
1394 return VERR_NO_MEMORY;
1395}
1396
1397
1398/**
1399 * @interface_method_impl{PDMDEVREG,pfnDestruct}
1400 */
1401static DECLCALLBACK(int) apicR3Destruct(PPDMDEVINS pDevIns)
1402{
1403 PVM pVM = PDMDevHlpGetVM(pDevIns);
1404 LogFlow(("APIC: apicR3Destruct: pVM=%p\n", pVM));
1405
1406 apicR3TermState(pVM);
1407 return VINF_SUCCESS;
1408}
1409
1410
1411/**
1412 * @interface_method_impl{PDMDEVREG,pfnInitComplete}
1413 */
1414static DECLCALLBACK(int) apicR3InitComplete(PPDMDEVINS pDevIns)
1415{
1416 PVM pVM = PDMDevHlpGetVM(pDevIns);
1417 PAPIC pApic = VM_TO_APIC(pVM);
1418
1419 /*
1420 * Init APIC settings that rely on HM and CPUM configurations.
1421 */
1422 CPUMCPUIDLEAF CpuLeaf;
1423 int rc = CPUMR3CpuIdGetLeaf(pVM, &CpuLeaf, 1, 0);
1424 AssertRCReturn(rc, rc);
1425
1426 pApic->fSupportsTscDeadline = RT_BOOL(CpuLeaf.uEcx & X86_CPUID_FEATURE_ECX_TSCDEADL);
1427 pApic->fPostedIntrsEnabled = HMR3IsPostedIntrsEnabled(pVM->pUVM);
1428 pApic->fVirtApicRegsEnabled = HMR3IsVirtApicRegsEnabled(pVM->pUVM);
1429
1430 LogRel(("APIC: fPostedIntrsEnabled=%RTbool fVirtApicRegsEnabled=%RTbool fSupportsTscDeadline=%RTbool\n",
1431 pApic->fPostedIntrsEnabled, pApic->fVirtApicRegsEnabled, pApic->fSupportsTscDeadline));
1432
1433 return VINF_SUCCESS;
1434}
1435
1436
1437/**
1438 * @interface_method_impl{PDMDEVREG,pfnConstruct}
1439 */
1440static DECLCALLBACK(int) apicR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
1441{
1442 /*
1443 * Validate inputs.
1444 */
1445 Assert(iInstance == 0);
1446 Assert(pDevIns);
1447
1448 PAPICDEV pApicDev = PDMINS_2_DATA(pDevIns, PAPICDEV);
1449 PVM pVM = PDMDevHlpGetVM(pDevIns);
1450 PAPIC pApic = VM_TO_APIC(pVM);
1451
1452 /*
1453 * Validate APIC settings.
1454 */
1455 if (!CFGMR3AreValuesValid(pCfg, "RZEnabled\0"
1456 "Mode\0"
1457 "IOAPIC\0"
1458 "NumCPUs\0"))
1459 {
1460 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
1461 N_("APIC configuration error: unknown option specified"));
1462 }
1463
1464 int rc = CFGMR3QueryBoolDef(pCfg, "RZEnabled", &pApic->fRZEnabled, true);
1465 AssertLogRelRCReturn(rc, rc);
1466
1467 rc = CFGMR3QueryBoolDef(pCfg, "IOAPIC", &pApic->fIoApicPresent, true);
1468 AssertLogRelRCReturn(rc, rc);
1469
1470 uint8_t uOriginalMode;
1471 rc = CFGMR3QueryU8Def(pCfg, "Mode", &uOriginalMode, APICMODE_XAPIC);
1472 AssertLogRelRCReturn(rc, rc);
1473
1474 /* Validate APIC modes. */
1475 APICMODE const enmOriginalMode = (APICMODE)uOriginalMode;
1476 switch (enmOriginalMode)
1477 {
1478 case APICMODE_DISABLED:
1479 {
1480 /** @todo permanently disabling the APIC won't really work (needs
1481 * fixing in HM, CPUM, PDM and possibly other places). See
1482 * @bugref{8353}. */
1483#if 0
1484 pApic->enmOriginalMode = enmOriginalMode;
1485 CPUMClearGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_APIC);
1486 CPUMClearGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_X2APIC);
1487 break;
1488#else
1489 return VMR3SetError(pVM->pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS, "APIC mode 'disabled' is not supported yet.");
1490#endif
1491 }
1492
1493 case APICMODE_X2APIC:
1494 pApic->enmOriginalMode = enmOriginalMode;
1495 CPUMSetGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_X2APIC);
1496 break;
1497
1498 case APICMODE_XAPIC:
1499 pApic->enmOriginalMode = enmOriginalMode;
1500 /* The CPUID bit will be updated in apicR3ResetBaseMsr(). */
1501 break;
1502
1503 default:
1504 return VMR3SetError(pVM->pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS, "APIC mode %#x unknown.", uOriginalMode);
1505 }
1506
1507 /*
1508 * Initialize the APIC state.
1509 */
1510 pApicDev->pDevInsR3 = pDevIns;
1511 pApicDev->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
1512 pApicDev->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1513
1514 pApic->pApicDevR0 = PDMINS_2_DATA_R0PTR(pDevIns);
1515 pApic->pApicDevR3 = (PAPICDEV)PDMINS_2_DATA_R3PTR(pDevIns);
1516 pApic->pApicDevRC = PDMINS_2_DATA_RCPTR(pDevIns);
1517
1518 rc = apicR3InitState(pVM);
1519 AssertRCReturn(rc, rc);
1520
1521 /*
1522 * Disable automatic PDM locking for this device.
1523 */
1524 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
1525 AssertRCReturn(rc, rc);
1526
1527 /*
1528 * Register the APIC.
1529 */
1530 PDMAPICREG ApicReg;
1531 RT_ZERO(ApicReg);
1532 ApicReg.u32Version = PDM_APICREG_VERSION;
1533 ApicReg.pfnGetInterruptR3 = APICGetInterrupt;
1534 ApicReg.pfnSetBaseMsrR3 = APICSetBaseMsr;
1535 ApicReg.pfnGetBaseMsrR3 = APICGetBaseMsr;
1536 ApicReg.pfnSetTprR3 = APICSetTpr;
1537 ApicReg.pfnGetTprR3 = APICGetTpr;
1538 ApicReg.pfnWriteMsrR3 = APICWriteMsr;
1539 ApicReg.pfnReadMsrR3 = APICReadMsr;
1540 ApicReg.pfnBusDeliverR3 = APICBusDeliver;
1541 ApicReg.pfnLocalInterruptR3 = APICLocalInterrupt;
1542 ApicReg.pfnGetTimerFreqR3 = APICGetTimerFreq;
1543
1544 /*
1545 * We always require R0 functionality (e.g. APICGetTpr() called by HMR0 VT-x/AMD-V code).
1546 * Hence, 'fRZEnabled' strictly only applies to MMIO and MSR read/write handlers returning
1547 * to ring-3. We still need other handlers like APICGetTpr() in ring-0 for now.
1548 */
1549 {
1550 ApicReg.pszGetInterruptRC = "APICGetInterrupt";
1551 ApicReg.pszSetBaseMsrRC = "APICSetBaseMsr";
1552 ApicReg.pszGetBaseMsrRC = "APICGetBaseMsr";
1553 ApicReg.pszSetTprRC = "APICSetTpr";
1554 ApicReg.pszGetTprRC = "APICGetTpr";
1555 ApicReg.pszWriteMsrRC = "APICWriteMsr";
1556 ApicReg.pszReadMsrRC = "APICReadMsr";
1557 ApicReg.pszBusDeliverRC = "APICBusDeliver";
1558 ApicReg.pszLocalInterruptRC = "APICLocalInterrupt";
1559 ApicReg.pszGetTimerFreqRC = "APICGetTimerFreq";
1560
1561 ApicReg.pszGetInterruptR0 = "APICGetInterrupt";
1562 ApicReg.pszSetBaseMsrR0 = "APICSetBaseMsr";
1563 ApicReg.pszGetBaseMsrR0 = "APICGetBaseMsr";
1564 ApicReg.pszSetTprR0 = "APICSetTpr";
1565 ApicReg.pszGetTprR0 = "APICGetTpr";
1566 ApicReg.pszWriteMsrR0 = "APICWriteMsr";
1567 ApicReg.pszReadMsrR0 = "APICReadMsr";
1568 ApicReg.pszBusDeliverR0 = "APICBusDeliver";
1569 ApicReg.pszLocalInterruptR0 = "APICLocalInterrupt";
1570 ApicReg.pszGetTimerFreqR0 = "APICGetTimerFreq";
1571 }
1572
1573 rc = PDMDevHlpAPICRegister(pDevIns, &ApicReg, &pApicDev->pApicHlpR3);
1574 AssertLogRelRCReturn(rc, rc);
1575 pApicDev->pCritSectR3 = pApicDev->pApicHlpR3->pfnGetR3CritSect(pDevIns);
1576
1577 /*
1578 * Register the MMIO range.
1579 */
1580 PAPICCPU pApicCpu0 = VMCPU_TO_APICCPU(&pVM->aCpus[0]);
1581 RTGCPHYS GCPhysApicBase = MSR_IA32_APICBASE_GET_ADDR(pApicCpu0->uApicBaseMsr);
1582
1583 rc = PDMDevHlpMMIORegister(pDevIns, GCPhysApicBase, sizeof(XAPICPAGE), NULL /* pvUser */,
1584 IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_DWORD_ZEROED,
1585 APICWriteMmio, APICReadMmio, "APIC");
1586 if (RT_FAILURE(rc))
1587 return rc;
1588
1589 if (pApic->fRZEnabled)
1590 {
1591 pApicDev->pApicHlpRC = pApicDev->pApicHlpR3->pfnGetRCHelpers(pDevIns);
1592 pApicDev->pCritSectRC = pApicDev->pApicHlpR3->pfnGetRCCritSect(pDevIns);
1593 rc = PDMDevHlpMMIORegisterRC(pDevIns, GCPhysApicBase, sizeof(XAPICPAGE), NIL_RTRCPTR /*pvUser*/,
1594 "APICWriteMmio", "APICReadMmio");
1595 if (RT_FAILURE(rc))
1596 return rc;
1597
1598 pApicDev->pApicHlpR0 = pApicDev->pApicHlpR3->pfnGetR0Helpers(pDevIns);
1599 pApicDev->pCritSectR0 = pApicDev->pApicHlpR3->pfnGetR0CritSect(pDevIns);
1600 rc = PDMDevHlpMMIORegisterR0(pDevIns, GCPhysApicBase, sizeof(XAPICPAGE), NIL_RTR0PTR /*pvUser*/,
1601 "APICWriteMmio", "APICReadMmio");
1602 if (RT_FAILURE(rc))
1603 return rc;
1604 }
1605
1606 /*
1607 * Create the APIC timers.
1608 */
1609 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1610 {
1611 PVMCPU pVCpu = &pVM->aCpus[idCpu];
1612 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
1613 RTStrPrintf(&pApicCpu->szTimerDesc[0], sizeof(pApicCpu->szTimerDesc), "APIC Timer %u", pVCpu->idCpu);
1614 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, apicR3TimerCallback, pVCpu, TMTIMER_FLAGS_NO_CRIT_SECT,
1615 pApicCpu->szTimerDesc, &pApicCpu->pTimerR3);
1616 if (RT_SUCCESS(rc))
1617 {
1618 pApicCpu->pTimerR0 = TMTimerR0Ptr(pApicCpu->pTimerR3);
1619 pApicCpu->pTimerRC = TMTimerRCPtr(pApicCpu->pTimerR3);
1620 }
1621 else
1622 return rc;
1623 }
1624
1625 /*
1626 * Register saved state callbacks.
1627 */
1628 rc = PDMDevHlpSSMRegister3(pDevIns, APIC_SAVED_STATE_VERSION, sizeof(*pApicDev), NULL /*pfnLiveExec*/, apicR3SaveExec,
1629 apicR3LoadExec);
1630 if (RT_FAILURE(rc))
1631 return rc;
1632
1633 /*
1634 * Register debugger info callbacks.
1635 *
1636 * We use separate callbacks rather than arguments so they can also be
1637 * dumped in an automated fashion while collecting crash diagnostics and
1638 * not just used during live debugging via the VM debugger.
1639 */
1640 rc = DBGFR3InfoRegisterInternalEx(pVM, "apic", "Dumps APIC basic information.", apicR3Info, DBGFINFO_FLAGS_RUN_ON_EMT);
1641 rc |= DBGFR3InfoRegisterInternalEx(pVM, "apiclvt", "Dumps APIC LVT information.", apicR3InfoLvt, DBGFINFO_FLAGS_RUN_ON_EMT);
1642 rc |= DBGFR3InfoRegisterInternalEx(pVM, "apictimer", "Dumps APIC timer information.", apicR3InfoTimer, DBGFINFO_FLAGS_RUN_ON_EMT);
1643 AssertRCReturn(rc, rc);
1644
1645#ifdef VBOX_WITH_STATISTICS
1646 /*
1647 * Statistics.
1648 */
1649#define APIC_REG_COUNTER(a_Reg, a_Desc, a_Key) \
1650 do { \
1651 rc = STAMR3RegisterF(pVM, a_Reg, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, a_Desc, a_Key, idCpu); \
1652 AssertRCReturn(rc, rc); \
1653 } while(0)
1654
1655#define APIC_PROF_COUNTER(a_Reg, a_Desc, a_Key) \
1656 do { \
1657 rc = STAMR3RegisterF(pVM, a_Reg, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, a_Desc, a_Key, \
1658 idCpu); \
1659 AssertRCReturn(rc, rc); \
1660 } while(0)
1661
1662 bool const fHasRC = !HMIsEnabled(pVM);
1663 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1664 {
1665 PVMCPU pVCpu = &pVM->aCpus[idCpu];
1666 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
1667
1668 APIC_REG_COUNTER(&pApicCpu->StatMmioReadR0, "Number of APIC MMIO reads in R0.", "/Devices/APIC/%u/R0/MmioRead");
1669 APIC_REG_COUNTER(&pApicCpu->StatMmioWriteR0, "Number of APIC MMIO writes in R0.", "/Devices/APIC/%u/R0/MmioWrite");
1670 APIC_REG_COUNTER(&pApicCpu->StatMsrReadR0, "Number of APIC MSR reads in R0.", "/Devices/APIC/%u/R0/MsrRead");
1671 APIC_REG_COUNTER(&pApicCpu->StatMsrWriteR0, "Number of APIC MSR writes in R0.", "/Devices/APIC/%u/R0/MsrWrite");
1672
1673 APIC_REG_COUNTER(&pApicCpu->StatMmioReadR3, "Number of APIC MMIO reads in R3.", "/Devices/APIC/%u/R3/MmioReadR3");
1674 APIC_REG_COUNTER(&pApicCpu->StatMmioWriteR3, "Number of APIC MMIO writes in R3.", "/Devices/APIC/%u/R3/MmioWriteR3");
1675 APIC_REG_COUNTER(&pApicCpu->StatMsrReadR3, "Number of APIC MSR reads in R3.", "/Devices/APIC/%u/R3/MsrReadR3");
1676 APIC_REG_COUNTER(&pApicCpu->StatMsrWriteR3, "Number of APIC MSR writes in R3.", "/Devices/APIC/%u/R3/MsrWriteR3");
1677
1678 if (fHasRC)
1679 {
1680 APIC_REG_COUNTER(&pApicCpu->StatMmioReadRC, "Number of APIC MMIO reads in RC.", "/Devices/APIC/%u/RC/MmioRead");
1681 APIC_REG_COUNTER(&pApicCpu->StatMmioWriteRC, "Number of APIC MMIO writes in RC.", "/Devices/APIC/%u/RC/MmioWrite");
1682 APIC_REG_COUNTER(&pApicCpu->StatMsrReadRC, "Number of APIC MSR reads in RC.", "/Devices/APIC/%u/RC/MsrRead");
1683 APIC_REG_COUNTER(&pApicCpu->StatMsrWriteRC, "Number of APIC MSR writes in RC.", "/Devices/APIC/%u/RC/MsrWrite");
1684 }
1685
1686 APIC_PROF_COUNTER(&pApicCpu->StatUpdatePendingIntrs, "Profiling of APICUpdatePendingInterrupts",
1687 "/PROF/CPU%d/APIC/UpdatePendingInterrupts");
1688 APIC_PROF_COUNTER(&pApicCpu->StatPostIntr, "Profiling of APICPostInterrupt", "/PROF/CPU%d/APIC/PostInterrupt");
1689
1690 APIC_REG_COUNTER(&pApicCpu->StatPostIntrAlreadyPending, "Number of times an interrupt is already pending.",
1691 "/Devices/APIC/%u/PostInterruptAlreadyPending");
1692 APIC_REG_COUNTER(&pApicCpu->StatTimerCallback, "Number of times the timer callback is invoked.",
1693 "/Devices/APIC/%u/TimerCallback");
1694
1695 APIC_REG_COUNTER(&pApicCpu->StatTprWrite, "Number of TPR writes.", "/Devices/APIC/%u/TprWrite");
1696 APIC_REG_COUNTER(&pApicCpu->StatTprRead, "Number of TPR reads.", "/Devices/APIC/%u/TprRead");
1697 APIC_REG_COUNTER(&pApicCpu->StatEoiWrite, "Number of EOI writes.", "/Devices/APIC/%u/EoiWrite");
1698 APIC_REG_COUNTER(&pApicCpu->StatMaskedByTpr, "Number of times TPR masks an interrupt in APICGetInterrupt.",
1699 "/Devices/APIC/%u/MaskedByTpr");
1700 APIC_REG_COUNTER(&pApicCpu->StatMaskedByPpr, "Number of times PPR masks an interrupt in APICGetInterrupt.",
1701 "/Devices/APIC/%u/MaskedByPpr");
1702 APIC_REG_COUNTER(&pApicCpu->StatTimerIcrWrite, "Number of times the timer ICR is written.",
1703 "/Devices/APIC/%u/TimerIcrWrite");
1704 APIC_REG_COUNTER(&pApicCpu->StatIcrLoWrite, "Number of times the ICR Lo (send IPI) is written.",
1705 "/Devices/APIC/%u/IcrLoWrite");
1706 }
1707# undef APIC_PROF_COUNTER
1708# undef APIC_REG_ACCESS_COUNTER
1709#endif
1710
1711 return VINF_SUCCESS;
1712}
1713
1714
1715/**
1716 * APIC device registration structure.
1717 */
1718const PDMDEVREG g_DeviceAPIC =
1719{
1720 /* u32Version */
1721 PDM_DEVREG_VERSION,
1722 /* szName */
1723 "apic",
1724 /* szRCMod */
1725 "VMMRC.rc",
1726 /* szR0Mod */
1727 "VMMR0.r0",
1728 /* pszDescription */
1729 "Advanced Programmable Interrupt Controller",
1730 /* fFlags */
1731 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64 | PDM_DEVREG_FLAGS_PAE36
1732 | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
1733 /* fClass */
1734 PDM_DEVREG_CLASS_PIC,
1735 /* cMaxInstances */
1736 1,
1737 /* cbInstance */
1738 sizeof(APICDEV),
1739 /* pfnConstruct */
1740 apicR3Construct,
1741 /* pfnDestruct */
1742 apicR3Destruct,
1743 /* pfnRelocate */
1744 apicR3Relocate,
1745 /* pfnMemSetup */
1746 NULL,
1747 /* pfnPowerOn */
1748 NULL,
1749 /* pfnReset */
1750 apicR3Reset,
1751 /* pfnSuspend */
1752 NULL,
1753 /* pfnResume */
1754 NULL,
1755 /* pfnAttach */
1756 NULL,
1757 /* pfnDetach */
1758 NULL,
1759 /* pfnQueryInterface. */
1760 NULL,
1761 /* pfnInitComplete */
1762 apicR3InitComplete,
1763 /* pfnPowerOff */
1764 NULL,
1765 /* pfnSoftReset */
1766 NULL,
1767 /* u32VersionEnd */
1768 PDM_DEVREG_VERSION
1769};
1770
1771#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
1772
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