VirtualBox

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

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

VMM/APIC: Bumps saved-state version and add the LINT0/LINT1 interrupt line states to the saved-state.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette