VirtualBox

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

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

VMM/APIC: Initial Hyper-V support for synthetic interrupts, Hyper-V interface for direct TPR, EOI, ICR accesses.
Support for Hyper-V compatibility mode (x2APIC interface while operating in xAPIC mode).

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