VirtualBox

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

Last change on this file since 107132 was 107113, checked in by vboxsync, 2 months ago

VMM: bugref:10759 Restructure the APIC to allow different backends to be used.

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