VirtualBox

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

Last change on this file since 107308 was 107308, checked in by vboxsync, 5 weeks ago

VMM: bugref:10759 Refactor GIC for use with different backends.

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