VirtualBox

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

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

VMM: Fixed TPR thresholding and related PDM interfaces.
Cleaned up the PDM interface and merged apicHasPendingIrq with apicGetTpr.
Fixed raw-mode with the new APIC code due to busted GC mapping relocation.

This finally fixes the NT4 VM boot-up issue with the new APIC code.

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

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