VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/APICAll.cpp@ 80704

Last change on this file since 80704 was 80704, checked in by vboxsync, 5 years ago

PDM,Devices: Changed PDM_DEVREG_FLAGS_MSI_X into a registration field giving the max MSI-X vector count config for the device (typically VBOX_MSIX_MAX_ENTRIES). bugref:9218

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 126.6 KB
Line 
1/* $Id: APICAll.cpp 80704 2019-09-10 15:19:39Z vboxsync $ */
2/** @file
3 * APIC - Advanced Programmable Interrupt Controller - All Contexts.
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.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_DEV_APIC
23#include "APICInternal.h"
24#include <VBox/vmm/pdmdev.h>
25#include <VBox/vmm/pdmapi.h>
26#include <VBox/vmm/rem.h>
27#include <VBox/vmm/vmcc.h>
28#include <VBox/vmm/vmm.h>
29#include <VBox/vmm/vmcpuset.h>
30
31
32/*********************************************************************************************************************************
33* Internal Functions *
34*********************************************************************************************************************************/
35static void apicSetInterruptFF(PVMCPUCC pVCpu, PDMAPICIRQ enmType);
36static void apicStopTimer(PVMCPUCC pVCpu);
37
38
39/*********************************************************************************************************************************
40* Global Variables *
41*********************************************************************************************************************************/
42#if XAPIC_HARDWARE_VERSION == XAPIC_HARDWARE_VERSION_P4
43/** An ordered array of valid LVT masks. */
44static const uint32_t g_au32LvtValidMasks[] =
45{
46 XAPIC_LVT_TIMER_VALID,
47 XAPIC_LVT_THERMAL_VALID,
48 XAPIC_LVT_PERF_VALID,
49 XAPIC_LVT_LINT_VALID, /* LINT0 */
50 XAPIC_LVT_LINT_VALID, /* LINT1 */
51 XAPIC_LVT_ERROR_VALID
52};
53#endif
54
55#if 0
56/** @todo CMCI */
57static const uint32_t g_au32LvtExtValidMask[] =
58{
59 XAPIC_LVT_CMCI_VALID
60};
61#endif
62
63
64/**
65 * Checks if a vector is set in an APIC 256-bit sparse register.
66 *
67 * @returns true if the specified vector is set, false otherwise.
68 * @param pApicReg The APIC 256-bit spare register.
69 * @param uVector The vector to check if set.
70 */
71DECLINLINE(bool) apicTestVectorInReg(const volatile XAPIC256BITREG *pApicReg, uint8_t uVector)
72{
73 const volatile uint8_t *pbBitmap = (const volatile uint8_t *)&pApicReg->u[0];
74 return ASMBitTest(pbBitmap + XAPIC_REG256_VECTOR_OFF(uVector), XAPIC_REG256_VECTOR_BIT(uVector));
75}
76
77
78/**
79 * Sets the vector in an APIC 256-bit sparse register.
80 *
81 * @param pApicReg The APIC 256-bit spare register.
82 * @param uVector The vector to set.
83 */
84DECLINLINE(void) apicSetVectorInReg(volatile XAPIC256BITREG *pApicReg, uint8_t uVector)
85{
86 volatile uint8_t *pbBitmap = (volatile uint8_t *)&pApicReg->u[0];
87 ASMAtomicBitSet(pbBitmap + XAPIC_REG256_VECTOR_OFF(uVector), XAPIC_REG256_VECTOR_BIT(uVector));
88}
89
90
91/**
92 * Clears the vector in an APIC 256-bit sparse register.
93 *
94 * @param pApicReg The APIC 256-bit spare register.
95 * @param uVector The vector to clear.
96 */
97DECLINLINE(void) apicClearVectorInReg(volatile XAPIC256BITREG *pApicReg, uint8_t uVector)
98{
99 volatile uint8_t *pbBitmap = (volatile uint8_t *)&pApicReg->u[0];
100 ASMAtomicBitClear(pbBitmap + XAPIC_REG256_VECTOR_OFF(uVector), XAPIC_REG256_VECTOR_BIT(uVector));
101}
102
103
104#if 0 /* unused */
105/**
106 * Checks if a vector is set in an APIC Pending-Interrupt Bitmap (PIB).
107 *
108 * @returns true if the specified vector is set, false otherwise.
109 * @param pvPib Opaque pointer to the PIB.
110 * @param uVector The vector to check if set.
111 */
112DECLINLINE(bool) apicTestVectorInPib(volatile void *pvPib, uint8_t uVector)
113{
114 return ASMBitTest(pvPib, uVector);
115}
116#endif /* unused */
117
118
119/**
120 * Atomically sets the PIB notification bit.
121 *
122 * @returns non-zero if the bit was already set, 0 otherwise.
123 * @param pApicPib Pointer to the PIB.
124 */
125DECLINLINE(uint32_t) apicSetNotificationBitInPib(PAPICPIB pApicPib)
126{
127 return ASMAtomicXchgU32(&pApicPib->fOutstandingNotification, RT_BIT_32(31));
128}
129
130
131/**
132 * Atomically tests and clears the PIB notification bit.
133 *
134 * @returns non-zero if the bit was already set, 0 otherwise.
135 * @param pApicPib Pointer to the PIB.
136 */
137DECLINLINE(uint32_t) apicClearNotificationBitInPib(PAPICPIB pApicPib)
138{
139 return ASMAtomicXchgU32(&pApicPib->fOutstandingNotification, UINT32_C(0));
140}
141
142
143/**
144 * Sets the vector in an APIC Pending-Interrupt Bitmap (PIB).
145 *
146 * @param pvPib Opaque pointer to the PIB.
147 * @param uVector The vector to set.
148 */
149DECLINLINE(void) apicSetVectorInPib(volatile void *pvPib, uint8_t uVector)
150{
151 ASMAtomicBitSet(pvPib, uVector);
152}
153
154#if 0 /* unused */
155/**
156 * Clears the vector in an APIC Pending-Interrupt Bitmap (PIB).
157 *
158 * @param pvPib Opaque pointer to the PIB.
159 * @param uVector The vector to clear.
160 */
161DECLINLINE(void) apicClearVectorInPib(volatile void *pvPib, uint8_t uVector)
162{
163 ASMAtomicBitClear(pvPib, uVector);
164}
165#endif /* unused */
166
167#if 0 /* unused */
168/**
169 * Atomically OR's a fragment (32 vectors) into an APIC 256-bit sparse
170 * register.
171 *
172 * @param pApicReg The APIC 256-bit spare register.
173 * @param idxFragment The index of the 32-bit fragment in @a
174 * pApicReg.
175 * @param u32Fragment The 32-bit vector fragment to OR.
176 */
177DECLINLINE(void) apicOrVectorsToReg(volatile XAPIC256BITREG *pApicReg, size_t idxFragment, uint32_t u32Fragment)
178{
179 Assert(idxFragment < RT_ELEMENTS(pApicReg->u));
180 ASMAtomicOrU32(&pApicReg->u[idxFragment].u32Reg, u32Fragment);
181}
182#endif /* unused */
183
184
185#if 0 /* unused */
186/**
187 * Atomically AND's a fragment (32 vectors) into an APIC
188 * 256-bit sparse register.
189 *
190 * @param pApicReg The APIC 256-bit spare register.
191 * @param idxFragment The index of the 32-bit fragment in @a
192 * pApicReg.
193 * @param u32Fragment The 32-bit vector fragment to AND.
194 */
195DECLINLINE(void) apicAndVectorsToReg(volatile XAPIC256BITREG *pApicReg, size_t idxFragment, uint32_t u32Fragment)
196{
197 Assert(idxFragment < RT_ELEMENTS(pApicReg->u));
198 ASMAtomicAndU32(&pApicReg->u[idxFragment].u32Reg, u32Fragment);
199}
200#endif /* unused */
201
202
203/**
204 * Reports and returns appropriate error code for invalid MSR accesses.
205 *
206 * @returns VERR_CPUM_RAISE_GP_0
207 *
208 * @param pVCpu The cross context virtual CPU structure.
209 * @param u32Reg The MSR being accessed.
210 * @param enmAccess The invalid-access type.
211 */
212static int apicMsrAccessError(PVMCPUCC pVCpu, uint32_t u32Reg, APICMSRACCESS enmAccess)
213{
214 static struct
215 {
216 const char *pszBefore; /* The error message before printing the MSR index */
217 const char *pszAfter; /* The error message after printing the MSR index */
218 } const s_aAccess[] =
219 {
220 /* enmAccess pszBefore pszAfter */
221 /* 0 */ { "read MSR", " while not in x2APIC mode" },
222 /* 1 */ { "write MSR", " while not in x2APIC mode" },
223 /* 2 */ { "read reserved/unknown MSR", "" },
224 /* 3 */ { "write reserved/unknown MSR", "" },
225 /* 4 */ { "read write-only MSR", "" },
226 /* 5 */ { "write read-only MSR", "" },
227 /* 6 */ { "read reserved bits of MSR", "" },
228 /* 7 */ { "write reserved bits of MSR", "" },
229 /* 8 */ { "write an invalid value to MSR", "" },
230 /* 9 */ { "write MSR", " disallowed by configuration" },
231 /* 10 */ { "read MSR", " disallowed by configuration" },
232 };
233 AssertCompile(RT_ELEMENTS(s_aAccess) == APICMSRACCESS_COUNT);
234
235 size_t const i = enmAccess;
236 Assert(i < RT_ELEMENTS(s_aAccess));
237 if (pVCpu->apic.s.cLogMaxAccessError++ < 5)
238 LogRel(("APIC%u: Attempt to %s (%#x)%s -> #GP(0)\n", pVCpu->idCpu, s_aAccess[i].pszBefore, u32Reg, s_aAccess[i].pszAfter));
239 return VERR_CPUM_RAISE_GP_0;
240}
241
242
243/**
244 * Gets the descriptive APIC mode.
245 *
246 * @returns The name.
247 * @param enmMode The xAPIC mode.
248 */
249const char *apicGetModeName(APICMODE enmMode)
250{
251 switch (enmMode)
252 {
253 case APICMODE_DISABLED: return "Disabled";
254 case APICMODE_XAPIC: return "xAPIC";
255 case APICMODE_X2APIC: return "x2APIC";
256 default: break;
257 }
258 return "Invalid";
259}
260
261
262/**
263 * Gets the descriptive destination format name.
264 *
265 * @returns The destination format name.
266 * @param enmDestFormat The destination format.
267 */
268const char *apicGetDestFormatName(XAPICDESTFORMAT enmDestFormat)
269{
270 switch (enmDestFormat)
271 {
272 case XAPICDESTFORMAT_FLAT: return "Flat";
273 case XAPICDESTFORMAT_CLUSTER: return "Cluster";
274 default: break;
275 }
276 return "Invalid";
277}
278
279
280/**
281 * Gets the descriptive delivery mode name.
282 *
283 * @returns The delivery mode name.
284 * @param enmDeliveryMode The delivery mode.
285 */
286const char *apicGetDeliveryModeName(XAPICDELIVERYMODE enmDeliveryMode)
287{
288 switch (enmDeliveryMode)
289 {
290 case XAPICDELIVERYMODE_FIXED: return "Fixed";
291 case XAPICDELIVERYMODE_LOWEST_PRIO: return "Lowest-priority";
292 case XAPICDELIVERYMODE_SMI: return "SMI";
293 case XAPICDELIVERYMODE_NMI: return "NMI";
294 case XAPICDELIVERYMODE_INIT: return "INIT";
295 case XAPICDELIVERYMODE_STARTUP: return "SIPI";
296 case XAPICDELIVERYMODE_EXTINT: return "ExtINT";
297 default: break;
298 }
299 return "Invalid";
300}
301
302
303/**
304 * Gets the descriptive destination mode name.
305 *
306 * @returns The destination mode name.
307 * @param enmDestMode The destination mode.
308 */
309const char *apicGetDestModeName(XAPICDESTMODE enmDestMode)
310{
311 switch (enmDestMode)
312 {
313 case XAPICDESTMODE_PHYSICAL: return "Physical";
314 case XAPICDESTMODE_LOGICAL: return "Logical";
315 default: break;
316 }
317 return "Invalid";
318}
319
320
321/**
322 * Gets the descriptive trigger mode name.
323 *
324 * @returns The trigger mode name.
325 * @param enmTriggerMode The trigger mode.
326 */
327const char *apicGetTriggerModeName(XAPICTRIGGERMODE enmTriggerMode)
328{
329 switch (enmTriggerMode)
330 {
331 case XAPICTRIGGERMODE_EDGE: return "Edge";
332 case XAPICTRIGGERMODE_LEVEL: return "Level";
333 default: break;
334 }
335 return "Invalid";
336}
337
338
339/**
340 * Gets the destination shorthand name.
341 *
342 * @returns The destination shorthand name.
343 * @param enmDestShorthand The destination shorthand.
344 */
345const char *apicGetDestShorthandName(XAPICDESTSHORTHAND enmDestShorthand)
346{
347 switch (enmDestShorthand)
348 {
349 case XAPICDESTSHORTHAND_NONE: return "None";
350 case XAPICDESTSHORTHAND_SELF: return "Self";
351 case XAPIDDESTSHORTHAND_ALL_INCL_SELF: return "All including self";
352 case XAPICDESTSHORTHAND_ALL_EXCL_SELF: return "All excluding self";
353 default: break;
354 }
355 return "Invalid";
356}
357
358
359/**
360 * Gets the timer mode name.
361 *
362 * @returns The timer mode name.
363 * @param enmTimerMode The timer mode.
364 */
365const char *apicGetTimerModeName(XAPICTIMERMODE enmTimerMode)
366{
367 switch (enmTimerMode)
368 {
369 case XAPICTIMERMODE_ONESHOT: return "One-shot";
370 case XAPICTIMERMODE_PERIODIC: return "Periodic";
371 case XAPICTIMERMODE_TSC_DEADLINE: return "TSC deadline";
372 default: break;
373 }
374 return "Invalid";
375}
376
377
378/**
379 * Gets the APIC mode given the base MSR value.
380 *
381 * @returns The APIC mode.
382 * @param uApicBaseMsr The APIC Base MSR value.
383 */
384APICMODE apicGetMode(uint64_t uApicBaseMsr)
385{
386 uint32_t const uMode = (uApicBaseMsr >> 10) & UINT64_C(3);
387 APICMODE const enmMode = (APICMODE)uMode;
388#ifdef VBOX_STRICT
389 /* Paranoia. */
390 switch (uMode)
391 {
392 case APICMODE_DISABLED:
393 case APICMODE_INVALID:
394 case APICMODE_XAPIC:
395 case APICMODE_X2APIC:
396 break;
397 default:
398 AssertMsgFailed(("Invalid mode"));
399 }
400#endif
401 return enmMode;
402}
403
404
405/**
406 * Returns whether the APIC is hardware enabled or not.
407 *
408 * @returns true if enabled, false otherwise.
409 * @param pVCpu The cross context virtual CPU structure.
410 */
411VMM_INT_DECL(bool) APICIsEnabled(PCVMCPUCC pVCpu)
412{
413 PCAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
414 return RT_BOOL(pApicCpu->uApicBaseMsr & MSR_IA32_APICBASE_EN);
415}
416
417
418/**
419 * Finds the most significant set bit in an APIC 256-bit sparse register.
420 *
421 * @returns @a rcNotFound if no bit was set, 0-255 otherwise.
422 * @param pReg The APIC 256-bit sparse register.
423 * @param rcNotFound What to return when no bit is set.
424 */
425static int apicGetHighestSetBitInReg(volatile const XAPIC256BITREG *pReg, int rcNotFound)
426{
427 ssize_t const cFragments = RT_ELEMENTS(pReg->u);
428 unsigned const uFragmentShift = 5;
429 AssertCompile(1 << uFragmentShift == sizeof(pReg->u[0].u32Reg) * 8);
430 for (ssize_t i = cFragments - 1; i >= 0; i--)
431 {
432 uint32_t const uFragment = pReg->u[i].u32Reg;
433 if (uFragment)
434 {
435 unsigned idxSetBit = ASMBitLastSetU32(uFragment);
436 --idxSetBit;
437 idxSetBit |= i << uFragmentShift;
438 return idxSetBit;
439 }
440 }
441 return rcNotFound;
442}
443
444
445/**
446 * Reads a 32-bit register at a specified offset.
447 *
448 * @returns The value at the specified offset.
449 * @param pXApicPage The xAPIC page.
450 * @param offReg The offset of the register being read.
451 */
452DECLINLINE(uint32_t) apicReadRaw32(PCXAPICPAGE pXApicPage, uint16_t offReg)
453{
454 Assert(offReg < sizeof(*pXApicPage) - sizeof(uint32_t));
455 uint8_t const *pbXApic = (const uint8_t *)pXApicPage;
456 uint32_t const uValue = *(const uint32_t *)(pbXApic + offReg);
457 return uValue;
458}
459
460
461/**
462 * Writes a 32-bit register at a specified offset.
463 *
464 * @param pXApicPage The xAPIC page.
465 * @param offReg The offset of the register being written.
466 * @param uReg The value of the register.
467 */
468DECLINLINE(void) apicWriteRaw32(PXAPICPAGE pXApicPage, uint16_t offReg, uint32_t uReg)
469{
470 Assert(offReg < sizeof(*pXApicPage) - sizeof(uint32_t));
471 uint8_t *pbXApic = (uint8_t *)pXApicPage;
472 *(uint32_t *)(pbXApic + offReg) = uReg;
473}
474
475
476/**
477 * Sets an error in the internal ESR of the specified APIC.
478 *
479 * @param pVCpu The cross context virtual CPU structure.
480 * @param uError The error.
481 * @thread Any.
482 */
483DECLINLINE(void) apicSetError(PVMCPUCC pVCpu, uint32_t uError)
484{
485 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
486 ASMAtomicOrU32(&pApicCpu->uEsrInternal, uError);
487}
488
489
490/**
491 * Clears all errors in the internal ESR.
492 *
493 * @returns The value of the internal ESR before clearing.
494 * @param pVCpu The cross context virtual CPU structure.
495 */
496DECLINLINE(uint32_t) apicClearAllErrors(PVMCPUCC pVCpu)
497{
498 VMCPU_ASSERT_EMT(pVCpu);
499 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
500 return ASMAtomicXchgU32(&pApicCpu->uEsrInternal, 0);
501}
502
503
504/**
505 * Signals the guest if a pending interrupt is ready to be serviced.
506 *
507 * @param pVCpu The cross context virtual CPU structure.
508 */
509static void apicSignalNextPendingIntr(PVMCPUCC pVCpu)
510{
511 VMCPU_ASSERT_EMT_OR_NOT_RUNNING(pVCpu);
512
513 PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
514 if (pXApicPage->svr.u.fApicSoftwareEnable)
515 {
516 int const irrv = apicGetHighestSetBitInReg(&pXApicPage->irr, -1 /* rcNotFound */);
517 if (irrv >= 0)
518 {
519 Assert(irrv <= (int)UINT8_MAX);
520 uint8_t const uVector = irrv;
521 uint8_t const uPpr = pXApicPage->ppr.u8Ppr;
522 if ( !uPpr
523 || XAPIC_PPR_GET_PP(uVector) > XAPIC_PPR_GET_PP(uPpr))
524 {
525 Log2(("APIC%u: apicSignalNextPendingIntr: Signalling pending interrupt. uVector=%#x\n", pVCpu->idCpu, uVector));
526 apicSetInterruptFF(pVCpu, PDMAPICIRQ_HARDWARE);
527 }
528 else
529 {
530 Log2(("APIC%u: apicSignalNextPendingIntr: Nothing to signal. uVector=%#x uPpr=%#x uTpr=%#x\n", pVCpu->idCpu,
531 uVector, uPpr, pXApicPage->tpr.u8Tpr));
532 }
533 }
534 }
535 else
536 {
537 Log2(("APIC%u: apicSignalNextPendingIntr: APIC software-disabled, clearing pending interrupt\n", pVCpu->idCpu));
538 apicClearInterruptFF(pVCpu, PDMAPICIRQ_HARDWARE);
539 }
540}
541
542
543/**
544 * Sets the Spurious-Interrupt Vector Register (SVR).
545 *
546 * @returns VINF_SUCCESS or VERR_CPUM_RAISE_GP_0.
547 * @param pVCpu The cross context virtual CPU structure.
548 * @param uSvr The SVR value.
549 */
550static int apicSetSvr(PVMCPUCC pVCpu, uint32_t uSvr)
551{
552 VMCPU_ASSERT_EMT(pVCpu);
553
554 uint32_t uValidMask = XAPIC_SVR_VALID;
555 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
556 if (pXApicPage->version.u.fEoiBroadcastSupression)
557 uValidMask |= XAPIC_SVR_SUPRESS_EOI_BROADCAST;
558
559 if ( XAPIC_IN_X2APIC_MODE(pVCpu)
560 && (uSvr & ~uValidMask))
561 return apicMsrAccessError(pVCpu, MSR_IA32_X2APIC_SVR, APICMSRACCESS_WRITE_RSVD_BITS);
562
563 Log2(("APIC%u: apicSetSvr: uSvr=%#RX32\n", pVCpu->idCpu, uSvr));
564 apicWriteRaw32(pXApicPage, XAPIC_OFF_SVR, uSvr);
565 if (!pXApicPage->svr.u.fApicSoftwareEnable)
566 {
567 /** @todo CMCI. */
568 pXApicPage->lvt_timer.u.u1Mask = 1;
569#if XAPIC_HARDWARE_VERSION == XAPIC_HARDWARE_VERSION_P4
570 pXApicPage->lvt_thermal.u.u1Mask = 1;
571#endif
572 pXApicPage->lvt_perf.u.u1Mask = 1;
573 pXApicPage->lvt_lint0.u.u1Mask = 1;
574 pXApicPage->lvt_lint1.u.u1Mask = 1;
575 pXApicPage->lvt_error.u.u1Mask = 1;
576 }
577
578 apicSignalNextPendingIntr(pVCpu);
579 return VINF_SUCCESS;
580}
581
582
583/**
584 * Sends an interrupt to one or more APICs.
585 *
586 * @returns Strict VBox status code.
587 * @param pVM The cross context VM structure.
588 * @param pVCpu The cross context virtual CPU structure, can be
589 * NULL if the source of the interrupt is not an
590 * APIC (for e.g. a bus).
591 * @param uVector The interrupt vector.
592 * @param enmTriggerMode The trigger mode.
593 * @param enmDeliveryMode The delivery mode.
594 * @param pDestCpuSet The destination CPU set.
595 * @param pfIntrAccepted Where to store whether this interrupt was
596 * accepted by the target APIC(s) or not.
597 * Optional, can be NULL.
598 * @param uSrcTag The interrupt source tag (debugging).
599 * @param rcRZ The return code if the operation cannot be
600 * performed in the current context.
601 */
602static VBOXSTRICTRC apicSendIntr(PVMCC pVM, PVMCPUCC pVCpu, uint8_t uVector, XAPICTRIGGERMODE enmTriggerMode,
603 XAPICDELIVERYMODE enmDeliveryMode, PCVMCPUSET pDestCpuSet, bool *pfIntrAccepted,
604 uint32_t uSrcTag, int rcRZ)
605{
606 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
607 VMCPUID const cCpus = pVM->cCpus;
608 bool fAccepted = false;
609 switch (enmDeliveryMode)
610 {
611 case XAPICDELIVERYMODE_FIXED:
612 {
613 for (VMCPUID idCpu = 0; idCpu < cCpus; idCpu++)
614 if (VMCPUSET_IS_PRESENT(pDestCpuSet, idCpu))
615 {
616 PVMCPUCC pItVCpu = pVM->CTX_SUFF(apCpus)[idCpu];
617 if (APICIsEnabled(pItVCpu))
618 fAccepted = apicPostInterrupt(pItVCpu, uVector, enmTriggerMode, uSrcTag);
619 }
620 break;
621 }
622
623 case XAPICDELIVERYMODE_LOWEST_PRIO:
624 {
625 VMCPUID const idCpu = VMCPUSET_FIND_FIRST_PRESENT(pDestCpuSet);
626 AssertMsgBreak(idCpu < pVM->cCpus, ("APIC: apicSendIntr: No CPU found for lowest-priority delivery mode! idCpu=%u\n", idCpu));
627 PVMCPUCC pVCpuDst = pVM->CTX_SUFF(apCpus)[idCpu];
628 if (APICIsEnabled(pVCpuDst))
629 fAccepted = apicPostInterrupt(pVCpuDst, uVector, enmTriggerMode, uSrcTag);
630 else
631 AssertMsgFailed(("APIC: apicSendIntr: Target APIC not enabled in lowest-priority delivery mode! idCpu=%u\n", idCpu));
632 break;
633 }
634
635 case XAPICDELIVERYMODE_SMI:
636 {
637 for (VMCPUID idCpu = 0; idCpu < cCpus; idCpu++)
638 if (VMCPUSET_IS_PRESENT(pDestCpuSet, idCpu))
639 {
640 Log2(("APIC: apicSendIntr: Raising SMI on VCPU%u\n", idCpu));
641 apicSetInterruptFF(pVM->CTX_SUFF(apCpus)[idCpu], PDMAPICIRQ_SMI);
642 fAccepted = true;
643 }
644 break;
645 }
646
647 case XAPICDELIVERYMODE_NMI:
648 {
649 for (VMCPUID idCpu = 0; idCpu < cCpus; idCpu++)
650 if (VMCPUSET_IS_PRESENT(pDestCpuSet, idCpu))
651 {
652 PVMCPUCC pItVCpu = pVM->CTX_SUFF(apCpus)[idCpu];
653 if (APICIsEnabled(pItVCpu))
654 {
655 Log2(("APIC: apicSendIntr: Raising NMI on VCPU%u\n", idCpu));
656 apicSetInterruptFF(pItVCpu, PDMAPICIRQ_NMI);
657 fAccepted = true;
658 }
659 }
660 break;
661 }
662
663 case XAPICDELIVERYMODE_INIT:
664 {
665#ifdef IN_RING3
666 for (VMCPUID idCpu = 0; idCpu < cCpus; idCpu++)
667 if (VMCPUSET_IS_PRESENT(pDestCpuSet, idCpu))
668 {
669 Log2(("APIC: apicSendIntr: Issuing INIT to VCPU%u\n", idCpu));
670 VMMR3SendInitIpi(pVM, idCpu);
671 fAccepted = true;
672 }
673#else
674 /* We need to return to ring-3 to deliver the INIT. */
675 rcStrict = rcRZ;
676 fAccepted = true;
677#endif
678 break;
679 }
680
681 case XAPICDELIVERYMODE_STARTUP:
682 {
683#ifdef IN_RING3
684 for (VMCPUID idCpu = 0; idCpu < cCpus; idCpu++)
685 if (VMCPUSET_IS_PRESENT(pDestCpuSet, idCpu))
686 {
687 Log2(("APIC: apicSendIntr: Issuing SIPI to VCPU%u\n", idCpu));
688 VMMR3SendStartupIpi(pVM, idCpu, uVector);
689 fAccepted = true;
690 }
691#else
692 /* We need to return to ring-3 to deliver the SIPI. */
693 rcStrict = rcRZ;
694 fAccepted = true;
695 Log2(("APIC: apicSendIntr: SIPI issued, returning to RZ. rc=%Rrc\n", rcRZ));
696#endif
697 break;
698 }
699
700 case XAPICDELIVERYMODE_EXTINT:
701 {
702 for (VMCPUID idCpu = 0; idCpu < cCpus; idCpu++)
703 if (VMCPUSET_IS_PRESENT(pDestCpuSet, idCpu))
704 {
705 Log2(("APIC: apicSendIntr: Raising EXTINT on VCPU%u\n", idCpu));
706 apicSetInterruptFF(pVM->CTX_SUFF(apCpus)[idCpu], PDMAPICIRQ_EXTINT);
707 fAccepted = true;
708 }
709 break;
710 }
711
712 default:
713 {
714 AssertMsgFailed(("APIC: apicSendIntr: Unsupported delivery mode %#x (%s)\n", enmDeliveryMode,
715 apicGetDeliveryModeName(enmDeliveryMode)));
716 break;
717 }
718 }
719
720 /*
721 * If an illegal vector is programmed, set the 'send illegal vector' error here if the
722 * interrupt is being sent by an APIC.
723 *
724 * The 'receive illegal vector' will be set on the target APIC when the interrupt
725 * gets generated, see apicPostInterrupt().
726 *
727 * See Intel spec. 10.5.3 "Error Handling".
728 */
729 if ( rcStrict != rcRZ
730 && pVCpu)
731 {
732 /*
733 * Flag only errors when the delivery mode is fixed and not others.
734 *
735 * Ubuntu 10.04-3 amd64 live CD with 2 VCPUs gets upset as it sends an SIPI to the
736 * 2nd VCPU with vector 6 and checks the ESR for no errors, see @bugref{8245#c86}.
737 */
738 /** @todo The spec says this for LVT, but not explcitly for ICR-lo
739 * but it probably is true. */
740 if (enmDeliveryMode == XAPICDELIVERYMODE_FIXED)
741 {
742 if (RT_UNLIKELY(uVector <= XAPIC_ILLEGAL_VECTOR_END))
743 apicSetError(pVCpu, XAPIC_ESR_SEND_ILLEGAL_VECTOR);
744 }
745 }
746
747 if (pfIntrAccepted)
748 *pfIntrAccepted = fAccepted;
749
750 return rcStrict;
751}
752
753
754/**
755 * Checks if this APIC belongs to a logical destination.
756 *
757 * @returns true if the APIC belongs to the logical
758 * destination, false otherwise.
759 * @param pVCpu The cross context virtual CPU structure.
760 * @param fDest The destination mask.
761 *
762 * @thread Any.
763 */
764static bool apicIsLogicalDest(PVMCPUCC pVCpu, uint32_t fDest)
765{
766 if (XAPIC_IN_X2APIC_MODE(pVCpu))
767 {
768 /*
769 * Flat logical mode is not supported in x2APIC mode.
770 * In clustered logical mode, the 32-bit logical ID in the LDR is interpreted as follows:
771 * - High 16 bits is the cluster ID.
772 * - Low 16 bits: each bit represents a unique APIC within the cluster.
773 */
774 PCX2APICPAGE pX2ApicPage = VMCPU_TO_CX2APICPAGE(pVCpu);
775 uint32_t const u32Ldr = pX2ApicPage->ldr.u32LogicalApicId;
776 if (X2APIC_LDR_GET_CLUSTER_ID(u32Ldr) == (fDest & X2APIC_LDR_CLUSTER_ID))
777 return RT_BOOL(u32Ldr & fDest & X2APIC_LDR_LOGICAL_ID);
778 return false;
779 }
780
781#if XAPIC_HARDWARE_VERSION == XAPIC_HARDWARE_VERSION_P4
782 /*
783 * In both flat and clustered logical mode, a destination mask of all set bits indicates a broadcast.
784 * See AMD spec. 16.6.1 "Receiving System and IPI Interrupts".
785 */
786 Assert(!XAPIC_IN_X2APIC_MODE(pVCpu));
787 if ((fDest & XAPIC_LDR_FLAT_LOGICAL_ID) == XAPIC_LDR_FLAT_LOGICAL_ID)
788 return true;
789
790 PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
791 XAPICDESTFORMAT enmDestFormat = (XAPICDESTFORMAT)pXApicPage->dfr.u.u4Model;
792 if (enmDestFormat == XAPICDESTFORMAT_FLAT)
793 {
794 /* The destination mask is interpreted as a bitmap of 8 unique logical APIC IDs. */
795 uint8_t const u8Ldr = pXApicPage->ldr.u.u8LogicalApicId;
796 return RT_BOOL(u8Ldr & fDest & XAPIC_LDR_FLAT_LOGICAL_ID);
797 }
798
799 /*
800 * In clustered logical mode, the 8-bit logical ID in the LDR is interpreted as follows:
801 * - High 4 bits is the cluster ID.
802 * - Low 4 bits: each bit represents a unique APIC within the cluster.
803 */
804 Assert(enmDestFormat == XAPICDESTFORMAT_CLUSTER);
805 uint8_t const u8Ldr = pXApicPage->ldr.u.u8LogicalApicId;
806 if (XAPIC_LDR_CLUSTERED_GET_CLUSTER_ID(u8Ldr) == (fDest & XAPIC_LDR_CLUSTERED_CLUSTER_ID))
807 return RT_BOOL(u8Ldr & fDest & XAPIC_LDR_CLUSTERED_LOGICAL_ID);
808 return false;
809#else
810# error "Implement Pentium and P6 family APIC architectures"
811#endif
812}
813
814
815/**
816 * Figures out the set of destination CPUs for a given destination mode, format
817 * and delivery mode setting.
818 *
819 * @param pVM The cross context VM structure.
820 * @param fDestMask The destination mask.
821 * @param fBroadcastMask The broadcast mask.
822 * @param enmDestMode The destination mode.
823 * @param enmDeliveryMode The delivery mode.
824 * @param pDestCpuSet The destination CPU set to update.
825 */
826static void apicGetDestCpuSet(PVMCC pVM, uint32_t fDestMask, uint32_t fBroadcastMask, XAPICDESTMODE enmDestMode,
827 XAPICDELIVERYMODE enmDeliveryMode, PVMCPUSET pDestCpuSet)
828{
829 VMCPUSET_EMPTY(pDestCpuSet);
830
831 /*
832 * Physical destination mode only supports either a broadcast or a single target.
833 * - Broadcast with lowest-priority delivery mode is not supported[1], we deliver it
834 * as a regular broadcast like in fixed delivery mode.
835 * - For a single target, lowest-priority delivery mode makes no sense. We deliver
836 * to the target like in fixed delivery mode.
837 *
838 * [1] See Intel spec. 10.6.2.1 "Physical Destination Mode".
839 */
840 if ( enmDestMode == XAPICDESTMODE_PHYSICAL
841 && enmDeliveryMode == XAPICDELIVERYMODE_LOWEST_PRIO)
842 {
843 AssertMsgFailed(("APIC: Lowest-priority delivery using physical destination mode!"));
844 enmDeliveryMode = XAPICDELIVERYMODE_FIXED;
845 }
846
847 uint32_t const cCpus = pVM->cCpus;
848 if (enmDeliveryMode == XAPICDELIVERYMODE_LOWEST_PRIO)
849 {
850 Assert(enmDestMode == XAPICDESTMODE_LOGICAL);
851#if XAPIC_HARDWARE_VERSION == XAPIC_HARDWARE_VERSION_P4
852 VMCPUID idCpuLowestTpr = NIL_VMCPUID;
853 uint8_t u8LowestTpr = UINT8_C(0xff);
854 for (VMCPUID idCpu = 0; idCpu < cCpus; idCpu++)
855 {
856 PVMCPUCC pVCpuDst = pVM->CTX_SUFF(apCpus)[idCpu];
857 if (apicIsLogicalDest(pVCpuDst, fDestMask))
858 {
859 PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpuDst);
860 uint8_t const u8Tpr = pXApicPage->tpr.u8Tpr; /* PAV */
861
862 /*
863 * If there is a tie for lowest priority, the local APIC with the highest ID is chosen.
864 * Hence the use of "<=" in the check below.
865 * See AMD spec. 16.6.2 "Lowest Priority Messages and Arbitration".
866 */
867 if (u8Tpr <= u8LowestTpr)
868 {
869 u8LowestTpr = u8Tpr;
870 idCpuLowestTpr = idCpu;
871 }
872 }
873 }
874 if (idCpuLowestTpr != NIL_VMCPUID)
875 VMCPUSET_ADD(pDestCpuSet, idCpuLowestTpr);
876#else
877# error "Implement Pentium and P6 family APIC architectures"
878#endif
879 return;
880 }
881
882 /*
883 * x2APIC:
884 * - In both physical and logical destination mode, a destination mask of 0xffffffff implies a broadcast[1].
885 * xAPIC:
886 * - In physical destination mode, a destination mask of 0xff implies a broadcast[2].
887 * - In both flat and clustered logical mode, a destination mask of 0xff implies a broadcast[3].
888 *
889 * [1] See Intel spec. 10.12.9 "ICR Operation in x2APIC Mode".
890 * [2] See Intel spec. 10.6.2.1 "Physical Destination Mode".
891 * [2] See AMD spec. 16.6.1 "Receiving System and IPI Interrupts".
892 */
893 if ((fDestMask & fBroadcastMask) == fBroadcastMask)
894 {
895 VMCPUSET_FILL(pDestCpuSet);
896 return;
897 }
898
899 if (enmDestMode == XAPICDESTMODE_PHYSICAL)
900 {
901 /* The destination mask is interpreted as the physical APIC ID of a single target. */
902#if 1
903 /* Since our physical APIC ID is read-only to software, set the corresponding bit in the CPU set. */
904 if (RT_LIKELY(fDestMask < cCpus))
905 VMCPUSET_ADD(pDestCpuSet, fDestMask);
906#else
907 /* The physical APIC ID may not match our VCPU ID, search through the list of targets. */
908 for (VMCPUID idCpu = 0; idCpu < cCpus; idCpu++)
909 {
910 PVMCPUCC pVCpuDst = &pVM->aCpus[idCpu];
911 if (XAPIC_IN_X2APIC_MODE(pVCpuDst))
912 {
913 PCX2APICPAGE pX2ApicPage = VMCPU_TO_CX2APICPAGE(pVCpuDst);
914 if (pX2ApicPage->id.u32ApicId == fDestMask)
915 VMCPUSET_ADD(pDestCpuSet, pVCpuDst->idCpu);
916 }
917 else
918 {
919 PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpuDst);
920 if (pXApicPage->id.u8ApicId == (uint8_t)fDestMask)
921 VMCPUSET_ADD(pDestCpuSet, pVCpuDst->idCpu);
922 }
923 }
924#endif
925 }
926 else
927 {
928 Assert(enmDestMode == XAPICDESTMODE_LOGICAL);
929
930 /* A destination mask of all 0's implies no target APICs (since it's interpreted as a bitmap or partial bitmap). */
931 if (RT_UNLIKELY(!fDestMask))
932 return;
933
934 /* The destination mask is interpreted as a bitmap of software-programmable logical APIC ID of the target APICs. */
935 for (VMCPUID idCpu = 0; idCpu < cCpus; idCpu++)
936 {
937 PVMCPUCC pVCpuDst = pVM->CTX_SUFF(apCpus)[idCpu];
938 if (apicIsLogicalDest(pVCpuDst, fDestMask))
939 VMCPUSET_ADD(pDestCpuSet, pVCpuDst->idCpu);
940 }
941 }
942}
943
944
945/**
946 * Sends an Interprocessor Interrupt (IPI) using values from the Interrupt
947 * Command Register (ICR).
948 *
949 * @returns VBox status code.
950 * @param pVCpu The cross context virtual CPU structure.
951 * @param rcRZ The return code if the operation cannot be
952 * performed in the current context.
953 */
954DECLINLINE(VBOXSTRICTRC) apicSendIpi(PVMCPUCC pVCpu, int rcRZ)
955{
956 VMCPU_ASSERT_EMT(pVCpu);
957
958 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
959 XAPICDELIVERYMODE const enmDeliveryMode = (XAPICDELIVERYMODE)pXApicPage->icr_lo.u.u3DeliveryMode;
960 XAPICDESTMODE const enmDestMode = (XAPICDESTMODE)pXApicPage->icr_lo.u.u1DestMode;
961 XAPICINITLEVEL const enmInitLevel = (XAPICINITLEVEL)pXApicPage->icr_lo.u.u1Level;
962 XAPICTRIGGERMODE const enmTriggerMode = (XAPICTRIGGERMODE)pXApicPage->icr_lo.u.u1TriggerMode;
963 XAPICDESTSHORTHAND const enmDestShorthand = (XAPICDESTSHORTHAND)pXApicPage->icr_lo.u.u2DestShorthand;
964 uint8_t const uVector = pXApicPage->icr_lo.u.u8Vector;
965
966 PX2APICPAGE pX2ApicPage = VMCPU_TO_X2APICPAGE(pVCpu);
967 uint32_t const fDest = XAPIC_IN_X2APIC_MODE(pVCpu) ? pX2ApicPage->icr_hi.u32IcrHi : pXApicPage->icr_hi.u.u8Dest;
968
969#if XAPIC_HARDWARE_VERSION == XAPIC_HARDWARE_VERSION_P4
970 /*
971 * INIT Level De-assert is not support on Pentium 4 and Xeon processors.
972 * Apparently, this also applies to NMI, SMI, lowest-priority and fixed delivery modes,
973 * see @bugref{8245#c116}.
974 *
975 * See AMD spec. 16.5 "Interprocessor Interrupts (IPI)" for a table of valid ICR combinations.
976 */
977 if ( enmTriggerMode == XAPICTRIGGERMODE_LEVEL
978 && enmInitLevel == XAPICINITLEVEL_DEASSERT
979 && ( enmDeliveryMode == XAPICDELIVERYMODE_FIXED
980 || enmDeliveryMode == XAPICDELIVERYMODE_LOWEST_PRIO
981 || enmDeliveryMode == XAPICDELIVERYMODE_SMI
982 || enmDeliveryMode == XAPICDELIVERYMODE_NMI
983 || enmDeliveryMode == XAPICDELIVERYMODE_INIT))
984 {
985 Log2(("APIC%u: %s level de-assert unsupported, ignoring!\n", pVCpu->idCpu, apicGetDeliveryModeName(enmDeliveryMode)));
986 return VINF_SUCCESS;
987 }
988#else
989# error "Implement Pentium and P6 family APIC architectures"
990#endif
991
992 /*
993 * The destination and delivery modes are ignored/by-passed when a destination shorthand is specified.
994 * See Intel spec. 10.6.2.3 "Broadcast/Self Delivery Mode".
995 */
996 VMCPUSET DestCpuSet;
997 switch (enmDestShorthand)
998 {
999 case XAPICDESTSHORTHAND_NONE:
1000 {
1001 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
1002 uint32_t const fBroadcastMask = XAPIC_IN_X2APIC_MODE(pVCpu) ? X2APIC_ID_BROADCAST_MASK : XAPIC_ID_BROADCAST_MASK;
1003 apicGetDestCpuSet(pVM, fDest, fBroadcastMask, enmDestMode, enmDeliveryMode, &DestCpuSet);
1004 break;
1005 }
1006
1007 case XAPICDESTSHORTHAND_SELF:
1008 {
1009 VMCPUSET_EMPTY(&DestCpuSet);
1010 VMCPUSET_ADD(&DestCpuSet, pVCpu->idCpu);
1011 break;
1012 }
1013
1014 case XAPIDDESTSHORTHAND_ALL_INCL_SELF:
1015 {
1016 VMCPUSET_FILL(&DestCpuSet);
1017 break;
1018 }
1019
1020 case XAPICDESTSHORTHAND_ALL_EXCL_SELF:
1021 {
1022 VMCPUSET_FILL(&DestCpuSet);
1023 VMCPUSET_DEL(&DestCpuSet, pVCpu->idCpu);
1024 break;
1025 }
1026 }
1027
1028 return apicSendIntr(pVCpu->CTX_SUFF(pVM), pVCpu, uVector, enmTriggerMode, enmDeliveryMode, &DestCpuSet,
1029 NULL /* pfIntrAccepted */, 0 /* uSrcTag */, rcRZ);
1030}
1031
1032
1033/**
1034 * Sets the Interrupt Command Register (ICR) high dword.
1035 *
1036 * @returns Strict VBox status code.
1037 * @param pVCpu The cross context virtual CPU structure.
1038 * @param uIcrHi The ICR high dword.
1039 */
1040static VBOXSTRICTRC apicSetIcrHi(PVMCPUCC pVCpu, uint32_t uIcrHi)
1041{
1042 VMCPU_ASSERT_EMT(pVCpu);
1043 Assert(!XAPIC_IN_X2APIC_MODE(pVCpu));
1044
1045 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
1046 pXApicPage->icr_hi.all.u32IcrHi = uIcrHi & XAPIC_ICR_HI_DEST;
1047 STAM_COUNTER_INC(&pVCpu->apic.s.StatIcrHiWrite);
1048 Log2(("APIC%u: apicSetIcrHi: uIcrHi=%#RX32\n", pVCpu->idCpu, pXApicPage->icr_hi.all.u32IcrHi));
1049
1050 return VINF_SUCCESS;
1051}
1052
1053
1054/**
1055 * Sets the Interrupt Command Register (ICR) low dword.
1056 *
1057 * @returns Strict VBox status code.
1058 * @param pVCpu The cross context virtual CPU structure.
1059 * @param uIcrLo The ICR low dword.
1060 * @param rcRZ The return code if the operation cannot be performed
1061 * in the current context.
1062 * @param fUpdateStat Whether to update the ICR low write statistics
1063 * counter.
1064 */
1065static VBOXSTRICTRC apicSetIcrLo(PVMCPUCC pVCpu, uint32_t uIcrLo, int rcRZ, bool fUpdateStat)
1066{
1067 VMCPU_ASSERT_EMT(pVCpu);
1068
1069 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
1070 pXApicPage->icr_lo.all.u32IcrLo = uIcrLo & XAPIC_ICR_LO_WR_VALID;
1071 Log2(("APIC%u: apicSetIcrLo: uIcrLo=%#RX32\n", pVCpu->idCpu, pXApicPage->icr_lo.all.u32IcrLo));
1072
1073 if (fUpdateStat)
1074 STAM_COUNTER_INC(&pVCpu->apic.s.StatIcrLoWrite);
1075 RT_NOREF(fUpdateStat);
1076
1077 return apicSendIpi(pVCpu, rcRZ);
1078}
1079
1080
1081/**
1082 * Sets the Interrupt Command Register (ICR).
1083 *
1084 * @returns Strict VBox status code.
1085 * @param pVCpu The cross context virtual CPU structure.
1086 * @param u64Icr The ICR (High and Low combined).
1087 * @param rcRZ The return code if the operation cannot be performed
1088 * in the current context.
1089 *
1090 * @remarks This function is used by both x2APIC interface and the Hyper-V
1091 * interface, see APICHvSetIcr. The Hyper-V spec isn't clear what
1092 * happens when invalid bits are set. For the time being, it will
1093 * \#GP like a regular x2APIC access.
1094 */
1095static VBOXSTRICTRC apicSetIcr(PVMCPUCC pVCpu, uint64_t u64Icr, int rcRZ)
1096{
1097 VMCPU_ASSERT_EMT(pVCpu);
1098
1099 /* Validate. */
1100 uint32_t const uLo = RT_LO_U32(u64Icr);
1101 if (RT_LIKELY(!(uLo & ~XAPIC_ICR_LO_WR_VALID)))
1102 {
1103 /* Update high dword first, then update the low dword which sends the IPI. */
1104 PX2APICPAGE pX2ApicPage = VMCPU_TO_X2APICPAGE(pVCpu);
1105 pX2ApicPage->icr_hi.u32IcrHi = RT_HI_U32(u64Icr);
1106 STAM_COUNTER_INC(&pVCpu->apic.s.StatIcrFullWrite);
1107 return apicSetIcrLo(pVCpu, uLo, rcRZ, false /* fUpdateStat */);
1108 }
1109 return apicMsrAccessError(pVCpu, MSR_IA32_X2APIC_ICR, APICMSRACCESS_WRITE_RSVD_BITS);
1110}
1111
1112
1113/**
1114 * Sets the Error Status Register (ESR).
1115 *
1116 * @returns VINF_SUCCESS or VERR_CPUM_RAISE_GP_0.
1117 * @param pVCpu The cross context virtual CPU structure.
1118 * @param uEsr The ESR value.
1119 */
1120static int apicSetEsr(PVMCPUCC pVCpu, uint32_t uEsr)
1121{
1122 VMCPU_ASSERT_EMT(pVCpu);
1123
1124 Log2(("APIC%u: apicSetEsr: uEsr=%#RX32\n", pVCpu->idCpu, uEsr));
1125
1126 if ( XAPIC_IN_X2APIC_MODE(pVCpu)
1127 && (uEsr & ~XAPIC_ESR_WO_VALID))
1128 return apicMsrAccessError(pVCpu, MSR_IA32_X2APIC_ESR, APICMSRACCESS_WRITE_RSVD_BITS);
1129
1130 /*
1131 * Writes to the ESR causes the internal state to be updated in the register,
1132 * clearing the original state. See AMD spec. 16.4.6 "APIC Error Interrupts".
1133 */
1134 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
1135 pXApicPage->esr.all.u32Errors = apicClearAllErrors(pVCpu);
1136 return VINF_SUCCESS;
1137}
1138
1139
1140/**
1141 * Updates the Processor Priority Register (PPR).
1142 *
1143 * @param pVCpu The cross context virtual CPU structure.
1144 */
1145static void apicUpdatePpr(PVMCPUCC pVCpu)
1146{
1147 VMCPU_ASSERT_EMT(pVCpu);
1148
1149 /* See Intel spec 10.8.3.1 "Task and Processor Priorities". */
1150 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
1151 uint8_t const uIsrv = apicGetHighestSetBitInReg(&pXApicPage->isr, 0 /* rcNotFound */);
1152 uint8_t uPpr;
1153 if (XAPIC_TPR_GET_TP(pXApicPage->tpr.u8Tpr) >= XAPIC_PPR_GET_PP(uIsrv))
1154 uPpr = pXApicPage->tpr.u8Tpr;
1155 else
1156 uPpr = XAPIC_PPR_GET_PP(uIsrv);
1157 pXApicPage->ppr.u8Ppr = uPpr;
1158}
1159
1160
1161/**
1162 * Gets the Processor Priority Register (PPR).
1163 *
1164 * @returns The PPR value.
1165 * @param pVCpu The cross context virtual CPU structure.
1166 */
1167static uint8_t apicGetPpr(PVMCPUCC pVCpu)
1168{
1169 VMCPU_ASSERT_EMT(pVCpu);
1170 STAM_COUNTER_INC(&pVCpu->apic.s.StatTprRead);
1171
1172 /*
1173 * With virtualized APIC registers or with TPR virtualization, the hardware may
1174 * update ISR/TPR transparently. We thus re-calculate the PPR which may be out of sync.
1175 * See Intel spec. 29.2.2 "Virtual-Interrupt Delivery".
1176 *
1177 * In all other instances, whenever the TPR or ISR changes, we need to update the PPR
1178 * as well (e.g. like we do manually in apicR3InitIpi and by calling apicUpdatePpr).
1179 */
1180 PCAPIC pApic = VM_TO_APIC(pVCpu->CTX_SUFF(pVM));
1181 if (pApic->fVirtApicRegsEnabled) /** @todo re-think this */
1182 apicUpdatePpr(pVCpu);
1183 PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
1184 return pXApicPage->ppr.u8Ppr;
1185}
1186
1187
1188/**
1189 * Sets the Task Priority Register (TPR).
1190 *
1191 * @returns VINF_SUCCESS or VERR_CPUM_RAISE_GP_0.
1192 * @param pVCpu The cross context virtual CPU structure.
1193 * @param uTpr The TPR value.
1194 * @param fForceX2ApicBehaviour Pretend the APIC is in x2APIC mode during
1195 * this write.
1196 */
1197static int apicSetTprEx(PVMCPUCC pVCpu, uint32_t uTpr, bool fForceX2ApicBehaviour)
1198{
1199 VMCPU_ASSERT_EMT(pVCpu);
1200
1201 Log2(("APIC%u: apicSetTprEx: uTpr=%#RX32\n", pVCpu->idCpu, uTpr));
1202 STAM_COUNTER_INC(&pVCpu->apic.s.StatTprWrite);
1203
1204 bool const fX2ApicMode = XAPIC_IN_X2APIC_MODE(pVCpu) || fForceX2ApicBehaviour;
1205 if ( fX2ApicMode
1206 && (uTpr & ~XAPIC_TPR_VALID))
1207 return apicMsrAccessError(pVCpu, MSR_IA32_X2APIC_TPR, APICMSRACCESS_WRITE_RSVD_BITS);
1208
1209 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
1210 pXApicPage->tpr.u8Tpr = uTpr;
1211 apicUpdatePpr(pVCpu);
1212 apicSignalNextPendingIntr(pVCpu);
1213 return VINF_SUCCESS;
1214}
1215
1216
1217/**
1218 * Sets the End-Of-Interrupt (EOI) register.
1219 *
1220 * @returns Strict VBox status code.
1221 * @param pVCpu The cross context virtual CPU structure.
1222 * @param uEoi The EOI value.
1223 * @param rcBusy The busy return code when the write cannot
1224 * be completed successfully in this context.
1225 * @param fForceX2ApicBehaviour Pretend the APIC is in x2APIC mode during
1226 * this write.
1227 */
1228static VBOXSTRICTRC apicSetEoi(PVMCPUCC pVCpu, uint32_t uEoi, int rcBusy, bool fForceX2ApicBehaviour)
1229{
1230 VMCPU_ASSERT_EMT(pVCpu);
1231
1232 Log2(("APIC%u: apicSetEoi: uEoi=%#RX32\n", pVCpu->idCpu, uEoi));
1233 STAM_COUNTER_INC(&pVCpu->apic.s.StatEoiWrite);
1234
1235 bool const fX2ApicMode = XAPIC_IN_X2APIC_MODE(pVCpu) || fForceX2ApicBehaviour;
1236 if ( fX2ApicMode
1237 && (uEoi & ~XAPIC_EOI_WO_VALID))
1238 return apicMsrAccessError(pVCpu, MSR_IA32_X2APIC_EOI, APICMSRACCESS_WRITE_RSVD_BITS);
1239
1240 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
1241 int isrv = apicGetHighestSetBitInReg(&pXApicPage->isr, -1 /* rcNotFound */);
1242 if (isrv >= 0)
1243 {
1244 /*
1245 * Broadcast the EOI to the I/O APIC(s).
1246 *
1247 * We'll handle the EOI broadcast first as there is tiny chance we get rescheduled to
1248 * ring-3 due to contention on the I/O APIC lock. This way we don't mess with the rest
1249 * of the APIC state and simply restart the EOI write operation from ring-3.
1250 */
1251 Assert(isrv <= (int)UINT8_MAX);
1252 uint8_t const uVector = isrv;
1253 bool const fLevelTriggered = apicTestVectorInReg(&pXApicPage->tmr, uVector);
1254 if (fLevelTriggered)
1255 {
1256 int rc = PDMIoApicBroadcastEoi(pVCpu->CTX_SUFF(pVM), uVector);
1257 if (rc == VINF_SUCCESS)
1258 { /* likely */ }
1259 else
1260 return rcBusy;
1261
1262 /*
1263 * Clear the vector from the TMR.
1264 *
1265 * The broadcast to I/O APIC can re-trigger new interrupts to arrive via the bus. However,
1266 * APICUpdatePendingInterrupts() which updates TMR can only be done from EMT which we
1267 * currently are on, so no possibility of concurrent updates.
1268 */
1269 apicClearVectorInReg(&pXApicPage->tmr, uVector);
1270
1271 /*
1272 * Clear the remote IRR bit for level-triggered, fixed mode LINT0 interrupt.
1273 * The LINT1 pin does not support level-triggered interrupts.
1274 * See Intel spec. 10.5.1 "Local Vector Table".
1275 */
1276 uint32_t const uLvtLint0 = pXApicPage->lvt_lint0.all.u32LvtLint0;
1277 if ( XAPIC_LVT_GET_REMOTE_IRR(uLvtLint0)
1278 && XAPIC_LVT_GET_VECTOR(uLvtLint0) == uVector
1279 && XAPIC_LVT_GET_DELIVERY_MODE(uLvtLint0) == XAPICDELIVERYMODE_FIXED)
1280 {
1281 ASMAtomicAndU32((volatile uint32_t *)&pXApicPage->lvt_lint0.all.u32LvtLint0, ~XAPIC_LVT_REMOTE_IRR);
1282 Log2(("APIC%u: apicSetEoi: Cleared remote-IRR for LINT0. uVector=%#x\n", pVCpu->idCpu, uVector));
1283 }
1284
1285 Log2(("APIC%u: apicSetEoi: Cleared level triggered interrupt from TMR. uVector=%#x\n", pVCpu->idCpu, uVector));
1286 }
1287
1288 /*
1289 * Mark interrupt as serviced, update the PPR and signal pending interrupts.
1290 */
1291 Log2(("APIC%u: apicSetEoi: Clearing interrupt from ISR. uVector=%#x\n", pVCpu->idCpu, uVector));
1292 apicClearVectorInReg(&pXApicPage->isr, uVector);
1293 apicUpdatePpr(pVCpu);
1294 apicSignalNextPendingIntr(pVCpu);
1295 }
1296 else
1297 {
1298#ifdef DEBUG_ramshankar
1299 /** @todo Figure out if this is done intentionally by guests or is a bug
1300 * in our emulation. Happened with Win10 SMP VM during reboot after
1301 * installation of guest additions with 3D support. */
1302 AssertMsgFailed(("APIC%u: apicSetEoi: Failed to find any ISR bit\n", pVCpu->idCpu));
1303#endif
1304 }
1305
1306 return VINF_SUCCESS;
1307}
1308
1309
1310/**
1311 * Sets the Logical Destination Register (LDR).
1312 *
1313 * @returns Strict VBox status code.
1314 * @param pVCpu The cross context virtual CPU structure.
1315 * @param uLdr The LDR value.
1316 *
1317 * @remarks LDR is read-only in x2APIC mode.
1318 */
1319static VBOXSTRICTRC apicSetLdr(PVMCPUCC pVCpu, uint32_t uLdr)
1320{
1321 VMCPU_ASSERT_EMT(pVCpu);
1322 PCAPIC pApic = VM_TO_APIC(pVCpu->CTX_SUFF(pVM));
1323 Assert(!XAPIC_IN_X2APIC_MODE(pVCpu) || pApic->fHyperVCompatMode); RT_NOREF_PV(pApic);
1324
1325 Log2(("APIC%u: apicSetLdr: uLdr=%#RX32\n", pVCpu->idCpu, uLdr));
1326
1327 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
1328 apicWriteRaw32(pXApicPage, XAPIC_OFF_LDR, uLdr & XAPIC_LDR_VALID);
1329 return VINF_SUCCESS;
1330}
1331
1332
1333/**
1334 * Sets the Destination Format Register (DFR).
1335 *
1336 * @returns Strict VBox status code.
1337 * @param pVCpu The cross context virtual CPU structure.
1338 * @param uDfr The DFR value.
1339 *
1340 * @remarks DFR is not available in x2APIC mode.
1341 */
1342static VBOXSTRICTRC apicSetDfr(PVMCPUCC pVCpu, uint32_t uDfr)
1343{
1344 VMCPU_ASSERT_EMT(pVCpu);
1345 Assert(!XAPIC_IN_X2APIC_MODE(pVCpu));
1346
1347 uDfr &= XAPIC_DFR_VALID;
1348 uDfr |= XAPIC_DFR_RSVD_MB1;
1349
1350 Log2(("APIC%u: apicSetDfr: uDfr=%#RX32\n", pVCpu->idCpu, uDfr));
1351
1352 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
1353 apicWriteRaw32(pXApicPage, XAPIC_OFF_DFR, uDfr);
1354 return VINF_SUCCESS;
1355}
1356
1357
1358/**
1359 * Sets the Timer Divide Configuration Register (DCR).
1360 *
1361 * @returns Strict VBox status code.
1362 * @param pVCpu The cross context virtual CPU structure.
1363 * @param uTimerDcr The timer DCR value.
1364 */
1365static VBOXSTRICTRC apicSetTimerDcr(PVMCPUCC pVCpu, uint32_t uTimerDcr)
1366{
1367 VMCPU_ASSERT_EMT(pVCpu);
1368 if ( XAPIC_IN_X2APIC_MODE(pVCpu)
1369 && (uTimerDcr & ~XAPIC_TIMER_DCR_VALID))
1370 return apicMsrAccessError(pVCpu, MSR_IA32_X2APIC_TIMER_DCR, APICMSRACCESS_WRITE_RSVD_BITS);
1371
1372 Log2(("APIC%u: apicSetTimerDcr: uTimerDcr=%#RX32\n", pVCpu->idCpu, uTimerDcr));
1373
1374 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
1375 apicWriteRaw32(pXApicPage, XAPIC_OFF_TIMER_DCR, uTimerDcr);
1376 return VINF_SUCCESS;
1377}
1378
1379
1380/**
1381 * Gets the timer's Current Count Register (CCR).
1382 *
1383 * @returns VBox status code.
1384 * @param pVCpu The cross context virtual CPU structure.
1385 * @param rcBusy The busy return code for the timer critical section.
1386 * @param puValue Where to store the LVT timer CCR.
1387 */
1388static VBOXSTRICTRC apicGetTimerCcr(PVMCPUCC pVCpu, int rcBusy, uint32_t *puValue)
1389{
1390 VMCPU_ASSERT_EMT(pVCpu);
1391 Assert(puValue);
1392
1393 PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
1394 *puValue = 0;
1395
1396 /* In TSC-deadline mode, CCR returns 0, see Intel spec. 10.5.4.1 "TSC-Deadline Mode". */
1397 if (pXApicPage->lvt_timer.u.u2TimerMode == XAPIC_TIMER_MODE_TSC_DEADLINE)
1398 return VINF_SUCCESS;
1399
1400 /* If the initial-count register is 0, CCR returns 0 as it cannot exceed the ICR. */
1401 uint32_t const uInitialCount = pXApicPage->timer_icr.u32InitialCount;
1402 if (!uInitialCount)
1403 return VINF_SUCCESS;
1404
1405 /*
1406 * Reading the virtual-sync clock requires locking its timer because it's not
1407 * a simple atomic operation, see tmVirtualSyncGetEx().
1408 *
1409 * We also need to lock before reading the timer CCR, see apicR3TimerCallback().
1410 */
1411 PCAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
1412 PTMTIMER pTimer = pApicCpu->CTX_SUFF(pTimer);
1413
1414 int rc = TMTimerLock(pTimer, rcBusy);
1415 if (rc == VINF_SUCCESS)
1416 {
1417 /* If the current-count register is 0, it implies the timer expired. */
1418 uint32_t const uCurrentCount = pXApicPage->timer_ccr.u32CurrentCount;
1419 if (uCurrentCount)
1420 {
1421 uint64_t const cTicksElapsed = TMTimerGet(pApicCpu->CTX_SUFF(pTimer)) - pApicCpu->u64TimerInitial;
1422 TMTimerUnlock(pTimer);
1423 uint8_t const uTimerShift = apicGetTimerShift(pXApicPage);
1424 uint64_t const uDelta = cTicksElapsed >> uTimerShift;
1425 if (uInitialCount > uDelta)
1426 *puValue = uInitialCount - uDelta;
1427 }
1428 else
1429 TMTimerUnlock(pTimer);
1430 }
1431 return rc;
1432}
1433
1434
1435/**
1436 * Sets the timer's Initial-Count Register (ICR).
1437 *
1438 * @returns Strict VBox status code.
1439 * @param pVCpu The cross context virtual CPU structure.
1440 * @param rcBusy The busy return code for the timer critical section.
1441 * @param uInitialCount The timer ICR.
1442 */
1443static VBOXSTRICTRC apicSetTimerIcr(PVMCPUCC pVCpu, int rcBusy, uint32_t uInitialCount)
1444{
1445 VMCPU_ASSERT_EMT(pVCpu);
1446
1447 PAPIC pApic = VM_TO_APIC(pVCpu->CTX_SUFF(pVM));
1448 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
1449 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
1450 PTMTIMER pTimer = pApicCpu->CTX_SUFF(pTimer);
1451
1452 Log2(("APIC%u: apicSetTimerIcr: uInitialCount=%#RX32\n", pVCpu->idCpu, uInitialCount));
1453 STAM_COUNTER_INC(&pApicCpu->StatTimerIcrWrite);
1454
1455 /* In TSC-deadline mode, timer ICR writes are ignored, see Intel spec. 10.5.4.1 "TSC-Deadline Mode". */
1456 if ( pApic->fSupportsTscDeadline
1457 && pXApicPage->lvt_timer.u.u2TimerMode == XAPIC_TIMER_MODE_TSC_DEADLINE)
1458 return VINF_SUCCESS;
1459
1460 /*
1461 * The timer CCR may be modified by apicR3TimerCallback() in parallel,
1462 * so obtain the lock -before- updating it here to be consistent with the
1463 * timer ICR. We rely on CCR being consistent in apicGetTimerCcr().
1464 */
1465 int rc = TMTimerLock(pTimer, rcBusy);
1466 if (rc == VINF_SUCCESS)
1467 {
1468 pXApicPage->timer_icr.u32InitialCount = uInitialCount;
1469 pXApicPage->timer_ccr.u32CurrentCount = uInitialCount;
1470 if (uInitialCount)
1471 apicStartTimer(pVCpu, uInitialCount);
1472 else
1473 apicStopTimer(pVCpu);
1474 TMTimerUnlock(pTimer);
1475 }
1476 return rc;
1477}
1478
1479
1480/**
1481 * Sets an LVT entry.
1482 *
1483 * @returns Strict VBox status code.
1484 * @param pVCpu The cross context virtual CPU structure.
1485 * @param offLvt The LVT entry offset in the xAPIC page.
1486 * @param uLvt The LVT value to set.
1487 */
1488static VBOXSTRICTRC apicSetLvtEntry(PVMCPUCC pVCpu, uint16_t offLvt, uint32_t uLvt)
1489{
1490 VMCPU_ASSERT_EMT(pVCpu);
1491
1492#if XAPIC_HARDWARE_VERSION == XAPIC_HARDWARE_VERSION_P4
1493 AssertMsg( offLvt == XAPIC_OFF_LVT_TIMER
1494 || offLvt == XAPIC_OFF_LVT_THERMAL
1495 || offLvt == XAPIC_OFF_LVT_PERF
1496 || offLvt == XAPIC_OFF_LVT_LINT0
1497 || offLvt == XAPIC_OFF_LVT_LINT1
1498 || offLvt == XAPIC_OFF_LVT_ERROR,
1499 ("APIC%u: apicSetLvtEntry: invalid offset, offLvt=%#RX16, uLvt=%#RX32\n", pVCpu->idCpu, offLvt, uLvt));
1500
1501 /*
1502 * If TSC-deadline mode isn't support, ignore the bit in xAPIC mode
1503 * and raise #GP(0) in x2APIC mode.
1504 */
1505 PCAPIC pApic = VM_TO_APIC(pVCpu->CTX_SUFF(pVM));
1506 if (offLvt == XAPIC_OFF_LVT_TIMER)
1507 {
1508 if ( !pApic->fSupportsTscDeadline
1509 && (uLvt & XAPIC_LVT_TIMER_TSCDEADLINE))
1510 {
1511 if (XAPIC_IN_X2APIC_MODE(pVCpu))
1512 return apicMsrAccessError(pVCpu, XAPIC_GET_X2APIC_MSR(offLvt), APICMSRACCESS_WRITE_RSVD_BITS);
1513 uLvt &= ~XAPIC_LVT_TIMER_TSCDEADLINE;
1514 /** @todo TSC-deadline timer mode transition */
1515 }
1516 }
1517
1518 /*
1519 * Validate rest of the LVT bits.
1520 */
1521 uint16_t const idxLvt = (offLvt - XAPIC_OFF_LVT_START) >> 4;
1522 AssertReturn(idxLvt < RT_ELEMENTS(g_au32LvtValidMasks), VERR_OUT_OF_RANGE);
1523
1524 /*
1525 * For x2APIC, disallow setting of invalid/reserved bits.
1526 * For xAPIC, mask out invalid/reserved bits (i.e. ignore them).
1527 */
1528 if ( XAPIC_IN_X2APIC_MODE(pVCpu)
1529 && (uLvt & ~g_au32LvtValidMasks[idxLvt]))
1530 return apicMsrAccessError(pVCpu, XAPIC_GET_X2APIC_MSR(offLvt), APICMSRACCESS_WRITE_RSVD_BITS);
1531
1532 uLvt &= g_au32LvtValidMasks[idxLvt];
1533
1534 /*
1535 * In the software-disabled state, LVT mask-bit must remain set and attempts to clear the mask
1536 * bit must be ignored. See Intel spec. 10.4.7.2 "Local APIC State After It Has Been Software Disabled".
1537 */
1538 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
1539 if (!pXApicPage->svr.u.fApicSoftwareEnable)
1540 uLvt |= XAPIC_LVT_MASK;
1541
1542 /*
1543 * It is unclear whether we should signal a 'send illegal vector' error here and ignore updating
1544 * the LVT entry when the delivery mode is 'fixed'[1] or update it in addition to signalling the
1545 * error or not signal the error at all. For now, we'll allow setting illegal vectors into the LVT
1546 * but set the 'send illegal vector' error here. The 'receive illegal vector' error will be set if
1547 * the interrupt for the vector happens to be generated, see apicPostInterrupt().
1548 *
1549 * [1] See Intel spec. 10.5.2 "Valid Interrupt Vectors".
1550 */
1551 if (RT_UNLIKELY( XAPIC_LVT_GET_VECTOR(uLvt) <= XAPIC_ILLEGAL_VECTOR_END
1552 && XAPIC_LVT_GET_DELIVERY_MODE(uLvt) == XAPICDELIVERYMODE_FIXED))
1553 apicSetError(pVCpu, XAPIC_ESR_SEND_ILLEGAL_VECTOR);
1554
1555 Log2(("APIC%u: apicSetLvtEntry: offLvt=%#RX16 uLvt=%#RX32\n", pVCpu->idCpu, offLvt, uLvt));
1556
1557 apicWriteRaw32(pXApicPage, offLvt, uLvt);
1558 return VINF_SUCCESS;
1559#else
1560# error "Implement Pentium and P6 family APIC architectures"
1561#endif /* XAPIC_HARDWARE_VERSION == XAPIC_HARDWARE_VERSION_P4 */
1562}
1563
1564
1565#if 0
1566/**
1567 * Sets an LVT entry in the extended LVT range.
1568 *
1569 * @returns VBox status code.
1570 * @param pVCpu The cross context virtual CPU structure.
1571 * @param offLvt The LVT entry offset in the xAPIC page.
1572 * @param uValue The LVT value to set.
1573 */
1574static int apicSetLvtExtEntry(PVMCPUCC pVCpu, uint16_t offLvt, uint32_t uLvt)
1575{
1576 VMCPU_ASSERT_EMT(pVCpu);
1577 AssertMsg(offLvt == XAPIC_OFF_CMCI, ("APIC%u: apicSetLvt1Entry: invalid offset %#RX16\n", pVCpu->idCpu, offLvt));
1578
1579 /** @todo support CMCI. */
1580 return VERR_NOT_IMPLEMENTED;
1581}
1582#endif
1583
1584
1585/**
1586 * Hints TM about the APIC timer frequency.
1587 *
1588 * @param pApicCpu The APIC CPU state.
1589 * @param uInitialCount The new initial count.
1590 * @param uTimerShift The new timer shift.
1591 * @thread Any.
1592 */
1593void apicHintTimerFreq(PAPICCPU pApicCpu, uint32_t uInitialCount, uint8_t uTimerShift)
1594{
1595 Assert(pApicCpu);
1596
1597 if ( pApicCpu->uHintedTimerInitialCount != uInitialCount
1598 || pApicCpu->uHintedTimerShift != uTimerShift)
1599 {
1600 uint32_t uHz;
1601 if (uInitialCount)
1602 {
1603 uint64_t cTicksPerPeriod = (uint64_t)uInitialCount << uTimerShift;
1604 uHz = TMTimerGetFreq(pApicCpu->CTX_SUFF(pTimer)) / cTicksPerPeriod;
1605 }
1606 else
1607 uHz = 0;
1608
1609 TMTimerSetFrequencyHint(pApicCpu->CTX_SUFF(pTimer), uHz);
1610 pApicCpu->uHintedTimerInitialCount = uInitialCount;
1611 pApicCpu->uHintedTimerShift = uTimerShift;
1612 }
1613}
1614
1615
1616/**
1617 * Gets the Interrupt Command Register (ICR), without performing any interface
1618 * checks.
1619 *
1620 * @returns The ICR value.
1621 * @param pVCpu The cross context virtual CPU structure.
1622 */
1623DECLINLINE(uint64_t) apicGetIcrNoCheck(PVMCPUCC pVCpu)
1624{
1625 PCX2APICPAGE pX2ApicPage = VMCPU_TO_CX2APICPAGE(pVCpu);
1626 uint64_t const uHi = pX2ApicPage->icr_hi.u32IcrHi;
1627 uint64_t const uLo = pX2ApicPage->icr_lo.all.u32IcrLo;
1628 uint64_t const uIcr = RT_MAKE_U64(uLo, uHi);
1629 return uIcr;
1630}
1631
1632
1633/**
1634 * Reads an APIC register.
1635 *
1636 * @returns VBox status code.
1637 * @param pApicDev The APIC device instance.
1638 * @param pVCpu The cross context virtual CPU structure.
1639 * @param offReg The offset of the register being read.
1640 * @param puValue Where to store the register value.
1641 */
1642DECLINLINE(VBOXSTRICTRC) apicReadRegister(PAPICDEV pApicDev, PVMCPUCC pVCpu, uint16_t offReg, uint32_t *puValue)
1643{
1644 VMCPU_ASSERT_EMT(pVCpu);
1645 Assert(offReg <= XAPIC_OFF_MAX_VALID);
1646
1647 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
1648 uint32_t uValue = 0;
1649 VBOXSTRICTRC rc = VINF_SUCCESS;
1650 switch (offReg)
1651 {
1652 case XAPIC_OFF_ID:
1653 case XAPIC_OFF_VERSION:
1654 case XAPIC_OFF_TPR:
1655 case XAPIC_OFF_EOI:
1656 case XAPIC_OFF_RRD:
1657 case XAPIC_OFF_LDR:
1658 case XAPIC_OFF_DFR:
1659 case XAPIC_OFF_SVR:
1660 case XAPIC_OFF_ISR0: case XAPIC_OFF_ISR1: case XAPIC_OFF_ISR2: case XAPIC_OFF_ISR3:
1661 case XAPIC_OFF_ISR4: case XAPIC_OFF_ISR5: case XAPIC_OFF_ISR6: case XAPIC_OFF_ISR7:
1662 case XAPIC_OFF_TMR0: case XAPIC_OFF_TMR1: case XAPIC_OFF_TMR2: case XAPIC_OFF_TMR3:
1663 case XAPIC_OFF_TMR4: case XAPIC_OFF_TMR5: case XAPIC_OFF_TMR6: case XAPIC_OFF_TMR7:
1664 case XAPIC_OFF_IRR0: case XAPIC_OFF_IRR1: case XAPIC_OFF_IRR2: case XAPIC_OFF_IRR3:
1665 case XAPIC_OFF_IRR4: case XAPIC_OFF_IRR5: case XAPIC_OFF_IRR6: case XAPIC_OFF_IRR7:
1666 case XAPIC_OFF_ESR:
1667 case XAPIC_OFF_ICR_LO:
1668 case XAPIC_OFF_ICR_HI:
1669 case XAPIC_OFF_LVT_TIMER:
1670#if XAPIC_HARDWARE_VERSION == XAPIC_HARDWARE_VERSION_P4
1671 case XAPIC_OFF_LVT_THERMAL:
1672#endif
1673 case XAPIC_OFF_LVT_PERF:
1674 case XAPIC_OFF_LVT_LINT0:
1675 case XAPIC_OFF_LVT_LINT1:
1676 case XAPIC_OFF_LVT_ERROR:
1677 case XAPIC_OFF_TIMER_ICR:
1678 case XAPIC_OFF_TIMER_DCR:
1679 {
1680 Assert( !XAPIC_IN_X2APIC_MODE(pVCpu)
1681 || ( offReg != XAPIC_OFF_DFR
1682 && offReg != XAPIC_OFF_ICR_HI
1683 && offReg != XAPIC_OFF_EOI));
1684 uValue = apicReadRaw32(pXApicPage, offReg);
1685 Log2(("APIC%u: apicReadRegister: offReg=%#x uValue=%#x\n", pVCpu->idCpu, offReg, uValue));
1686 break;
1687 }
1688
1689 case XAPIC_OFF_PPR:
1690 {
1691 uValue = apicGetPpr(pVCpu);
1692 break;
1693 }
1694
1695 case XAPIC_OFF_TIMER_CCR:
1696 {
1697 Assert(!XAPIC_IN_X2APIC_MODE(pVCpu));
1698 rc = apicGetTimerCcr(pVCpu, VINF_IOM_R3_MMIO_READ, &uValue);
1699 break;
1700 }
1701
1702 case XAPIC_OFF_APR:
1703 {
1704#if XAPIC_HARDWARE_VERSION == XAPIC_HARDWARE_VERSION_P4
1705 /* Unsupported on Pentium 4 and Xeon CPUs, invalid in x2APIC mode. */
1706 Assert(!XAPIC_IN_X2APIC_MODE(pVCpu));
1707#else
1708# error "Implement Pentium and P6 family APIC architectures"
1709#endif
1710 break;
1711 }
1712
1713 default:
1714 {
1715 Assert(!XAPIC_IN_X2APIC_MODE(pVCpu));
1716 rc = PDMDevHlpDBGFStop(pApicDev->CTX_SUFF(pDevIns), RT_SRC_POS, "VCPU[%u]: offReg=%#RX16\n", pVCpu->idCpu,
1717 offReg);
1718 apicSetError(pVCpu, XAPIC_ESR_ILLEGAL_REG_ADDRESS);
1719 break;
1720 }
1721 }
1722
1723 *puValue = uValue;
1724 return rc;
1725}
1726
1727
1728/**
1729 * Writes an APIC register.
1730 *
1731 * @returns Strict VBox status code.
1732 * @param pApicDev The APIC device instance.
1733 * @param pVCpu The cross context virtual CPU structure.
1734 * @param offReg The offset of the register being written.
1735 * @param uValue The register value.
1736 */
1737DECLINLINE(VBOXSTRICTRC) apicWriteRegister(PAPICDEV pApicDev, PVMCPUCC pVCpu, uint16_t offReg, uint32_t uValue)
1738{
1739 VMCPU_ASSERT_EMT(pVCpu);
1740 Assert(offReg <= XAPIC_OFF_MAX_VALID);
1741 Assert(!XAPIC_IN_X2APIC_MODE(pVCpu));
1742
1743 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
1744 switch (offReg)
1745 {
1746 case XAPIC_OFF_TPR:
1747 {
1748 rcStrict = apicSetTprEx(pVCpu, uValue, false /* fForceX2ApicBehaviour */);
1749 break;
1750 }
1751
1752 case XAPIC_OFF_LVT_TIMER:
1753#if XAPIC_HARDWARE_VERSION == XAPIC_HARDWARE_VERSION_P4
1754 case XAPIC_OFF_LVT_THERMAL:
1755#endif
1756 case XAPIC_OFF_LVT_PERF:
1757 case XAPIC_OFF_LVT_LINT0:
1758 case XAPIC_OFF_LVT_LINT1:
1759 case XAPIC_OFF_LVT_ERROR:
1760 {
1761 rcStrict = apicSetLvtEntry(pVCpu, offReg, uValue);
1762 break;
1763 }
1764
1765 case XAPIC_OFF_TIMER_ICR:
1766 {
1767 rcStrict = apicSetTimerIcr(pVCpu, VINF_IOM_R3_MMIO_WRITE, uValue);
1768 break;
1769 }
1770
1771 case XAPIC_OFF_EOI:
1772 {
1773 rcStrict = apicSetEoi(pVCpu, uValue, VINF_IOM_R3_MMIO_WRITE, false /* fForceX2ApicBehaviour */);
1774 break;
1775 }
1776
1777 case XAPIC_OFF_LDR:
1778 {
1779 rcStrict = apicSetLdr(pVCpu, uValue);
1780 break;
1781 }
1782
1783 case XAPIC_OFF_DFR:
1784 {
1785 rcStrict = apicSetDfr(pVCpu, uValue);
1786 break;
1787 }
1788
1789 case XAPIC_OFF_SVR:
1790 {
1791 rcStrict = apicSetSvr(pVCpu, uValue);
1792 break;
1793 }
1794
1795 case XAPIC_OFF_ICR_LO:
1796 {
1797 rcStrict = apicSetIcrLo(pVCpu, uValue, VINF_IOM_R3_MMIO_WRITE, true /* fUpdateStat */);
1798 break;
1799 }
1800
1801 case XAPIC_OFF_ICR_HI:
1802 {
1803 rcStrict = apicSetIcrHi(pVCpu, uValue);
1804 break;
1805 }
1806
1807 case XAPIC_OFF_TIMER_DCR:
1808 {
1809 rcStrict = apicSetTimerDcr(pVCpu, uValue);
1810 break;
1811 }
1812
1813 case XAPIC_OFF_ESR:
1814 {
1815 rcStrict = apicSetEsr(pVCpu, uValue);
1816 break;
1817 }
1818
1819 case XAPIC_OFF_APR:
1820 case XAPIC_OFF_RRD:
1821 {
1822#if XAPIC_HARDWARE_VERSION == XAPIC_HARDWARE_VERSION_P4
1823 /* Unsupported on Pentium 4 and Xeon CPUs but writes do -not- set an illegal register access error. */
1824#else
1825# error "Implement Pentium and P6 family APIC architectures"
1826#endif
1827 break;
1828 }
1829
1830 /* Read-only, write ignored: */
1831 case XAPIC_OFF_VERSION:
1832 case XAPIC_OFF_ID:
1833 break;
1834
1835 /* Unavailable/reserved in xAPIC mode: */
1836 case X2APIC_OFF_SELF_IPI:
1837 /* Read-only registers: */
1838 case XAPIC_OFF_PPR:
1839 case XAPIC_OFF_ISR0: case XAPIC_OFF_ISR1: case XAPIC_OFF_ISR2: case XAPIC_OFF_ISR3:
1840 case XAPIC_OFF_ISR4: case XAPIC_OFF_ISR5: case XAPIC_OFF_ISR6: case XAPIC_OFF_ISR7:
1841 case XAPIC_OFF_TMR0: case XAPIC_OFF_TMR1: case XAPIC_OFF_TMR2: case XAPIC_OFF_TMR3:
1842 case XAPIC_OFF_TMR4: case XAPIC_OFF_TMR5: case XAPIC_OFF_TMR6: case XAPIC_OFF_TMR7:
1843 case XAPIC_OFF_IRR0: case XAPIC_OFF_IRR1: case XAPIC_OFF_IRR2: case XAPIC_OFF_IRR3:
1844 case XAPIC_OFF_IRR4: case XAPIC_OFF_IRR5: case XAPIC_OFF_IRR6: case XAPIC_OFF_IRR7:
1845 case XAPIC_OFF_TIMER_CCR:
1846 default:
1847 {
1848 rcStrict = PDMDevHlpDBGFStop(pApicDev->CTX_SUFF(pDevIns), RT_SRC_POS, "APIC%u: offReg=%#RX16\n", pVCpu->idCpu,
1849 offReg);
1850 apicSetError(pVCpu, XAPIC_ESR_ILLEGAL_REG_ADDRESS);
1851 break;
1852 }
1853 }
1854
1855 return rcStrict;
1856}
1857
1858
1859/**
1860 * Reads an APIC MSR.
1861 *
1862 * @returns Strict VBox status code.
1863 * @param pVCpu The cross context virtual CPU structure.
1864 * @param u32Reg The MSR being read.
1865 * @param pu64Value Where to store the read value.
1866 */
1867VMM_INT_DECL(VBOXSTRICTRC) APICReadMsr(PVMCPUCC pVCpu, uint32_t u32Reg, uint64_t *pu64Value)
1868{
1869 /*
1870 * Validate.
1871 */
1872 VMCPU_ASSERT_EMT(pVCpu);
1873 Assert(u32Reg >= MSR_IA32_X2APIC_ID && u32Reg <= MSR_IA32_X2APIC_SELF_IPI);
1874 Assert(pu64Value);
1875
1876 /*
1877 * Is the APIC enabled?
1878 */
1879 PCAPIC pApic = VM_TO_APIC(pVCpu->CTX_SUFF(pVM));
1880 if (APICIsEnabled(pVCpu))
1881 { /* likely */ }
1882 else
1883 {
1884 return apicMsrAccessError(pVCpu, u32Reg, pApic->enmMaxMode == PDMAPICMODE_NONE ?
1885 APICMSRACCESS_READ_DISALLOWED_CONFIG : APICMSRACCESS_READ_RSVD_OR_UNKNOWN);
1886 }
1887
1888#ifndef IN_RING3
1889 if (pApic->fRZEnabled)
1890 { /* likely */}
1891 else
1892 return VINF_CPUM_R3_MSR_READ;
1893#endif
1894
1895 STAM_COUNTER_INC(&pVCpu->apic.s.CTX_SUFF_Z(StatMsrRead));
1896
1897 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
1898 if (RT_LIKELY( XAPIC_IN_X2APIC_MODE(pVCpu)
1899 || pApic->fHyperVCompatMode))
1900 {
1901 switch (u32Reg)
1902 {
1903 /* Special handling for x2APIC: */
1904 case MSR_IA32_X2APIC_ICR:
1905 {
1906 *pu64Value = apicGetIcrNoCheck(pVCpu);
1907 break;
1908 }
1909
1910 /* Special handling, compatible with xAPIC: */
1911 case MSR_IA32_X2APIC_TIMER_CCR:
1912 {
1913 uint32_t uValue;
1914 rcStrict = apicGetTimerCcr(pVCpu, VINF_CPUM_R3_MSR_READ, &uValue);
1915 *pu64Value = uValue;
1916 break;
1917 }
1918
1919 /* Special handling, compatible with xAPIC: */
1920 case MSR_IA32_X2APIC_PPR:
1921 {
1922 *pu64Value = apicGetPpr(pVCpu);
1923 break;
1924 }
1925
1926 /* Raw read, compatible with xAPIC: */
1927 case MSR_IA32_X2APIC_ID:
1928 case MSR_IA32_X2APIC_VERSION:
1929 case MSR_IA32_X2APIC_TPR:
1930 case MSR_IA32_X2APIC_LDR:
1931 case MSR_IA32_X2APIC_SVR:
1932 case MSR_IA32_X2APIC_ISR0: case MSR_IA32_X2APIC_ISR1: case MSR_IA32_X2APIC_ISR2: case MSR_IA32_X2APIC_ISR3:
1933 case MSR_IA32_X2APIC_ISR4: case MSR_IA32_X2APIC_ISR5: case MSR_IA32_X2APIC_ISR6: case MSR_IA32_X2APIC_ISR7:
1934 case MSR_IA32_X2APIC_TMR0: case MSR_IA32_X2APIC_TMR1: case MSR_IA32_X2APIC_TMR2: case MSR_IA32_X2APIC_TMR3:
1935 case MSR_IA32_X2APIC_TMR4: case MSR_IA32_X2APIC_TMR5: case MSR_IA32_X2APIC_TMR6: case MSR_IA32_X2APIC_TMR7:
1936 case MSR_IA32_X2APIC_IRR0: case MSR_IA32_X2APIC_IRR1: case MSR_IA32_X2APIC_IRR2: case MSR_IA32_X2APIC_IRR3:
1937 case MSR_IA32_X2APIC_IRR4: case MSR_IA32_X2APIC_IRR5: case MSR_IA32_X2APIC_IRR6: case MSR_IA32_X2APIC_IRR7:
1938 case MSR_IA32_X2APIC_ESR:
1939 case MSR_IA32_X2APIC_LVT_TIMER:
1940 case MSR_IA32_X2APIC_LVT_THERMAL:
1941 case MSR_IA32_X2APIC_LVT_PERF:
1942 case MSR_IA32_X2APIC_LVT_LINT0:
1943 case MSR_IA32_X2APIC_LVT_LINT1:
1944 case MSR_IA32_X2APIC_LVT_ERROR:
1945 case MSR_IA32_X2APIC_TIMER_ICR:
1946 case MSR_IA32_X2APIC_TIMER_DCR:
1947 {
1948 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
1949 uint16_t const offReg = X2APIC_GET_XAPIC_OFF(u32Reg);
1950 *pu64Value = apicReadRaw32(pXApicPage, offReg);
1951 break;
1952 }
1953
1954 /* Write-only MSRs: */
1955 case MSR_IA32_X2APIC_SELF_IPI:
1956 case MSR_IA32_X2APIC_EOI:
1957 {
1958 rcStrict = apicMsrAccessError(pVCpu, u32Reg, APICMSRACCESS_READ_WRITE_ONLY);
1959 break;
1960 }
1961
1962 /*
1963 * Windows guest using Hyper-V x2APIC MSR compatibility mode tries to read the "high"
1964 * LDR bits, which is quite absurd (as it's a 32-bit register) using this invalid MSR
1965 * index (0x80E), see @bugref{8382#c175}.
1966 */
1967 case MSR_IA32_X2APIC_LDR + 1:
1968 {
1969 if (pApic->fHyperVCompatMode)
1970 *pu64Value = 0;
1971 else
1972 rcStrict = apicMsrAccessError(pVCpu, u32Reg, APICMSRACCESS_READ_RSVD_OR_UNKNOWN);
1973 break;
1974 }
1975
1976 /* Reserved MSRs: */
1977 case MSR_IA32_X2APIC_LVT_CMCI:
1978 default:
1979 {
1980 rcStrict = apicMsrAccessError(pVCpu, u32Reg, APICMSRACCESS_READ_RSVD_OR_UNKNOWN);
1981 break;
1982 }
1983 }
1984 }
1985 else
1986 rcStrict = apicMsrAccessError(pVCpu, u32Reg, APICMSRACCESS_INVALID_READ_MODE);
1987
1988 return rcStrict;
1989}
1990
1991
1992/**
1993 * Writes an APIC MSR.
1994 *
1995 * @returns Strict VBox status code.
1996 * @param pVCpu The cross context virtual CPU structure.
1997 * @param u32Reg The MSR being written.
1998 * @param u64Value The value to write.
1999 */
2000VMM_INT_DECL(VBOXSTRICTRC) APICWriteMsr(PVMCPUCC pVCpu, uint32_t u32Reg, uint64_t u64Value)
2001{
2002 /*
2003 * Validate.
2004 */
2005 VMCPU_ASSERT_EMT(pVCpu);
2006 Assert(u32Reg >= MSR_IA32_X2APIC_ID && u32Reg <= MSR_IA32_X2APIC_SELF_IPI);
2007
2008 /*
2009 * Is the APIC enabled?
2010 */
2011 PCAPIC pApic = VM_TO_APIC(pVCpu->CTX_SUFF(pVM));
2012 if (APICIsEnabled(pVCpu))
2013 { /* likely */ }
2014 else
2015 {
2016 return apicMsrAccessError(pVCpu, u32Reg, pApic->enmMaxMode == PDMAPICMODE_NONE ?
2017 APICMSRACCESS_WRITE_DISALLOWED_CONFIG : APICMSRACCESS_WRITE_RSVD_OR_UNKNOWN);
2018 }
2019
2020#ifndef IN_RING3
2021 if (pApic->fRZEnabled)
2022 { /* likely */ }
2023 else
2024 return VINF_CPUM_R3_MSR_WRITE;
2025#endif
2026
2027 STAM_COUNTER_INC(&pVCpu->apic.s.CTX_SUFF_Z(StatMsrWrite));
2028
2029 /*
2030 * In x2APIC mode, we need to raise #GP(0) for writes to reserved bits, unlike MMIO
2031 * accesses where they are ignored. Hence, we need to validate each register before
2032 * invoking the generic/xAPIC write functions.
2033 *
2034 * Bits 63:32 of all registers except the ICR are reserved, we'll handle this common
2035 * case first and handle validating the remaining bits on a per-register basis.
2036 * See Intel spec. 10.12.1.2 "x2APIC Register Address Space".
2037 */
2038 if ( u32Reg != MSR_IA32_X2APIC_ICR
2039 && RT_HI_U32(u64Value))
2040 return apicMsrAccessError(pVCpu, u32Reg, APICMSRACCESS_WRITE_RSVD_BITS);
2041
2042 uint32_t u32Value = RT_LO_U32(u64Value);
2043 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
2044 if (RT_LIKELY( XAPIC_IN_X2APIC_MODE(pVCpu)
2045 || pApic->fHyperVCompatMode))
2046 {
2047 switch (u32Reg)
2048 {
2049 case MSR_IA32_X2APIC_TPR:
2050 {
2051 rcStrict = apicSetTprEx(pVCpu, u32Value, false /* fForceX2ApicBehaviour */);
2052 break;
2053 }
2054
2055 case MSR_IA32_X2APIC_ICR:
2056 {
2057 rcStrict = apicSetIcr(pVCpu, u64Value, VINF_CPUM_R3_MSR_WRITE);
2058 break;
2059 }
2060
2061 case MSR_IA32_X2APIC_SVR:
2062 {
2063 rcStrict = apicSetSvr(pVCpu, u32Value);
2064 break;
2065 }
2066
2067 case MSR_IA32_X2APIC_ESR:
2068 {
2069 rcStrict = apicSetEsr(pVCpu, u32Value);
2070 break;
2071 }
2072
2073 case MSR_IA32_X2APIC_TIMER_DCR:
2074 {
2075 rcStrict = apicSetTimerDcr(pVCpu, u32Value);
2076 break;
2077 }
2078
2079 case MSR_IA32_X2APIC_LVT_TIMER:
2080 case MSR_IA32_X2APIC_LVT_THERMAL:
2081 case MSR_IA32_X2APIC_LVT_PERF:
2082 case MSR_IA32_X2APIC_LVT_LINT0:
2083 case MSR_IA32_X2APIC_LVT_LINT1:
2084 case MSR_IA32_X2APIC_LVT_ERROR:
2085 {
2086 rcStrict = apicSetLvtEntry(pVCpu, X2APIC_GET_XAPIC_OFF(u32Reg), u32Value);
2087 break;
2088 }
2089
2090 case MSR_IA32_X2APIC_TIMER_ICR:
2091 {
2092 rcStrict = apicSetTimerIcr(pVCpu, VINF_CPUM_R3_MSR_WRITE, u32Value);
2093 break;
2094 }
2095
2096 /* Write-only MSRs: */
2097 case MSR_IA32_X2APIC_SELF_IPI:
2098 {
2099 uint8_t const uVector = XAPIC_SELF_IPI_GET_VECTOR(u32Value);
2100 apicPostInterrupt(pVCpu, uVector, XAPICTRIGGERMODE_EDGE, 0 /* uSrcTag */);
2101 rcStrict = VINF_SUCCESS;
2102 break;
2103 }
2104
2105 case MSR_IA32_X2APIC_EOI:
2106 {
2107 rcStrict = apicSetEoi(pVCpu, u32Value, VINF_CPUM_R3_MSR_WRITE, false /* fForceX2ApicBehaviour */);
2108 break;
2109 }
2110
2111 /*
2112 * Windows guest using Hyper-V x2APIC MSR compatibility mode tries to write the "high"
2113 * LDR bits, which is quite absurd (as it's a 32-bit register) using this invalid MSR
2114 * index (0x80E). The write value was 0xffffffff on a Windows 8.1 64-bit guest. We can
2115 * safely ignore this nonsense, See @bugref{8382#c7}.
2116 */
2117 case MSR_IA32_X2APIC_LDR + 1:
2118 {
2119 if (pApic->fHyperVCompatMode)
2120 rcStrict = VINF_SUCCESS;
2121 else
2122 rcStrict = apicMsrAccessError(pVCpu, u32Reg, APICMSRACCESS_WRITE_RSVD_OR_UNKNOWN);
2123 break;
2124 }
2125
2126 /* Special-treament (read-only normally, but not with Hyper-V) */
2127 case MSR_IA32_X2APIC_LDR:
2128 {
2129 if (pApic->fHyperVCompatMode)
2130 {
2131 rcStrict = apicSetLdr(pVCpu, u32Value);
2132 break;
2133 }
2134 }
2135 RT_FALL_THRU();
2136 /* Read-only MSRs: */
2137 case MSR_IA32_X2APIC_ID:
2138 case MSR_IA32_X2APIC_VERSION:
2139 case MSR_IA32_X2APIC_PPR:
2140 case MSR_IA32_X2APIC_ISR0: case MSR_IA32_X2APIC_ISR1: case MSR_IA32_X2APIC_ISR2: case MSR_IA32_X2APIC_ISR3:
2141 case MSR_IA32_X2APIC_ISR4: case MSR_IA32_X2APIC_ISR5: case MSR_IA32_X2APIC_ISR6: case MSR_IA32_X2APIC_ISR7:
2142 case MSR_IA32_X2APIC_TMR0: case MSR_IA32_X2APIC_TMR1: case MSR_IA32_X2APIC_TMR2: case MSR_IA32_X2APIC_TMR3:
2143 case MSR_IA32_X2APIC_TMR4: case MSR_IA32_X2APIC_TMR5: case MSR_IA32_X2APIC_TMR6: case MSR_IA32_X2APIC_TMR7:
2144 case MSR_IA32_X2APIC_IRR0: case MSR_IA32_X2APIC_IRR1: case MSR_IA32_X2APIC_IRR2: case MSR_IA32_X2APIC_IRR3:
2145 case MSR_IA32_X2APIC_IRR4: case MSR_IA32_X2APIC_IRR5: case MSR_IA32_X2APIC_IRR6: case MSR_IA32_X2APIC_IRR7:
2146 case MSR_IA32_X2APIC_TIMER_CCR:
2147 {
2148 rcStrict = apicMsrAccessError(pVCpu, u32Reg, APICMSRACCESS_WRITE_READ_ONLY);
2149 break;
2150 }
2151
2152 /* Reserved MSRs: */
2153 case MSR_IA32_X2APIC_LVT_CMCI:
2154 default:
2155 {
2156 rcStrict = apicMsrAccessError(pVCpu, u32Reg, APICMSRACCESS_WRITE_RSVD_OR_UNKNOWN);
2157 break;
2158 }
2159 }
2160 }
2161 else
2162 rcStrict = apicMsrAccessError(pVCpu, u32Reg, APICMSRACCESS_INVALID_WRITE_MODE);
2163
2164 return rcStrict;
2165}
2166
2167
2168/**
2169 * Resets the APIC base MSR.
2170 *
2171 * @param pVCpu The cross context virtual CPU structure.
2172 */
2173static void apicResetBaseMsr(PVMCPUCC pVCpu)
2174{
2175 /*
2176 * Initialize the APIC base MSR. The APIC enable-bit is set upon power-up or reset[1].
2177 *
2178 * A Reset (in xAPIC and x2APIC mode) brings up the local APIC in xAPIC mode.
2179 * An INIT IPI does -not- cause a transition between xAPIC and x2APIC mode[2].
2180 *
2181 * [1] See AMD spec. 14.1.3 "Processor Initialization State"
2182 * [2] See Intel spec. 10.12.5.1 "x2APIC States".
2183 */
2184 VMCPU_ASSERT_EMT_OR_NOT_RUNNING(pVCpu);
2185
2186 /* Construct. */
2187 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
2188 PAPIC pApic = VM_TO_APIC(pVCpu->CTX_SUFF(pVM));
2189 uint64_t uApicBaseMsr = MSR_IA32_APICBASE_ADDR;
2190 if (pVCpu->idCpu == 0)
2191 uApicBaseMsr |= MSR_IA32_APICBASE_BSP;
2192
2193 /* If the VM was configured with no APIC, don't enable xAPIC mode, obviously. */
2194 if (pApic->enmMaxMode != PDMAPICMODE_NONE)
2195 {
2196 uApicBaseMsr |= MSR_IA32_APICBASE_EN;
2197
2198 /*
2199 * While coming out of a reset the APIC is enabled and in xAPIC mode. If software had previously
2200 * disabled the APIC (which results in the CPUID bit being cleared as well) we re-enable it here.
2201 * See Intel spec. 10.12.5.1 "x2APIC States".
2202 */
2203 if (CPUMSetGuestCpuIdPerCpuApicFeature(pVCpu, true /*fVisible*/) == false)
2204 LogRel(("APIC%u: Resetting mode to xAPIC\n", pVCpu->idCpu));
2205 }
2206
2207 /* Commit. */
2208 ASMAtomicWriteU64(&pApicCpu->uApicBaseMsr, uApicBaseMsr);
2209}
2210
2211
2212/**
2213 * Initializes per-VCPU APIC to the state following an INIT reset
2214 * ("Wait-for-SIPI" state).
2215 *
2216 * @param pVCpu The cross context virtual CPU structure.
2217 */
2218void apicInitIpi(PVMCPUCC pVCpu)
2219{
2220 VMCPU_ASSERT_EMT_OR_NOT_RUNNING(pVCpu);
2221 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
2222
2223 /*
2224 * See Intel spec. 10.4.7.3 "Local APIC State After an INIT Reset (Wait-for-SIPI State)"
2225 * and AMD spec 16.3.2 "APIC Registers".
2226 *
2227 * The reason we don't simply zero out the entire APIC page and only set the non-zero members
2228 * is because there are some registers that are not touched by the INIT IPI (e.g. version)
2229 * operation and this function is only a subset of the reset operation.
2230 */
2231 RT_ZERO(pXApicPage->irr);
2232 RT_ZERO(pXApicPage->irr);
2233 RT_ZERO(pXApicPage->isr);
2234 RT_ZERO(pXApicPage->tmr);
2235 RT_ZERO(pXApicPage->icr_hi);
2236 RT_ZERO(pXApicPage->icr_lo);
2237 RT_ZERO(pXApicPage->ldr);
2238 RT_ZERO(pXApicPage->tpr);
2239 RT_ZERO(pXApicPage->ppr);
2240 RT_ZERO(pXApicPage->timer_icr);
2241 RT_ZERO(pXApicPage->timer_ccr);
2242 RT_ZERO(pXApicPage->timer_dcr);
2243
2244 pXApicPage->dfr.u.u4Model = XAPICDESTFORMAT_FLAT;
2245 pXApicPage->dfr.u.u28ReservedMb1 = UINT32_C(0xfffffff);
2246
2247 /** @todo CMCI. */
2248
2249 RT_ZERO(pXApicPage->lvt_timer);
2250 pXApicPage->lvt_timer.u.u1Mask = 1;
2251
2252#if XAPIC_HARDWARE_VERSION == XAPIC_HARDWARE_VERSION_P4
2253 RT_ZERO(pXApicPage->lvt_thermal);
2254 pXApicPage->lvt_thermal.u.u1Mask = 1;
2255#endif
2256
2257 RT_ZERO(pXApicPage->lvt_perf);
2258 pXApicPage->lvt_perf.u.u1Mask = 1;
2259
2260 RT_ZERO(pXApicPage->lvt_lint0);
2261 pXApicPage->lvt_lint0.u.u1Mask = 1;
2262
2263 RT_ZERO(pXApicPage->lvt_lint1);
2264 pXApicPage->lvt_lint1.u.u1Mask = 1;
2265
2266 RT_ZERO(pXApicPage->lvt_error);
2267 pXApicPage->lvt_error.u.u1Mask = 1;
2268
2269 RT_ZERO(pXApicPage->svr);
2270 pXApicPage->svr.u.u8SpuriousVector = 0xff;
2271
2272 /* The self-IPI register is reset to 0. See Intel spec. 10.12.5.1 "x2APIC States" */
2273 PX2APICPAGE pX2ApicPage = VMCPU_TO_X2APICPAGE(pVCpu);
2274 RT_ZERO(pX2ApicPage->self_ipi);
2275
2276 /* Clear the pending-interrupt bitmaps. */
2277 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
2278 RT_BZERO(&pApicCpu->ApicPibLevel, sizeof(APICPIB));
2279 RT_BZERO(pApicCpu->CTX_SUFF(pvApicPib), sizeof(APICPIB));
2280
2281 /* Clear the interrupt line states for LINT0 and LINT1 pins. */
2282 pApicCpu->fActiveLint0 = false;
2283 pApicCpu->fActiveLint1 = false;
2284}
2285
2286
2287/**
2288 * Initializes per-VCPU APIC to the state following a power-up or hardware
2289 * reset.
2290 *
2291 * @param pVCpu The cross context virtual CPU structure.
2292 * @param fResetApicBaseMsr Whether to reset the APIC base MSR.
2293 */
2294void apicResetCpu(PVMCPUCC pVCpu, bool fResetApicBaseMsr)
2295{
2296 VMCPU_ASSERT_EMT_OR_NOT_RUNNING(pVCpu);
2297
2298 LogFlow(("APIC%u: apicR3ResetCpu: fResetApicBaseMsr=%RTbool\n", pVCpu->idCpu, fResetApicBaseMsr));
2299
2300#ifdef VBOX_STRICT
2301 /* Verify that the initial APIC ID reported via CPUID matches our VMCPU ID assumption. */
2302 uint32_t uEax, uEbx, uEcx, uEdx;
2303 uEax = uEbx = uEcx = uEdx = UINT32_MAX;
2304 CPUMGetGuestCpuId(pVCpu, 1, 0, &uEax, &uEbx, &uEcx, &uEdx);
2305 Assert(((uEbx >> 24) & 0xff) == pVCpu->idCpu);
2306#endif
2307
2308 /*
2309 * The state following a power-up or reset is a superset of the INIT state.
2310 * See Intel spec. 10.4.7.3 "Local APIC State After an INIT Reset ('Wait-for-SIPI' State)"
2311 */
2312 apicInitIpi(pVCpu);
2313
2314 /*
2315 * The APIC version register is read-only, so just initialize it here.
2316 * It is not clear from the specs, where exactly it is initialized.
2317 * The version determines the number of LVT entries and size of the APIC ID (8 bits for P4).
2318 */
2319 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
2320#if XAPIC_HARDWARE_VERSION == XAPIC_HARDWARE_VERSION_P4
2321 pXApicPage->version.u.u8MaxLvtEntry = XAPIC_MAX_LVT_ENTRIES_P4 - 1;
2322 pXApicPage->version.u.u8Version = XAPIC_HARDWARE_VERSION_P4;
2323 AssertCompile(sizeof(pXApicPage->id.u8ApicId) >= XAPIC_APIC_ID_BIT_COUNT_P4 / 8);
2324#else
2325# error "Implement Pentium and P6 family APIC architectures"
2326#endif
2327
2328 /** @todo It isn't clear in the spec. where exactly the default base address
2329 * is (re)initialized, atm we do it here in Reset. */
2330 if (fResetApicBaseMsr)
2331 apicResetBaseMsr(pVCpu);
2332
2333 /*
2334 * Initialize the APIC ID register to xAPIC format.
2335 */
2336 ASMMemZero32(&pXApicPage->id, sizeof(pXApicPage->id));
2337 pXApicPage->id.u8ApicId = pVCpu->idCpu;
2338}
2339
2340
2341/**
2342 * Sets the APIC base MSR.
2343 *
2344 * @returns VBox status code - no informational ones, esp. not
2345 * VINF_CPUM_R3_MSR_WRITE. Only the following two:
2346 * @retval VINF_SUCCESS
2347 * @retval VERR_CPUM_RAISE_GP_0
2348 *
2349 * @param pVCpu The cross context virtual CPU structure.
2350 * @param u64BaseMsr The value to set.
2351 */
2352VMM_INT_DECL(int) APICSetBaseMsr(PVMCPUCC pVCpu, uint64_t u64BaseMsr)
2353{
2354 Assert(pVCpu);
2355
2356 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
2357 PAPIC pApic = VM_TO_APIC(pVCpu->CTX_SUFF(pVM));
2358 APICMODE enmOldMode = apicGetMode(pApicCpu->uApicBaseMsr);
2359 APICMODE enmNewMode = apicGetMode(u64BaseMsr);
2360 uint64_t uBaseMsr = pApicCpu->uApicBaseMsr;
2361
2362 Log2(("APIC%u: ApicSetBaseMsr: u64BaseMsr=%#RX64 enmNewMode=%s enmOldMode=%s\n", pVCpu->idCpu, u64BaseMsr,
2363 apicGetModeName(enmNewMode), apicGetModeName(enmOldMode)));
2364
2365 /*
2366 * We do not support re-mapping the APIC base address because:
2367 * - We'll have to manage all the mappings ourselves in the APIC (reference counting based unmapping etc.)
2368 * i.e. we can only unmap the MMIO region if no other APIC is mapped on that location.
2369 * - It's unclear how/if IOM can fallback to handling regions as regular memory (if the MMIO
2370 * region remains mapped but doesn't belong to the called VCPU's APIC).
2371 */
2372 /** @todo Handle per-VCPU APIC base relocation. */
2373 if (MSR_IA32_APICBASE_GET_ADDR(uBaseMsr) != MSR_IA32_APICBASE_ADDR)
2374 {
2375 if (pVCpu->apic.s.cLogMaxSetApicBaseAddr++ < 5)
2376 LogRel(("APIC%u: Attempt to relocate base to %#RGp, unsupported -> #GP(0)\n", pVCpu->idCpu,
2377 MSR_IA32_APICBASE_GET_ADDR(uBaseMsr)));
2378 return VERR_CPUM_RAISE_GP_0;
2379 }
2380
2381 /* Don't allow enabling xAPIC/x2APIC if the VM is configured with the APIC disabled. */
2382 if (pApic->enmMaxMode == PDMAPICMODE_NONE)
2383 {
2384 LogRel(("APIC%u: Disallowing APIC base MSR write as the VM is configured with APIC disabled!\n", pVCpu->idCpu));
2385 return apicMsrAccessError(pVCpu, MSR_IA32_APICBASE, APICMSRACCESS_WRITE_DISALLOWED_CONFIG);
2386 }
2387
2388 /*
2389 * Act on state transition.
2390 */
2391 if (enmNewMode != enmOldMode)
2392 {
2393 switch (enmNewMode)
2394 {
2395 case APICMODE_DISABLED:
2396 {
2397 /*
2398 * The APIC state needs to be reset (especially the APIC ID as x2APIC APIC ID bit layout
2399 * is different). We can start with a clean slate identical to the state after a power-up/reset.
2400 *
2401 * See Intel spec. 10.4.3 "Enabling or Disabling the Local APIC".
2402 *
2403 * We'll also manually manage the APIC base MSR here. We want a single-point of commit
2404 * at the end of this function rather than updating it in apicR3ResetCpu. This means we also
2405 * need to update the CPUID leaf ourselves.
2406 */
2407 apicResetCpu(pVCpu, false /* fResetApicBaseMsr */);
2408 uBaseMsr &= ~(MSR_IA32_APICBASE_EN | MSR_IA32_APICBASE_EXTD);
2409 CPUMSetGuestCpuIdPerCpuApicFeature(pVCpu, false /*fVisible*/);
2410 LogRel(("APIC%u: Switched mode to disabled\n", pVCpu->idCpu));
2411 break;
2412 }
2413
2414 case APICMODE_XAPIC:
2415 {
2416 if (enmOldMode != APICMODE_DISABLED)
2417 {
2418 LogRel(("APIC%u: Can only transition to xAPIC state from disabled state\n", pVCpu->idCpu));
2419 return apicMsrAccessError(pVCpu, MSR_IA32_APICBASE, APICMSRACCESS_WRITE_INVALID);
2420 }
2421
2422 uBaseMsr |= MSR_IA32_APICBASE_EN;
2423 CPUMSetGuestCpuIdPerCpuApicFeature(pVCpu, true /*fVisible*/);
2424 LogRel(("APIC%u: Switched mode to xAPIC\n", pVCpu->idCpu));
2425 break;
2426 }
2427
2428 case APICMODE_X2APIC:
2429 {
2430 if (pApic->enmMaxMode != PDMAPICMODE_X2APIC)
2431 {
2432 LogRel(("APIC%u: Disallowing transition to x2APIC mode as the VM is configured with the x2APIC disabled!\n",
2433 pVCpu->idCpu));
2434 return apicMsrAccessError(pVCpu, MSR_IA32_APICBASE, APICMSRACCESS_WRITE_INVALID);
2435 }
2436
2437 if (enmOldMode != APICMODE_XAPIC)
2438 {
2439 LogRel(("APIC%u: Can only transition to x2APIC state from xAPIC state\n", pVCpu->idCpu));
2440 return apicMsrAccessError(pVCpu, MSR_IA32_APICBASE, APICMSRACCESS_WRITE_INVALID);
2441 }
2442
2443 uBaseMsr |= MSR_IA32_APICBASE_EN | MSR_IA32_APICBASE_EXTD;
2444
2445 /*
2446 * The APIC ID needs updating when entering x2APIC mode.
2447 * Software written APIC ID in xAPIC mode isn't preserved.
2448 * The APIC ID becomes read-only to software in x2APIC mode.
2449 *
2450 * See Intel spec. 10.12.5.1 "x2APIC States".
2451 */
2452 PX2APICPAGE pX2ApicPage = VMCPU_TO_X2APICPAGE(pVCpu);
2453 ASMMemZero32(&pX2ApicPage->id, sizeof(pX2ApicPage->id));
2454 pX2ApicPage->id.u32ApicId = pVCpu->idCpu;
2455
2456 /*
2457 * LDR initialization occurs when entering x2APIC mode.
2458 * See Intel spec. 10.12.10.2 "Deriving Logical x2APIC ID from the Local x2APIC ID".
2459 */
2460 pX2ApicPage->ldr.u32LogicalApicId = ((pX2ApicPage->id.u32ApicId & UINT32_C(0xffff0)) << 16)
2461 | (UINT32_C(1) << pX2ApicPage->id.u32ApicId & UINT32_C(0xf));
2462
2463 LogRel(("APIC%u: Switched mode to x2APIC\n", pVCpu->idCpu));
2464 break;
2465 }
2466
2467 case APICMODE_INVALID:
2468 default:
2469 {
2470 Log(("APIC%u: Invalid state transition attempted\n", pVCpu->idCpu));
2471 return apicMsrAccessError(pVCpu, MSR_IA32_APICBASE, APICMSRACCESS_WRITE_INVALID);
2472 }
2473 }
2474 }
2475
2476 ASMAtomicWriteU64(&pApicCpu->uApicBaseMsr, uBaseMsr);
2477 return VINF_SUCCESS;
2478}
2479
2480
2481/**
2482 * Gets the APIC base MSR (no checks are performed wrt APIC hardware or its
2483 * state).
2484 *
2485 * @returns The base MSR value.
2486 * @param pVCpu The cross context virtual CPU structure.
2487 */
2488VMM_INT_DECL(uint64_t) APICGetBaseMsrNoCheck(PCVMCPUCC pVCpu)
2489{
2490 VMCPU_ASSERT_EMT_OR_NOT_RUNNING(pVCpu);
2491 PCAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
2492 return pApicCpu->uApicBaseMsr;
2493}
2494
2495
2496/**
2497 * Gets the APIC base MSR.
2498 *
2499 * @returns Strict VBox status code.
2500 * @param pVCpu The cross context virtual CPU structure.
2501 * @param pu64Value Where to store the MSR value.
2502 */
2503VMM_INT_DECL(VBOXSTRICTRC) APICGetBaseMsr(PVMCPUCC pVCpu, uint64_t *pu64Value)
2504{
2505 VMCPU_ASSERT_EMT_OR_NOT_RUNNING(pVCpu);
2506
2507 PCAPIC pApic = VM_TO_APIC(pVCpu->CTX_SUFF(pVM));
2508 if (pApic->enmMaxMode != PDMAPICMODE_NONE)
2509 {
2510 *pu64Value = APICGetBaseMsrNoCheck(pVCpu);
2511 return VINF_SUCCESS;
2512 }
2513
2514 if (pVCpu->apic.s.cLogMaxGetApicBaseAddr++ < 5)
2515 LogRel(("APIC%u: Reading APIC base MSR (%#x) when there is no APIC -> #GP(0)\n", pVCpu->idCpu, MSR_IA32_APICBASE));
2516 return VERR_CPUM_RAISE_GP_0;
2517}
2518
2519
2520/**
2521 * Sets the TPR (Task Priority Register).
2522 *
2523 * @retval VINF_SUCCESS
2524 * @retval VERR_CPUM_RAISE_GP_0
2525 * @retval VERR_PDM_NO_APIC_INSTANCE
2526 *
2527 * @param pVCpu The cross context virtual CPU structure.
2528 * @param u8Tpr The TPR value to set.
2529 */
2530VMMDECL(int) APICSetTpr(PVMCPUCC pVCpu, uint8_t u8Tpr)
2531{
2532 if (APICIsEnabled(pVCpu))
2533 return apicSetTprEx(pVCpu, u8Tpr, false /* fForceX2ApicBehaviour */);
2534 return VERR_PDM_NO_APIC_INSTANCE;
2535}
2536
2537
2538/**
2539 * Gets the highest priority pending interrupt.
2540 *
2541 * @returns true if any interrupt is pending, false otherwise.
2542 * @param pVCpu The cross context virtual CPU structure.
2543 * @param pu8PendingIntr Where to store the interrupt vector if the
2544 * interrupt is pending (optional, can be NULL).
2545 */
2546static bool apicGetHighestPendingInterrupt(PCVMCPUCC pVCpu, uint8_t *pu8PendingIntr)
2547{
2548 PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
2549 int const irrv = apicGetHighestSetBitInReg(&pXApicPage->irr, -1);
2550 if (irrv >= 0)
2551 {
2552 Assert(irrv <= (int)UINT8_MAX);
2553 if (pu8PendingIntr)
2554 *pu8PendingIntr = (uint8_t)irrv;
2555 return true;
2556 }
2557 return false;
2558}
2559
2560
2561/**
2562 * Gets the APIC TPR (Task Priority Register).
2563 *
2564 * @returns VBox status code.
2565 * @param pVCpu The cross context virtual CPU structure.
2566 * @param pu8Tpr Where to store the TPR.
2567 * @param pfPending Where to store whether there is a pending interrupt
2568 * (optional, can be NULL).
2569 * @param pu8PendingIntr Where to store the highest-priority pending
2570 * interrupt (optional, can be NULL).
2571 */
2572VMMDECL(int) APICGetTpr(PCVMCPUCC pVCpu, uint8_t *pu8Tpr, bool *pfPending, uint8_t *pu8PendingIntr)
2573{
2574 VMCPU_ASSERT_EMT(pVCpu);
2575 if (APICIsEnabled(pVCpu))
2576 {
2577 PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
2578 if (pfPending)
2579 {
2580 /*
2581 * Just return whatever the highest pending interrupt is in the IRR.
2582 * The caller is responsible for figuring out if it's masked by the TPR etc.
2583 */
2584 *pfPending = apicGetHighestPendingInterrupt(pVCpu, pu8PendingIntr);
2585 }
2586
2587 *pu8Tpr = pXApicPage->tpr.u8Tpr;
2588 return VINF_SUCCESS;
2589 }
2590
2591 *pu8Tpr = 0;
2592 return VERR_PDM_NO_APIC_INSTANCE;
2593}
2594
2595
2596/**
2597 * Gets the APIC timer frequency.
2598 *
2599 * @returns Strict VBox status code.
2600 * @param pVM The cross context VM structure.
2601 * @param pu64Value Where to store the timer frequency.
2602 */
2603VMM_INT_DECL(int) APICGetTimerFreq(PVMCC pVM, uint64_t *pu64Value)
2604{
2605 /*
2606 * Validate.
2607 */
2608 Assert(pVM);
2609 AssertPtrReturn(pu64Value, VERR_INVALID_PARAMETER);
2610
2611 PVMCPUCC pVCpu = pVM->CTX_SUFF(apCpus)[0];
2612 if (APICIsEnabled(pVCpu))
2613 {
2614 PCAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
2615 *pu64Value = TMTimerGetFreq(pApicCpu->CTX_SUFF(pTimer));
2616 return VINF_SUCCESS;
2617 }
2618 return VERR_PDM_NO_APIC_INSTANCE;
2619}
2620
2621
2622/**
2623 * Delivers an interrupt message via the system bus.
2624 *
2625 * @returns VBox status code.
2626 * @param pVM The cross context VM structure.
2627 * @param uDest The destination mask.
2628 * @param uDestMode The destination mode.
2629 * @param uDeliveryMode The delivery mode.
2630 * @param uVector The interrupt vector.
2631 * @param uPolarity The interrupt line polarity.
2632 * @param uTriggerMode The trigger mode.
2633 * @param uSrcTag The interrupt source tag (debugging).
2634 */
2635VMM_INT_DECL(int) APICBusDeliver(PVMCC pVM, uint8_t uDest, uint8_t uDestMode, uint8_t uDeliveryMode, uint8_t uVector,
2636 uint8_t uPolarity, uint8_t uTriggerMode, uint32_t uSrcTag)
2637{
2638 NOREF(uPolarity);
2639
2640 /*
2641 * If the APIC isn't enabled, do nothing and pretend success.
2642 */
2643 if (APICIsEnabled(pVM->CTX_SUFF(apCpus)[0]))
2644 { /* likely */ }
2645 else
2646 return VINF_SUCCESS;
2647
2648 /*
2649 * The destination field (mask) in the IO APIC redirectable table entry is 8-bits.
2650 * Hence, the broadcast mask is 0xff.
2651 * See IO APIC spec. 3.2.4. "IOREDTBL[23:0] - I/O Redirectable Table Registers".
2652 */
2653 XAPICTRIGGERMODE enmTriggerMode = (XAPICTRIGGERMODE)uTriggerMode;
2654 XAPICDELIVERYMODE enmDeliveryMode = (XAPICDELIVERYMODE)uDeliveryMode;
2655 XAPICDESTMODE enmDestMode = (XAPICDESTMODE)uDestMode;
2656 uint32_t fDestMask = uDest;
2657 uint32_t fBroadcastMask = UINT32_C(0xff);
2658
2659 Log2(("APIC: apicBusDeliver: fDestMask=%#x enmDestMode=%s enmTriggerMode=%s enmDeliveryMode=%s uVector=%#x\n", fDestMask,
2660 apicGetDestModeName(enmDestMode), apicGetTriggerModeName(enmTriggerMode), apicGetDeliveryModeName(enmDeliveryMode),
2661 uVector));
2662
2663 bool fIntrAccepted;
2664 VMCPUSET DestCpuSet;
2665 apicGetDestCpuSet(pVM, fDestMask, fBroadcastMask, enmDestMode, enmDeliveryMode, &DestCpuSet);
2666 VBOXSTRICTRC rcStrict = apicSendIntr(pVM, NULL /* pVCpu */, uVector, enmTriggerMode, enmDeliveryMode, &DestCpuSet,
2667 &fIntrAccepted, uSrcTag, VINF_SUCCESS /* rcRZ */);
2668 if (fIntrAccepted)
2669 return VBOXSTRICTRC_VAL(rcStrict);
2670 return VERR_APIC_INTR_DISCARDED;
2671}
2672
2673
2674/**
2675 * Assert/de-assert the local APIC's LINT0/LINT1 interrupt pins.
2676 *
2677 * @returns Strict VBox status code.
2678 * @param pVCpu The cross context virtual CPU structure.
2679 * @param u8Pin The interrupt pin (0 for LINT0 or 1 for LINT1).
2680 * @param u8Level The level (0 for low or 1 for high).
2681 * @param rcRZ The return code if the operation cannot be performed in
2682 * the current context.
2683 */
2684VMM_INT_DECL(VBOXSTRICTRC) APICLocalInterrupt(PVMCPUCC pVCpu, uint8_t u8Pin, uint8_t u8Level, int rcRZ)
2685{
2686 AssertReturn(u8Pin <= 1, VERR_INVALID_PARAMETER);
2687 AssertReturn(u8Level <= 1, VERR_INVALID_PARAMETER);
2688
2689 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
2690
2691 /* If the APIC is enabled, the interrupt is subject to LVT programming. */
2692 if (APICIsEnabled(pVCpu))
2693 {
2694 PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
2695
2696 /* Pick the LVT entry corresponding to the interrupt pin. */
2697 static const uint16_t s_au16LvtOffsets[] =
2698 {
2699 XAPIC_OFF_LVT_LINT0,
2700 XAPIC_OFF_LVT_LINT1
2701 };
2702 Assert(u8Pin < RT_ELEMENTS(s_au16LvtOffsets));
2703 uint16_t const offLvt = s_au16LvtOffsets[u8Pin];
2704 uint32_t const uLvt = apicReadRaw32(pXApicPage, offLvt);
2705
2706 /* If software hasn't masked the interrupt in the LVT entry, proceed interrupt processing. */
2707 if (!XAPIC_LVT_IS_MASKED(uLvt))
2708 {
2709 XAPICDELIVERYMODE const enmDeliveryMode = XAPIC_LVT_GET_DELIVERY_MODE(uLvt);
2710 XAPICTRIGGERMODE enmTriggerMode = XAPIC_LVT_GET_TRIGGER_MODE(uLvt);
2711
2712 switch (enmDeliveryMode)
2713 {
2714 case XAPICDELIVERYMODE_INIT:
2715 {
2716 /** @todo won't work in R0/RC because callers don't care about rcRZ. */
2717 AssertMsgFailed(("INIT through LINT0/LINT1 is not yet supported\n"));
2718 }
2719 RT_FALL_THRU();
2720 case XAPICDELIVERYMODE_FIXED:
2721 {
2722 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
2723 uint8_t const uVector = XAPIC_LVT_GET_VECTOR(uLvt);
2724 bool fActive = RT_BOOL(u8Level & 1);
2725 bool volatile *pfActiveLine = u8Pin == 0 ? &pApicCpu->fActiveLint0 : &pApicCpu->fActiveLint1;
2726 /** @todo Polarity is busted elsewhere, we need to fix that
2727 * first. See @bugref{8386#c7}. */
2728#if 0
2729 uint8_t const u8Polarity = XAPIC_LVT_GET_POLARITY(uLvt);
2730 fActive ^= u8Polarity; */
2731#endif
2732 if (!fActive)
2733 {
2734 ASMAtomicCmpXchgBool(pfActiveLine, false, true);
2735 break;
2736 }
2737
2738 /* Level-sensitive interrupts are not supported for LINT1. See Intel spec. 10.5.1 "Local Vector Table". */
2739 if (offLvt == XAPIC_OFF_LVT_LINT1)
2740 enmTriggerMode = XAPICTRIGGERMODE_EDGE;
2741 /** @todo figure out what "If the local APIC is not used in conjunction with an I/O APIC and fixed
2742 delivery mode is selected; the Pentium 4, Intel Xeon, and P6 family processors will always
2743 use level-sensitive triggering, regardless if edge-sensitive triggering is selected."
2744 means. */
2745
2746 bool fSendIntr;
2747 if (enmTriggerMode == XAPICTRIGGERMODE_EDGE)
2748 {
2749 /* Recognize and send the interrupt only on an edge transition. */
2750 fSendIntr = ASMAtomicCmpXchgBool(pfActiveLine, true, false);
2751 }
2752 else
2753 {
2754 /* For level-triggered interrupts, redundant interrupts are not a problem. */
2755 Assert(enmTriggerMode == XAPICTRIGGERMODE_LEVEL);
2756 ASMAtomicCmpXchgBool(pfActiveLine, true, false);
2757
2758 /* Only when the remote IRR isn't set, set it and send the interrupt. */
2759 if (!(pXApicPage->lvt_lint0.all.u32LvtLint0 & XAPIC_LVT_REMOTE_IRR))
2760 {
2761 Assert(offLvt == XAPIC_OFF_LVT_LINT0);
2762 ASMAtomicOrU32((volatile uint32_t *)&pXApicPage->lvt_lint0.all.u32LvtLint0, XAPIC_LVT_REMOTE_IRR);
2763 fSendIntr = true;
2764 }
2765 else
2766 fSendIntr = false;
2767 }
2768
2769 if (fSendIntr)
2770 {
2771 VMCPUSET DestCpuSet;
2772 VMCPUSET_EMPTY(&DestCpuSet);
2773 VMCPUSET_ADD(&DestCpuSet, pVCpu->idCpu);
2774 rcStrict = apicSendIntr(pVCpu->CTX_SUFF(pVM), pVCpu, uVector, enmTriggerMode, enmDeliveryMode,
2775 &DestCpuSet, NULL /* pfIntrAccepted */, 0 /* uSrcTag */, rcRZ);
2776 }
2777 break;
2778 }
2779
2780 case XAPICDELIVERYMODE_SMI:
2781 case XAPICDELIVERYMODE_NMI:
2782 {
2783 VMCPUSET DestCpuSet;
2784 VMCPUSET_EMPTY(&DestCpuSet);
2785 VMCPUSET_ADD(&DestCpuSet, pVCpu->idCpu);
2786 uint8_t const uVector = XAPIC_LVT_GET_VECTOR(uLvt);
2787 rcStrict = apicSendIntr(pVCpu->CTX_SUFF(pVM), pVCpu, uVector, enmTriggerMode, enmDeliveryMode, &DestCpuSet,
2788 NULL /* pfIntrAccepted */, 0 /* uSrcTag */, rcRZ);
2789 break;
2790 }
2791
2792 case XAPICDELIVERYMODE_EXTINT:
2793 {
2794 Log2(("APIC%u: apicLocalInterrupt: %s ExtINT through LINT%u\n", pVCpu->idCpu,
2795 u8Level ? "Raising" : "Lowering", u8Pin));
2796 if (u8Level)
2797 apicSetInterruptFF(pVCpu, PDMAPICIRQ_EXTINT);
2798 else
2799 apicClearInterruptFF(pVCpu, PDMAPICIRQ_EXTINT);
2800 break;
2801 }
2802
2803 /* Reserved/unknown delivery modes: */
2804 case XAPICDELIVERYMODE_LOWEST_PRIO:
2805 case XAPICDELIVERYMODE_STARTUP:
2806 default:
2807 {
2808 rcStrict = VERR_INTERNAL_ERROR_3;
2809 AssertMsgFailed(("APIC%u: LocalInterrupt: Invalid delivery mode %#x (%s) on LINT%d\n", pVCpu->idCpu,
2810 enmDeliveryMode, apicGetDeliveryModeName(enmDeliveryMode), u8Pin));
2811 break;
2812 }
2813 }
2814 }
2815 }
2816 else
2817 {
2818 /* The APIC is hardware disabled. The CPU behaves as though there is no on-chip APIC. */
2819 if (u8Pin == 0)
2820 {
2821 /* LINT0 behaves as an external interrupt pin. */
2822 Log2(("APIC%u: apicLocalInterrupt: APIC hardware-disabled, %s INTR\n", pVCpu->idCpu,
2823 u8Level ? "raising" : "lowering"));
2824 if (u8Level)
2825 apicSetInterruptFF(pVCpu, PDMAPICIRQ_EXTINT);
2826 else
2827 apicClearInterruptFF(pVCpu, PDMAPICIRQ_EXTINT);
2828 }
2829 else
2830 {
2831 /* LINT1 behaves as NMI. */
2832 Log2(("APIC%u: apicLocalInterrupt: APIC hardware-disabled, raising NMI\n", pVCpu->idCpu));
2833 apicSetInterruptFF(pVCpu, PDMAPICIRQ_NMI);
2834 }
2835 }
2836
2837 return rcStrict;
2838}
2839
2840
2841/**
2842 * Gets the next highest-priority interrupt from the APIC, marking it as an
2843 * "in-service" interrupt.
2844 *
2845 * @returns VBox status code.
2846 * @param pVCpu The cross context virtual CPU structure.
2847 * @param pu8Vector Where to store the vector.
2848 * @param puSrcTag Where to store the interrupt source tag (debugging).
2849 */
2850VMM_INT_DECL(int) APICGetInterrupt(PVMCPUCC pVCpu, uint8_t *pu8Vector, uint32_t *puSrcTag)
2851{
2852 VMCPU_ASSERT_EMT(pVCpu);
2853 Assert(pu8Vector);
2854
2855 LogFlow(("APIC%u: apicGetInterrupt:\n", pVCpu->idCpu));
2856
2857 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
2858 bool const fApicHwEnabled = APICIsEnabled(pVCpu);
2859 if ( fApicHwEnabled
2860 && pXApicPage->svr.u.fApicSoftwareEnable)
2861 {
2862 int const irrv = apicGetHighestSetBitInReg(&pXApicPage->irr, -1);
2863 if (RT_LIKELY(irrv >= 0))
2864 {
2865 Assert(irrv <= (int)UINT8_MAX);
2866 uint8_t const uVector = irrv;
2867
2868 /*
2869 * This can happen if the APIC receives an interrupt when the CPU has interrupts
2870 * disabled but the TPR is raised by the guest before re-enabling interrupts.
2871 */
2872 uint8_t const uTpr = pXApicPage->tpr.u8Tpr;
2873 if ( uTpr > 0
2874 && XAPIC_TPR_GET_TP(uVector) <= XAPIC_TPR_GET_TP(uTpr))
2875 {
2876 Log2(("APIC%u: apicGetInterrupt: Interrupt masked. uVector=%#x uTpr=%#x SpuriousVector=%#x\n", pVCpu->idCpu,
2877 uVector, uTpr, pXApicPage->svr.u.u8SpuriousVector));
2878 *pu8Vector = uVector;
2879 *puSrcTag = 0;
2880 STAM_COUNTER_INC(&pVCpu->apic.s.StatMaskedByTpr);
2881 return VERR_APIC_INTR_MASKED_BY_TPR;
2882 }
2883
2884 /*
2885 * The PPR should be up-to-date at this point through apicSetEoi().
2886 * We're on EMT so no parallel updates possible.
2887 * Subject the pending vector to PPR prioritization.
2888 */
2889 uint8_t const uPpr = pXApicPage->ppr.u8Ppr;
2890 if ( !uPpr
2891 || XAPIC_PPR_GET_PP(uVector) > XAPIC_PPR_GET_PP(uPpr))
2892 {
2893 apicClearVectorInReg(&pXApicPage->irr, uVector);
2894 apicSetVectorInReg(&pXApicPage->isr, uVector);
2895 apicUpdatePpr(pVCpu);
2896 apicSignalNextPendingIntr(pVCpu);
2897
2898 /* Retrieve the interrupt source tag associated with this interrupt. */
2899 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
2900 AssertCompile(RT_ELEMENTS(pApicCpu->auSrcTags) > UINT8_MAX);
2901 *puSrcTag = pApicCpu->auSrcTags[uVector];
2902 pApicCpu->auSrcTags[uVector] = 0;
2903
2904 Log2(("APIC%u: apicGetInterrupt: Valid Interrupt. uVector=%#x\n", pVCpu->idCpu, uVector));
2905 *pu8Vector = uVector;
2906 return VINF_SUCCESS;
2907 }
2908 else
2909 {
2910 STAM_COUNTER_INC(&pVCpu->apic.s.StatMaskedByPpr);
2911 Log2(("APIC%u: apicGetInterrupt: Interrupt's priority is not higher than the PPR. uVector=%#x PPR=%#x\n",
2912 pVCpu->idCpu, uVector, uPpr));
2913 }
2914 }
2915 else
2916 Log2(("APIC%u: apicGetInterrupt: No pending bits in IRR\n", pVCpu->idCpu));
2917 }
2918 else
2919 Log2(("APIC%u: apicGetInterrupt: APIC %s disabled\n", pVCpu->idCpu, !fApicHwEnabled ? "hardware" : "software"));
2920
2921 *pu8Vector = 0;
2922 *puSrcTag = 0;
2923 return VERR_APIC_INTR_NOT_PENDING;
2924}
2925
2926
2927/**
2928 * @callback_method_impl{FNIOMMMIOREAD}
2929 */
2930APICBOTHCBDECL(int) apicReadMmio(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
2931{
2932 NOREF(pvUser);
2933 Assert(!(GCPhysAddr & 0xf));
2934 Assert(cb == 4); RT_NOREF_PV(cb);
2935
2936 PAPICDEV pApicDev = PDMINS_2_DATA(pDevIns, PAPICDEV);
2937 PVMCPUCC pVCpu = PDMDevHlpGetVMCPU(pDevIns);
2938 uint16_t offReg = GCPhysAddr & 0xff0;
2939 uint32_t uValue = 0;
2940
2941 STAM_COUNTER_INC(&pVCpu->apic.s.CTX_SUFF_Z(StatMmioRead));
2942
2943 int rc = VBOXSTRICTRC_VAL(apicReadRegister(pApicDev, pVCpu, offReg, &uValue));
2944 *(uint32_t *)pv = uValue;
2945
2946 Log2(("APIC%u: apicReadMmio: offReg=%#RX16 uValue=%#RX32\n", pVCpu->idCpu, offReg, uValue));
2947 return rc;
2948}
2949
2950
2951/**
2952 * @callback_method_impl{FNIOMMMIOWRITE}
2953 */
2954APICBOTHCBDECL(int) apicWriteMmio(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb)
2955{
2956 NOREF(pvUser);
2957 Assert(!(GCPhysAddr & 0xf));
2958 Assert(cb == 4); RT_NOREF_PV(cb);
2959
2960 PAPICDEV pApicDev = PDMINS_2_DATA(pDevIns, PAPICDEV);
2961 PVMCPUCC pVCpu = PDMDevHlpGetVMCPU(pDevIns);
2962 uint16_t offReg = GCPhysAddr & 0xff0;
2963 uint32_t uValue = *(uint32_t *)pv;
2964
2965 STAM_COUNTER_INC(&pVCpu->apic.s.CTX_SUFF_Z(StatMmioWrite));
2966
2967 Log2(("APIC%u: apicWriteMmio: offReg=%#RX16 uValue=%#RX32\n", pVCpu->idCpu, offReg, uValue));
2968
2969 int rc = VBOXSTRICTRC_VAL(apicWriteRegister(pApicDev, pVCpu, offReg, uValue));
2970 return rc;
2971}
2972
2973
2974/**
2975 * Sets the interrupt pending force-flag and pokes the EMT if required.
2976 *
2977 * @param pVCpu The cross context virtual CPU structure.
2978 * @param enmType The IRQ type.
2979 */
2980static void apicSetInterruptFF(PVMCPUCC pVCpu, PDMAPICIRQ enmType)
2981{
2982#ifdef IN_RING3
2983 /* IRQ state should be loaded as-is by "LoadExec". Changes can be made from LoadDone. */
2984 Assert(pVCpu->pVMR3->enmVMState != VMSTATE_LOADING || PDMR3HasLoadedState(pVCpu->pVMR3));
2985#endif
2986
2987 switch (enmType)
2988 {
2989 case PDMAPICIRQ_HARDWARE:
2990 VMCPU_ASSERT_EMT_OR_NOT_RUNNING(pVCpu);
2991 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC);
2992 break;
2993 case PDMAPICIRQ_UPDATE_PENDING: VMCPU_FF_SET(pVCpu, VMCPU_FF_UPDATE_APIC); break;
2994 case PDMAPICIRQ_NMI: VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI); break;
2995 case PDMAPICIRQ_SMI: VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_SMI); break;
2996 case PDMAPICIRQ_EXTINT: VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_PIC); break;
2997 default:
2998 AssertMsgFailed(("enmType=%d\n", enmType));
2999 break;
3000 }
3001
3002 /*
3003 * We need to wake up the target CPU if we're not on EMT.
3004 */
3005#if defined(IN_RING0)
3006 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3007 VMCPUID idCpu = pVCpu->idCpu;
3008 if ( enmType != PDMAPICIRQ_HARDWARE
3009 && VMMGetCpuId(pVM) != idCpu)
3010 {
3011 switch (VMCPU_GET_STATE(pVCpu))
3012 {
3013 case VMCPUSTATE_STARTED_EXEC:
3014 GVMMR0SchedPokeNoGVMNoLock(pVM, idCpu);
3015 break;
3016
3017 case VMCPUSTATE_STARTED_HALTED:
3018 GVMMR0SchedWakeUpNoGVMNoLock(pVM, idCpu);
3019 break;
3020
3021 default:
3022 break; /* nothing to do in other states. */
3023 }
3024 }
3025#elif defined(IN_RING3)
3026# ifdef VBOX_WITH_REM
3027 REMR3NotifyInterruptSet(pVCpu->CTX_SUFF(pVM), pVCpu);
3028# endif
3029 if (enmType != PDMAPICIRQ_HARDWARE)
3030 VMR3NotifyCpuFFU(pVCpu->pUVCpu, VMNOTIFYFF_FLAGS_DONE_REM | VMNOTIFYFF_FLAGS_POKE);
3031#endif
3032}
3033
3034
3035/**
3036 * Clears the interrupt pending force-flag.
3037 *
3038 * @param pVCpu The cross context virtual CPU structure.
3039 * @param enmType The IRQ type.
3040 */
3041VMM_INT_DECL(void) apicClearInterruptFF(PVMCPUCC pVCpu, PDMAPICIRQ enmType)
3042{
3043#ifdef IN_RING3
3044 /* IRQ state should be loaded as-is by "LoadExec". Changes can be made from LoadDone. */
3045 Assert(pVCpu->pVMR3->enmVMState != VMSTATE_LOADING || PDMR3HasLoadedState(pVCpu->pVMR3));
3046#endif
3047
3048 /* NMI/SMI can't be cleared. */
3049 switch (enmType)
3050 {
3051 case PDMAPICIRQ_HARDWARE: VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_APIC); break;
3052 case PDMAPICIRQ_EXTINT: VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_PIC); break;
3053 default:
3054 AssertMsgFailed(("enmType=%d\n", enmType));
3055 break;
3056 }
3057
3058#if defined(IN_RING3) && defined(VBOX_WITH_REM)
3059 REMR3NotifyInterruptClear(pVCpu->CTX_SUFF(pVM), pVCpu);
3060#endif
3061}
3062
3063
3064/**
3065 * Posts an interrupt to a target APIC.
3066 *
3067 * This function handles interrupts received from the system bus or
3068 * interrupts generated locally from the LVT or via a self IPI.
3069 *
3070 * Don't use this function to try and deliver ExtINT style interrupts.
3071 *
3072 * @returns true if the interrupt was accepted, false otherwise.
3073 * @param pVCpu The cross context virtual CPU structure.
3074 * @param uVector The vector of the interrupt to be posted.
3075 * @param enmTriggerMode The trigger mode of the interrupt.
3076 * @param uSrcTag The interrupt source tag (debugging).
3077 *
3078 * @thread Any.
3079 */
3080VMM_INT_DECL(bool) apicPostInterrupt(PVMCPUCC pVCpu, uint8_t uVector, XAPICTRIGGERMODE enmTriggerMode, uint32_t uSrcTag)
3081{
3082 Assert(pVCpu);
3083 Assert(uVector > XAPIC_ILLEGAL_VECTOR_END);
3084
3085 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3086 PCAPIC pApic = VM_TO_APIC(pVM);
3087 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
3088 bool fAccepted = true;
3089
3090 STAM_PROFILE_START(&pApicCpu->StatPostIntr, a);
3091
3092 /*
3093 * Only post valid interrupt vectors.
3094 * See Intel spec. 10.5.2 "Valid Interrupt Vectors".
3095 */
3096 if (RT_LIKELY(uVector > XAPIC_ILLEGAL_VECTOR_END))
3097 {
3098 /*
3099 * If the interrupt is already pending in the IRR we can skip the
3100 * potential expensive operation of poking the guest EMT out of execution.
3101 */
3102 PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
3103 if (!apicTestVectorInReg(&pXApicPage->irr, uVector)) /* PAV */
3104 {
3105 /* Update the interrupt source tag (debugging). */
3106 if (!pApicCpu->auSrcTags[uVector])
3107 pApicCpu->auSrcTags[uVector] = uSrcTag;
3108 else
3109 pApicCpu->auSrcTags[uVector] |= RT_BIT_32(31);
3110
3111 Log2(("APIC: apicPostInterrupt: SrcCpu=%u TargetCpu=%u uVector=%#x\n", VMMGetCpuId(pVM), pVCpu->idCpu, uVector));
3112 if (enmTriggerMode == XAPICTRIGGERMODE_EDGE)
3113 {
3114 if (pApic->fPostedIntrsEnabled)
3115 { /** @todo posted-interrupt call to hardware */ }
3116 else
3117 {
3118 apicSetVectorInPib(pApicCpu->CTX_SUFF(pvApicPib), uVector);
3119 uint32_t const fAlreadySet = apicSetNotificationBitInPib((PAPICPIB)pApicCpu->CTX_SUFF(pvApicPib));
3120 if (!fAlreadySet)
3121 {
3122 Log2(("APIC: apicPostInterrupt: Setting UPDATE_APIC FF for edge-triggered intr. uVector=%#x\n", uVector));
3123 apicSetInterruptFF(pVCpu, PDMAPICIRQ_UPDATE_PENDING);
3124 }
3125 }
3126 }
3127 else
3128 {
3129 /*
3130 * Level-triggered interrupts requires updating of the TMR and thus cannot be
3131 * delivered asynchronously.
3132 */
3133 apicSetVectorInPib(&pApicCpu->ApicPibLevel, uVector);
3134 uint32_t const fAlreadySet = apicSetNotificationBitInPib(&pApicCpu->ApicPibLevel);
3135 if (!fAlreadySet)
3136 {
3137 Log2(("APIC: apicPostInterrupt: Setting UPDATE_APIC FF for level-triggered intr. uVector=%#x\n", uVector));
3138 apicSetInterruptFF(pVCpu, PDMAPICIRQ_UPDATE_PENDING);
3139 }
3140 }
3141 }
3142 else
3143 {
3144 Log2(("APIC: apicPostInterrupt: SrcCpu=%u TargetCpu=%u. Vector %#x Already in IRR, skipping\n", VMMGetCpuId(pVM),
3145 pVCpu->idCpu, uVector));
3146 STAM_COUNTER_INC(&pApicCpu->StatPostIntrAlreadyPending);
3147 }
3148 }
3149 else
3150 {
3151 fAccepted = false;
3152 apicSetError(pVCpu, XAPIC_ESR_RECV_ILLEGAL_VECTOR);
3153 }
3154
3155 STAM_PROFILE_STOP(&pApicCpu->StatPostIntr, a);
3156 return fAccepted;
3157}
3158
3159
3160/**
3161 * Starts the APIC timer.
3162 *
3163 * @param pVCpu The cross context virtual CPU structure.
3164 * @param uInitialCount The timer's Initial-Count Register (ICR), must be >
3165 * 0.
3166 * @thread Any.
3167 */
3168VMM_INT_DECL(void) apicStartTimer(PVMCPUCC pVCpu, uint32_t uInitialCount)
3169{
3170 Assert(pVCpu);
3171 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
3172 Assert(TMTimerIsLockOwner(pApicCpu->CTX_SUFF(pTimer)));
3173 Assert(uInitialCount > 0);
3174
3175 PCXAPICPAGE pXApicPage = APICCPU_TO_CXAPICPAGE(pApicCpu);
3176 uint8_t const uTimerShift = apicGetTimerShift(pXApicPage);
3177 uint64_t const cTicksToNext = (uint64_t)uInitialCount << uTimerShift;
3178
3179 Log2(("APIC%u: apicStartTimer: uInitialCount=%#RX32 uTimerShift=%u cTicksToNext=%RU64\n", pVCpu->idCpu, uInitialCount,
3180 uTimerShift, cTicksToNext));
3181
3182 /*
3183 * The assumption here is that the timer doesn't tick during this call
3184 * and thus setting a relative time to fire next is accurate. The advantage
3185 * however is updating u64TimerInitial 'atomically' while setting the next
3186 * tick.
3187 */
3188 PTMTIMER pTimer = pApicCpu->CTX_SUFF(pTimer);
3189 TMTimerSetRelative(pTimer, cTicksToNext, &pApicCpu->u64TimerInitial);
3190 apicHintTimerFreq(pApicCpu, uInitialCount, uTimerShift);
3191}
3192
3193
3194/**
3195 * Stops the APIC timer.
3196 *
3197 * @param pVCpu The cross context virtual CPU structure.
3198 * @thread Any.
3199 */
3200static void apicStopTimer(PVMCPUCC pVCpu)
3201{
3202 Assert(pVCpu);
3203 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
3204 Assert(TMTimerIsLockOwner(pApicCpu->CTX_SUFF(pTimer)));
3205
3206 Log2(("APIC%u: apicStopTimer\n", pVCpu->idCpu));
3207
3208 PTMTIMER pTimer = pApicCpu->CTX_SUFF(pTimer);
3209 TMTimerStop(pTimer); /* This will reset the hint, no need to explicitly call TMTimerSetFrequencyHint(). */
3210 pApicCpu->uHintedTimerInitialCount = 0;
3211 pApicCpu->uHintedTimerShift = 0;
3212}
3213
3214
3215/**
3216 * Queues a pending interrupt as in-service.
3217 *
3218 * This function should only be needed without virtualized APIC
3219 * registers. With virtualized APIC registers, it's sufficient to keep
3220 * the interrupts pending in the IRR as the hardware takes care of
3221 * virtual interrupt delivery.
3222 *
3223 * @returns true if the interrupt was queued to in-service interrupts,
3224 * false otherwise.
3225 * @param pVCpu The cross context virtual CPU structure.
3226 * @param u8PendingIntr The pending interrupt to queue as
3227 * in-service.
3228 *
3229 * @remarks This assumes the caller has done the necessary checks and
3230 * is ready to take actually service the interrupt (TPR,
3231 * interrupt shadow etc.)
3232 */
3233VMM_INT_DECL(bool) APICQueueInterruptToService(PVMCPUCC pVCpu, uint8_t u8PendingIntr)
3234{
3235 VMCPU_ASSERT_EMT(pVCpu);
3236
3237 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3238 PAPIC pApic = VM_TO_APIC(pVM);
3239 Assert(!pApic->fVirtApicRegsEnabled);
3240 NOREF(pApic);
3241
3242 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
3243 bool const fIsPending = apicTestVectorInReg(&pXApicPage->irr, u8PendingIntr);
3244 if (fIsPending)
3245 {
3246 apicClearVectorInReg(&pXApicPage->irr, u8PendingIntr);
3247 apicSetVectorInReg(&pXApicPage->isr, u8PendingIntr);
3248 apicUpdatePpr(pVCpu);
3249 return true;
3250 }
3251 return false;
3252}
3253
3254
3255/**
3256 * De-queues a pending interrupt from in-service.
3257 *
3258 * This undoes APICQueueInterruptToService() for premature VM-exits before event
3259 * injection.
3260 *
3261 * @param pVCpu The cross context virtual CPU structure.
3262 * @param u8PendingIntr The pending interrupt to de-queue from
3263 * in-service.
3264 */
3265VMM_INT_DECL(void) APICDequeueInterruptFromService(PVMCPUCC pVCpu, uint8_t u8PendingIntr)
3266{
3267 VMCPU_ASSERT_EMT(pVCpu);
3268
3269 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3270 PAPIC pApic = VM_TO_APIC(pVM);
3271 Assert(!pApic->fVirtApicRegsEnabled);
3272 NOREF(pApic);
3273
3274 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
3275 bool const fInService = apicTestVectorInReg(&pXApicPage->isr, u8PendingIntr);
3276 if (fInService)
3277 {
3278 apicClearVectorInReg(&pXApicPage->isr, u8PendingIntr);
3279 apicSetVectorInReg(&pXApicPage->irr, u8PendingIntr);
3280 apicUpdatePpr(pVCpu);
3281 }
3282}
3283
3284
3285/**
3286 * Updates pending interrupts from the pending-interrupt bitmaps to the IRR.
3287 *
3288 * @param pVCpu The cross context virtual CPU structure.
3289 *
3290 * @note NEM/win is ASSUMING the an up to date TPR is not required here.
3291 */
3292VMMDECL(void) APICUpdatePendingInterrupts(PVMCPUCC pVCpu)
3293{
3294 VMCPU_ASSERT_EMT_OR_NOT_RUNNING(pVCpu);
3295
3296 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
3297 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
3298 bool fHasPendingIntrs = false;
3299
3300 Log3(("APIC%u: APICUpdatePendingInterrupts:\n", pVCpu->idCpu));
3301 STAM_PROFILE_START(&pApicCpu->StatUpdatePendingIntrs, a);
3302
3303 /* Update edge-triggered pending interrupts. */
3304 PAPICPIB pPib = (PAPICPIB)pApicCpu->CTX_SUFF(pvApicPib);
3305 for (;;)
3306 {
3307 uint32_t const fAlreadySet = apicClearNotificationBitInPib((PAPICPIB)pApicCpu->CTX_SUFF(pvApicPib));
3308 if (!fAlreadySet)
3309 break;
3310
3311 AssertCompile(RT_ELEMENTS(pXApicPage->irr.u) == 2 * RT_ELEMENTS(pPib->au64VectorBitmap));
3312 for (size_t idxPib = 0, idxReg = 0; idxPib < RT_ELEMENTS(pPib->au64VectorBitmap); idxPib++, idxReg += 2)
3313 {
3314 uint64_t const u64Fragment = ASMAtomicXchgU64(&pPib->au64VectorBitmap[idxPib], 0);
3315 if (u64Fragment)
3316 {
3317 uint32_t const u32FragmentLo = RT_LO_U32(u64Fragment);
3318 uint32_t const u32FragmentHi = RT_HI_U32(u64Fragment);
3319
3320 pXApicPage->irr.u[idxReg].u32Reg |= u32FragmentLo;
3321 pXApicPage->irr.u[idxReg + 1].u32Reg |= u32FragmentHi;
3322
3323 pXApicPage->tmr.u[idxReg].u32Reg &= ~u32FragmentLo;
3324 pXApicPage->tmr.u[idxReg + 1].u32Reg &= ~u32FragmentHi;
3325 fHasPendingIntrs = true;
3326 }
3327 }
3328 }
3329
3330 /* Update level-triggered pending interrupts. */
3331 pPib = (PAPICPIB)&pApicCpu->ApicPibLevel;
3332 for (;;)
3333 {
3334 uint32_t const fAlreadySet = apicClearNotificationBitInPib((PAPICPIB)&pApicCpu->ApicPibLevel);
3335 if (!fAlreadySet)
3336 break;
3337
3338 AssertCompile(RT_ELEMENTS(pXApicPage->irr.u) == 2 * RT_ELEMENTS(pPib->au64VectorBitmap));
3339 for (size_t idxPib = 0, idxReg = 0; idxPib < RT_ELEMENTS(pPib->au64VectorBitmap); idxPib++, idxReg += 2)
3340 {
3341 uint64_t const u64Fragment = ASMAtomicXchgU64(&pPib->au64VectorBitmap[idxPib], 0);
3342 if (u64Fragment)
3343 {
3344 uint32_t const u32FragmentLo = RT_LO_U32(u64Fragment);
3345 uint32_t const u32FragmentHi = RT_HI_U32(u64Fragment);
3346
3347 pXApicPage->irr.u[idxReg].u32Reg |= u32FragmentLo;
3348 pXApicPage->irr.u[idxReg + 1].u32Reg |= u32FragmentHi;
3349
3350 pXApicPage->tmr.u[idxReg].u32Reg |= u32FragmentLo;
3351 pXApicPage->tmr.u[idxReg + 1].u32Reg |= u32FragmentHi;
3352 fHasPendingIntrs = true;
3353 }
3354 }
3355 }
3356
3357 STAM_PROFILE_STOP(&pApicCpu->StatUpdatePendingIntrs, a);
3358 Log3(("APIC%u: APICUpdatePendingInterrupts: fHasPendingIntrs=%RTbool\n", pVCpu->idCpu, fHasPendingIntrs));
3359
3360 if ( fHasPendingIntrs
3361 && !VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC))
3362 apicSignalNextPendingIntr(pVCpu);
3363}
3364
3365
3366/**
3367 * Gets the highest priority pending interrupt.
3368 *
3369 * @returns true if any interrupt is pending, false otherwise.
3370 * @param pVCpu The cross context virtual CPU structure.
3371 * @param pu8PendingIntr Where to store the interrupt vector if the
3372 * interrupt is pending.
3373 */
3374VMM_INT_DECL(bool) APICGetHighestPendingInterrupt(PVMCPUCC pVCpu, uint8_t *pu8PendingIntr)
3375{
3376 VMCPU_ASSERT_EMT(pVCpu);
3377 return apicGetHighestPendingInterrupt(pVCpu, pu8PendingIntr);
3378}
3379
3380
3381/**
3382 * Posts an interrupt to a target APIC, Hyper-V interface.
3383 *
3384 * @returns true if the interrupt was accepted, false otherwise.
3385 * @param pVCpu The cross context virtual CPU structure.
3386 * @param uVector The vector of the interrupt to be posted.
3387 * @param fAutoEoi Whether this interrupt has automatic EOI
3388 * treatment.
3389 * @param enmTriggerMode The trigger mode of the interrupt.
3390 *
3391 * @thread Any.
3392 */
3393VMM_INT_DECL(void) APICHvSendInterrupt(PVMCPUCC pVCpu, uint8_t uVector, bool fAutoEoi, XAPICTRIGGERMODE enmTriggerMode)
3394{
3395 Assert(pVCpu);
3396 Assert(!fAutoEoi); /** @todo AutoEOI. */
3397 RT_NOREF(fAutoEoi);
3398 apicPostInterrupt(pVCpu, uVector, enmTriggerMode, 0 /* uSrcTag */);
3399}
3400
3401
3402/**
3403 * Sets the Task Priority Register (TPR), Hyper-V interface.
3404 *
3405 * @returns Strict VBox status code.
3406 * @param pVCpu The cross context virtual CPU structure.
3407 * @param uTpr The TPR value to set.
3408 *
3409 * @remarks Validates like in x2APIC mode.
3410 */
3411VMM_INT_DECL(VBOXSTRICTRC) APICHvSetTpr(PVMCPUCC pVCpu, uint8_t uTpr)
3412{
3413 Assert(pVCpu);
3414 VMCPU_ASSERT_EMT(pVCpu);
3415 return apicSetTprEx(pVCpu, uTpr, true /* fForceX2ApicBehaviour */);
3416}
3417
3418
3419/**
3420 * Gets the Task Priority Register (TPR), Hyper-V interface.
3421 *
3422 * @returns The TPR value.
3423 * @param pVCpu The cross context virtual CPU structure.
3424 */
3425VMM_INT_DECL(uint8_t) APICHvGetTpr(PVMCPUCC pVCpu)
3426{
3427 Assert(pVCpu);
3428 VMCPU_ASSERT_EMT(pVCpu);
3429
3430 /*
3431 * The APIC could be operating in xAPIC mode and thus we should not use the apicReadMsr()
3432 * interface which validates the APIC mode and will throw a #GP(0) if not in x2APIC mode.
3433 * We could use the apicReadRegister() MMIO interface, but why bother getting the PDMDEVINS
3434 * pointer, so just directly read the APIC page.
3435 */
3436 PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
3437 return apicReadRaw32(pXApicPage, XAPIC_OFF_TPR);
3438}
3439
3440
3441/**
3442 * Sets the Interrupt Command Register (ICR), Hyper-V interface.
3443 *
3444 * @returns Strict VBox status code.
3445 * @param pVCpu The cross context virtual CPU structure.
3446 * @param uIcr The ICR value to set.
3447 */
3448VMM_INT_DECL(VBOXSTRICTRC) APICHvSetIcr(PVMCPUCC pVCpu, uint64_t uIcr)
3449{
3450 Assert(pVCpu);
3451 VMCPU_ASSERT_EMT(pVCpu);
3452 return apicSetIcr(pVCpu, uIcr, VINF_CPUM_R3_MSR_WRITE);
3453}
3454
3455
3456/**
3457 * Gets the Interrupt Command Register (ICR), Hyper-V interface.
3458 *
3459 * @returns The ICR value.
3460 * @param pVCpu The cross context virtual CPU structure.
3461 */
3462VMM_INT_DECL(uint64_t) APICHvGetIcr(PVMCPUCC pVCpu)
3463{
3464 Assert(pVCpu);
3465 VMCPU_ASSERT_EMT(pVCpu);
3466 return apicGetIcrNoCheck(pVCpu);
3467}
3468
3469
3470/**
3471 * Sets the End-Of-Interrupt (EOI) register, Hyper-V interface.
3472 *
3473 * @returns Strict VBox status code.
3474 * @param pVCpu The cross context virtual CPU structure.
3475 * @param uEoi The EOI value.
3476 */
3477VMM_INT_DECL(VBOXSTRICTRC) APICHvSetEoi(PVMCPUCC pVCpu, uint32_t uEoi)
3478{
3479 Assert(pVCpu);
3480 VMCPU_ASSERT_EMT_OR_NOT_RUNNING(pVCpu);
3481 return apicSetEoi(pVCpu, uEoi, VINF_CPUM_R3_MSR_WRITE, true /* fForceX2ApicBehaviour */);
3482}
3483
3484
3485/**
3486 * Gets the APIC page pointers for the specified VCPU.
3487 *
3488 * @returns VBox status code.
3489 * @param pVCpu The cross context virtual CPU structure.
3490 * @param pHCPhys Where to store the host-context physical address.
3491 * @param pR0Ptr Where to store the ring-0 address.
3492 * @param pR3Ptr Where to store the ring-3 address (optional).
3493 */
3494VMM_INT_DECL(int) APICGetApicPageForCpu(PCVMCPUCC pVCpu, PRTHCPHYS pHCPhys, PRTR0PTR pR0Ptr, PRTR3PTR pR3Ptr)
3495{
3496 AssertReturn(pVCpu, VERR_INVALID_PARAMETER);
3497 AssertReturn(pHCPhys, VERR_INVALID_PARAMETER);
3498 AssertReturn(pR0Ptr, VERR_INVALID_PARAMETER);
3499
3500 Assert(PDMHasApic(pVCpu->CTX_SUFF(pVM)));
3501
3502 PCAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
3503 *pHCPhys = pApicCpu->HCPhysApicPage;
3504 *pR0Ptr = pApicCpu->pvApicPageR0;
3505 if (pR3Ptr)
3506 *pR3Ptr = pApicCpu->pvApicPageR3;
3507 return VINF_SUCCESS;
3508}
3509
3510
3511/**
3512 * APIC device registration structure.
3513 */
3514const PDMDEVREG g_DeviceAPIC =
3515{
3516 /* .u32Version = */ PDM_DEVREG_VERSION,
3517 /* .uReserved0 = */ 0,
3518 /* .szName = */ "apic",
3519 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_R0,
3520 /* .fClass = */ PDM_DEVREG_CLASS_PIC,
3521 /* .cMaxInstances = */ 1,
3522 /* .uSharedVersion = */ 42,
3523 /* .cbInstanceShared = */ sizeof(APICDEV),
3524 /* .cbInstanceCC = */ 0,
3525 /* .cbInstanceRC = */ 0,
3526 /* .cMaxPciDevices = */ 0,
3527 /* .cMaxMsixVectors = */ 0,
3528 /* .pszDescription = */ "Advanced Programmable Interrupt Controller",
3529#if defined(IN_RING3)
3530 /* .szRCMod = */ "VMMRC.rc",
3531 /* .szR0Mod = */ "VMMR0.r0",
3532 /* .pfnConstruct = */ apicR3Construct,
3533 /* .pfnDestruct = */ apicR3Destruct,
3534 /* .pfnRelocate = */ apicR3Relocate,
3535 /* .pfnMemSetup = */ NULL,
3536 /* .pfnPowerOn = */ NULL,
3537 /* .pfnReset = */ apicR3Reset,
3538 /* .pfnSuspend = */ NULL,
3539 /* .pfnResume = */ NULL,
3540 /* .pfnAttach = */ NULL,
3541 /* .pfnDetach = */ NULL,
3542 /* .pfnQueryInterface = */ NULL,
3543 /* .pfnInitComplete = */ apicR3InitComplete,
3544 /* .pfnPowerOff = */ NULL,
3545 /* .pfnSoftReset = */ NULL,
3546 /* .pfnReserved0 = */ NULL,
3547 /* .pfnReserved1 = */ NULL,
3548 /* .pfnReserved2 = */ NULL,
3549 /* .pfnReserved3 = */ NULL,
3550 /* .pfnReserved4 = */ NULL,
3551 /* .pfnReserved5 = */ NULL,
3552 /* .pfnReserved6 = */ NULL,
3553 /* .pfnReserved7 = */ NULL,
3554#elif defined(IN_RING0)
3555 /* .pfnEarlyConstruct = */ NULL,
3556 /* .pfnConstruct = */ NULL,
3557 /* .pfnDestruct = */ NULL,
3558 /* .pfnFinalDestruct = */ NULL,
3559 /* .pfnRequest = */ NULL,
3560 /* .pfnReserved0 = */ NULL,
3561 /* .pfnReserved1 = */ NULL,
3562 /* .pfnReserved2 = */ NULL,
3563 /* .pfnReserved3 = */ NULL,
3564 /* .pfnReserved4 = */ NULL,
3565 /* .pfnReserved5 = */ NULL,
3566 /* .pfnReserved6 = */ NULL,
3567 /* .pfnReserved7 = */ NULL,
3568#elif defined(IN_RC)
3569 /* .pfnConstruct = */ NULL,
3570 /* .pfnReserved0 = */ NULL,
3571 /* .pfnReserved1 = */ NULL,
3572 /* .pfnReserved2 = */ NULL,
3573 /* .pfnReserved3 = */ NULL,
3574 /* .pfnReserved4 = */ NULL,
3575 /* .pfnReserved5 = */ NULL,
3576 /* .pfnReserved6 = */ NULL,
3577 /* .pfnReserved7 = */ NULL,
3578#else
3579# error "Not in IN_RING3, IN_RING0 or IN_RC!"
3580#endif
3581 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
3582};
3583
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