VirtualBox

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

最後變更 在這個檔案從82031是 82031,由 vboxsync 提交於 5 年 前

APIC: Converted the timer pointers to timer handles. This requires PPDMDEVINS to be accessible when called directly from the VMM, so adding pointers to the APIC specific GVM and VM structures. bugref:9218

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette