VirtualBox

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

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

VMM/APIC: No longer needed function.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 55.8 KB
Line 
1/* $Id: APIC.cpp 60400 2016-04-08 17:06:17Z 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 * Initializes per-VCPU APIC to the state following a power-up or hardware
378 * reset.
379 *
380 * @param pVCpu The cross context virtual CPU structure.
381 */
382VMMR3_INT_DECL(void) APICR3Reset(PVMCPU pVCpu)
383{
384 VMCPU_ASSERT_EMT_OR_NOT_RUNNING(pVCpu);
385
386#ifdef RT_STRICT
387 /* Verify that the initial APIC ID reported via CPUID matches our VMCPU ID assumption. */
388 CPUMCPUIDLEAF CpuLeaf;
389 int rc = CPUMR3CpuIdGetLeaf(pVCpu->CTX_SUFF(pVM), &CpuLeaf, 1, 0);
390 AssertRC(rc);
391 Assert(((CpuLeaf.uEbx >> 24) & 0xff) == pVCpu->idCpu);
392#endif
393
394 apicR3InitIpi(pVCpu);
395
396 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
397
398 /*
399 * The APIC version register is read-only, so just initialize it here.
400 * It is not clear from the specs, where exactly it is initalized.
401 * The version determines the number of LVT entries and size of the APIC ID (8 bits for P4).
402 */
403#if XAPIC_HARDWARE_VERSION == XAPIC_HARDWARE_VERSION_P4
404 pXApicPage->version.u.u8MaxLvtEntry = XAPIC_MAX_LVT_ENTRIES_P4 - 1;
405 pXApicPage->version.u.u8Version = XAPIC_HARDWARE_VERSION_P4;
406 AssertCompile(sizeof(pXApicPage->id.u8ApicId) >= XAPIC_APIC_ID_BIT_COUNT_P4 / 8);
407#else
408# error "Implement Pentium and P6 family APIC architectures"
409#endif
410
411 /** @todo It isn't very clear where the default base address is (re)initialized,
412 * atm we do it here in Reset. */
413 apicR3ResetBaseMsr(pVCpu);
414
415 /*
416 * Initialize the APIC ID register to xAPIC format.
417 */
418 ASMMemZero32(&pXApicPage->id, sizeof(pXApicPage->id));
419 pXApicPage->id.u8ApicId = pVCpu->idCpu;
420}
421
422
423/**
424 * Receives an INIT IPI.
425 *
426 * @param pVCpu The cross context virtual CPU structure.
427 */
428VMMR3_INT_DECL(void) APICR3InitIpi(PVMCPU pVCpu)
429{
430 VMCPU_ASSERT_EMT(pVCpu);
431 apicR3InitIpi(pVCpu);
432}
433
434
435/**
436 * Helper for dumping an APIC 256-bit sparse register.
437 *
438 * @param pApicReg The APIC 256-bit spare register.
439 * @param pHlp The debug output helper.
440 */
441static void apicR3DbgInfo256BitReg(volatile const XAPIC256BITREG *pApicReg, PCDBGFINFOHLP pHlp)
442{
443 ssize_t const cFragments = RT_ELEMENTS(pApicReg->u);
444 unsigned const cBitsPerFragment = sizeof(pApicReg->u[0].u32Reg) * 8;
445 XAPIC256BITREG ApicReg;
446 RT_ZERO(ApicReg);
447
448 pHlp->pfnPrintf(pHlp, " ");
449 for (ssize_t i = cFragments - 1; i >= 0; i--)
450 {
451 uint32_t const uFragment = pApicReg->u[i].u32Reg;
452 ApicReg.u[i].u32Reg = uFragment;
453 pHlp->pfnPrintf(pHlp, "%08x", uFragment);
454 }
455 pHlp->pfnPrintf(pHlp, "\n");
456
457 size_t cPending = 0;
458 pHlp->pfnPrintf(pHlp, " Pending\n");
459 pHlp->pfnPrintf(pHlp, " ");
460 for (ssize_t i = cFragments - 1; i >= 0; i--)
461 {
462 uint32_t uFragment = ApicReg.u[i].u32Reg;
463 if (uFragment)
464 {
465 do
466 {
467 unsigned idxSetBit = ASMBitLastSetU32(uFragment);
468 --idxSetBit;
469 ASMBitClear(&uFragment, idxSetBit);
470
471 idxSetBit += (i * cBitsPerFragment);
472 pHlp->pfnPrintf(pHlp, " %02x", idxSetBit);
473 ++cPending;
474 } while (uFragment);
475 }
476 }
477 if (!cPending)
478 pHlp->pfnPrintf(pHlp, " None");
479 pHlp->pfnPrintf(pHlp, "\n");
480}
481
482
483/**
484 * Dumps basic APIC state.
485 *
486 * @param pVCpu The cross context virtual CPU structure.
487 * @param pHlp The debug output helper.
488 */
489static void apicR3DbgInfoBasic(PVMCPU pVCpu, PCDBGFINFOHLP pHlp)
490{
491 PCAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
492 PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
493 PCX2APICPAGE pX2ApicPage = VMCPU_TO_CX2APICPAGE(pVCpu);
494 bool const fX2ApicMode = XAPIC_IN_X2APIC_MODE(pVCpu);
495
496 pHlp->pfnPrintf(pHlp, "VCPU[%u] APIC at %#RGp (%s mode):\n", pVCpu->idCpu, MSR_APICBASE_GET_PHYSADDR(pApicCpu->uApicBaseMsr),
497 fX2ApicMode ? "x2APIC" : "xAPIC");
498 if (fX2ApicMode)
499 {
500 pHlp->pfnPrintf(pHlp, " APIC ID = %u (%#x)\n", pX2ApicPage->id.u32ApicId,
501 pX2ApicPage->id.u32ApicId);
502 }
503 else
504 pHlp->pfnPrintf(pHlp, " APIC ID = %u (%#x)\n", pXApicPage->id.u8ApicId, pXApicPage->id.u8ApicId);
505 pHlp->pfnPrintf(pHlp, " Version = %#x\n", pXApicPage->version.all.u32Version);
506 pHlp->pfnPrintf(pHlp, " APIC Version = %#x\n", pXApicPage->version.u.u8Version);
507 pHlp->pfnPrintf(pHlp, " Max LVT entries = %u\n", pXApicPage->version.u.u8MaxLvtEntry);
508 pHlp->pfnPrintf(pHlp, " EOI Broadcast supression = %RTbool\n", pXApicPage->version.u.fEoiBroadcastSupression);
509 if (!fX2ApicMode)
510 pHlp->pfnPrintf(pHlp, " APR = %u (%#x)\n", pXApicPage->apr.u8Apr, pXApicPage->apr.u8Apr);
511 pHlp->pfnPrintf(pHlp, " TPR = %u (%#x)\n", pXApicPage->tpr.u8Tpr, pXApicPage->tpr.u8Tpr);
512 pHlp->pfnPrintf(pHlp, " Task-priority class = %u\n", XAPIC_TPR_GET_TP(pXApicPage->tpr.u8Tpr));
513 pHlp->pfnPrintf(pHlp, " Task-priority subclass = %u\n", XAPIC_TPR_GET_TP_SUBCLASS(pXApicPage->tpr.u8Tpr));
514 pHlp->pfnPrintf(pHlp, " PPR = %u (%#x)\n", pXApicPage->ppr.u8Ppr, pXApicPage->ppr.u8Ppr);
515 pHlp->pfnPrintf(pHlp, " Processor-priority class = %u\n", XAPIC_PPR_GET_PP(pXApicPage->ppr.u8Ppr));
516 pHlp->pfnPrintf(pHlp, " Processor-priority subclass = %u\n", XAPIC_PPR_GET_PP_SUBCLASS(pXApicPage->ppr.u8Ppr));
517 if (!fX2ApicMode)
518 pHlp->pfnPrintf(pHlp, " RRD = %u (%#x)\n", pXApicPage->rrd.u32Rrd, pXApicPage->rrd.u32Rrd);
519 pHlp->pfnPrintf(pHlp, " LDR = %u (%#x)\n", pXApicPage->ldr.all.u32Ldr, pXApicPage->ldr.all.u32Ldr);
520 pHlp->pfnPrintf(pHlp, " Logical APIC ID = %u\n", fX2ApicMode ? pX2ApicPage->ldr.u32LogicalApicId
521 : pXApicPage->ldr.u.u8LogicalApicId);
522 if (!fX2ApicMode)
523 {
524 pHlp->pfnPrintf(pHlp, " DFR = %RX32\n", pXApicPage->dfr.all.u32Dfr);
525 pHlp->pfnPrintf(pHlp, " Model = %#x (%s)\n", pXApicPage->dfr.u.u4Model,
526 apicGetDestFormatName((XAPICDESTFORMAT)pXApicPage->dfr.u.u4Model));
527 }
528 pHlp->pfnPrintf(pHlp, " SVR\n");
529 pHlp->pfnPrintf(pHlp, " Vector = %u (%#x)\n", pXApicPage->svr.u.u8SpuriousVector,
530 pXApicPage->svr.u.u8SpuriousVector);
531 pHlp->pfnPrintf(pHlp, " Software Enabled = %RTbool\n", RT_BOOL(pXApicPage->svr.u.fApicSoftwareEnable));
532 pHlp->pfnPrintf(pHlp, " Supress EOI broadcast = %RTbool\n", RT_BOOL(pXApicPage->svr.u.fSupressEoiBroadcast));
533 pHlp->pfnPrintf(pHlp, " ISR\n");
534 apicR3DbgInfo256BitReg(&pXApicPage->isr, pHlp);
535 pHlp->pfnPrintf(pHlp, " TMR\n");
536 apicR3DbgInfo256BitReg(&pXApicPage->tmr, pHlp);
537 pHlp->pfnPrintf(pHlp, " IRR\n");
538 apicR3DbgInfo256BitReg(&pXApicPage->irr, pHlp);
539 pHlp->pfnPrintf(pHlp, "ESR Internal = %#x\n", pApicCpu->uEsrInternal);
540 pHlp->pfnPrintf(pHlp, " ESR = %#x\n", pXApicPage->esr.all.u32Errors);
541 pHlp->pfnPrintf(pHlp, " Redirectable IPI = %RTbool\n", pXApicPage->esr.u.fRedirectableIpi);
542 pHlp->pfnPrintf(pHlp, " Send Illegal Vector = %RTbool\n", pXApicPage->esr.u.fSendIllegalVector);
543 pHlp->pfnPrintf(pHlp, " Recv Illegal Vector = %RTbool\n", pXApicPage->esr.u.fRcvdIllegalVector);
544 pHlp->pfnPrintf(pHlp, " Illegal Register Address = %RTbool\n", pXApicPage->esr.u.fIllegalRegAddr);
545 pHlp->pfnPrintf(pHlp, " ICR Low = %#x\n", pXApicPage->icr_lo.all);
546 pHlp->pfnPrintf(pHlp, " Vector = %u (%#x)\n", pXApicPage->icr_lo.u.u8Vector,
547 pXApicPage->icr_lo.u.u8Vector);
548 pHlp->pfnPrintf(pHlp, " Delivery Mode = %#x (%s)\n", pXApicPage->icr_lo.u.u3DeliveryMode,
549 apicGetDeliveryModeName((XAPICDELIVERYMODE)pXApicPage->icr_lo.u.u3DeliveryMode));
550 pHlp->pfnPrintf(pHlp, " Destination Mode = %#x (%s)\n", pXApicPage->icr_lo.u.u1DestMode,
551 apicGetDestModeName((XAPICDESTMODE)pXApicPage->icr_lo.u.u1DestMode));
552 if (!fX2ApicMode)
553 pHlp->pfnPrintf(pHlp, " Delivery Status = %u\n", pXApicPage->icr_lo.u.u1DeliveryStatus);
554 pHlp->pfnPrintf(pHlp, " Level = %u\n", pXApicPage->icr_lo.u.u1Level);
555 pHlp->pfnPrintf(pHlp, " Trigger Mode = %u (%s)\n", pXApicPage->icr_lo.u.u1TriggerMode,
556 apicGetTriggerModeName((XAPICTRIGGERMODE)pXApicPage->icr_lo.u.u1TriggerMode));
557 pHlp->pfnPrintf(pHlp, " Destination shorthand = %#x (%s)\n", pXApicPage->icr_lo.u.u2DestShorthand,
558 apicGetDestShorthandName((XAPICDESTSHORTHAND)pXApicPage->icr_lo.u.u2DestShorthand));
559 pHlp->pfnPrintf(pHlp, " ICR High = %#x\n", pXApicPage->icr_hi.all.u32IcrHi);
560 pHlp->pfnPrintf(pHlp, " Destination field/mask = %#x\n", fX2ApicMode ? pX2ApicPage->icr_hi.u32IcrHi
561 : pXApicPage->icr_hi.u.u8Dest);
562}
563
564
565/**
566 * Helper for dumping the LVT timer.
567 *
568 * @param pVCpu The cross context virtual CPU structure.
569 * @param pHlp The debug output helper.
570 */
571static void apicR3DbgInfoLvtTimer(PVMCPU pVCpu, PCDBGFINFOHLP pHlp)
572{
573 PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
574 uint32_t const uLvtTimer = pXApicPage->lvt_timer.all.u32LvtTimer;
575 pHlp->pfnPrintf(pHlp, "LVT Timer = %#RX32\n", uLvtTimer);
576 pHlp->pfnPrintf(pHlp, " Vector = %u (%#x)\n", pXApicPage->lvt_timer.u.u8Vector);
577 pHlp->pfnPrintf(pHlp, " Delivery status = %u\n", pXApicPage->lvt_timer.u.u1DeliveryStatus);
578 pHlp->pfnPrintf(pHlp, " Masked = %RTbool\n", XAPIC_LVT_IS_MASKED(uLvtTimer));
579 pHlp->pfnPrintf(pHlp, " Timer Mode = %#x (%s)\n", pXApicPage->lvt_timer.u.u2TimerMode,
580 apicGetTimerModeName((XAPICTIMERMODE)pXApicPage->lvt_timer.u.u2TimerMode));
581 pHlp->pfnPrintf(pHlp, "\n");
582}
583
584
585/**
586 * Dumps APIC Local Vector Table (LVT) state.
587 *
588 * @param pVCpu The cross context virtual CPU structure.
589 * @param pHlp The debug output helper.
590 */
591static void apicR3DbgInfoLvt(PVMCPU pVCpu, PCDBGFINFOHLP pHlp)
592{
593 PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
594
595 apicR3DbgInfoLvtTimer(pVCpu, pHlp);
596
597#if XAPIC_HARDWARE_VERSION == XAPIC_HARDWARE_VERSION_P4
598 uint32_t const uLvtThermal = pXApicPage->lvt_thermal.all.u32LvtThermal;
599 pHlp->pfnPrintf(pHlp, "LVT Thermal = %#RX32)\n", uLvtThermal);
600 pHlp->pfnPrintf(pHlp, " Vector = %u (%#x)\n", pXApicPage->lvt_thermal.u.u8Vector, pXApicPage->lvt_thermal.u.u8Vector);
601 pHlp->pfnPrintf(pHlp, " Delivery Mode = %#x (%s)\n", pXApicPage->lvt_thermal.u.u3DeliveryMode,
602 apicGetDeliveryModeName((XAPICDELIVERYMODE)pXApicPage->lvt_thermal.u.u3DeliveryMode));
603 pHlp->pfnPrintf(pHlp, " Delivery status = %u\n", pXApicPage->lvt_thermal.u.u1DeliveryStatus);
604 pHlp->pfnPrintf(pHlp, " Masked = %RTbool\n", XAPIC_LVT_IS_MASKED(uLvtThermal));
605 pHlp->pfnPrintf(pHlp, "\n");
606#endif
607
608 uint32_t const uLvtPerf = pXApicPage->lvt_perf.all.u32LvtPerf;
609 pHlp->pfnPrintf(pHlp, "LVT Perf = %#RX32\n", uLvtPerf);
610 pHlp->pfnPrintf(pHlp, " Vector = %u (%#x)\n", pXApicPage->lvt_perf.u.u8Vector, pXApicPage->lvt_perf.u.u8Vector);
611 pHlp->pfnPrintf(pHlp, " Delivery Mode = %#x (%s)\n", pXApicPage->lvt_perf.u.u3DeliveryMode,
612 apicGetDeliveryModeName((XAPICDELIVERYMODE)pXApicPage->lvt_perf.u.u3DeliveryMode));
613 pHlp->pfnPrintf(pHlp, " Delivery status = %u\n", pXApicPage->lvt_perf.u.u1DeliveryStatus);
614 pHlp->pfnPrintf(pHlp, " Masked = %RTbool\n", XAPIC_LVT_IS_MASKED(uLvtPerf));
615 pHlp->pfnPrintf(pHlp, "\n");
616
617 uint32_t const uLvtLint0 = pXApicPage->lvt_lint0.all.u32LvtLint0;
618 pHlp->pfnPrintf(pHlp, "LVT LINT0 = %#RX32\n", uLvtLint0);
619 pHlp->pfnPrintf(pHlp, " Vector = %u (%#x)\n", pXApicPage->lvt_lint0.u.u8Vector, pXApicPage->lvt_lint0.u.u8Vector);
620 pHlp->pfnPrintf(pHlp, " Delivery Mode = %#x (%s)\n", pXApicPage->lvt_lint0.u.u3DeliveryMode,
621 apicGetDeliveryModeName((XAPICDELIVERYMODE)pXApicPage->lvt_lint0.u.u3DeliveryMode));
622 pHlp->pfnPrintf(pHlp, " Delivery status = %u\n", pXApicPage->lvt_lint0.u.u1DeliveryStatus);
623 pHlp->pfnPrintf(pHlp, " Pin polarity = %u\n", pXApicPage->lvt_lint0.u.u1IntrPolarity);
624 pHlp->pfnPrintf(pHlp, " Remote IRR = %u\n", pXApicPage->lvt_lint0.u.u1RemoteIrr);
625 pHlp->pfnPrintf(pHlp, " Trigger Mode = %u (%s)\n", pXApicPage->lvt_lint0.u.u1TriggerMode,
626 apicGetTriggerModeName((XAPICTRIGGERMODE)pXApicPage->lvt_lint0.u.u1TriggerMode));
627 pHlp->pfnPrintf(pHlp, " Masked = %RTbool\n", XAPIC_LVT_IS_MASKED(uLvtLint0));
628
629 uint32_t const uLvtLint1 = pXApicPage->lvt_lint1.all.u32LvtLint1;
630 pHlp->pfnPrintf(pHlp, "LVT LINT1 = %#RX32\n", uLvtLint1);
631 pHlp->pfnPrintf(pHlp, " Vector = %u (%#x)\n", pXApicPage->lvt_lint1.u.u8Vector, pXApicPage->lvt_lint1.u.u8Vector);
632 pHlp->pfnPrintf(pHlp, " Delivery Mode = %#x (%s)\n", pXApicPage->lvt_lint1.u.u3DeliveryMode,
633 apicGetDeliveryModeName((XAPICDELIVERYMODE)pXApicPage->lvt_lint1.u.u3DeliveryMode));
634 pHlp->pfnPrintf(pHlp, " Delivery status = %u\n", pXApicPage->lvt_lint1.u.u1DeliveryStatus);
635 pHlp->pfnPrintf(pHlp, " Pin polarity = %u\n", pXApicPage->lvt_lint1.u.u1IntrPolarity);
636 pHlp->pfnPrintf(pHlp, " Remote IRR = %u\n", pXApicPage->lvt_lint1.u.u1RemoteIrr);
637 pHlp->pfnPrintf(pHlp, " Trigger Mode = %u (%s)\n", pXApicPage->lvt_lint1.u.u1TriggerMode,
638 apicGetTriggerModeName((XAPICTRIGGERMODE)pXApicPage->lvt_lint1.u.u1TriggerMode));
639 pHlp->pfnPrintf(pHlp, " Masked = %RTbool\n", XAPIC_LVT_IS_MASKED(uLvtLint1));
640 pHlp->pfnPrintf(pHlp, "\n");
641
642 uint32_t const uLvtError = pXApicPage->lvt_error.all.u32LvtError;
643 pHlp->pfnPrintf(pHlp, "LVT Perf = %#RX32\n", uLvtError);
644 pHlp->pfnPrintf(pHlp, " Vector = %u (%#x)\n", pXApicPage->lvt_error.u.u8Vector, pXApicPage->lvt_error.u.u8Vector);
645 pHlp->pfnPrintf(pHlp, " Delivery status = %u\n", pXApicPage->lvt_error.u.u1DeliveryStatus);
646 pHlp->pfnPrintf(pHlp, " Masked = %RTbool\n", XAPIC_LVT_IS_MASKED(uLvtError));
647 pHlp->pfnPrintf(pHlp, "\n");
648}
649
650
651/**
652 * Dumps APIC Timer state.
653 *
654 * @param pVCpu The cross context virtual CPU structure.
655 * @param pHlp The debug output helper.
656 */
657static void apicR3DbgInfoTimer(PVMCPU pVCpu, PCDBGFINFOHLP pHlp)
658{
659 PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
660 PCAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
661
662 pHlp->pfnPrintf(pHlp, "Local APIC timer:\n");
663 pHlp->pfnPrintf(pHlp, " ICR = %#RX32\n", pXApicPage->timer_icr.u32InitialCount);
664 pHlp->pfnPrintf(pHlp, " CCR = %#RX32\n", pXApicPage->timer_ccr.u32CurrentCount);
665 pHlp->pfnPrintf(pHlp, " DCR = %#RX32\n", pXApicPage->timer_dcr.all.u32DivideValue);
666 pHlp->pfnPrintf(pHlp, " Timer shift = %#x\n", apicGetTimerShift(pXApicPage));
667 pHlp->pfnPrintf(pHlp, " Timer initial TS = %#RU64", pApicCpu->u64TimerInitial);
668 pHlp->pfnPrintf(pHlp, "\n");
669
670 apicR3DbgInfoLvtTimer(pVCpu, pHlp);
671}
672
673
674/**
675 * @callback_method_impl{FNDBGFHANDLERDEV,
676 * Dumps the APIC state according to given argument for debugging purposes.}
677 */
678static DECLCALLBACK(void) apicR3DbgInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
679{
680 PVM pVM = PDMDevHlpGetVM(pDevIns);
681 PVMCPU pVCpu = VMMGetCpu(pVM);
682 Assert(pVCpu);
683
684 if (pszArgs == NULL || !*pszArgs || !strcmp(pszArgs, "basic"))
685 apicR3DbgInfoBasic(pVCpu, pHlp);
686 else if (!strcmp(pszArgs, "lvt"))
687 apicR3DbgInfoLvt(pVCpu, pHlp);
688 else if (!strcmp(pszArgs, "timer"))
689 apicR3DbgInfoTimer(pVCpu, pHlp);
690 else
691 pHlp->pfnPrintf(pHlp, "Invalid argument. Recognized arguments are 'basic', 'lvt', 'timer'\n");
692}
693
694
695/**
696 * Converts legacy PDMAPICMODE to the new APICMODE enum.
697 *
698 * @returns The new APIC mode.
699 * @param enmLegacyMode The legacy mode to convert.
700 */
701static APICMODE apicR3ConvertFromLegacyApicMode(PDMAPICMODE enmLegacyMode)
702{
703 switch (enmLegacyMode)
704 {
705 case PDMAPICMODE_NONE: return APICMODE_DISABLED;
706 case PDMAPICMODE_APIC: return APICMODE_XAPIC;
707 case PDMAPICMODE_X2APIC: return APICMODE_X2APIC;
708 case PDMAPICMODE_INVALID: return APICMODE_INVALID;
709 default: break;
710 }
711 return (APICMODE)enmLegacyMode;
712}
713
714
715/**
716 * Converts the new APICMODE enum to the legacy PDMAPICMODE enum.
717 *
718 * @returns The legacy APIC mode.
719 * @param enmMode The APIC mode to convert.
720 */
721static PDMAPICMODE apicR3ConvertToLegacyApicMode(APICMODE enmMode)
722{
723 switch (enmMode)
724 {
725 case APICMODE_DISABLED: return PDMAPICMODE_NONE;
726 case APICMODE_XAPIC: return PDMAPICMODE_APIC;
727 case APICMODE_X2APIC: return PDMAPICMODE_X2APIC;
728 case APICMODE_INVALID: return PDMAPICMODE_INVALID;
729 default: break;
730 }
731 return (PDMAPICMODE)enmMode;
732}
733
734
735/**
736 * Worker for saving per-VM APIC data.
737 *
738 * @returns VBox status code.
739 * @param pVM The cross context VM structure.
740 * @param pSSM The SSM handle.
741 */
742static int apicR3SaveVMData(PVM pVM, PSSMHANDLE pSSM)
743{
744 PAPIC pApic = VM_TO_APIC(pVM);
745 SSMR3PutU32(pSSM, pVM->cCpus);
746 SSMR3PutBool(pSSM, pApic->fIoApicPresent);
747 return SSMR3PutU32(pSSM, apicR3ConvertToLegacyApicMode(pApic->enmOriginalMode));
748}
749
750
751/**
752 * @copydoc FNSSMDEVLIVEEXEC
753 */
754static DECLCALLBACK(int) apicR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
755{
756 PAPICDEV pApicDev = PDMINS_2_DATA(pDevIns, PAPICDEV);
757 PVM pVM = PDMDevHlpGetVM(pApicDev->pDevInsR3);
758
759 int rc = apicR3SaveVMData(pVM, pSSM);
760 AssertRCReturn(rc, rc);
761 return VINF_SSM_DONT_CALL_AGAIN;
762}
763
764
765/**
766 * @copydoc FNSSMDEVSAVEEXEC
767 */
768static DECLCALLBACK(int) apicR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
769{
770 PAPICDEV pApicDev = PDMINS_2_DATA(pDevIns, PAPICDEV);
771 PVM pVM = PDMDevHlpGetVM(pDevIns);
772 PAPIC pApic = VM_TO_APIC(pVM);
773 AssertReturn(pVM, VERR_INVALID_VM_HANDLE);
774
775 /* Save per-VM data. */
776 int rc = apicR3SaveVMData(pVM, pSSM);
777 AssertRCReturn(rc, rc);
778
779 /* Save per-VCPU data.*/
780 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
781 {
782 PVMCPU pVCpu = &pVM->aCpus[idCpu];
783 PCAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
784
785 SSMR3PutU64(pSSM, pApicCpu->uApicBaseMsr);
786
787 /** @todo */
788 }
789
790 return rc;
791}
792
793
794/**
795 * @copydoc FNSSMDEVLOADEXEC
796 */
797static DECLCALLBACK(int) apicR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
798{
799 PAPICDEV pApicDev = PDMINS_2_DATA(pDevIns, PAPICDEV);
800 PVM pVM = PDMDevHlpGetVM(pDevIns);
801 PAPIC pApic = VM_TO_APIC(pVM);
802 AssertReturn(pVM, VERR_INVALID_VM_HANDLE);
803
804 /* Weed out invalid versions. */
805 if ( uVersion != APIC_SAVED_STATE_VERSION
806 && uVersion != APIC_SAVED_STATE_VERSION_VBOX_30
807 && uVersion != APIC_SAVED_STATE_VERSION_ANCIENT)
808 {
809 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
810 }
811
812 if (uVersion > APIC_SAVED_STATE_VERSION_VBOX_30)
813 {
814 /* Verify number of CPUs. */
815 uint32_t cCpus;
816 int rc = SSMR3GetU32(pSSM, &cCpus);
817 AssertRCReturn(rc, rc);
818 if (cCpus != pVM->cCpus)
819 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - cCpus: saved=%u config=%u"), cCpus, pVM->cCpus);
820
821 /* Verify I/O APIC presence. */
822 bool fIoApicPresent;
823 rc = SSMR3GetBool(pSSM, &fIoApicPresent);
824 AssertRCReturn(rc, rc);
825 if (fIoApicPresent != pApic->fIoApicPresent)
826 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - fIoApicPresent: saved=%RTbool config=%RTbool"),
827 fIoApicPresent, pApic->fIoApicPresent);
828
829 /* Verify configured APIC mode. */
830 uint32_t uLegacyApicMode;
831 rc = SSMR3GetU32(pSSM, &uLegacyApicMode);
832 AssertRCReturn(rc, rc);
833 APICMODE const enmApicMode = apicR3ConvertFromLegacyApicMode((PDMAPICMODE)uLegacyApicMode);
834 if (enmApicMode != pApic->enmOriginalMode)
835 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - uApicMode: saved=%#x(%#x) config=%#x(%#x)"),
836 uLegacyApicMode, enmApicMode, apicR3ConvertToLegacyApicMode(pApic->enmOriginalMode),
837 pApic->enmOriginalMode);
838
839 if (uVersion == APIC_SAVED_STATE_VERSION)
840 {
841 /** @todo load any new additional per-VM data. */
842 }
843 }
844
845 if (uPass != SSM_PASS_FINAL)
846 return VINF_SUCCESS;
847
848 int rc = VINF_SUCCESS;
849 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
850 {
851 PVMCPU pVCpu = &pVM->aCpus[idCpu];
852 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
853
854 if (uVersion == APIC_SAVED_STATE_VERSION)
855 {
856 /** @todo load new per-VCPU data. */
857 }
858 else
859 {
860 /** @todo load & translate old per-VCPU data to new APIC code. */
861 uint32_t uApicBaseMsrLo;
862 SSMR3GetU32(pSSM, &uApicBaseMsrLo);
863 pApicCpu->uApicBaseMsr = uApicBaseMsrLo;
864 }
865 }
866
867 return rc;
868}
869
870
871/**
872 * The timer callback.
873 *
874 * @param pDevIns The device instance.
875 * @param pTimer The timer handle.
876 * @param pvUser Opaque pointer to the VMCPU.
877 *
878 * @thread Any.
879 * @remarks Currently this function is invoked on the last EMT, see @c
880 * idTimerCpu in tmR3TimerCallback(). However, the code does -not-
881 * rely on this and is designed to work with being invoked on any
882 * thread.
883 */
884static DECLCALLBACK(void) apicR3TimerCallback(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
885{
886 PVMCPU pVCpu = (PVMCPU)pvUser;
887 Assert(TMTimerIsLockOwner(pTimer));
888 Assert(pVCpu);
889
890 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
891 uint32_t const uLvtTimer = pXApicPage->lvt_timer.all.u32LvtTimer;
892 if (!XAPIC_LVT_IS_MASKED(uLvtTimer))
893 {
894 uint8_t uVector = XAPIC_LVT_GET_VECTOR(uLvtTimer);
895 APICPostInterrupt(pVCpu, uVector, XAPICTRIGGERMODE_EDGE);
896 }
897
898 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
899 XAPICTIMERMODE enmTimerMode = XAPIC_LVT_GET_TIMER_MODE(uLvtTimer);
900 switch (enmTimerMode)
901 {
902 case XAPICTIMERMODE_PERIODIC:
903 {
904 /* The initial-count register determines if the periodic timer is re-armed. */
905 uint32_t const uInitialCount = pXApicPage->timer_icr.u32InitialCount;
906 pXApicPage->timer_ccr.u32CurrentCount = uInitialCount;
907 if (uInitialCount)
908 APICStartTimer(pApicCpu, uInitialCount);
909 break;
910 }
911
912 case XAPICTIMERMODE_ONESHOT:
913 {
914 pXApicPage->timer_ccr.u32CurrentCount = 0;
915 break;
916 }
917
918 case XAPICTIMERMODE_TSC_DEADLINE:
919 {
920 /** @todo implement TSC deadline. */
921 AssertMsgFailed(("APIC: TSC deadline mode unimplemented\n"));
922 break;
923 }
924 }
925}
926
927
928/**
929 * @interface_method_impl{PDMDEVREG,pfnReset}
930 */
931static DECLCALLBACK(void) apicR3Reset(PPDMDEVINS pDevIns)
932{
933 PAPICDEV pApicDev = PDMINS_2_DATA(pDevIns, PAPICDEV);
934 PVM pVM = PDMDevHlpGetVM(pDevIns);
935 VM_ASSERT_EMT0(pVM);
936 VM_ASSERT_IS_NOT_RUNNING(pVM);
937
938 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
939 {
940 PVMCPU pVCpuDest = &pVM->aCpus[idCpu];
941 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpuDest);
942
943 int rc = TMTimerLock(pApicCpu->pTimerR3, VERR_IGNORED);
944 Assert(rc == VINF_SUCCESS); NOREF(rc);
945 TMTimerStop(pApicCpu->pTimerR3);
946 TMTimerUnlock(pApicCpu->pTimerR3);
947
948 APICR3Reset(pVCpuDest);
949
950 /* Clear the interrupt pending force flag. */
951 APICClearInterruptFF(pVCpuDest, PDMAPICIRQ_HARDWARE);
952 }
953}
954
955
956/**
957 * @interface_method_impl{PDMDEVREG,pfnRelocate}
958 */
959static DECLCALLBACK(void) apicR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
960{
961 PVM pVM = PDMDevHlpGetVM(pDevIns);
962 PAPIC pApic = VM_TO_APIC(pVM);
963 PAPICDEV pApicDev = PDMINS_2_DATA(pDevIns, PAPICDEV);
964
965 LogFlow(("APIC: apicR3Relocate: pDevIns=%p offDelta=%RGi\n", pDevIns, offDelta));
966
967 pApicDev->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
968 pApicDev->pApicHlpRC = pApicDev->pApicHlpR3->pfnGetRCHelpers(pDevIns);
969 pApicDev->pCritSectRC = pApicDev->pApicHlpR3->pfnGetRCCritSect(pDevIns);
970
971 pApic->pApicDevRC = PDMINS_2_DATA_RCPTR(pDevIns);
972 if (pApic->pvApicPibRC)
973 pApic->pvApicPibRC = MMHyperR3ToRC(pVM, (void *)pApic->pvApicPibR3);
974
975 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
976 {
977 PVMCPU pVCpu = &pVM->aCpus[idCpu];
978 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
979 pApicCpu->pTimerRC = TMTimerRCPtr(pApicCpu->pTimerR3);
980
981 if (pApicCpu->pvApicPageRC)
982 pApicCpu->pvApicPageRC = MMHyperR3ToRC(pVM, (void *)pApicCpu->pvApicPageR3);
983 if (pApicCpu->pvApicPibRC)
984 pApicCpu->pvApicPibRC = MMHyperR3ToRC(pVM, (void *)pApicCpu->pvApicPibR3);
985 }
986}
987
988
989/**
990 * Terminates the APIC state.
991 *
992 * @param pVM The cross context VM structure.
993 */
994static void apicR3TermState(PVM pVM)
995{
996 PAPIC pApic = VM_TO_APIC(pVM);
997 if (pApic->pvApicPibR3)
998 {
999 size_t const cPages = pApic->cbApicPib >> PAGE_SHIFT;
1000 if (cPages == 1)
1001 SUPR3PageFreeEx((void *)pApic->pvApicPibR3, cPages);
1002 else
1003 SUPR3ContFree((void *)pApic->pvApicPibR3, cPages);
1004 pApic->pvApicPibR3 = NULL;
1005 }
1006
1007 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1008 {
1009 PVMCPU pVCpu = &pVM->aCpus[idCpu];
1010 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
1011 if (pApicCpu->pvApicPageR3)
1012 {
1013 SUPR3PageFreeEx((void *)pApicCpu->pvApicPageR3, 1 /* cPages */);
1014 pApicCpu->pvApicPageR3 = NULL;
1015 }
1016 }
1017}
1018
1019
1020/**
1021 * Initializes the APIC state.
1022 *
1023 * @returns VBox status code.
1024 * @param pVM The cross context VM structure.
1025 */
1026static int apicR3InitState(PVM pVM)
1027{
1028 PAPIC pApic = VM_TO_APIC(pVM);
1029 bool const fNeedGCMapping = !HMIsEnabled(pVM);
1030
1031 /*
1032 * Allocate and map the pending-interrupt bitmap (PIB).
1033 *
1034 * We allocate all the VCPUs' PIBs contiguously in order to save space as
1035 * physically contiguous allocations are rounded to a multiple of page size.
1036 */
1037 pApic->cbApicPib = RT_ALIGN_Z(pVM->cCpus * sizeof(APICPIB), PAGE_SIZE);
1038 size_t const cPages = pApic->cbApicPib >> PAGE_SHIFT;
1039 Assert(!pApic->pvApicPibR3);
1040 if (cPages == 1)
1041 {
1042 SUPPAGE SupApicPib;
1043 RT_ZERO(SupApicPib);
1044 SupApicPib.Phys = NIL_RTHCPHYS;
1045 int rc = SUPR3PageAllocEx(cPages, 0 /* fFlags */, (void **)&pApic->pvApicPibR3, &pApic->pvApicPibR0, &SupApicPib);
1046 if (RT_SUCCESS(rc))
1047 {
1048 pApic->HCPhysApicPib = SupApicPib.Phys;
1049 Assert(pApic->HCPhysApicPib != NIL_RTHCPHYS);
1050 Assert(pApic->pvApicPibR3);
1051 }
1052 else
1053 {
1054 LogRel(("APIC: Failed to allocate %u bytes for the pending-interrupt bitmap, rc=%Rrc\n", pApic->cbApicPib, rc));
1055 return rc;
1056 }
1057 }
1058 else
1059 pApic->pvApicPibR3 = SUPR3ContAlloc(cPages, &pApic->pvApicPibR0, &pApic->HCPhysApicPib);
1060
1061 if (pApic->pvApicPibR3)
1062 {
1063 /* Map the pending-interrupt bitmap (PIB) into GC. */
1064 if (fNeedGCMapping)
1065 {
1066 int rc = MMR3HyperMapHCPhys(pVM, (void *)pApic->pvApicPibR3, NIL_RTR0PTR, pApic->HCPhysApicPib, pApic->cbApicPib,
1067 "APIC PIB", (PRTGCPTR)&pApic->pvApicPibRC);
1068 if (RT_FAILURE(rc))
1069 {
1070 LogRel(("APIC: Failed to map %u bytes for the pending-interrupt bitmap to GC, rc=%Rrc\n", pApic->cbApicPib, rc));
1071 apicR3TermState(pVM);
1072 return rc;
1073 }
1074 }
1075
1076 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1077 {
1078 PVMCPU pVCpu = &pVM->aCpus[idCpu];
1079 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
1080
1081 /* Allocate and map the virtual-APIC page. */
1082 SUPPAGE SupApicPage;
1083 RT_ZERO(SupApicPage);
1084 SupApicPage.Phys = NIL_RTHCPHYS;
1085
1086 pApicCpu->cbApicPage = sizeof(XAPICPAGE);
1087 AssertCompile(sizeof(XAPICPAGE) == PAGE_SIZE);
1088
1089 Assert(!pApicCpu->pvApicPageR3);
1090 int rc = SUPR3PageAllocEx(1 /* cPages */, 0 /* fFlags */, (void **)&pApicCpu->pvApicPageR3, &pApicCpu->pvApicPageR0,
1091 &SupApicPage);
1092 if (RT_SUCCESS(rc))
1093 {
1094 pApicCpu->HCPhysApicPage = SupApicPage.Phys;
1095 Assert(pApicCpu->HCPhysApicPage != NIL_RTHCPHYS);
1096
1097 /* Map the virtual-APIC page into GC. */
1098 if (fNeedGCMapping)
1099 {
1100 rc = MMR3HyperMapHCPhys(pVM, (void *)pApicCpu->pvApicPageR3, NIL_RTR0PTR, pApicCpu->HCPhysApicPage,
1101 pApicCpu->cbApicPage, "APIC", (PRTGCPTR)&pApicCpu->pvApicPageRC);
1102 if (RT_FAILURE(rc))
1103 {
1104 LogRel(("APIC%u: Failed to map %u bytes for the virtual-APIC page to GC, rc=%Rrc", idCpu,
1105 pApicCpu->cbApicPage, rc));
1106 apicR3TermState(pVM);
1107 return rc;
1108 }
1109 }
1110
1111 /* Associate the per-VCPU PIB pointers to the per-VM PIB mapping. */
1112 size_t const offApicPib = idCpu * sizeof(APICPIB);
1113 pApicCpu->pvApicPibR0 = (RTR0PTR)((const uint8_t *)pApic->pvApicPibR0 + offApicPib);
1114 pApicCpu->pvApicPibR3 = (RTR3PTR)((const uint8_t *)pApic->pvApicPibR3 + offApicPib);
1115 if (fNeedGCMapping)
1116 pApicCpu->pvApicPibRC += offApicPib;
1117
1118 /* Initialize the virtual-APIC state. */
1119 memset((void *)pApicCpu->pvApicPageR3, 0, pApicCpu->cbApicPage);
1120 APICR3Reset(pVCpu);
1121 }
1122 else
1123 {
1124 LogRel(("APIC%u: Failed to allocate %u bytes for the virtual-APIC page\n", pApicCpu->cbApicPage));
1125 apicR3TermState(pVM);
1126 return VERR_NO_MEMORY;
1127 }
1128 }
1129
1130 return VINF_SUCCESS;
1131 }
1132
1133 LogRel(("APIC: Failed to allocate %u bytes of contiguous low-memory for the pending-interrupt bitmap\n", pApic->cbApicPib));
1134 return VERR_NO_MEMORY;
1135}
1136
1137
1138/**
1139 * @interface_method_impl{PDMDEVREG,pfnDestruct}
1140 */
1141static DECLCALLBACK(int) apicR3Destruct(PPDMDEVINS pDevIns)
1142{
1143 PVM pVM = PDMDevHlpGetVM(pDevIns);
1144 apicR3TermState(pVM);
1145 return VINF_SUCCESS;
1146}
1147
1148
1149/**
1150 * @interface_method_impl{PDMDEVREG,pfnInitComplete}
1151 */
1152static DECLCALLBACK(int) apicR3InitComplete(PPDMDEVINS pDevIns)
1153{
1154 PVM pVM = PDMDevHlpGetVM(pDevIns);
1155 PAPIC pApic = VM_TO_APIC(pVM);
1156
1157 CPUMCPUIDLEAF CpuLeaf;
1158 int rc = CPUMR3CpuIdGetLeaf(pVM, &CpuLeaf, 1, 0);
1159 AssertRCReturn(rc, rc);
1160 pApic->fSupportsTscDeadline = RT_BOOL(CpuLeaf.uEcx & X86_CPUID_FEATURE_ECX_TSCDEADL);
1161
1162 pApic->fPostedIntrsEnabled = HMR3IsPostedIntrsEnabled(pVM->pUVM);
1163 pApic->fVirtApicRegsEnabled = HMR3IsVirtApicRegsEnabled(pVM->pUVM);
1164
1165 LogRel(("APIC: fPostedIntrsEnabled=%RTbool fVirtApicRegsEnabled=%RTbool fSupportsTscDeadline=%RTbool\n",
1166 pApic->fPostedIntrsEnabled, pApic->fVirtApicRegsEnabled, pApic->fSupportsTscDeadline));
1167 return VINF_SUCCESS;
1168}
1169
1170
1171/**
1172 * @interface_method_impl{PDMDEVREG,pfnConstruct}
1173 */
1174static DECLCALLBACK(int) apicR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
1175{
1176 /*
1177 * Validate inputs.
1178 */
1179 Assert(iInstance == 0);
1180 Assert(pDevIns);
1181
1182 PAPICDEV pApicDev = PDMINS_2_DATA(pDevIns, PAPICDEV);
1183 PVM pVM = PDMDevHlpGetVM(pDevIns);
1184 PAPIC pApic = VM_TO_APIC(pVM);
1185
1186 /*
1187 * Validate APIC settings.
1188 */
1189 int rc = CFGMR3ValidateConfig(pCfg, "/APIC/",
1190 "RZEnabled"
1191 "|Mode"
1192 "|IOAPIC"
1193 "|NumCPUs",
1194 "" /* pszValidNodes */, "APIC" /* pszWho */, 0 /* uInstance */);
1195 if (RT_FAILURE(rc))
1196 return rc;
1197
1198 rc = CFGMR3QueryBoolDef(pCfg, "RZEnabled", &pApic->fRZEnabled, true);
1199 AssertLogRelRCReturn(rc, rc);
1200
1201 rc = CFGMR3QueryBoolDef(pCfg, "IOAPIC", &pApic->fIoApicPresent, true);
1202 AssertLogRelRCReturn(rc, rc);
1203
1204 uint8_t uOriginalMode;
1205 rc = CFGMR3QueryU8Def(pCfg, "Mode", &uOriginalMode, APICMODE_XAPIC);
1206 AssertLogRelRCReturn(rc, rc);
1207 /* Validate APIC modes. */
1208 switch (uOriginalMode)
1209 {
1210 case APICMODE_DISABLED:
1211 case APICMODE_X2APIC:
1212 case APICMODE_XAPIC:
1213 pApic->enmOriginalMode = (APICMODE)uOriginalMode;
1214 break;
1215 default:
1216 return VMR3SetError(pVM->pUVM, VERR_INVALID_STATE, RT_SRC_POS, "APIC mode %#x unknown.", uOriginalMode);
1217 }
1218
1219 /*
1220 * Initialize the APIC state.
1221 */
1222 pApicDev->pDevInsR3 = pDevIns;
1223 pApicDev->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
1224 pApicDev->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1225
1226 pApic->pApicDevR0 = PDMINS_2_DATA_R0PTR(pDevIns);
1227 pApic->pApicDevR3 = (PAPICDEV)PDMINS_2_DATA_R3PTR(pDevIns);
1228 pApic->pApicDevRC = PDMINS_2_DATA_RCPTR(pDevIns);
1229
1230 rc = apicR3InitState(pVM);
1231 AssertRCReturn(rc, rc);
1232
1233 /*
1234 * Disable automatic PDM locking for this device.
1235 */
1236 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
1237 AssertRCReturn(rc, rc);
1238
1239 /*
1240 * Register the APIC.
1241 */
1242 PDMAPICREG ApicReg;
1243 RT_ZERO(ApicReg);
1244 ApicReg.u32Version = PDM_APICREG_VERSION;
1245 ApicReg.pfnGetInterruptR3 = APICGetInterrupt;
1246 ApicReg.pfnHasPendingIrqR3 = APICHasPendingIrq;
1247 ApicReg.pfnSetBaseMsrR3 = APICSetBaseMsr;
1248 ApicReg.pfnGetBaseMsrR3 = APICGetBaseMsr;
1249 ApicReg.pfnSetTprR3 = APICSetTpr;
1250 ApicReg.pfnGetTprR3 = APICGetTpr;
1251 ApicReg.pfnWriteMsrR3 = APICWriteMsr;
1252 ApicReg.pfnReadMsrR3 = APICReadMsr;
1253 ApicReg.pfnBusDeliverR3 = APICBusDeliver;
1254 ApicReg.pfnLocalInterruptR3 = APICLocalInterrupt;
1255 ApicReg.pfnGetTimerFreqR3 = APICGetTimerFreq;
1256 if (pApic->fRZEnabled)
1257 {
1258 ApicReg.pszGetInterruptRC = "APICGetInterrupt";
1259 ApicReg.pszHasPendingIrqRC = "APICHasPendingIrq";
1260 ApicReg.pszSetBaseMsrRC = "APICSetBaseMsr";
1261 ApicReg.pszGetBaseMsrRC = "APICGetBaseMsr";
1262 ApicReg.pszSetTprRC = "APICSetTpr";
1263 ApicReg.pszGetTprRC = "APICGetTpr";
1264 ApicReg.pszWriteMsrRC = "APICWriteMsr";
1265 ApicReg.pszReadMsrRC = "APICReadMsr";
1266 ApicReg.pszBusDeliverRC = "APICBusDeliver";
1267 ApicReg.pszLocalInterruptRC = "APICLocalInterrupt";
1268 ApicReg.pszGetTimerFreqRC = "APICGetTimerFreq";
1269
1270 ApicReg.pszGetInterruptR0 = "APICGetInterrupt";
1271 ApicReg.pszHasPendingIrqR0 = "APICHasPendingIrq";
1272 ApicReg.pszSetBaseMsrR0 = "APICSetBaseMsr";
1273 ApicReg.pszGetBaseMsrR0 = "APICGetBaseMsr";
1274 ApicReg.pszSetTprR0 = "APICSetTpr";
1275 ApicReg.pszGetTprR0 = "APICGetTpr";
1276 ApicReg.pszWriteMsrR0 = "APICWriteMsr";
1277 ApicReg.pszReadMsrR0 = "APICReadMsr";
1278 ApicReg.pszBusDeliverR0 = "APICBusDeliver";
1279 ApicReg.pszLocalInterruptR0 = "APICLocalInterrupt";
1280 ApicReg.pszGetTimerFreqR0 = "APICGetTimerFreq";
1281 }
1282
1283 rc = PDMDevHlpAPICRegister(pDevIns, &ApicReg, &pApicDev->pApicHlpR3);
1284 AssertLogRelRCReturn(rc, rc);
1285 pApicDev->pCritSectR3 = pApicDev->pApicHlpR3->pfnGetR3CritSect(pDevIns);
1286
1287 /*
1288 * Update the CPUID bits.
1289 */
1290 APICUpdateCpuIdForMode(pVM, pApic->enmOriginalMode);
1291 LogRel(("APIC: Switched mode to %s\n", apicGetModeName(pApic->enmOriginalMode)));
1292
1293 /*
1294 * Register the MMIO range.
1295 */
1296 PAPICCPU pApicCpu0 = VMCPU_TO_APICCPU(&pVM->aCpus[0]);
1297 RTGCPHYS GCPhysApicBase = MSR_APICBASE_GET_PHYSADDR(pApicCpu0->uApicBaseMsr);
1298 rc = PDMDevHlpMMIORegister(pDevIns, GCPhysApicBase, sizeof(XAPICPAGE), pVM,
1299 IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_DWORD_ZEROED,
1300 APICWriteMmio, APICReadMmio, "APIC");
1301 if (RT_FAILURE(rc))
1302 return rc;
1303
1304 if (pApic->fRZEnabled)
1305 {
1306 pApicDev->pApicHlpRC = pApicDev->pApicHlpR3->pfnGetRCHelpers(pDevIns);
1307 pApicDev->pCritSectRC = pApicDev->pApicHlpR3->pfnGetRCCritSect(pDevIns);
1308 rc = PDMDevHlpMMIORegisterRC(pDevIns, GCPhysApicBase, sizeof(XAPICPAGE), NIL_RTRCPTR /*pvUser*/,
1309 "APICWriteMmio", "APICReadMmio");
1310 if (RT_FAILURE(rc))
1311 return rc;
1312
1313 pApicDev->pApicHlpR0 = pApicDev->pApicHlpR3->pfnGetR0Helpers(pDevIns);
1314 pApicDev->pCritSectR0 = pApicDev->pApicHlpR3->pfnGetR0CritSect(pDevIns);
1315 rc = PDMDevHlpMMIORegisterR0(pDevIns, GCPhysApicBase, sizeof(XAPICPAGE), NIL_RTR0PTR /*pvUser*/,
1316 "APICWriteMmio", "APICReadMmio");
1317 if (RT_FAILURE(rc))
1318 return rc;
1319 }
1320
1321 /*
1322 * Create the APIC timers.
1323 */
1324 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1325 {
1326 PVMCPU pVCpu = &pVM->aCpus[idCpu];
1327 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
1328 RTStrPrintf(&pApicCpu->szTimerDesc[0], sizeof(pApicCpu->szTimerDesc), "APIC Timer %u", pVCpu->idCpu);
1329 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, apicR3TimerCallback, pVCpu, TMTIMER_FLAGS_NO_CRIT_SECT,
1330 pApicCpu->szTimerDesc, &pApicCpu->pTimerR3);
1331 if (RT_SUCCESS(rc))
1332 {
1333 pApicCpu->pTimerR0 = TMTimerR0Ptr(pApicCpu->pTimerR3);
1334 pApicCpu->pTimerRC = TMTimerRCPtr(pApicCpu->pTimerR3);
1335
1336 rc = PDMR3CritSectInit(pVM, &pApicCpu->TimerCritSect, RT_SRC_POS, pApicCpu->szTimerDesc);
1337 if (RT_SUCCESS(rc))
1338 TMR3TimerSetCritSect(pApicCpu->pTimerR3, &pApicCpu->TimerCritSect);
1339 else
1340 return rc;
1341 }
1342 else
1343 return rc;
1344 }
1345
1346 /*
1347 * Register saved state callbacks.
1348 */
1349 rc = PDMDevHlpSSMRegister3(pDevIns, APIC_SAVED_STATE_VERSION, sizeof(*pApicDev), NULL /*pfnLiveExec*/, apicR3SaveExec,
1350 apicR3LoadExec);
1351 if (RT_FAILURE(rc))
1352 return rc;
1353
1354 /*
1355 * Register debugger info callback.
1356 */
1357 PDMDevHlpDBGFInfoRegister(pDevIns, "apic", "Display Local APIC state for current CPU. "
1358 "Recognizes 'basic', 'lvt', 'timer' as arguments, defaulting to 'basic'.", apicR3DbgInfo);
1359
1360#ifdef VBOX_WITH_STATISTICS
1361 /*
1362 * Statistics.
1363 */
1364 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1365 {
1366 PVMCPU pVCpu = &pVM->aCpus[idCpu];
1367 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
1368 PDMDevHlpSTAMRegisterF(pDevIns, &pApicCpu->StatMmioReadGC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1369 "Number of APIC MMIO reads in GC.", "/Devices/APIC/%u/MmioReadGC", idCpu);
1370 PDMDevHlpSTAMRegisterF(pDevIns, &pApicCpu->StatMmioReadHC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1371 "Number of APIC MMIO reads in HC.", "/Devices/APIC/%u/MmioReadHC", idCpu);
1372
1373 PDMDevHlpSTAMRegisterF(pDevIns, &pApicCpu->StatMmioWriteGC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1374 "Number of APIC MMIO writes in GC.", "/Devices/APIC/%u/MmioWriteGC", idCpu);
1375 PDMDevHlpSTAMRegisterF(pDevIns, &pApicCpu->StatMmioWriteHC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1376 "Number of APIC MMIO writes in HC.", "/Devices/APIC/%u/MmioWriteHC", idCpu);
1377
1378 PDMDevHlpSTAMRegisterF(pDevIns, &pApicCpu->StatMsrWrite, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1379 "Number of APIC MSR writes.", "/Devices/APIC/%u/MsrWrite", idCpu);
1380 PDMDevHlpSTAMRegisterF(pDevIns, &pApicCpu->StatMsrRead, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1381 "Number of APIC MSR reads.", "/Devices/APIC/%u/MsrRead", idCpu);
1382 }
1383#endif
1384 return VINF_SUCCESS;
1385}
1386
1387
1388/**
1389 * APIC device registration structure.
1390 */
1391const PDMDEVREG g_DeviceAPIC =
1392{
1393 /* u32Version */
1394 PDM_DEVREG_VERSION,
1395 /* szName */
1396 "apic",
1397 /* szRCMod */
1398 "VMMRC.rc",
1399 /* szR0Mod */
1400 "VMMR0.r0",
1401 /* pszDescription */
1402 "Advanced Programmable Interrupt Controller",
1403 /* fFlags */
1404 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64 | PDM_DEVREG_FLAGS_PAE36
1405 | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
1406 /* fClass */
1407 PDM_DEVREG_CLASS_PIC,
1408 /* cMaxInstances */
1409 1,
1410 /* cbInstance */
1411 sizeof(APICDEV),
1412 /* pfnConstruct */
1413 apicR3Construct,
1414 /* pfnDestruct */
1415 apicR3Destruct,
1416 /* pfnRelocate */
1417 apicR3Relocate,
1418 /* pfnMemSetup */
1419 NULL,
1420 /* pfnPowerOn */
1421 NULL,
1422 /* pfnReset */
1423 apicR3Reset,
1424 /* pfnSuspend */
1425 NULL,
1426 /* pfnResume */
1427 NULL,
1428 /* pfnAttach */
1429 NULL,
1430 /* pfnDetach */
1431 NULL,
1432 /* pfnQueryInterface. */
1433 NULL,
1434 /* pfnInitComplete */
1435 apicR3InitComplete,
1436 /* pfnPowerOff */
1437 NULL,
1438 /* pfnSoftReset */
1439 NULL,
1440 /* u32VersionEnd */
1441 PDM_DEVREG_VERSION
1442};
1443
1444#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
1445
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