VirtualBox

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

Last change on this file since 61414 was 61351, checked in by vboxsync, 9 years ago

APIC: Reset fix.

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