VirtualBox

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

Last change on this file since 94249 was 93554, checked in by vboxsync, 3 years ago

VMM: Changed PAGE_SIZE -> GUEST_PAGE_SIZE / HOST_PAGE_SIZE, PAGE_SHIFT -> GUEST_PAGE_SHIFT / HOST_PAGE_SHIFT, and PAGE_OFFSET_MASK -> GUEST_PAGE_OFFSET_MASK / HOST_PAGE_OFFSET_MASK. Also removed most usage of ASMMemIsZeroPage and ASMMemZeroPage since the host and guest page size doesn't need to be the same any more. Some work left to do in the page pool code. bugref:9898

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 67.5 KB
Line 
1/* $Id: APIC.cpp 93554 2022-02-02 22:57:02Z vboxsync $ */
2/** @file
3 * APIC - Advanced Programmable Interrupt Controller.
4 */
5
6/*
7 * Copyright (C) 2016-2022 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 >> HOST_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), HOST_PAGE_SIZE);
1264 size_t const cHostPages = pApic->cbApicPib >> HOST_PAGE_SHIFT;
1265 if (cHostPages == 1)
1266 {
1267 SUPPAGE SupApicPib;
1268 RT_ZERO(SupApicPib);
1269 SupApicPib.Phys = NIL_RTHCPHYS;
1270 int rc = SUPR3PageAllocEx(1 /* cHostPages */, 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(cHostPages, &pApic->pvApicPibR0, &pApic->HCPhysApicPib);
1284
1285 if (pApic->pvApicPibR3)
1286 {
1287 bool const fDriverless = SUPR3IsDriverless();
1288 AssertLogRelReturn(pApic->pvApicPibR0 != NIL_RTR0PTR || fDriverless, VERR_INTERNAL_ERROR);
1289 AssertLogRelReturn(pApic->HCPhysApicPib != NIL_RTHCPHYS || fDriverless, VERR_INTERNAL_ERROR);
1290
1291 /* Initialize the PIB. */
1292 RT_BZERO(pApic->pvApicPibR3, pApic->cbApicPib);
1293
1294 /*
1295 * Allocate the map the virtual-APIC pages.
1296 */
1297 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1298 {
1299 PVMCPU pVCpu = pVM->apCpusR3[idCpu];
1300 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
1301
1302 SUPPAGE SupApicPage;
1303 RT_ZERO(SupApicPage);
1304 SupApicPage.Phys = NIL_RTHCPHYS;
1305
1306 Assert(pVCpu->idCpu == idCpu);
1307 Assert(pApicCpu->pvApicPageR3 == NIL_RTR3PTR);
1308 Assert(pApicCpu->pvApicPageR0 == NIL_RTR0PTR);
1309 AssertCompile(sizeof(XAPICPAGE) <= HOST_PAGE_SIZE);
1310 pApicCpu->cbApicPage = sizeof(XAPICPAGE);
1311 int rc = SUPR3PageAllocEx(1 /* cHostPages */, 0 /* fFlags */, &pApicCpu->pvApicPageR3, &pApicCpu->pvApicPageR0,
1312 &SupApicPage);
1313 if (RT_SUCCESS(rc))
1314 {
1315 AssertLogRelReturn(pApicCpu->pvApicPageR3 != NIL_RTR3PTR || fDriverless, VERR_INTERNAL_ERROR);
1316 pApicCpu->HCPhysApicPage = SupApicPage.Phys;
1317 AssertLogRelReturn(pApicCpu->HCPhysApicPage != NIL_RTHCPHYS || fDriverless, VERR_INTERNAL_ERROR);
1318
1319 /* Associate the per-VCPU PIB pointers to the per-VM PIB mapping. */
1320 uint32_t const offApicPib = idCpu * sizeof(APICPIB);
1321 pApicCpu->pvApicPibR0 = !fDriverless ? (RTR0PTR)((RTR0UINTPTR)pApic->pvApicPibR0 + offApicPib) : NIL_RTR0PTR;
1322 pApicCpu->pvApicPibR3 = (RTR3PTR)((RTR3UINTPTR)pApic->pvApicPibR3 + offApicPib);
1323
1324 /* Initialize the virtual-APIC state. */
1325 RT_BZERO(pApicCpu->pvApicPageR3, pApicCpu->cbApicPage);
1326 apicResetCpu(pVCpu, true /* fResetApicBaseMsr */);
1327
1328#ifdef DEBUG_ramshankar
1329 Assert(pApicCpu->pvApicPibR3 != NIL_RTR3PTR);
1330 Assert(pApicCpu->pvApicPibR0 != NIL_RTR0PTR || fDriverless);
1331 Assert(pApicCpu->pvApicPageR3 != NIL_RTR3PTR);
1332#endif
1333 }
1334 else
1335 {
1336 LogRel(("APIC%u: Failed to allocate %u bytes for the virtual-APIC page, rc=%Rrc\n", idCpu, pApicCpu->cbApicPage, rc));
1337 apicR3TermState(pVM);
1338 return rc;
1339 }
1340 }
1341
1342#ifdef DEBUG_ramshankar
1343 Assert(pApic->pvApicPibR3 != NIL_RTR3PTR);
1344 Assert(pApic->pvApicPibR0 != NIL_RTR0PTR || fDriverless);
1345#endif
1346 return VINF_SUCCESS;
1347 }
1348
1349 LogRel(("APIC: Failed to allocate %u bytes of physically contiguous memory for the pending-interrupt bitmap\n",
1350 pApic->cbApicPib));
1351 return VERR_NO_MEMORY;
1352}
1353
1354
1355/**
1356 * @interface_method_impl{PDMDEVREG,pfnDestruct}
1357 */
1358DECLCALLBACK(int) apicR3Destruct(PPDMDEVINS pDevIns)
1359{
1360 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
1361 PVM pVM = PDMDevHlpGetVM(pDevIns);
1362 LogFlow(("APIC: apicR3Destruct: pVM=%p\n", pVM));
1363
1364 apicR3TermState(pVM);
1365 return VINF_SUCCESS;
1366}
1367
1368
1369/**
1370 * @interface_method_impl{PDMDEVREG,pfnInitComplete}
1371 */
1372DECLCALLBACK(int) apicR3InitComplete(PPDMDEVINS pDevIns)
1373{
1374 PVM pVM = PDMDevHlpGetVM(pDevIns);
1375 PAPIC pApic = VM_TO_APIC(pVM);
1376
1377 /*
1378 * Init APIC settings that rely on HM and CPUM configurations.
1379 */
1380 CPUMCPUIDLEAF CpuLeaf;
1381 int rc = CPUMR3CpuIdGetLeaf(pVM, &CpuLeaf, 1, 0);
1382 AssertRCReturn(rc, rc);
1383
1384 pApic->fSupportsTscDeadline = RT_BOOL(CpuLeaf.uEcx & X86_CPUID_FEATURE_ECX_TSCDEADL);
1385 pApic->fPostedIntrsEnabled = HMR3IsPostedIntrsEnabled(pVM->pUVM);
1386 pApic->fVirtApicRegsEnabled = HMR3AreVirtApicRegsEnabled(pVM->pUVM);
1387
1388 LogRel(("APIC: fPostedIntrsEnabled=%RTbool fVirtApicRegsEnabled=%RTbool fSupportsTscDeadline=%RTbool\n",
1389 pApic->fPostedIntrsEnabled, pApic->fVirtApicRegsEnabled, pApic->fSupportsTscDeadline));
1390
1391 return VINF_SUCCESS;
1392}
1393
1394
1395/**
1396 * @interface_method_impl{PDMDEVREG,pfnConstruct}
1397 */
1398DECLCALLBACK(int) apicR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
1399{
1400 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1401 PAPICDEV pApicDev = PDMDEVINS_2_DATA(pDevIns, PAPICDEV);
1402 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
1403 PVM pVM = PDMDevHlpGetVM(pDevIns);
1404 PAPIC pApic = VM_TO_APIC(pVM);
1405 Assert(iInstance == 0); NOREF(iInstance);
1406
1407 /*
1408 * Init the data.
1409 */
1410 pApic->pDevInsR3 = pDevIns;
1411 pApic->fR0Enabled = pDevIns->fR0Enabled;
1412 pApic->fRCEnabled = pDevIns->fRCEnabled;
1413
1414 /*
1415 * Validate APIC settings.
1416 */
1417 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "Mode|IOAPIC|NumCPUs|MacOSWorkaround", "");
1418
1419 /** @devcfgm{apic, IOAPIC, bool, true}
1420 * Indicates whether an I/O APIC is present in the system. */
1421 int rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "IOAPIC", &pApic->fIoApicPresent, true);
1422 AssertLogRelRCReturn(rc, rc);
1423
1424 /** @devcfgm{apic, Mode, PDMAPICMODE, APIC(2)}
1425 * Max APIC feature level. */
1426 uint8_t uMaxMode;
1427 rc = pHlp->pfnCFGMQueryU8Def(pCfg, "Mode", &uMaxMode, PDMAPICMODE_APIC);
1428 AssertLogRelRCReturn(rc, rc);
1429 switch ((PDMAPICMODE)uMaxMode)
1430 {
1431 case PDMAPICMODE_NONE:
1432 LogRel(("APIC: APIC maximum mode configured as 'None', effectively disabled/not-present!\n"));
1433 case PDMAPICMODE_APIC:
1434 case PDMAPICMODE_X2APIC:
1435 break;
1436 default:
1437 return VMR3SetError(pVM->pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS, "APIC mode %d unknown.", uMaxMode);
1438 }
1439 pApic->enmMaxMode = (PDMAPICMODE)uMaxMode;
1440
1441 /** @devcfgm{apic, MacOSWorkaround, bool, false}
1442 * Enables a workaround for incorrect MSR_IA32_X2APIC_ID handling in macOS.
1443 *
1444 * Vital code in osfmk/i386/i386_init.c's vstart() routine incorrectly applies a
1445 * 24 right shift to the ID register value (correct for legacy APIC, but
1446 * entirely wrong for x2APIC), with the consequence that all CPUs use the same
1447 * per-cpu data and things panic pretty quickly. There are some shifty ID
1448 * reads in lapic_native.c too, but they are for either harmless (assuming boot
1449 * CPU has ID 0) or are for logging/debugging purposes only. */
1450 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "MacOSWorkaround", &pApic->fMacOSWorkaround, false);
1451 AssertLogRelRCReturn(rc, rc);
1452
1453 /*
1454 * Disable automatic PDM locking for this device.
1455 */
1456 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
1457 AssertRCReturn(rc, rc);
1458
1459 /*
1460 * Register the APIC with PDM.
1461 */
1462 rc = PDMDevHlpApicRegister(pDevIns);
1463 AssertLogRelRCReturn(rc, rc);
1464
1465 /*
1466 * Initialize the APIC state.
1467 */
1468 if (pApic->enmMaxMode == PDMAPICMODE_X2APIC)
1469 {
1470 rc = CPUMR3MsrRangesInsert(pVM, &g_MsrRange_x2Apic);
1471 AssertLogRelRCReturn(rc, rc);
1472 }
1473 else
1474 {
1475 /* We currently don't have a function to remove the range, so we register an range which will cause a #GP. */
1476 rc = CPUMR3MsrRangesInsert(pVM, &g_MsrRange_x2Apic_Invalid);
1477 AssertLogRelRCReturn(rc, rc);
1478 }
1479
1480 /* Tell CPUM about the APIC feature level so it can adjust APICBASE MSR GP mask and CPUID bits. */
1481 apicR3SetCpuIdFeatureLevel(pVM, pApic->enmMaxMode);
1482
1483 /* Finally, initialize the state. */
1484 rc = apicR3InitState(pVM);
1485 AssertRCReturn(rc, rc);
1486
1487 /*
1488 * Register the MMIO range.
1489 */
1490 PAPICCPU pApicCpu0 = VMCPU_TO_APICCPU(pVM->apCpusR3[0]);
1491 RTGCPHYS GCPhysApicBase = MSR_IA32_APICBASE_GET_ADDR(pApicCpu0->uApicBaseMsr);
1492
1493 rc = PDMDevHlpMmioCreateAndMap(pDevIns, GCPhysApicBase, sizeof(XAPICPAGE), apicWriteMmio, apicReadMmio,
1494 IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_DWORD_ZEROED, "APIC", &pApicDev->hMmio);
1495 AssertRCReturn(rc, rc);
1496
1497 /*
1498 * Create the APIC timers.
1499 */
1500 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1501 {
1502 PVMCPU pVCpu = pVM->apCpusR3[idCpu];
1503 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
1504 RTStrPrintf(&pApicCpu->szTimerDesc[0], sizeof(pApicCpu->szTimerDesc), "APIC Timer %u", pVCpu->idCpu);
1505 rc = PDMDevHlpTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, apicR3TimerCallback, pVCpu,
1506 TMTIMER_FLAGS_NO_CRIT_SECT | TMTIMER_FLAGS_RING0, pApicCpu->szTimerDesc, &pApicCpu->hTimer);
1507 AssertRCReturn(rc, rc);
1508 }
1509
1510 /*
1511 * Register saved state callbacks.
1512 */
1513 rc = PDMDevHlpSSMRegister(pDevIns, APIC_SAVED_STATE_VERSION, sizeof(*pApicDev), apicR3SaveExec, apicR3LoadExec);
1514 AssertRCReturn(rc, rc);
1515
1516 /*
1517 * Register debugger info callbacks.
1518 *
1519 * We use separate callbacks rather than arguments so they can also be
1520 * dumped in an automated fashion while collecting crash diagnostics and
1521 * not just used during live debugging via the VM debugger.
1522 */
1523 DBGFR3InfoRegisterInternalEx(pVM, "apic", "Dumps APIC basic information.", apicR3Info, DBGFINFO_FLAGS_ALL_EMTS);
1524 DBGFR3InfoRegisterInternalEx(pVM, "apiclvt", "Dumps APIC LVT information.", apicR3InfoLvt, DBGFINFO_FLAGS_ALL_EMTS);
1525 DBGFR3InfoRegisterInternalEx(pVM, "apictimer", "Dumps APIC timer information.", apicR3InfoTimer, DBGFINFO_FLAGS_ALL_EMTS);
1526
1527 /*
1528 * Statistics.
1529 */
1530#define APIC_REG_COUNTER(a_pvReg, a_pszNameFmt, a_pszDesc) \
1531 PDMDevHlpSTAMRegisterF(pDevIns, a_pvReg, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, \
1532 STAMUNIT_OCCURENCES, a_pszDesc, a_pszNameFmt, idCpu)
1533#define APIC_PROF_COUNTER(a_pvReg, a_pszNameFmt, a_pszDesc) \
1534 PDMDevHlpSTAMRegisterF(pDevIns, a_pvReg, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, \
1535 STAMUNIT_TICKS_PER_CALL, a_pszDesc, a_pszNameFmt, idCpu)
1536
1537 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1538 {
1539 PVMCPU pVCpu = pVM->apCpusR3[idCpu];
1540 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
1541
1542 APIC_REG_COUNTER(&pApicCpu->StatPostIntrCnt, "%u", "APIC/VCPU stats / number of apicPostInterrupt calls.");
1543 for (size_t i = 0; i < RT_ELEMENTS(pApicCpu->aStatVectors); i++)
1544 PDMDevHlpSTAMRegisterF(pDevIns, &pApicCpu->aStatVectors[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
1545 "Number of APICPostInterrupt calls for the vector.", "%u/Vectors/%02x", idCpu, i);
1546
1547#ifdef VBOX_WITH_STATISTICS
1548 APIC_REG_COUNTER(&pApicCpu->StatMmioReadRZ, "%u/RZ/MmioRead", "Number of APIC MMIO reads in RZ.");
1549 APIC_REG_COUNTER(&pApicCpu->StatMmioWriteRZ, "%u/RZ/MmioWrite", "Number of APIC MMIO writes in RZ.");
1550 APIC_REG_COUNTER(&pApicCpu->StatMsrReadRZ, "%u/RZ/MsrRead", "Number of APIC MSR reads in RZ.");
1551 APIC_REG_COUNTER(&pApicCpu->StatMsrWriteRZ, "%u/RZ/MsrWrite", "Number of APIC MSR writes in RZ.");
1552
1553 APIC_REG_COUNTER(&pApicCpu->StatMmioReadR3, "%u/R3/MmioRead", "Number of APIC MMIO reads in R3.");
1554 APIC_REG_COUNTER(&pApicCpu->StatMmioWriteR3, "%u/R3/MmioWrite", "Number of APIC MMIO writes in R3.");
1555 APIC_REG_COUNTER(&pApicCpu->StatMsrReadR3, "%u/R3/MsrRead", "Number of APIC MSR reads in R3.");
1556 APIC_REG_COUNTER(&pApicCpu->StatMsrWriteR3, "%u/R3/MsrWrite", "Number of APIC MSR writes in R3.");
1557
1558 APIC_REG_COUNTER(&pApicCpu->StatPostIntrAlreadyPending,
1559 "%u/PostInterruptAlreadyPending", "Number of times an interrupt is already pending.");
1560 APIC_REG_COUNTER(&pApicCpu->StatTimerCallback, "%u/TimerCallback", "Number of times the timer callback is invoked.");
1561
1562 APIC_REG_COUNTER(&pApicCpu->StatTprWrite, "%u/TprWrite", "Number of TPR writes.");
1563 APIC_REG_COUNTER(&pApicCpu->StatTprRead, "%u/TprRead", "Number of TPR reads.");
1564 APIC_REG_COUNTER(&pApicCpu->StatEoiWrite, "%u/EoiWrite", "Number of EOI writes.");
1565 APIC_REG_COUNTER(&pApicCpu->StatMaskedByTpr, "%u/MaskedByTpr", "Number of times TPR masks an interrupt in apicGetInterrupt.");
1566 APIC_REG_COUNTER(&pApicCpu->StatMaskedByPpr, "%u/MaskedByPpr", "Number of times PPR masks an interrupt in apicGetInterrupt.");
1567 APIC_REG_COUNTER(&pApicCpu->StatTimerIcrWrite, "%u/TimerIcrWrite", "Number of times the timer ICR is written.");
1568 APIC_REG_COUNTER(&pApicCpu->StatIcrLoWrite, "%u/IcrLoWrite", "Number of times the ICR Lo (send IPI) is written.");
1569 APIC_REG_COUNTER(&pApicCpu->StatIcrHiWrite, "%u/IcrHiWrite", "Number of times the ICR Hi is written.");
1570 APIC_REG_COUNTER(&pApicCpu->StatIcrFullWrite, "%u/IcrFullWrite", "Number of times the ICR full (send IPI, x2APIC) is written.");
1571 APIC_REG_COUNTER(&pApicCpu->StatIdMsrRead, "%u/IdMsrRead", "Number of times the APIC-ID MSR is read.");
1572 APIC_REG_COUNTER(&pApicCpu->StatDcrWrite, "%u/DcrWrite", "Number of times the DCR is written.");
1573 APIC_REG_COUNTER(&pApicCpu->StatDfrWrite, "%u/DfrWrite", "Number of times the DFR is written.");
1574 APIC_REG_COUNTER(&pApicCpu->StatLdrWrite, "%u/LdrWrite", "Number of times the LDR is written.");
1575 APIC_REG_COUNTER(&pApicCpu->StatLvtTimerWrite, "%u/LvtTimerWrite", "Number of times the LVT timer is written.");
1576
1577 APIC_PROF_COUNTER(&pApicCpu->StatUpdatePendingIntrs,
1578 "/PROF/CPU%u/APIC/UpdatePendingInterrupts", "Profiling of APICUpdatePendingInterrupts");
1579 APIC_PROF_COUNTER(&pApicCpu->StatPostIntr, "/PROF/CPU%u/APIC/PostInterrupt", "Profiling of APICPostInterrupt");
1580#endif
1581 }
1582
1583# undef APIC_PROF_COUNTER
1584# undef APIC_REG_ACCESS_COUNTER
1585
1586 return VINF_SUCCESS;
1587}
1588
1589#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
1590
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