VirtualBox

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

Last change on this file since 93718 was 93655, checked in by vboxsync, 3 years ago

VMM/TM,VMM/*: Moved RTTIMENANOTSDATAR0 into the ring-0 only part of the VM structure. Added a VMCC_CTX macro for selecting between tm and tmr0 VM components depending on the compilation context. Added a bunch of missing padding checks for GVM. bugref:10094

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