VirtualBox

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

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use