VirtualBox

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

Last change on this file since 92473 was 88557, checked in by vboxsync, 4 years ago

APIC: More statistics for certain registers.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 67.3 KB
Line 
1/* $Id: APIC.cpp 88557 2021-04-16 03:36:25Z vboxsync $ */
2/** @file
3 * APIC - Advanced Programmable Interrupt Controller.
4 */
5
6/*
7 * Copyright (C) 2016-2020 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/apic.h>
26#include <VBox/vmm/cpum.h>
27#include <VBox/vmm/hm.h>
28#include <VBox/vmm/mm.h>
29#include <VBox/vmm/pdmdev.h>
30#include <VBox/vmm/ssm.h>
31#include <VBox/vmm/vm.h>
32
33
34#ifndef VBOX_DEVICE_STRUCT_TESTCASE
35
36
37/*********************************************************************************************************************************
38* Defined Constants And Macros *
39*********************************************************************************************************************************/
40/** The current APIC saved state version. */
41#define APIC_SAVED_STATE_VERSION 5
42/** VirtualBox 5.1 beta2 - pre fActiveLintX. */
43#define APIC_SAVED_STATE_VERSION_VBOX_51_BETA2 4
44/** The saved state version used by VirtualBox 5.0 and
45 * earlier. */
46#define APIC_SAVED_STATE_VERSION_VBOX_50 3
47/** The saved state version used by VirtualBox v3 and earlier.
48 * This does not include the config. */
49#define APIC_SAVED_STATE_VERSION_VBOX_30 2
50/** Some ancient version... */
51#define APIC_SAVED_STATE_VERSION_ANCIENT 1
52
53#ifdef VBOX_WITH_STATISTICS
54# define X2APIC_MSRRANGE(a_uFirst, a_uLast, a_szName) \
55 { (a_uFirst), (a_uLast), kCpumMsrRdFn_Ia32X2ApicN, kCpumMsrWrFn_Ia32X2ApicN, 0, 0, 0, 0, 0, a_szName, { 0 }, { 0 }, { 0 }, { 0 } }
56# define X2APIC_MSRRANGE_INVALID(a_uFirst, a_uLast, a_szName) \
57 { (a_uFirst), (a_uLast), kCpumMsrRdFn_WriteOnly, kCpumMsrWrFn_ReadOnly, 0, 0, 0, 0, UINT64_MAX /*fWrGpMask*/, a_szName, { 0 }, { 0 }, { 0 }, { 0 } }
58#else
59# define X2APIC_MSRRANGE(a_uFirst, a_uLast, a_szName) \
60 { (a_uFirst), (a_uLast), kCpumMsrRdFn_Ia32X2ApicN, kCpumMsrWrFn_Ia32X2ApicN, 0, 0, 0, 0, 0, a_szName }
61# define X2APIC_MSRRANGE_INVALID(a_uFirst, a_uLast, a_szName) \
62 { (a_uFirst), (a_uLast), kCpumMsrRdFn_WriteOnly, kCpumMsrWrFn_ReadOnly, 0, 0, 0, 0, UINT64_MAX /*fWrGpMask*/, a_szName }
63#endif
64
65
66/*********************************************************************************************************************************
67* Global Variables *
68*********************************************************************************************************************************/
69/**
70 * MSR range supported by the x2APIC.
71 * See Intel spec. 10.12.2 "x2APIC Register Availability".
72 */
73static CPUMMSRRANGE const g_MsrRange_x2Apic = X2APIC_MSRRANGE(MSR_IA32_X2APIC_START, MSR_IA32_X2APIC_END, "x2APIC range");
74static CPUMMSRRANGE const g_MsrRange_x2Apic_Invalid = X2APIC_MSRRANGE_INVALID(MSR_IA32_X2APIC_START, MSR_IA32_X2APIC_END, "x2APIC range invalid");
75#undef X2APIC_MSRRANGE
76#undef X2APIC_MSRRANGE_GP
77
78/** Saved state field descriptors for XAPICPAGE. */
79static const SSMFIELD g_aXApicPageFields[] =
80{
81 SSMFIELD_ENTRY( XAPICPAGE, id.u8ApicId),
82 SSMFIELD_ENTRY( XAPICPAGE, version.all.u32Version),
83 SSMFIELD_ENTRY( XAPICPAGE, tpr.u8Tpr),
84 SSMFIELD_ENTRY( XAPICPAGE, apr.u8Apr),
85 SSMFIELD_ENTRY( XAPICPAGE, ppr.u8Ppr),
86 SSMFIELD_ENTRY( XAPICPAGE, ldr.all.u32Ldr),
87 SSMFIELD_ENTRY( XAPICPAGE, dfr.all.u32Dfr),
88 SSMFIELD_ENTRY( XAPICPAGE, svr.all.u32Svr),
89 SSMFIELD_ENTRY( XAPICPAGE, isr.u[0].u32Reg),
90 SSMFIELD_ENTRY( XAPICPAGE, isr.u[1].u32Reg),
91 SSMFIELD_ENTRY( XAPICPAGE, isr.u[2].u32Reg),
92 SSMFIELD_ENTRY( XAPICPAGE, isr.u[3].u32Reg),
93 SSMFIELD_ENTRY( XAPICPAGE, isr.u[4].u32Reg),
94 SSMFIELD_ENTRY( XAPICPAGE, isr.u[5].u32Reg),
95 SSMFIELD_ENTRY( XAPICPAGE, isr.u[6].u32Reg),
96 SSMFIELD_ENTRY( XAPICPAGE, isr.u[7].u32Reg),
97 SSMFIELD_ENTRY( XAPICPAGE, tmr.u[0].u32Reg),
98 SSMFIELD_ENTRY( XAPICPAGE, tmr.u[1].u32Reg),
99 SSMFIELD_ENTRY( XAPICPAGE, tmr.u[2].u32Reg),
100 SSMFIELD_ENTRY( XAPICPAGE, tmr.u[3].u32Reg),
101 SSMFIELD_ENTRY( XAPICPAGE, tmr.u[4].u32Reg),
102 SSMFIELD_ENTRY( XAPICPAGE, tmr.u[5].u32Reg),
103 SSMFIELD_ENTRY( XAPICPAGE, tmr.u[6].u32Reg),
104 SSMFIELD_ENTRY( XAPICPAGE, tmr.u[7].u32Reg),
105 SSMFIELD_ENTRY( XAPICPAGE, irr.u[0].u32Reg),
106 SSMFIELD_ENTRY( XAPICPAGE, irr.u[1].u32Reg),
107 SSMFIELD_ENTRY( XAPICPAGE, irr.u[2].u32Reg),
108 SSMFIELD_ENTRY( XAPICPAGE, irr.u[3].u32Reg),
109 SSMFIELD_ENTRY( XAPICPAGE, irr.u[4].u32Reg),
110 SSMFIELD_ENTRY( XAPICPAGE, irr.u[5].u32Reg),
111 SSMFIELD_ENTRY( XAPICPAGE, irr.u[6].u32Reg),
112 SSMFIELD_ENTRY( XAPICPAGE, irr.u[7].u32Reg),
113 SSMFIELD_ENTRY( XAPICPAGE, esr.all.u32Errors),
114 SSMFIELD_ENTRY( XAPICPAGE, icr_lo.all.u32IcrLo),
115 SSMFIELD_ENTRY( XAPICPAGE, icr_hi.all.u32IcrHi),
116 SSMFIELD_ENTRY( XAPICPAGE, lvt_timer.all.u32LvtTimer),
117 SSMFIELD_ENTRY( XAPICPAGE, lvt_thermal.all.u32LvtThermal),
118 SSMFIELD_ENTRY( XAPICPAGE, lvt_perf.all.u32LvtPerf),
119 SSMFIELD_ENTRY( XAPICPAGE, lvt_lint0.all.u32LvtLint0),
120 SSMFIELD_ENTRY( XAPICPAGE, lvt_lint1.all.u32LvtLint1),
121 SSMFIELD_ENTRY( XAPICPAGE, lvt_error.all.u32LvtError),
122 SSMFIELD_ENTRY( XAPICPAGE, timer_icr.u32InitialCount),
123 SSMFIELD_ENTRY( XAPICPAGE, timer_ccr.u32CurrentCount),
124 SSMFIELD_ENTRY( XAPICPAGE, timer_dcr.all.u32DivideValue),
125 SSMFIELD_ENTRY_TERM()
126};
127
128/** Saved state field descriptors for X2APICPAGE. */
129static const SSMFIELD g_aX2ApicPageFields[] =
130{
131 SSMFIELD_ENTRY(X2APICPAGE, id.u32ApicId),
132 SSMFIELD_ENTRY(X2APICPAGE, version.all.u32Version),
133 SSMFIELD_ENTRY(X2APICPAGE, tpr.u8Tpr),
134 SSMFIELD_ENTRY(X2APICPAGE, ppr.u8Ppr),
135 SSMFIELD_ENTRY(X2APICPAGE, ldr.u32LogicalApicId),
136 SSMFIELD_ENTRY(X2APICPAGE, svr.all.u32Svr),
137 SSMFIELD_ENTRY(X2APICPAGE, isr.u[0].u32Reg),
138 SSMFIELD_ENTRY(X2APICPAGE, isr.u[1].u32Reg),
139 SSMFIELD_ENTRY(X2APICPAGE, isr.u[2].u32Reg),
140 SSMFIELD_ENTRY(X2APICPAGE, isr.u[3].u32Reg),
141 SSMFIELD_ENTRY(X2APICPAGE, isr.u[4].u32Reg),
142 SSMFIELD_ENTRY(X2APICPAGE, isr.u[5].u32Reg),
143 SSMFIELD_ENTRY(X2APICPAGE, isr.u[6].u32Reg),
144 SSMFIELD_ENTRY(X2APICPAGE, isr.u[7].u32Reg),
145 SSMFIELD_ENTRY(X2APICPAGE, tmr.u[0].u32Reg),
146 SSMFIELD_ENTRY(X2APICPAGE, tmr.u[1].u32Reg),
147 SSMFIELD_ENTRY(X2APICPAGE, tmr.u[2].u32Reg),
148 SSMFIELD_ENTRY(X2APICPAGE, tmr.u[3].u32Reg),
149 SSMFIELD_ENTRY(X2APICPAGE, tmr.u[4].u32Reg),
150 SSMFIELD_ENTRY(X2APICPAGE, tmr.u[5].u32Reg),
151 SSMFIELD_ENTRY(X2APICPAGE, tmr.u[6].u32Reg),
152 SSMFIELD_ENTRY(X2APICPAGE, tmr.u[7].u32Reg),
153 SSMFIELD_ENTRY(X2APICPAGE, irr.u[0].u32Reg),
154 SSMFIELD_ENTRY(X2APICPAGE, irr.u[1].u32Reg),
155 SSMFIELD_ENTRY(X2APICPAGE, irr.u[2].u32Reg),
156 SSMFIELD_ENTRY(X2APICPAGE, irr.u[3].u32Reg),
157 SSMFIELD_ENTRY(X2APICPAGE, irr.u[4].u32Reg),
158 SSMFIELD_ENTRY(X2APICPAGE, irr.u[5].u32Reg),
159 SSMFIELD_ENTRY(X2APICPAGE, irr.u[6].u32Reg),
160 SSMFIELD_ENTRY(X2APICPAGE, irr.u[7].u32Reg),
161 SSMFIELD_ENTRY(X2APICPAGE, esr.all.u32Errors),
162 SSMFIELD_ENTRY(X2APICPAGE, icr_lo.all.u32IcrLo),
163 SSMFIELD_ENTRY(X2APICPAGE, icr_hi.u32IcrHi),
164 SSMFIELD_ENTRY(X2APICPAGE, lvt_timer.all.u32LvtTimer),
165 SSMFIELD_ENTRY(X2APICPAGE, lvt_thermal.all.u32LvtThermal),
166 SSMFIELD_ENTRY(X2APICPAGE, lvt_perf.all.u32LvtPerf),
167 SSMFIELD_ENTRY(X2APICPAGE, lvt_lint0.all.u32LvtLint0),
168 SSMFIELD_ENTRY(X2APICPAGE, lvt_lint1.all.u32LvtLint1),
169 SSMFIELD_ENTRY(X2APICPAGE, lvt_error.all.u32LvtError),
170 SSMFIELD_ENTRY(X2APICPAGE, timer_icr.u32InitialCount),
171 SSMFIELD_ENTRY(X2APICPAGE, timer_ccr.u32CurrentCount),
172 SSMFIELD_ENTRY(X2APICPAGE, timer_dcr.all.u32DivideValue),
173 SSMFIELD_ENTRY_TERM()
174};
175
176
177/**
178 * Sets the CPUID feature bits for the APIC mode.
179 *
180 * @param pVM The cross context VM structure.
181 * @param enmMode The APIC mode.
182 */
183static void apicR3SetCpuIdFeatureLevel(PVM pVM, PDMAPICMODE enmMode)
184{
185 switch (enmMode)
186 {
187 case PDMAPICMODE_NONE:
188 CPUMR3ClearGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_X2APIC);
189 CPUMR3ClearGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_APIC);
190 break;
191
192 case PDMAPICMODE_APIC:
193 CPUMR3ClearGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_X2APIC);
194 CPUMR3SetGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_APIC);
195 break;
196
197 case PDMAPICMODE_X2APIC:
198 CPUMR3SetGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_APIC);
199 CPUMR3SetGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_X2APIC);
200 break;
201
202 default:
203 AssertMsgFailed(("Unknown/invalid APIC mode: %d\n", (int)enmMode));
204 }
205}
206
207
208/**
209 * Receives an INIT IPI.
210 *
211 * @param pVCpu The cross context virtual CPU structure.
212 */
213VMMR3_INT_DECL(void) APICR3InitIpi(PVMCPU pVCpu)
214{
215 VMCPU_ASSERT_EMT(pVCpu);
216 LogFlow(("APIC%u: APICR3InitIpi\n", pVCpu->idCpu));
217 apicInitIpi(pVCpu);
218}
219
220
221/**
222 * Sets whether Hyper-V compatibility mode (MSR interface) is enabled or not.
223 *
224 * This mode is a hybrid of xAPIC and x2APIC modes, some caveats:
225 * 1. MSRs are used even ones that are missing (illegal) in x2APIC like DFR.
226 * 2. A single ICR is used by the guest to send IPIs rather than 2 ICR writes.
227 * 3. It is unclear what the behaviour will be when invalid bits are set,
228 * currently we follow x2APIC behaviour of causing a \#GP.
229 *
230 * @param pVM The cross context VM structure.
231 * @param fHyperVCompatMode Whether the compatibility mode is enabled.
232 */
233VMMR3_INT_DECL(void) APICR3HvSetCompatMode(PVM pVM, bool fHyperVCompatMode)
234{
235 Assert(pVM);
236 PAPIC pApic = VM_TO_APIC(pVM);
237 pApic->fHyperVCompatMode = fHyperVCompatMode;
238
239 if (fHyperVCompatMode)
240 LogRel(("APIC: Enabling Hyper-V x2APIC compatibility mode\n"));
241
242 int rc = CPUMR3MsrRangesInsert(pVM, &g_MsrRange_x2Apic);
243 AssertLogRelRC(rc);
244}
245
246
247/**
248 * Helper for dumping an APIC 256-bit sparse register.
249 *
250 * @param pApicReg The APIC 256-bit spare register.
251 * @param pHlp The debug output helper.
252 */
253static void apicR3DbgInfo256BitReg(volatile const XAPIC256BITREG *pApicReg, PCDBGFINFOHLP pHlp)
254{
255 ssize_t const cFragments = RT_ELEMENTS(pApicReg->u);
256 unsigned const cBitsPerFragment = sizeof(pApicReg->u[0].u32Reg) * 8;
257 XAPIC256BITREG ApicReg;
258 RT_ZERO(ApicReg);
259
260 pHlp->pfnPrintf(pHlp, " ");
261 for (ssize_t i = cFragments - 1; i >= 0; i--)
262 {
263 uint32_t const uFragment = pApicReg->u[i].u32Reg;
264 ApicReg.u[i].u32Reg = uFragment;
265 pHlp->pfnPrintf(pHlp, "%08x", uFragment);
266 }
267 pHlp->pfnPrintf(pHlp, "\n");
268
269 uint32_t cPending = 0;
270 pHlp->pfnPrintf(pHlp, " Pending:");
271 for (ssize_t i = cFragments - 1; i >= 0; i--)
272 {
273 uint32_t uFragment = ApicReg.u[i].u32Reg;
274 if (uFragment)
275 {
276 do
277 {
278 unsigned idxSetBit = ASMBitLastSetU32(uFragment);
279 --idxSetBit;
280 ASMBitClear(&uFragment, idxSetBit);
281
282 idxSetBit += (i * cBitsPerFragment);
283 pHlp->pfnPrintf(pHlp, " %#02x", idxSetBit);
284 ++cPending;
285 } while (uFragment);
286 }
287 }
288 if (!cPending)
289 pHlp->pfnPrintf(pHlp, " None");
290 pHlp->pfnPrintf(pHlp, "\n");
291}
292
293
294/**
295 * Helper for dumping an APIC pending-interrupt bitmap.
296 *
297 * @param pApicPib The pending-interrupt bitmap.
298 * @param pHlp The debug output helper.
299 */
300static void apicR3DbgInfoPib(PCAPICPIB pApicPib, PCDBGFINFOHLP pHlp)
301{
302 /* Copy the pending-interrupt bitmap as an APIC 256-bit sparse register. */
303 XAPIC256BITREG ApicReg;
304 RT_ZERO(ApicReg);
305 ssize_t const cFragmentsDst = RT_ELEMENTS(ApicReg.u);
306 ssize_t const cFragmentsSrc = RT_ELEMENTS(pApicPib->au64VectorBitmap);
307 AssertCompile(RT_ELEMENTS(ApicReg.u) == 2 * RT_ELEMENTS(pApicPib->au64VectorBitmap));
308 for (ssize_t idxPib = cFragmentsSrc - 1, idxReg = cFragmentsDst - 1; idxPib >= 0; idxPib--, idxReg -= 2)
309 {
310 uint64_t const uFragment = pApicPib->au64VectorBitmap[idxPib];
311 uint32_t const uFragmentLo = RT_LO_U32(uFragment);
312 uint32_t const uFragmentHi = RT_HI_U32(uFragment);
313 ApicReg.u[idxReg].u32Reg = uFragmentHi;
314 ApicReg.u[idxReg - 1].u32Reg = uFragmentLo;
315 }
316
317 /* Dump it. */
318 apicR3DbgInfo256BitReg(&ApicReg, pHlp);
319}
320
321
322/**
323 * Dumps basic APIC state.
324 *
325 * @param pVM The cross context VM structure.
326 * @param pHlp The info helpers.
327 * @param pszArgs Arguments, ignored.
328 */
329static DECLCALLBACK(void) apicR3Info(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
330{
331 NOREF(pszArgs);
332 PVMCPU pVCpu = VMMGetCpu(pVM);
333 if (!pVCpu)
334 pVCpu = pVM->apCpusR3[0];
335
336 PCAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
337 PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
338 PCX2APICPAGE pX2ApicPage = VMCPU_TO_CX2APICPAGE(pVCpu);
339
340 uint64_t const uBaseMsr = pApicCpu->uApicBaseMsr;
341 APICMODE const enmMode = apicGetMode(uBaseMsr);
342 bool const fX2ApicMode = XAPIC_IN_X2APIC_MODE(pVCpu);
343
344 pHlp->pfnPrintf(pHlp, "APIC%u:\n", pVCpu->idCpu);
345 pHlp->pfnPrintf(pHlp, " APIC Base MSR = %#RX64 (Addr=%#RX64)\n", uBaseMsr,
346 MSR_IA32_APICBASE_GET_ADDR(uBaseMsr));
347 pHlp->pfnPrintf(pHlp, " Mode = %u (%s)\n", enmMode, apicGetModeName(enmMode));
348 if (fX2ApicMode)
349 {
350 pHlp->pfnPrintf(pHlp, " APIC ID = %u (%#x)\n", pX2ApicPage->id.u32ApicId,
351 pX2ApicPage->id.u32ApicId);
352 }
353 else
354 pHlp->pfnPrintf(pHlp, " APIC ID = %u (%#x)\n", pXApicPage->id.u8ApicId, pXApicPage->id.u8ApicId);
355 pHlp->pfnPrintf(pHlp, " Version = %#x\n", pXApicPage->version.all.u32Version);
356 pHlp->pfnPrintf(pHlp, " APIC Version = %#x\n", pXApicPage->version.u.u8Version);
357 pHlp->pfnPrintf(pHlp, " Max LVT entry index (0..N) = %u\n", pXApicPage->version.u.u8MaxLvtEntry);
358 pHlp->pfnPrintf(pHlp, " EOI Broadcast supression = %RTbool\n", pXApicPage->version.u.fEoiBroadcastSupression);
359 if (!fX2ApicMode)
360 pHlp->pfnPrintf(pHlp, " APR = %u (%#x)\n", pXApicPage->apr.u8Apr, pXApicPage->apr.u8Apr);
361 pHlp->pfnPrintf(pHlp, " TPR = %u (%#x)\n", pXApicPage->tpr.u8Tpr, pXApicPage->tpr.u8Tpr);
362 pHlp->pfnPrintf(pHlp, " Task-priority class = %#x\n", XAPIC_TPR_GET_TP(pXApicPage->tpr.u8Tpr) >> 4);
363 pHlp->pfnPrintf(pHlp, " Task-priority subclass = %#x\n", XAPIC_TPR_GET_TP_SUBCLASS(pXApicPage->tpr.u8Tpr));
364 pHlp->pfnPrintf(pHlp, " PPR = %u (%#x)\n", pXApicPage->ppr.u8Ppr, pXApicPage->ppr.u8Ppr);
365 pHlp->pfnPrintf(pHlp, " Processor-priority class = %#x\n", XAPIC_PPR_GET_PP(pXApicPage->ppr.u8Ppr) >> 4);
366 pHlp->pfnPrintf(pHlp, " Processor-priority subclass = %#x\n", XAPIC_PPR_GET_PP_SUBCLASS(pXApicPage->ppr.u8Ppr));
367 if (!fX2ApicMode)
368 pHlp->pfnPrintf(pHlp, " RRD = %u (%#x)\n", pXApicPage->rrd.u32Rrd, pXApicPage->rrd.u32Rrd);
369 pHlp->pfnPrintf(pHlp, " LDR = %#x\n", pXApicPage->ldr.all.u32Ldr);
370 pHlp->pfnPrintf(pHlp, " Logical APIC ID = %#x\n", fX2ApicMode ? pX2ApicPage->ldr.u32LogicalApicId
371 : pXApicPage->ldr.u.u8LogicalApicId);
372 if (!fX2ApicMode)
373 {
374 pHlp->pfnPrintf(pHlp, " DFR = %#x\n", pXApicPage->dfr.all.u32Dfr);
375 pHlp->pfnPrintf(pHlp, " Model = %#x (%s)\n", pXApicPage->dfr.u.u4Model,
376 apicGetDestFormatName((XAPICDESTFORMAT)pXApicPage->dfr.u.u4Model));
377 }
378 pHlp->pfnPrintf(pHlp, " SVR = %#x\n", pXApicPage->svr.all.u32Svr);
379 pHlp->pfnPrintf(pHlp, " Vector = %u (%#x)\n", pXApicPage->svr.u.u8SpuriousVector,
380 pXApicPage->svr.u.u8SpuriousVector);
381 pHlp->pfnPrintf(pHlp, " Software Enabled = %RTbool\n", RT_BOOL(pXApicPage->svr.u.fApicSoftwareEnable));
382 pHlp->pfnPrintf(pHlp, " Supress EOI broadcast = %RTbool\n", RT_BOOL(pXApicPage->svr.u.fSupressEoiBroadcast));
383 pHlp->pfnPrintf(pHlp, " ISR\n");
384 apicR3DbgInfo256BitReg(&pXApicPage->isr, pHlp);
385 pHlp->pfnPrintf(pHlp, " TMR\n");
386 apicR3DbgInfo256BitReg(&pXApicPage->tmr, pHlp);
387 pHlp->pfnPrintf(pHlp, " IRR\n");
388 apicR3DbgInfo256BitReg(&pXApicPage->irr, pHlp);
389 pHlp->pfnPrintf(pHlp, " PIB\n");
390 apicR3DbgInfoPib((PCAPICPIB)pApicCpu->pvApicPibR3, pHlp);
391 pHlp->pfnPrintf(pHlp, " Level PIB\n");
392 apicR3DbgInfoPib(&pApicCpu->ApicPibLevel, pHlp);
393 pHlp->pfnPrintf(pHlp, " ESR Internal = %#x\n", pApicCpu->uEsrInternal);
394 pHlp->pfnPrintf(pHlp, " ESR = %#x\n", pXApicPage->esr.all.u32Errors);
395 pHlp->pfnPrintf(pHlp, " Redirectable IPI = %RTbool\n", pXApicPage->esr.u.fRedirectableIpi);
396 pHlp->pfnPrintf(pHlp, " Send Illegal Vector = %RTbool\n", pXApicPage->esr.u.fSendIllegalVector);
397 pHlp->pfnPrintf(pHlp, " Recv Illegal Vector = %RTbool\n", pXApicPage->esr.u.fRcvdIllegalVector);
398 pHlp->pfnPrintf(pHlp, " Illegal Register Address = %RTbool\n", pXApicPage->esr.u.fIllegalRegAddr);
399 pHlp->pfnPrintf(pHlp, " ICR Low = %#x\n", pXApicPage->icr_lo.all.u32IcrLo);
400 pHlp->pfnPrintf(pHlp, " Vector = %u (%#x)\n", pXApicPage->icr_lo.u.u8Vector,
401 pXApicPage->icr_lo.u.u8Vector);
402 pHlp->pfnPrintf(pHlp, " Delivery Mode = %#x (%s)\n", pXApicPage->icr_lo.u.u3DeliveryMode,
403 apicGetDeliveryModeName((XAPICDELIVERYMODE)pXApicPage->icr_lo.u.u3DeliveryMode));
404 pHlp->pfnPrintf(pHlp, " Destination Mode = %#x (%s)\n", pXApicPage->icr_lo.u.u1DestMode,
405 apicGetDestModeName((XAPICDESTMODE)pXApicPage->icr_lo.u.u1DestMode));
406 if (!fX2ApicMode)
407 pHlp->pfnPrintf(pHlp, " Delivery Status = %u\n", pXApicPage->icr_lo.u.u1DeliveryStatus);
408 pHlp->pfnPrintf(pHlp, " Level = %u\n", pXApicPage->icr_lo.u.u1Level);
409 pHlp->pfnPrintf(pHlp, " Trigger Mode = %u (%s)\n", pXApicPage->icr_lo.u.u1TriggerMode,
410 apicGetTriggerModeName((XAPICTRIGGERMODE)pXApicPage->icr_lo.u.u1TriggerMode));
411 pHlp->pfnPrintf(pHlp, " Destination shorthand = %#x (%s)\n", pXApicPage->icr_lo.u.u2DestShorthand,
412 apicGetDestShorthandName((XAPICDESTSHORTHAND)pXApicPage->icr_lo.u.u2DestShorthand));
413 pHlp->pfnPrintf(pHlp, " ICR High = %#x\n", pXApicPage->icr_hi.all.u32IcrHi);
414 pHlp->pfnPrintf(pHlp, " Destination field/mask = %#x\n", fX2ApicMode ? pX2ApicPage->icr_hi.u32IcrHi
415 : pXApicPage->icr_hi.u.u8Dest);
416}
417
418
419/**
420 * Helper for dumping the LVT timer.
421 *
422 * @param pVCpu The cross context virtual CPU structure.
423 * @param pHlp The debug output helper.
424 */
425static void apicR3InfoLvtTimer(PVMCPU pVCpu, PCDBGFINFOHLP pHlp)
426{
427 PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
428 uint32_t const uLvtTimer = pXApicPage->lvt_timer.all.u32LvtTimer;
429 pHlp->pfnPrintf(pHlp, "LVT Timer = %#RX32\n", uLvtTimer);
430 pHlp->pfnPrintf(pHlp, " Vector = %u (%#x)\n", pXApicPage->lvt_timer.u.u8Vector, pXApicPage->lvt_timer.u.u8Vector);
431 pHlp->pfnPrintf(pHlp, " Delivery status = %u\n", pXApicPage->lvt_timer.u.u1DeliveryStatus);
432 pHlp->pfnPrintf(pHlp, " Masked = %RTbool\n", XAPIC_LVT_IS_MASKED(uLvtTimer));
433 pHlp->pfnPrintf(pHlp, " Timer Mode = %#x (%s)\n", pXApicPage->lvt_timer.u.u2TimerMode,
434 apicGetTimerModeName((XAPICTIMERMODE)pXApicPage->lvt_timer.u.u2TimerMode));
435}
436
437
438/**
439 * Dumps APIC Local Vector Table (LVT) information.
440 *
441 * @param pVM The cross context VM structure.
442 * @param pHlp The info helpers.
443 * @param pszArgs Arguments, ignored.
444 */
445static DECLCALLBACK(void) apicR3InfoLvt(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
446{
447 NOREF(pszArgs);
448 PVMCPU pVCpu = VMMGetCpu(pVM);
449 if (!pVCpu)
450 pVCpu = pVM->apCpusR3[0];
451
452 PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
453
454 /*
455 * Delivery modes available in the LVT entries. They're different (more reserved stuff) from the
456 * ICR delivery modes and hence we don't use apicGetDeliveryMode but mostly because we want small,
457 * fixed-length strings to fit our formatting needs here.
458 */
459 static const char * const s_apszLvtDeliveryModes[] =
460 {
461 "Fixed ",
462 "Rsvd ",
463 "SMI ",
464 "Rsvd ",
465 "NMI ",
466 "INIT ",
467 "Rsvd ",
468 "ExtINT"
469 };
470 /* Delivery Status. */
471 static const char * const s_apszLvtDeliveryStatus[] =
472 {
473 "Idle",
474 "Pend"
475 };
476 const char *pszNotApplicable = "";
477
478 pHlp->pfnPrintf(pHlp, "VCPU[%u] APIC Local Vector Table (LVT):\n", pVCpu->idCpu);
479 pHlp->pfnPrintf(pHlp, "lvt timermode mask trigger rirr polarity dlvr_st dlvr_mode vector\n");
480 /* Timer. */
481 {
482 /* Timer modes. */
483 static const char * const s_apszLvtTimerModes[] =
484 {
485 "One-shot ",
486 "Periodic ",
487 "TSC-dline"
488 };
489 const uint32_t uLvtTimer = pXApicPage->lvt_timer.all.u32LvtTimer;
490 const XAPICTIMERMODE enmTimerMode = XAPIC_LVT_GET_TIMER_MODE(uLvtTimer);
491 const char *pszTimerMode = s_apszLvtTimerModes[enmTimerMode];
492 const uint8_t uMask = XAPIC_LVT_IS_MASKED(uLvtTimer);
493 const uint8_t uDeliveryStatus = uLvtTimer & XAPIC_LVT_DELIVERY_STATUS;
494 const char *pszDeliveryStatus = s_apszLvtDeliveryStatus[uDeliveryStatus];
495 const uint8_t uVector = XAPIC_LVT_GET_VECTOR(uLvtTimer);
496
497 pHlp->pfnPrintf(pHlp, "%-7s %9s %u %5s %1s %8s %4s %6s %3u (%#x)\n",
498 "Timer",
499 pszTimerMode,
500 uMask,
501 pszNotApplicable, /* TriggerMode */
502 pszNotApplicable, /* Remote IRR */
503 pszNotApplicable, /* Polarity */
504 pszDeliveryStatus,
505 pszNotApplicable, /* Delivery Mode */
506 uVector,
507 uVector);
508 }
509
510#if XAPIC_HARDWARE_VERSION == XAPIC_HARDWARE_VERSION_P4
511 /* Thermal sensor. */
512 {
513 uint32_t const uLvtThermal = pXApicPage->lvt_thermal.all.u32LvtThermal;
514 const uint8_t uMask = XAPIC_LVT_IS_MASKED(uLvtThermal);
515 const uint8_t uDeliveryStatus = uLvtThermal & XAPIC_LVT_DELIVERY_STATUS;
516 const char *pszDeliveryStatus = s_apszLvtDeliveryStatus[uDeliveryStatus];
517 const XAPICDELIVERYMODE enmDeliveryMode = XAPIC_LVT_GET_DELIVERY_MODE(uLvtThermal);
518 const char *pszDeliveryMode = s_apszLvtDeliveryModes[enmDeliveryMode];
519 const uint8_t uVector = XAPIC_LVT_GET_VECTOR(uLvtThermal);
520
521 pHlp->pfnPrintf(pHlp, "%-7s %9s %u %5s %1s %8s %4s %6s %3u (%#x)\n",
522 "Thermal",
523 pszNotApplicable, /* Timer mode */
524 uMask,
525 pszNotApplicable, /* TriggerMode */
526 pszNotApplicable, /* Remote IRR */
527 pszNotApplicable, /* Polarity */
528 pszDeliveryStatus,
529 pszDeliveryMode,
530 uVector,
531 uVector);
532 }
533#endif
534
535 /* Performance Monitor Counters. */
536 {
537 uint32_t const uLvtPerf = pXApicPage->lvt_thermal.all.u32LvtThermal;
538 const uint8_t uMask = XAPIC_LVT_IS_MASKED(uLvtPerf);
539 const uint8_t uDeliveryStatus = uLvtPerf & XAPIC_LVT_DELIVERY_STATUS;
540 const char *pszDeliveryStatus = s_apszLvtDeliveryStatus[uDeliveryStatus];
541 const XAPICDELIVERYMODE enmDeliveryMode = XAPIC_LVT_GET_DELIVERY_MODE(uLvtPerf);
542 const char *pszDeliveryMode = s_apszLvtDeliveryModes[enmDeliveryMode];
543 const uint8_t uVector = XAPIC_LVT_GET_VECTOR(uLvtPerf);
544
545 pHlp->pfnPrintf(pHlp, "%-7s %9s %u %5s %1s %8s %4s %6s %3u (%#x)\n",
546 "Perf",
547 pszNotApplicable, /* Timer mode */
548 uMask,
549 pszNotApplicable, /* TriggerMode */
550 pszNotApplicable, /* Remote IRR */
551 pszNotApplicable, /* Polarity */
552 pszDeliveryStatus,
553 pszDeliveryMode,
554 uVector,
555 uVector);
556 }
557
558 /* LINT0, LINT1. */
559 {
560 /* LINTx name. */
561 static const char * const s_apszLvtLint[] =
562 {
563 "LINT0",
564 "LINT1"
565 };
566 /* Trigger mode. */
567 static const char * const s_apszLvtTriggerModes[] =
568 {
569 "Edge ",
570 "Level"
571 };
572 /* Polarity. */
573 static const char * const s_apszLvtPolarity[] =
574 {
575 "ActiveHi",
576 "ActiveLo"
577 };
578
579 uint32_t aLvtLint[2];
580 aLvtLint[0] = pXApicPage->lvt_lint0.all.u32LvtLint0;
581 aLvtLint[1] = pXApicPage->lvt_lint1.all.u32LvtLint1;
582 for (size_t i = 0; i < RT_ELEMENTS(aLvtLint); i++)
583 {
584 uint32_t const uLvtLint = aLvtLint[i];
585 const char *pszLint = s_apszLvtLint[i];
586 const uint8_t uMask = XAPIC_LVT_IS_MASKED(uLvtLint);
587 const XAPICTRIGGERMODE enmTriggerMode = XAPIC_LVT_GET_TRIGGER_MODE(uLvtLint);
588 const char *pszTriggerMode = s_apszLvtTriggerModes[enmTriggerMode];
589 const uint8_t uRemoteIrr = XAPIC_LVT_GET_REMOTE_IRR(uLvtLint);
590 const uint8_t uPolarity = XAPIC_LVT_GET_POLARITY(uLvtLint);
591 const char *pszPolarity = s_apszLvtPolarity[uPolarity];
592 const uint8_t uDeliveryStatus = uLvtLint & XAPIC_LVT_DELIVERY_STATUS;
593 const char *pszDeliveryStatus = s_apszLvtDeliveryStatus[uDeliveryStatus];
594 const XAPICDELIVERYMODE enmDeliveryMode = XAPIC_LVT_GET_DELIVERY_MODE(uLvtLint);
595 const char *pszDeliveryMode = s_apszLvtDeliveryModes[enmDeliveryMode];
596 const uint8_t uVector = XAPIC_LVT_GET_VECTOR(uLvtLint);
597
598 pHlp->pfnPrintf(pHlp, "%-7s %9s %u %5s %u %8s %4s %6s %3u (%#x)\n",
599 pszLint,
600 pszNotApplicable, /* Timer mode */
601 uMask,
602 pszTriggerMode,
603 uRemoteIrr,
604 pszPolarity,
605 pszDeliveryStatus,
606 pszDeliveryMode,
607 uVector,
608 uVector);
609 }
610 }
611
612 /* Error. */
613 {
614 uint32_t const uLvtError = pXApicPage->lvt_thermal.all.u32LvtThermal;
615 const uint8_t uMask = XAPIC_LVT_IS_MASKED(uLvtError);
616 const uint8_t uDeliveryStatus = uLvtError & XAPIC_LVT_DELIVERY_STATUS;
617 const char *pszDeliveryStatus = s_apszLvtDeliveryStatus[uDeliveryStatus];
618 const XAPICDELIVERYMODE enmDeliveryMode = XAPIC_LVT_GET_DELIVERY_MODE(uLvtError);
619 const char *pszDeliveryMode = s_apszLvtDeliveryModes[enmDeliveryMode];
620 const uint8_t uVector = XAPIC_LVT_GET_VECTOR(uLvtError);
621
622 pHlp->pfnPrintf(pHlp, "%-7s %9s %u %5s %1s %8s %4s %6s %3u (%#x)\n",
623 "Error",
624 pszNotApplicable, /* Timer mode */
625 uMask,
626 pszNotApplicable, /* TriggerMode */
627 pszNotApplicable, /* Remote IRR */
628 pszNotApplicable, /* Polarity */
629 pszDeliveryStatus,
630 pszDeliveryMode,
631 uVector,
632 uVector);
633 }
634}
635
636
637/**
638 * Dumps the APIC timer information.
639 *
640 * @param pVM The cross context VM structure.
641 * @param pHlp The info helpers.
642 * @param pszArgs Arguments, ignored.
643 */
644static DECLCALLBACK(void) apicR3InfoTimer(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
645{
646 NOREF(pszArgs);
647 PVMCPU pVCpu = VMMGetCpu(pVM);
648 if (!pVCpu)
649 pVCpu = pVM->apCpusR3[0];
650
651 PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
652 PCAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
653
654 pHlp->pfnPrintf(pHlp, "VCPU[%u] Local APIC timer:\n", pVCpu->idCpu);
655 pHlp->pfnPrintf(pHlp, " ICR = %#RX32\n", pXApicPage->timer_icr.u32InitialCount);
656 pHlp->pfnPrintf(pHlp, " CCR = %#RX32\n", pXApicPage->timer_ccr.u32CurrentCount);
657 pHlp->pfnPrintf(pHlp, " DCR = %#RX32\n", pXApicPage->timer_dcr.all.u32DivideValue);
658 pHlp->pfnPrintf(pHlp, " Timer shift = %#x\n", apicGetTimerShift(pXApicPage));
659 pHlp->pfnPrintf(pHlp, " Timer initial TS = %#RU64\n", pApicCpu->u64TimerInitial);
660 apicR3InfoLvtTimer(pVCpu, pHlp);
661}
662
663
664#ifdef APIC_FUZZY_SSM_COMPAT_TEST
665
666/**
667 * Reads a 32-bit register at a specified offset.
668 *
669 * @returns The value at the specified offset.
670 * @param pXApicPage The xAPIC page.
671 * @param offReg The offset of the register being read.
672 *
673 * @remarks Duplicate of apicReadRaw32()!
674 */
675static uint32_t apicR3ReadRawR32(PCXAPICPAGE pXApicPage, uint16_t offReg)
676{
677 Assert(offReg < sizeof(*pXApicPage) - sizeof(uint32_t));
678 uint8_t const *pbXApic = (const uint8_t *)pXApicPage;
679 uint32_t const uValue = *(const uint32_t *)(pbXApic + offReg);
680 return uValue;
681}
682
683
684/**
685 * Helper for dumping per-VCPU APIC state to the release logger.
686 *
687 * This is primarily concerned about the APIC state relevant for saved-states.
688 *
689 * @param pVCpu The cross context virtual CPU structure.
690 * @param pszPrefix A caller supplied prefix before dumping the state.
691 * @param uVersion Data layout version.
692 */
693static void apicR3DumpState(PVMCPU pVCpu, const char *pszPrefix, uint32_t uVersion)
694{
695 PCAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
696
697 LogRel(("APIC%u: %s (version %u):\n", pVCpu->idCpu, pszPrefix, uVersion));
698
699 switch (uVersion)
700 {
701 case APIC_SAVED_STATE_VERSION:
702 case APIC_SAVED_STATE_VERSION_VBOX_51_BETA2:
703 {
704 /* The auxiliary state. */
705 LogRel(("APIC%u: uApicBaseMsr = %#RX64\n", pVCpu->idCpu, pApicCpu->uApicBaseMsr));
706 LogRel(("APIC%u: uEsrInternal = %#RX64\n", pVCpu->idCpu, pApicCpu->uEsrInternal));
707
708 /* The timer. */
709 LogRel(("APIC%u: u64TimerInitial = %#RU64\n", pVCpu->idCpu, pApicCpu->u64TimerInitial));
710 LogRel(("APIC%u: uHintedTimerInitialCount = %#RU64\n", pVCpu->idCpu, pApicCpu->uHintedTimerInitialCount));
711 LogRel(("APIC%u: uHintedTimerShift = %#RU64\n", pVCpu->idCpu, pApicCpu->uHintedTimerShift));
712
713 PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
714 LogRel(("APIC%u: uTimerICR = %#RX32\n", pVCpu->idCpu, pXApicPage->timer_icr.u32InitialCount));
715 LogRel(("APIC%u: uTimerCCR = %#RX32\n", pVCpu->idCpu, pXApicPage->timer_ccr.u32CurrentCount));
716
717 /* The PIBs. */
718 LogRel(("APIC%u: Edge PIB : %.*Rhxs\n", pVCpu->idCpu, sizeof(APICPIB), pApicCpu->pvApicPibR3));
719 LogRel(("APIC%u: Level PIB: %.*Rhxs\n", pVCpu->idCpu, sizeof(APICPIB), &pApicCpu->ApicPibLevel));
720
721 /* The LINT0, LINT1 interrupt line active states. */
722 LogRel(("APIC%u: fActiveLint0 = %RTbool\n", pVCpu->idCpu, pApicCpu->fActiveLint0));
723 LogRel(("APIC%u: fActiveLint1 = %RTbool\n", pVCpu->idCpu, pApicCpu->fActiveLint1));
724
725 /* The APIC page. */
726 LogRel(("APIC%u: APIC page: %.*Rhxs\n", pVCpu->idCpu, sizeof(XAPICPAGE), pApicCpu->pvApicPageR3));
727 break;
728 }
729
730 case APIC_SAVED_STATE_VERSION_VBOX_50:
731 case APIC_SAVED_STATE_VERSION_VBOX_30:
732 case APIC_SAVED_STATE_VERSION_ANCIENT:
733 {
734 PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
735 LogRel(("APIC%u: uApicBaseMsr = %#RX32\n", pVCpu->idCpu, RT_LO_U32(pApicCpu->uApicBaseMsr)));
736 LogRel(("APIC%u: uId = %#RX32\n", pVCpu->idCpu, pXApicPage->id.u8ApicId));
737 LogRel(("APIC%u: uPhysId = N/A\n", pVCpu->idCpu));
738 LogRel(("APIC%u: uArbId = N/A\n", pVCpu->idCpu));
739 LogRel(("APIC%u: uTpr = %#RX32\n", pVCpu->idCpu, pXApicPage->tpr.u8Tpr));
740 LogRel(("APIC%u: uSvr = %#RX32\n", pVCpu->idCpu, pXApicPage->svr.all.u32Svr));
741 LogRel(("APIC%u: uLdr = %#x\n", pVCpu->idCpu, pXApicPage->ldr.all.u32Ldr));
742 LogRel(("APIC%u: uDfr = %#x\n", pVCpu->idCpu, pXApicPage->dfr.all.u32Dfr));
743
744 for (size_t i = 0; i < 8; i++)
745 {
746 LogRel(("APIC%u: Isr[%u].u32Reg = %#RX32\n", pVCpu->idCpu, i, pXApicPage->isr.u[i].u32Reg));
747 LogRel(("APIC%u: Tmr[%u].u32Reg = %#RX32\n", pVCpu->idCpu, i, pXApicPage->tmr.u[i].u32Reg));
748 LogRel(("APIC%u: Irr[%u].u32Reg = %#RX32\n", pVCpu->idCpu, i, pXApicPage->irr.u[i].u32Reg));
749 }
750
751 for (size_t i = 0; i < XAPIC_MAX_LVT_ENTRIES_P4; i++)
752 {
753 uint16_t const offReg = XAPIC_OFF_LVT_START + (i << 4);
754 LogRel(("APIC%u: Lvt[%u].u32Reg = %#RX32\n", pVCpu->idCpu, i, apicR3ReadRawR32(pXApicPage, offReg)));
755 }
756
757 LogRel(("APIC%u: uEsr = %#RX32\n", pVCpu->idCpu, pXApicPage->esr.all.u32Errors));
758 LogRel(("APIC%u: uIcr_Lo = %#RX32\n", pVCpu->idCpu, pXApicPage->icr_lo.all.u32IcrLo));
759 LogRel(("APIC%u: uIcr_Hi = %#RX32\n", pVCpu->idCpu, pXApicPage->icr_hi.all.u32IcrHi));
760 LogRel(("APIC%u: uTimerDcr = %#RX32\n", pVCpu->idCpu, pXApicPage->timer_dcr.all.u32DivideValue));
761 LogRel(("APIC%u: uCountShift = %#RX32\n", pVCpu->idCpu, apicGetTimerShift(pXApicPage)));
762 LogRel(("APIC%u: uInitialCount = %#RX32\n", pVCpu->idCpu, pXApicPage->timer_icr.u32InitialCount));
763 LogRel(("APIC%u: u64InitialCountLoadTime = %#RX64\n", pVCpu->idCpu, pApicCpu->u64TimerInitial));
764 LogRel(("APIC%u: u64NextTime / TimerCCR = %#RX64\n", pVCpu->idCpu, pXApicPage->timer_ccr.u32CurrentCount));
765 break;
766 }
767
768 default:
769 {
770 LogRel(("APIC: apicR3DumpState: Invalid/unrecognized saved-state version %u (%#x)\n", uVersion, uVersion));
771 break;
772 }
773 }
774}
775
776#endif /* APIC_FUZZY_SSM_COMPAT_TEST */
777
778/**
779 * Worker for saving per-VM APIC data.
780 *
781 * @returns VBox status code.
782 * @param pDevIns The device instance.
783 * @param pVM The cross context VM structure.
784 * @param pSSM The SSM handle.
785 */
786static int apicR3SaveVMData(PPDMDEVINS pDevIns, PVM pVM, PSSMHANDLE pSSM)
787{
788 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
789 PAPIC pApic = VM_TO_APIC(pVM);
790 pHlp->pfnSSMPutU32(pSSM, pVM->cCpus);
791 pHlp->pfnSSMPutBool(pSSM, pApic->fIoApicPresent);
792 return pHlp->pfnSSMPutU32(pSSM, pApic->enmMaxMode);
793}
794
795
796/**
797 * Worker for loading per-VM APIC data.
798 *
799 * @returns VBox status code.
800 * @param pDevIns The device instance.
801 * @param pVM The cross context VM structure.
802 * @param pSSM The SSM handle.
803 */
804static int apicR3LoadVMData(PPDMDEVINS pDevIns, PVM pVM, PSSMHANDLE pSSM)
805{
806 PAPIC pApic = VM_TO_APIC(pVM);
807 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
808
809 /* Load and verify number of CPUs. */
810 uint32_t cCpus;
811 int rc = pHlp->pfnSSMGetU32(pSSM, &cCpus);
812 AssertRCReturn(rc, rc);
813 if (cCpus != pVM->cCpus)
814 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - cCpus: saved=%u config=%u"), cCpus, pVM->cCpus);
815
816 /* Load and verify I/O APIC presence. */
817 bool fIoApicPresent;
818 rc = pHlp->pfnSSMGetBool(pSSM, &fIoApicPresent);
819 AssertRCReturn(rc, rc);
820 if (fIoApicPresent != pApic->fIoApicPresent)
821 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - fIoApicPresent: saved=%RTbool config=%RTbool"),
822 fIoApicPresent, pApic->fIoApicPresent);
823
824 /* Load and verify configured max APIC mode. */
825 uint32_t uSavedMaxApicMode;
826 rc = pHlp->pfnSSMGetU32(pSSM, &uSavedMaxApicMode);
827 AssertRCReturn(rc, rc);
828 if (uSavedMaxApicMode != (uint32_t)pApic->enmMaxMode)
829 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - uApicMode: saved=%u config=%u"),
830 uSavedMaxApicMode, pApic->enmMaxMode);
831 return VINF_SUCCESS;
832}
833
834
835/**
836 * Worker for loading per-VCPU APIC data for legacy (old) saved-states.
837 *
838 * @returns VBox status code.
839 * @param pDevIns The device instance.
840 * @param pVCpu The cross context virtual CPU structure.
841 * @param pSSM The SSM handle.
842 * @param uVersion Data layout version.
843 */
844static int apicR3LoadLegacyVCpuData(PPDMDEVINS pDevIns, PVMCPU pVCpu, PSSMHANDLE pSSM, uint32_t uVersion)
845{
846 AssertReturn(uVersion <= APIC_SAVED_STATE_VERSION_VBOX_50, VERR_NOT_SUPPORTED);
847
848 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
849 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
850 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
851
852 uint32_t uApicBaseLo;
853 int rc = pHlp->pfnSSMGetU32(pSSM, &uApicBaseLo);
854 AssertRCReturn(rc, rc);
855 pApicCpu->uApicBaseMsr = uApicBaseLo;
856 Log2(("APIC%u: apicR3LoadLegacyVCpuData: uApicBaseMsr=%#RX64\n", pVCpu->idCpu, pApicCpu->uApicBaseMsr));
857
858 switch (uVersion)
859 {
860 case APIC_SAVED_STATE_VERSION_VBOX_50:
861 case APIC_SAVED_STATE_VERSION_VBOX_30:
862 {
863 uint32_t uApicId, uPhysApicId, uArbId;
864 pHlp->pfnSSMGetU32(pSSM, &uApicId); pXApicPage->id.u8ApicId = uApicId;
865 pHlp->pfnSSMGetU32(pSSM, &uPhysApicId); NOREF(uPhysApicId); /* PhysId == pVCpu->idCpu */
866 pHlp->pfnSSMGetU32(pSSM, &uArbId); NOREF(uArbId); /* ArbID is & was unused. */
867 break;
868 }
869
870 case APIC_SAVED_STATE_VERSION_ANCIENT:
871 {
872 uint8_t uPhysApicId;
873 pHlp->pfnSSMGetU8(pSSM, &pXApicPage->id.u8ApicId);
874 pHlp->pfnSSMGetU8(pSSM, &uPhysApicId); NOREF(uPhysApicId); /* PhysId == pVCpu->idCpu */
875 break;
876 }
877
878 default:
879 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
880 }
881
882 uint32_t u32Tpr;
883 pHlp->pfnSSMGetU32(pSSM, &u32Tpr);
884 pXApicPage->tpr.u8Tpr = u32Tpr & XAPIC_TPR_VALID;
885
886 pHlp->pfnSSMGetU32(pSSM, &pXApicPage->svr.all.u32Svr);
887 pHlp->pfnSSMGetU8(pSSM, &pXApicPage->ldr.u.u8LogicalApicId);
888
889 uint8_t uDfr;
890 pHlp->pfnSSMGetU8(pSSM, &uDfr);
891 pXApicPage->dfr.u.u4Model = uDfr >> 4;
892
893 AssertCompile(RT_ELEMENTS(pXApicPage->isr.u) == 8);
894 AssertCompile(RT_ELEMENTS(pXApicPage->tmr.u) == 8);
895 AssertCompile(RT_ELEMENTS(pXApicPage->irr.u) == 8);
896 for (size_t i = 0; i < 8; i++)
897 {
898 pHlp->pfnSSMGetU32(pSSM, &pXApicPage->isr.u[i].u32Reg);
899 pHlp->pfnSSMGetU32(pSSM, &pXApicPage->tmr.u[i].u32Reg);
900 pHlp->pfnSSMGetU32(pSSM, &pXApicPage->irr.u[i].u32Reg);
901 }
902
903 pHlp->pfnSSMGetU32(pSSM, &pXApicPage->lvt_timer.all.u32LvtTimer);
904 pHlp->pfnSSMGetU32(pSSM, &pXApicPage->lvt_thermal.all.u32LvtThermal);
905 pHlp->pfnSSMGetU32(pSSM, &pXApicPage->lvt_perf.all.u32LvtPerf);
906 pHlp->pfnSSMGetU32(pSSM, &pXApicPage->lvt_lint0.all.u32LvtLint0);
907 pHlp->pfnSSMGetU32(pSSM, &pXApicPage->lvt_lint1.all.u32LvtLint1);
908 pHlp->pfnSSMGetU32(pSSM, &pXApicPage->lvt_error.all.u32LvtError);
909
910 pHlp->pfnSSMGetU32(pSSM, &pXApicPage->esr.all.u32Errors);
911 pHlp->pfnSSMGetU32(pSSM, &pXApicPage->icr_lo.all.u32IcrLo);
912 pHlp->pfnSSMGetU32(pSSM, &pXApicPage->icr_hi.all.u32IcrHi);
913
914 uint32_t u32TimerShift;
915 pHlp->pfnSSMGetU32(pSSM, &pXApicPage->timer_dcr.all.u32DivideValue);
916 pHlp->pfnSSMGetU32(pSSM, &u32TimerShift);
917 /*
918 * Old implementation may have left the timer shift uninitialized until
919 * the timer configuration register was written. Unfortunately zero is
920 * also a valid timer shift value, so we're just going to ignore it
921 * completely. The shift count can always be derived from the DCR.
922 * See @bugref{8245#c98}.
923 */
924 uint8_t const uTimerShift = apicGetTimerShift(pXApicPage);
925
926 pHlp->pfnSSMGetU32(pSSM, &pXApicPage->timer_icr.u32InitialCount);
927 pHlp->pfnSSMGetU64(pSSM, &pApicCpu->u64TimerInitial);
928 uint64_t uNextTS;
929 rc = pHlp->pfnSSMGetU64(pSSM, &uNextTS); AssertRCReturn(rc, rc);
930 if (uNextTS >= pApicCpu->u64TimerInitial + ((pXApicPage->timer_icr.u32InitialCount + 1) << uTimerShift))
931 pXApicPage->timer_ccr.u32CurrentCount = pXApicPage->timer_icr.u32InitialCount;
932
933 rc = PDMDevHlpTimerLoad(pDevIns, pApicCpu->hTimer, pSSM);
934 AssertRCReturn(rc, rc);
935 Assert(pApicCpu->uHintedTimerInitialCount == 0);
936 Assert(pApicCpu->uHintedTimerShift == 0);
937 if (PDMDevHlpTimerIsActive(pDevIns, pApicCpu->hTimer))
938 {
939 uint32_t const uInitialCount = pXApicPage->timer_icr.u32InitialCount;
940 apicHintTimerFreq(pDevIns, pApicCpu, uInitialCount, uTimerShift);
941 }
942
943 return rc;
944}
945
946
947/**
948 * @copydoc FNSSMDEVSAVEEXEC
949 */
950static DECLCALLBACK(int) apicR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
951{
952 PVM pVM = PDMDevHlpGetVM(pDevIns);
953 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
954
955 AssertReturn(pVM, VERR_INVALID_VM_HANDLE);
956
957 LogFlow(("APIC: apicR3SaveExec\n"));
958
959 /* Save per-VM data. */
960 int rc = apicR3SaveVMData(pDevIns, pVM, pSSM);
961 AssertRCReturn(rc, rc);
962
963 /* Save per-VCPU data.*/
964 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
965 {
966 PVMCPU pVCpu = pVM->apCpusR3[idCpu];
967 PCAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
968
969 /* Update interrupts from the pending-interrupts bitmaps to the IRR. */
970 APICUpdatePendingInterrupts(pVCpu);
971
972 /* Save the auxiliary data. */
973 pHlp->pfnSSMPutU64(pSSM, pApicCpu->uApicBaseMsr);
974 pHlp->pfnSSMPutU32(pSSM, pApicCpu->uEsrInternal);
975
976 /* Save the APIC page. */
977 if (XAPIC_IN_X2APIC_MODE(pVCpu))
978 pHlp->pfnSSMPutStruct(pSSM, (const void *)pApicCpu->pvApicPageR3, &g_aX2ApicPageFields[0]);
979 else
980 pHlp->pfnSSMPutStruct(pSSM, (const void *)pApicCpu->pvApicPageR3, &g_aXApicPageFields[0]);
981
982 /* Save the timer. */
983 pHlp->pfnSSMPutU64(pSSM, pApicCpu->u64TimerInitial);
984 PDMDevHlpTimerSave(pDevIns, pApicCpu->hTimer, pSSM);
985
986 /* Save the LINT0, LINT1 interrupt line states. */
987 pHlp->pfnSSMPutBool(pSSM, pApicCpu->fActiveLint0);
988 pHlp->pfnSSMPutBool(pSSM, pApicCpu->fActiveLint1);
989
990#if defined(APIC_FUZZY_SSM_COMPAT_TEST) || defined(DEBUG_ramshankar)
991 apicR3DumpState(pVCpu, "Saved state", APIC_SAVED_STATE_VERSION);
992#endif
993 }
994
995#ifdef APIC_FUZZY_SSM_COMPAT_TEST
996 /* The state is fuzzy, don't even bother trying to load the guest. */
997 return VERR_INVALID_STATE;
998#else
999 return rc;
1000#endif
1001}
1002
1003
1004/**
1005 * @copydoc FNSSMDEVLOADEXEC
1006 */
1007static DECLCALLBACK(int) apicR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1008{
1009 PVM pVM = PDMDevHlpGetVM(pDevIns);
1010 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
1011
1012 AssertReturn(pVM, VERR_INVALID_VM_HANDLE);
1013 AssertReturn(uPass == SSM_PASS_FINAL, VERR_WRONG_ORDER);
1014
1015 LogFlow(("APIC: apicR3LoadExec: uVersion=%u uPass=%#x\n", uVersion, uPass));
1016
1017 /* Weed out invalid versions. */
1018 if ( uVersion != APIC_SAVED_STATE_VERSION
1019 && uVersion != APIC_SAVED_STATE_VERSION_VBOX_51_BETA2
1020 && uVersion != APIC_SAVED_STATE_VERSION_VBOX_50
1021 && uVersion != APIC_SAVED_STATE_VERSION_VBOX_30
1022 && uVersion != APIC_SAVED_STATE_VERSION_ANCIENT)
1023 {
1024 LogRel(("APIC: apicR3LoadExec: Invalid/unrecognized saved-state version %u (%#x)\n", uVersion, uVersion));
1025 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1026 }
1027
1028 int rc = VINF_SUCCESS;
1029 if (uVersion > APIC_SAVED_STATE_VERSION_VBOX_30)
1030 {
1031 rc = apicR3LoadVMData(pDevIns, pVM, pSSM);
1032 AssertRCReturn(rc, rc);
1033
1034 if (uVersion == APIC_SAVED_STATE_VERSION)
1035 { /* Load any new additional per-VM data. */ }
1036 }
1037
1038 /*
1039 * Restore per CPU state.
1040 *
1041 * Note! PDM will restore the VMCPU_FF_INTERRUPT_APIC flag for us.
1042 * This code doesn't touch it. No devices should make us touch
1043 * it later during the restore either, only during the 'done' phase.
1044 */
1045 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1046 {
1047 PVMCPU pVCpu = pVM->apCpusR3[idCpu];
1048 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
1049
1050 if (uVersion > APIC_SAVED_STATE_VERSION_VBOX_50)
1051 {
1052 /* Load the auxiliary data. */
1053 pHlp->pfnSSMGetU64V(pSSM, &pApicCpu->uApicBaseMsr);
1054 pHlp->pfnSSMGetU32(pSSM, &pApicCpu->uEsrInternal);
1055
1056 /* Load the APIC page. */
1057 if (XAPIC_IN_X2APIC_MODE(pVCpu))
1058 pHlp->pfnSSMGetStruct(pSSM, pApicCpu->pvApicPageR3, &g_aX2ApicPageFields[0]);
1059 else
1060 pHlp->pfnSSMGetStruct(pSSM, pApicCpu->pvApicPageR3, &g_aXApicPageFields[0]);
1061
1062 /* Load the timer. */
1063 rc = pHlp->pfnSSMGetU64(pSSM, &pApicCpu->u64TimerInitial); AssertRCReturn(rc, rc);
1064 rc = PDMDevHlpTimerLoad(pDevIns, pApicCpu->hTimer, pSSM); AssertRCReturn(rc, rc);
1065 Assert(pApicCpu->uHintedTimerShift == 0);
1066 Assert(pApicCpu->uHintedTimerInitialCount == 0);
1067 if (PDMDevHlpTimerIsActive(pDevIns, pApicCpu->hTimer))
1068 {
1069 PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
1070 uint32_t const uInitialCount = pXApicPage->timer_icr.u32InitialCount;
1071 uint8_t const uTimerShift = apicGetTimerShift(pXApicPage);
1072 apicHintTimerFreq(pDevIns, pApicCpu, uInitialCount, uTimerShift);
1073 }
1074
1075 /* Load the LINT0, LINT1 interrupt line states. */
1076 if (uVersion > APIC_SAVED_STATE_VERSION_VBOX_51_BETA2)
1077 {
1078 pHlp->pfnSSMGetBoolV(pSSM, &pApicCpu->fActiveLint0);
1079 pHlp->pfnSSMGetBoolV(pSSM, &pApicCpu->fActiveLint1);
1080 }
1081 }
1082 else
1083 {
1084 rc = apicR3LoadLegacyVCpuData(pDevIns, pVCpu, pSSM, uVersion);
1085 AssertRCReturn(rc, rc);
1086 }
1087
1088 /*
1089 * Check that we're still good wrt restored data, then tell CPUM about the current CPUID[1].EDX[9] visibility.
1090 */
1091 rc = pHlp->pfnSSMHandleGetStatus(pSSM);
1092 AssertRCReturn(rc, rc);
1093 CPUMSetGuestCpuIdPerCpuApicFeature(pVCpu, RT_BOOL(pApicCpu->uApicBaseMsr & MSR_IA32_APICBASE_EN));
1094
1095#if defined(APIC_FUZZY_SSM_COMPAT_TEST) || defined(DEBUG_ramshankar)
1096 apicR3DumpState(pVCpu, "Loaded state", uVersion);
1097#endif
1098 }
1099
1100 return rc;
1101}
1102
1103
1104/**
1105 * @callback_method_impl{FNTMTIMERDEV}
1106 *
1107 * @note pvUser points to the VMCPU.
1108 *
1109 * @remarks Currently this function is invoked on the last EMT, see @c
1110 * idTimerCpu in tmR3TimerCallback(). However, the code does -not-
1111 * rely on this and is designed to work with being invoked on any
1112 * thread.
1113 */
1114static DECLCALLBACK(void) apicR3TimerCallback(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, void *pvUser)
1115{
1116 PVMCPU pVCpu = (PVMCPU)pvUser;
1117 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
1118 Assert(PDMDevHlpTimerIsLockOwner(pDevIns, pApicCpu->hTimer));
1119 Assert(pVCpu);
1120 LogFlow(("APIC%u: apicR3TimerCallback\n", pVCpu->idCpu));
1121 RT_NOREF(pDevIns, hTimer, pApicCpu);
1122
1123 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
1124 uint32_t const uLvtTimer = pXApicPage->lvt_timer.all.u32LvtTimer;
1125#ifdef VBOX_WITH_STATISTICS
1126 STAM_COUNTER_INC(&pApicCpu->StatTimerCallback);
1127#endif
1128 if (!XAPIC_LVT_IS_MASKED(uLvtTimer))
1129 {
1130 uint8_t uVector = XAPIC_LVT_GET_VECTOR(uLvtTimer);
1131 Log2(("APIC%u: apicR3TimerCallback: Raising timer interrupt. uVector=%#x\n", pVCpu->idCpu, uVector));
1132 apicPostInterrupt(pVCpu, uVector, XAPICTRIGGERMODE_EDGE, 0 /* uSrcTag */);
1133 }
1134
1135 XAPICTIMERMODE enmTimerMode = XAPIC_LVT_GET_TIMER_MODE(uLvtTimer);
1136 switch (enmTimerMode)
1137 {
1138 case XAPICTIMERMODE_PERIODIC:
1139 {
1140 /* The initial-count register determines if the periodic timer is re-armed. */
1141 uint32_t const uInitialCount = pXApicPage->timer_icr.u32InitialCount;
1142 pXApicPage->timer_ccr.u32CurrentCount = uInitialCount;
1143 if (uInitialCount)
1144 {
1145 Log2(("APIC%u: apicR3TimerCallback: Re-arming timer. uInitialCount=%#RX32\n", pVCpu->idCpu, uInitialCount));
1146 apicStartTimer(pVCpu, uInitialCount);
1147 }
1148 break;
1149 }
1150
1151 case XAPICTIMERMODE_ONESHOT:
1152 {
1153 pXApicPage->timer_ccr.u32CurrentCount = 0;
1154 break;
1155 }
1156
1157 case XAPICTIMERMODE_TSC_DEADLINE:
1158 {
1159 /** @todo implement TSC deadline. */
1160 AssertMsgFailed(("APIC: TSC deadline mode unimplemented\n"));
1161 break;
1162 }
1163 }
1164}
1165
1166
1167/**
1168 * @interface_method_impl{PDMDEVREG,pfnReset}
1169 */
1170DECLCALLBACK(void) apicR3Reset(PPDMDEVINS pDevIns)
1171{
1172 PVM pVM = PDMDevHlpGetVM(pDevIns);
1173 VM_ASSERT_EMT0(pVM);
1174 VM_ASSERT_IS_NOT_RUNNING(pVM);
1175
1176 LogFlow(("APIC: apicR3Reset\n"));
1177
1178 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1179 {
1180 PVMCPU pVCpuDest = pVM->apCpusR3[idCpu];
1181 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpuDest);
1182
1183 if (PDMDevHlpTimerIsActive(pDevIns, pApicCpu->hTimer))
1184 PDMDevHlpTimerStop(pDevIns, pApicCpu->hTimer);
1185
1186 apicResetCpu(pVCpuDest, true /* fResetApicBaseMsr */);
1187
1188 /* Clear the interrupt pending force flag. */
1189 apicClearInterruptFF(pVCpuDest, PDMAPICIRQ_HARDWARE);
1190 }
1191}
1192
1193
1194/**
1195 * @interface_method_impl{PDMDEVREG,pfnRelocate}
1196 */
1197DECLCALLBACK(void) apicR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
1198{
1199 RT_NOREF(pDevIns, offDelta);
1200}
1201
1202
1203/**
1204 * Terminates the APIC state.
1205 *
1206 * @param pVM The cross context VM structure.
1207 */
1208static void apicR3TermState(PVM pVM)
1209{
1210 PAPIC pApic = VM_TO_APIC(pVM);
1211 LogFlow(("APIC: apicR3TermState: pVM=%p\n", pVM));
1212
1213 /* Unmap and free the PIB. */
1214 if (pApic->pvApicPibR3 != NIL_RTR3PTR)
1215 {
1216 size_t const cPages = pApic->cbApicPib >> PAGE_SHIFT;
1217 if (cPages == 1)
1218 SUPR3PageFreeEx(pApic->pvApicPibR3, cPages);
1219 else
1220 SUPR3ContFree(pApic->pvApicPibR3, cPages);
1221 pApic->pvApicPibR3 = NIL_RTR3PTR;
1222 pApic->pvApicPibR0 = NIL_RTR0PTR;
1223 }
1224
1225 /* Unmap and free the virtual-APIC pages. */
1226 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1227 {
1228 PVMCPU pVCpu = pVM->apCpusR3[idCpu];
1229 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
1230
1231 pApicCpu->pvApicPibR3 = NIL_RTR3PTR;
1232 pApicCpu->pvApicPibR0 = NIL_RTR0PTR;
1233
1234 if (pApicCpu->pvApicPageR3 != NIL_RTR3PTR)
1235 {
1236 SUPR3PageFreeEx(pApicCpu->pvApicPageR3, 1 /* cPages */);
1237 pApicCpu->pvApicPageR3 = NIL_RTR3PTR;
1238 pApicCpu->pvApicPageR0 = NIL_RTR0PTR;
1239 }
1240 }
1241}
1242
1243
1244/**
1245 * Initializes the APIC state.
1246 *
1247 * @returns VBox status code.
1248 * @param pVM The cross context VM structure.
1249 */
1250static int apicR3InitState(PVM pVM)
1251{
1252 PAPIC pApic = VM_TO_APIC(pVM);
1253 LogFlow(("APIC: apicR3InitState: pVM=%p\n", pVM));
1254
1255 /*
1256 * Allocate and map the pending-interrupt bitmap (PIB).
1257 *
1258 * We allocate all the VCPUs' PIBs contiguously in order to save space as
1259 * physically contiguous allocations are rounded to a multiple of page size.
1260 */
1261 Assert(pApic->pvApicPibR3 == NIL_RTR3PTR);
1262 Assert(pApic->pvApicPibR0 == NIL_RTR0PTR);
1263 pApic->cbApicPib = RT_ALIGN_Z(pVM->cCpus * sizeof(APICPIB), PAGE_SIZE);
1264 size_t const cPages = pApic->cbApicPib >> PAGE_SHIFT;
1265 if (cPages == 1)
1266 {
1267 SUPPAGE SupApicPib;
1268 RT_ZERO(SupApicPib);
1269 SupApicPib.Phys = NIL_RTHCPHYS;
1270 int rc = SUPR3PageAllocEx(1 /* cPages */, 0 /* fFlags */, &pApic->pvApicPibR3, &pApic->pvApicPibR0, &SupApicPib);
1271 if (RT_SUCCESS(rc))
1272 {
1273 pApic->HCPhysApicPib = SupApicPib.Phys;
1274 AssertLogRelReturn(pApic->pvApicPibR3, VERR_INTERNAL_ERROR);
1275 }
1276 else
1277 {
1278 LogRel(("APIC: Failed to allocate %u bytes for the pending-interrupt bitmap, rc=%Rrc\n", pApic->cbApicPib, rc));
1279 return rc;
1280 }
1281 }
1282 else
1283 pApic->pvApicPibR3 = SUPR3ContAlloc(cPages, &pApic->pvApicPibR0, &pApic->HCPhysApicPib);
1284
1285 if (pApic->pvApicPibR3)
1286 {
1287 AssertLogRelReturn(pApic->pvApicPibR0 != NIL_RTR0PTR, VERR_INTERNAL_ERROR);
1288 AssertLogRelReturn(pApic->HCPhysApicPib != NIL_RTHCPHYS, VERR_INTERNAL_ERROR);
1289
1290 /* Initialize the PIB. */
1291 RT_BZERO(pApic->pvApicPibR3, pApic->cbApicPib);
1292
1293 /*
1294 * Allocate the map the virtual-APIC pages.
1295 */
1296 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1297 {
1298 PVMCPU pVCpu = pVM->apCpusR3[idCpu];
1299 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
1300
1301 SUPPAGE SupApicPage;
1302 RT_ZERO(SupApicPage);
1303 SupApicPage.Phys = NIL_RTHCPHYS;
1304
1305 Assert(pVCpu->idCpu == idCpu);
1306 Assert(pApicCpu->pvApicPageR3 == NIL_RTR3PTR);
1307 Assert(pApicCpu->pvApicPageR0 == NIL_RTR0PTR);
1308 AssertCompile(sizeof(XAPICPAGE) == PAGE_SIZE);
1309 pApicCpu->cbApicPage = sizeof(XAPICPAGE);
1310 int rc = SUPR3PageAllocEx(1 /* cPages */, 0 /* fFlags */, &pApicCpu->pvApicPageR3, &pApicCpu->pvApicPageR0,
1311 &SupApicPage);
1312 if (RT_SUCCESS(rc))
1313 {
1314 AssertLogRelReturn(pApicCpu->pvApicPageR3 != NIL_RTR3PTR, VERR_INTERNAL_ERROR);
1315 AssertLogRelReturn(pApicCpu->HCPhysApicPage != NIL_RTHCPHYS, VERR_INTERNAL_ERROR);
1316 pApicCpu->HCPhysApicPage = SupApicPage.Phys;
1317
1318 /* Associate the per-VCPU PIB pointers to the per-VM PIB mapping. */
1319 uint32_t const offApicPib = idCpu * sizeof(APICPIB);
1320 pApicCpu->pvApicPibR0 = (RTR0PTR)((RTR0UINTPTR)pApic->pvApicPibR0 + offApicPib);
1321 pApicCpu->pvApicPibR3 = (RTR3PTR)((RTR3UINTPTR)pApic->pvApicPibR3 + offApicPib);
1322
1323 /* Initialize the virtual-APIC state. */
1324 RT_BZERO(pApicCpu->pvApicPageR3, pApicCpu->cbApicPage);
1325 apicResetCpu(pVCpu, true /* fResetApicBaseMsr */);
1326
1327#ifdef DEBUG_ramshankar
1328 Assert(pApicCpu->pvApicPibR3 != NIL_RTR3PTR);
1329 Assert(pApicCpu->pvApicPibR0 != NIL_RTR0PTR);
1330 Assert(pApicCpu->pvApicPageR3 != NIL_RTR3PTR);
1331#endif
1332 }
1333 else
1334 {
1335 LogRel(("APIC%u: Failed to allocate %u bytes for the virtual-APIC page, rc=%Rrc\n", idCpu, pApicCpu->cbApicPage, rc));
1336 apicR3TermState(pVM);
1337 return rc;
1338 }
1339 }
1340
1341#ifdef DEBUG_ramshankar
1342 Assert(pApic->pvApicPibR3 != NIL_RTR3PTR);
1343 Assert(pApic->pvApicPibR0 != NIL_RTR0PTR);
1344#endif
1345 return VINF_SUCCESS;
1346 }
1347
1348 LogRel(("APIC: Failed to allocate %u bytes of physically contiguous memory for the pending-interrupt bitmap\n",
1349 pApic->cbApicPib));
1350 return VERR_NO_MEMORY;
1351}
1352
1353
1354/**
1355 * @interface_method_impl{PDMDEVREG,pfnDestruct}
1356 */
1357DECLCALLBACK(int) apicR3Destruct(PPDMDEVINS pDevIns)
1358{
1359 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
1360 PVM pVM = PDMDevHlpGetVM(pDevIns);
1361 LogFlow(("APIC: apicR3Destruct: pVM=%p\n", pVM));
1362
1363 apicR3TermState(pVM);
1364 return VINF_SUCCESS;
1365}
1366
1367
1368/**
1369 * @interface_method_impl{PDMDEVREG,pfnInitComplete}
1370 */
1371DECLCALLBACK(int) apicR3InitComplete(PPDMDEVINS pDevIns)
1372{
1373 PVM pVM = PDMDevHlpGetVM(pDevIns);
1374 PAPIC pApic = VM_TO_APIC(pVM);
1375
1376 /*
1377 * Init APIC settings that rely on HM and CPUM configurations.
1378 */
1379 CPUMCPUIDLEAF CpuLeaf;
1380 int rc = CPUMR3CpuIdGetLeaf(pVM, &CpuLeaf, 1, 0);
1381 AssertRCReturn(rc, rc);
1382
1383 pApic->fSupportsTscDeadline = RT_BOOL(CpuLeaf.uEcx & X86_CPUID_FEATURE_ECX_TSCDEADL);
1384 pApic->fPostedIntrsEnabled = HMR3IsPostedIntrsEnabled(pVM->pUVM);
1385 pApic->fVirtApicRegsEnabled = HMR3AreVirtApicRegsEnabled(pVM->pUVM);
1386
1387 LogRel(("APIC: fPostedIntrsEnabled=%RTbool fVirtApicRegsEnabled=%RTbool fSupportsTscDeadline=%RTbool\n",
1388 pApic->fPostedIntrsEnabled, pApic->fVirtApicRegsEnabled, pApic->fSupportsTscDeadline));
1389
1390 return VINF_SUCCESS;
1391}
1392
1393
1394/**
1395 * @interface_method_impl{PDMDEVREG,pfnConstruct}
1396 */
1397DECLCALLBACK(int) apicR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
1398{
1399 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1400 PAPICDEV pApicDev = PDMDEVINS_2_DATA(pDevIns, PAPICDEV);
1401 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
1402 PVM pVM = PDMDevHlpGetVM(pDevIns);
1403 PAPIC pApic = VM_TO_APIC(pVM);
1404 Assert(iInstance == 0); NOREF(iInstance);
1405
1406 /*
1407 * Init the data.
1408 */
1409 pApic->pDevInsR3 = pDevIns;
1410 pApic->fR0Enabled = pDevIns->fR0Enabled;
1411 pApic->fRCEnabled = pDevIns->fRCEnabled;
1412
1413 /*
1414 * Validate APIC settings.
1415 */
1416 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "Mode|IOAPIC|NumCPUs|MacOSWorkaround", "");
1417
1418 /** @devcfgm{apic, IOAPIC, bool, true}
1419 * Indicates whether an I/O APIC is present in the system. */
1420 int rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "IOAPIC", &pApic->fIoApicPresent, true);
1421 AssertLogRelRCReturn(rc, rc);
1422
1423 /** @devcfgm{apic, Mode, PDMAPICMODE, APIC(2)}
1424 * Max APIC feature level. */
1425 uint8_t uMaxMode;
1426 rc = pHlp->pfnCFGMQueryU8Def(pCfg, "Mode", &uMaxMode, PDMAPICMODE_APIC);
1427 AssertLogRelRCReturn(rc, rc);
1428 switch ((PDMAPICMODE)uMaxMode)
1429 {
1430 case PDMAPICMODE_NONE:
1431 LogRel(("APIC: APIC maximum mode configured as 'None', effectively disabled/not-present!\n"));
1432 case PDMAPICMODE_APIC:
1433 case PDMAPICMODE_X2APIC:
1434 break;
1435 default:
1436 return VMR3SetError(pVM->pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS, "APIC mode %d unknown.", uMaxMode);
1437 }
1438 pApic->enmMaxMode = (PDMAPICMODE)uMaxMode;
1439
1440 /** @devcfgm{apic, MacOSWorkaround, bool, false}
1441 * Enables a workaround for incorrect MSR_IA32_X2APIC_ID handling in macOS.
1442 *
1443 * Vital code in osfmk/i386/i386_init.c's vstart() routine incorrectly applies a
1444 * 24 right shift to the ID register value (correct for legacy APIC, but
1445 * entirely wrong for x2APIC), with the consequence that all CPUs use the same
1446 * per-cpu data and things panic pretty quickly. There are some shifty ID
1447 * reads in lapic_native.c too, but they are for either harmless (assuming boot
1448 * CPU has ID 0) or are for logging/debugging purposes only. */
1449 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "MacOSWorkaround", &pApic->fMacOSWorkaround, false);
1450 AssertLogRelRCReturn(rc, rc);
1451
1452 /*
1453 * Disable automatic PDM locking for this device.
1454 */
1455 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
1456 AssertRCReturn(rc, rc);
1457
1458 /*
1459 * Register the APIC with PDM.
1460 */
1461 rc = PDMDevHlpApicRegister(pDevIns);
1462 AssertLogRelRCReturn(rc, rc);
1463
1464 /*
1465 * Initialize the APIC state.
1466 */
1467 if (pApic->enmMaxMode == PDMAPICMODE_X2APIC)
1468 {
1469 rc = CPUMR3MsrRangesInsert(pVM, &g_MsrRange_x2Apic);
1470 AssertLogRelRCReturn(rc, rc);
1471 }
1472 else
1473 {
1474 /* We currently don't have a function to remove the range, so we register an range which will cause a #GP. */
1475 rc = CPUMR3MsrRangesInsert(pVM, &g_MsrRange_x2Apic_Invalid);
1476 AssertLogRelRCReturn(rc, rc);
1477 }
1478
1479 /* Tell CPUM about the APIC feature level so it can adjust APICBASE MSR GP mask and CPUID bits. */
1480 apicR3SetCpuIdFeatureLevel(pVM, pApic->enmMaxMode);
1481
1482 /* Finally, initialize the state. */
1483 rc = apicR3InitState(pVM);
1484 AssertRCReturn(rc, rc);
1485
1486 /*
1487 * Register the MMIO range.
1488 */
1489 PAPICCPU pApicCpu0 = VMCPU_TO_APICCPU(pVM->apCpusR3[0]);
1490 RTGCPHYS GCPhysApicBase = MSR_IA32_APICBASE_GET_ADDR(pApicCpu0->uApicBaseMsr);
1491
1492 rc = PDMDevHlpMmioCreateAndMap(pDevIns, GCPhysApicBase, sizeof(XAPICPAGE), apicWriteMmio, apicReadMmio,
1493 IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_DWORD_ZEROED, "APIC", &pApicDev->hMmio);
1494 AssertRCReturn(rc, rc);
1495
1496 /*
1497 * Create the APIC timers.
1498 */
1499 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1500 {
1501 PVMCPU pVCpu = pVM->apCpusR3[idCpu];
1502 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
1503 RTStrPrintf(&pApicCpu->szTimerDesc[0], sizeof(pApicCpu->szTimerDesc), "APIC Timer %u", pVCpu->idCpu);
1504 rc = PDMDevHlpTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, apicR3TimerCallback, pVCpu,
1505 TMTIMER_FLAGS_NO_CRIT_SECT | TMTIMER_FLAGS_RING0, pApicCpu->szTimerDesc, &pApicCpu->hTimer);
1506 AssertRCReturn(rc, rc);
1507 }
1508
1509 /*
1510 * Register saved state callbacks.
1511 */
1512 rc = PDMDevHlpSSMRegister(pDevIns, APIC_SAVED_STATE_VERSION, sizeof(*pApicDev), apicR3SaveExec, apicR3LoadExec);
1513 AssertRCReturn(rc, rc);
1514
1515 /*
1516 * Register debugger info callbacks.
1517 *
1518 * We use separate callbacks rather than arguments so they can also be
1519 * dumped in an automated fashion while collecting crash diagnostics and
1520 * not just used during live debugging via the VM debugger.
1521 */
1522 DBGFR3InfoRegisterInternalEx(pVM, "apic", "Dumps APIC basic information.", apicR3Info, DBGFINFO_FLAGS_ALL_EMTS);
1523 DBGFR3InfoRegisterInternalEx(pVM, "apiclvt", "Dumps APIC LVT information.", apicR3InfoLvt, DBGFINFO_FLAGS_ALL_EMTS);
1524 DBGFR3InfoRegisterInternalEx(pVM, "apictimer", "Dumps APIC timer information.", apicR3InfoTimer, DBGFINFO_FLAGS_ALL_EMTS);
1525
1526 /*
1527 * Statistics.
1528 */
1529#define APIC_REG_COUNTER(a_pvReg, a_pszNameFmt, a_pszDesc) \
1530 PDMDevHlpSTAMRegisterF(pDevIns, a_pvReg, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, \
1531 STAMUNIT_OCCURENCES, a_pszDesc, a_pszNameFmt, idCpu)
1532#define APIC_PROF_COUNTER(a_pvReg, a_pszNameFmt, a_pszDesc) \
1533 PDMDevHlpSTAMRegisterF(pDevIns, a_pvReg, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, \
1534 STAMUNIT_TICKS_PER_CALL, a_pszDesc, a_pszNameFmt, idCpu)
1535
1536 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1537 {
1538 PVMCPU pVCpu = pVM->apCpusR3[idCpu];
1539 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
1540
1541 APIC_REG_COUNTER(&pApicCpu->StatPostIntrCnt, "%u", "APIC/VCPU stats / number of apicPostInterrupt calls.");
1542 for (size_t i = 0; i < RT_ELEMENTS(pApicCpu->aStatVectors); i++)
1543 PDMDevHlpSTAMRegisterF(pDevIns, &pApicCpu->aStatVectors[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
1544 "Number of APICPostInterrupt calls for the vector.", "%u/Vectors/%02x", idCpu, i);
1545
1546#ifdef VBOX_WITH_STATISTICS
1547 APIC_REG_COUNTER(&pApicCpu->StatMmioReadRZ, "%u/RZ/MmioRead", "Number of APIC MMIO reads in RZ.");
1548 APIC_REG_COUNTER(&pApicCpu->StatMmioWriteRZ, "%u/RZ/MmioWrite", "Number of APIC MMIO writes in RZ.");
1549 APIC_REG_COUNTER(&pApicCpu->StatMsrReadRZ, "%u/RZ/MsrRead", "Number of APIC MSR reads in RZ.");
1550 APIC_REG_COUNTER(&pApicCpu->StatMsrWriteRZ, "%u/RZ/MsrWrite", "Number of APIC MSR writes in RZ.");
1551
1552 APIC_REG_COUNTER(&pApicCpu->StatMmioReadR3, "%u/R3/MmioRead", "Number of APIC MMIO reads in R3.");
1553 APIC_REG_COUNTER(&pApicCpu->StatMmioWriteR3, "%u/R3/MmioWrite", "Number of APIC MMIO writes in R3.");
1554 APIC_REG_COUNTER(&pApicCpu->StatMsrReadR3, "%u/R3/MsrRead", "Number of APIC MSR reads in R3.");
1555 APIC_REG_COUNTER(&pApicCpu->StatMsrWriteR3, "%u/R3/MsrWrite", "Number of APIC MSR writes in R3.");
1556
1557 APIC_REG_COUNTER(&pApicCpu->StatPostIntrAlreadyPending,
1558 "%u/PostInterruptAlreadyPending", "Number of times an interrupt is already pending.");
1559 APIC_REG_COUNTER(&pApicCpu->StatTimerCallback, "%u/TimerCallback", "Number of times the timer callback is invoked.");
1560
1561 APIC_REG_COUNTER(&pApicCpu->StatTprWrite, "%u/TprWrite", "Number of TPR writes.");
1562 APIC_REG_COUNTER(&pApicCpu->StatTprRead, "%u/TprRead", "Number of TPR reads.");
1563 APIC_REG_COUNTER(&pApicCpu->StatEoiWrite, "%u/EoiWrite", "Number of EOI writes.");
1564 APIC_REG_COUNTER(&pApicCpu->StatMaskedByTpr, "%u/MaskedByTpr", "Number of times TPR masks an interrupt in apicGetInterrupt.");
1565 APIC_REG_COUNTER(&pApicCpu->StatMaskedByPpr, "%u/MaskedByPpr", "Number of times PPR masks an interrupt in apicGetInterrupt.");
1566 APIC_REG_COUNTER(&pApicCpu->StatTimerIcrWrite, "%u/TimerIcrWrite", "Number of times the timer ICR is written.");
1567 APIC_REG_COUNTER(&pApicCpu->StatIcrLoWrite, "%u/IcrLoWrite", "Number of times the ICR Lo (send IPI) is written.");
1568 APIC_REG_COUNTER(&pApicCpu->StatIcrHiWrite, "%u/IcrHiWrite", "Number of times the ICR Hi is written.");
1569 APIC_REG_COUNTER(&pApicCpu->StatIcrFullWrite, "%u/IcrFullWrite", "Number of times the ICR full (send IPI, x2APIC) is written.");
1570 APIC_REG_COUNTER(&pApicCpu->StatIdMsrRead, "%u/IdMsrRead", "Number of times the APIC-ID MSR is read.");
1571 APIC_REG_COUNTER(&pApicCpu->StatDcrWrite, "%u/DcrWrite", "Number of times the DCR is written.");
1572 APIC_REG_COUNTER(&pApicCpu->StatDfrWrite, "%u/DfrWrite", "Number of times the DFR is written.");
1573 APIC_REG_COUNTER(&pApicCpu->StatLdrWrite, "%u/LdrWrite", "Number of times the LDR is written.");
1574 APIC_REG_COUNTER(&pApicCpu->StatLvtTimerWrite, "%u/LvtTimerWrite", "Number of times the LVT timer is written.");
1575
1576 APIC_PROF_COUNTER(&pApicCpu->StatUpdatePendingIntrs,
1577 "/PROF/CPU%u/APIC/UpdatePendingInterrupts", "Profiling of APICUpdatePendingInterrupts");
1578 APIC_PROF_COUNTER(&pApicCpu->StatPostIntr, "/PROF/CPU%u/APIC/PostInterrupt", "Profiling of APICPostInterrupt");
1579#endif
1580 }
1581
1582# undef APIC_PROF_COUNTER
1583# undef APIC_REG_ACCESS_COUNTER
1584
1585 return VINF_SUCCESS;
1586}
1587
1588#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
1589
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