VirtualBox

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

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

VMM: Doxygen fixes for r106369.

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

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