VirtualBox

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

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

VMM/APIC: Get rid of specialized R0 code and clean up ordering issues.
It's still not nice that CPUMR3Reset() momentarily gets an un-initialized APIC base MSR until
it's re-cached again using CPUMR3InitCompleted() but I hope to eventually get rid of this
caching business entirely once the old APIC infrastructure can be kicked out.

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