VirtualBox

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

Last change on this file since 60741 was 60741, checked in by vboxsync, 9 years ago

VMM/APIC: Eliminate multiplication with shift when possible.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 93.6 KB
Line 
1/* $Id: APICAll.cpp 60741 2016-04-28 13:22:07Z vboxsync $ */
2/** @file
3 * APIC - Advanced Programmable Interrupt Controller - All Contexts.
4 */
5
6/*
7 * Copyright (C) 2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_DEV_APIC
23#include "APICInternal.h"
24#include <VBox/vmm/pdmdev.h>
25#include <VBox/vmm/vm.h>
26#include <VBox/vmm/vmcpuset.h>
27
28/*********************************************************************************************************************************
29* Global Variables *
30*********************************************************************************************************************************/
31#if XAPIC_HARDWARE_VERSION == XAPIC_HARDWARE_VERSION_P4
32/** An ordered array of valid LVT masks. */
33static const uint32_t g_au32LvtValidMasks[] =
34{
35 XAPIC_LVT_TIMER,
36 XAPIC_LVT_THERMAL,
37 XAPIC_LVT_PERF,
38 XAPIC_LVT_LINT0,
39 XAPIC_LVT_LINT1,
40 XAPIC_LVT_ERROR
41};
42#endif
43
44#if 0
45/** @todo CMCI */
46static const uint32_t g_au32LvtExtValidMask[] =
47{
48 XAPIC_LVT_CMCI
49};
50#endif
51
52
53/**
54 * Checks if a vector is set in an APIC 256-bit sparse register.
55 *
56 * @returns true if the specified vector is set, false otherwise.
57 * @param pApicReg The APIC 256-bit spare register.
58 * @param uVector The vector to check if set.
59 */
60DECLINLINE(bool) apicTestVectorInReg(const volatile XAPIC256BITREG *pApicReg, uint8_t uVector)
61{
62 const volatile uint8_t *pbBitmap = (const volatile uint8_t *)&pApicReg->u[0];
63 return ASMBitTest(pbBitmap + XAPIC_REG256_VECTOR_OFF(uVector), XAPIC_REG256_VECTOR_BIT(uVector));
64}
65
66
67/**
68 * Sets the vector in an APIC 256-bit sparse register.
69 *
70 * @param pApicReg The APIC 256-bit spare register.
71 * @param uVector The vector to set.
72 */
73DECLINLINE(void) apicSetVectorInReg(volatile XAPIC256BITREG *pApicReg, uint8_t uVector)
74{
75 volatile uint8_t *pbBitmap = (volatile uint8_t *)&pApicReg->u[0];
76 ASMAtomicBitSet(pbBitmap + XAPIC_REG256_VECTOR_OFF(uVector), XAPIC_REG256_VECTOR_BIT(uVector));
77}
78
79
80/**
81 * Clears the vector in an APIC 256-bit sparse register.
82 *
83 * @param pApicReg The APIC 256-bit spare register.
84 * @param uVector The vector to clear.
85 */
86DECLINLINE(void) apicClearVectorInReg(volatile XAPIC256BITREG *pApicReg, uint8_t uVector)
87{
88 volatile uint8_t *pbBitmap = (volatile uint8_t *)&pApicReg->u[0];
89 ASMAtomicBitClear(pbBitmap + XAPIC_REG256_VECTOR_OFF(uVector), XAPIC_REG256_VECTOR_BIT(uVector));
90}
91
92
93/**
94 * Checks if a vector is set in an APIC Pending-Interrupt Bitmap (PIB).
95 *
96 * @returns true if the specified vector is set, false otherwise.
97 * @param pvPib Opaque pointer to the PIB.
98 * @param uVector The vector to check if set.
99 */
100DECLINLINE(bool) apicTestVectorInPib(volatile void *pvPib, uint8_t uVector)
101{
102 return ASMBitTest(pvPib, uVector);
103}
104
105
106/**
107 * Atomically sets the PIB notification bit.
108 *
109 * @returns non-zero if the bit was already set, 0 otherwise.
110 * @param pApicPib Pointer to the PIB.
111 */
112DECLINLINE(uint32_t) apicSetNotificationBitInPib(PAPICPIB pApicPib)
113{
114 return ASMAtomicXchgU32(&pApicPib->fOutstandingNotification, RT_BIT_32(31));
115}
116
117
118/**
119 * Atomically tests and clears the PIB notification bit.
120 *
121 * @returns non-zero if the bit was already set, 0 otherwise.
122 * @param pApicPib Pointer to the PIB.
123 */
124DECLINLINE(uint32_t) apicClearNotificationBitInPib(PAPICPIB pApicPib)
125{
126 return ASMAtomicXchgU32(&pApicPib->fOutstandingNotification, UINT32_C(0));
127}
128
129
130/**
131 * Sets the vector in an APIC Pending-Interrupt Bitmap (PIB).
132 *
133 * @param pvPib Opaque pointer to the PIB.
134 * @param uVector The vector to set.
135 */
136DECLINLINE(void) apicSetVectorInPib(volatile void *pvPib, uint8_t uVector)
137{
138 ASMAtomicBitSet(pvPib, uVector);
139}
140
141
142/**
143 * Clears the vector in an APIC Pending-Interrupt Bitmap (PIB).
144 *
145 * @param pvPib Opaque pointer to the PIB.
146 * @param uVector The vector to clear.
147 */
148DECLINLINE(void) apicClearVectorInPib(volatile void *pvPib, uint8_t uVector)
149{
150 ASMAtomicBitClear(pvPib, uVector);
151}
152
153
154/**
155 * Atomically OR's a fragment (32 vectors) into an APIC 256-bit sparse
156 * register.
157 *
158 * @param pApicReg The APIC 256-bit spare register.
159 * @param idxFragment The index of the 32-bit fragment in @a
160 * pApicReg.
161 * @param u32Fragment The 32-bit vector fragment to OR.
162 */
163DECLINLINE(void) apicOrVectorsToReg(volatile XAPIC256BITREG *pApicReg, size_t idxFragment, uint32_t u32Fragment)
164{
165 Assert(idxFragment < RT_ELEMENTS(pApicReg->u));
166 ASMAtomicOrU32(&pApicReg->u[idxFragment].u32Reg, u32Fragment);
167}
168
169
170/**
171 * Atomically AND's a fragment (32 vectors) into an APIC
172 * 256-bit sparse register.
173 *
174 * @param pApicReg The APIC 256-bit spare register.
175 * @param idxFragment The index of the 32-bit fragment in @a
176 * pApicReg.
177 * @param u32Fragment The 32-bit vector fragment to AND.
178 */
179DECLINLINE(void) apicAndVectorsToReg(volatile XAPIC256BITREG *pApicReg, size_t idxFragment, uint32_t u32Fragment)
180{
181 Assert(idxFragment < RT_ELEMENTS(pApicReg->u));
182 ASMAtomicAndU32(&pApicReg->u[idxFragment].u32Reg, u32Fragment);
183}
184
185
186/**
187 * Reports and returns appropriate error code for invalid MSR accesses.
188 *
189 * @returns Strict VBox status code.
190 * @retval VINF_CPUM_R3_MSR_WRITE if the MSR write could not be serviced in the
191 * current context (raw-mode or ring-0).
192 * @retval VINF_CPUM_R3_MSR_READ if the MSR read could not be serviced in the
193 * current context (raw-mode or ring-0).
194 * @retval VERR_CPUM_RAISE_GP_0 on failure, the caller is expected to take the
195 * appropriate actions.
196 *
197 * @param pVCpu The cross context virtual CPU structure.
198 * @param u32Reg The MSR being accessed.
199 * @param enmAccess The invalid-access type.
200 */
201static VBOXSTRICTRC apicMsrAccessError(PVMCPU pVCpu, uint32_t u32Reg, APICMSRACCESS enmAccess)
202{
203 static struct
204 {
205 const char *pszBefore; /* The error message before printing the MSR index */
206 const char *pszAfter; /* The error message after printing the MSR index */
207 int rcRZ; /* The RZ error code */
208 } const s_aAccess[] =
209 {
210 { "read MSR", " while not in x2APIC mode", VINF_CPUM_R3_MSR_READ },
211 { "write MSR", " while not in x2APIC mode", VINF_CPUM_R3_MSR_WRITE },
212 { "read reserved/unknown MSR", "", VINF_CPUM_R3_MSR_READ },
213 { "write reserved/unknown MSR", "", VINF_CPUM_R3_MSR_WRITE },
214 { "read write-only MSR", "", VINF_CPUM_R3_MSR_READ },
215 { "write read-only MSR", "", VINF_CPUM_R3_MSR_WRITE },
216 { "read reserved bits of MSR", "", VINF_CPUM_R3_MSR_READ },
217 { "write reserved bits of MSR", "", VINF_CPUM_R3_MSR_WRITE },
218 { "write an invalid value to MSR", "", VINF_CPUM_R3_MSR_WRITE },
219 { "write MSR", "disallowed by configuration", VINF_CPUM_R3_MSR_WRITE }
220 };
221 AssertCompile(RT_ELEMENTS(s_aAccess) == APICMSRACCESS_COUNT);
222
223 size_t const i = enmAccess;
224 Assert(i < RT_ELEMENTS(s_aAccess));
225#ifdef IN_RING3
226 LogRelMax(5, ("APIC%u: Attempt to %s (%#x)%s -> #GP(0)\n", pVCpu->idCpu, s_aAccess[i].pszBefore, u32Reg,
227 s_aAccess[i].pszAfter));
228 return VERR_CPUM_RAISE_GP_0;
229#else
230 return s_aAccess[i].rcRZ;
231#endif
232}
233
234
235/**
236 * Gets the descriptive APIC mode.
237 *
238 * @returns The name.
239 * @param enmMode The xAPIC mode.
240 */
241const char *apicGetModeName(APICMODE enmMode)
242{
243 switch (enmMode)
244 {
245 case APICMODE_DISABLED: return "Disabled";
246 case APICMODE_XAPIC: return "xAPIC";
247 case APICMODE_X2APIC: return "x2APIC";
248 default: break;
249 }
250 return "Invalid";
251}
252
253
254/**
255 * Gets the descriptive destination format name.
256 *
257 * @returns The destination format name.
258 * @param enmDestFormat The destination format.
259 */
260const char *apicGetDestFormatName(XAPICDESTFORMAT enmDestFormat)
261{
262 switch (enmDestFormat)
263 {
264 case XAPICDESTFORMAT_FLAT: return "Flat";
265 case XAPICDESTFORMAT_CLUSTER: return "Cluster";
266 default: break;
267 }
268 return "Invalid";
269}
270
271
272/**
273 * Gets the descriptive delivery mode name.
274 *
275 * @returns The delivery mode name.
276 * @param enmDeliveryMode The delivery mode.
277 */
278const char *apicGetDeliveryModeName(XAPICDELIVERYMODE enmDeliveryMode)
279{
280 switch (enmDeliveryMode)
281 {
282 case XAPICDELIVERYMODE_FIXED: return "Fixed";
283 case XAPICDELIVERYMODE_LOWEST_PRIO: return "Lowest-priority";
284 case XAPICDELIVERYMODE_SMI: return "SMI";
285 case XAPICDELIVERYMODE_NMI: return "NMI";
286 case XAPICDELIVERYMODE_INIT: return "INIT";
287 case XAPICDELIVERYMODE_STARTUP: return "SIPI";
288 case XAPICDELIVERYMODE_EXTINT: return "ExtINT";
289 default: break;
290 }
291 return "Invalid";
292}
293
294
295/**
296 * Gets the descriptive destination mode name.
297 *
298 * @returns The destination mode name.
299 * @param enmDestMode The destination mode.
300 */
301const char *apicGetDestModeName(XAPICDESTMODE enmDestMode)
302{
303 switch (enmDestMode)
304 {
305 case XAPICDESTMODE_PHYSICAL: return "Physical";
306 case XAPICDESTMODE_LOGICAL: return "Logical";
307 default: break;
308 }
309 return "Invalid";
310}
311
312
313/**
314 * Gets the descriptive trigger mode name.
315 *
316 * @returns The trigger mode name.
317 * @param enmTriggerMode The trigger mode.
318 */
319const char *apicGetTriggerModeName(XAPICTRIGGERMODE enmTriggerMode)
320{
321 switch (enmTriggerMode)
322 {
323 case XAPICTRIGGERMODE_EDGE: return "Edge";
324 case XAPICTRIGGERMODE_LEVEL: return "Level";
325 default: break;
326 }
327 return "Invalid";
328}
329
330
331/**
332 * Gets the destination shorthand name.
333 *
334 * @returns The destination shorthand name.
335 * @param enmDestShorthand The destination shorthand.
336 */
337const char *apicGetDestShorthandName(XAPICDESTSHORTHAND enmDestShorthand)
338{
339 switch (enmDestShorthand)
340 {
341 case XAPICDESTSHORTHAND_NONE: return "None";
342 case XAPICDESTSHORTHAND_SELF: return "Self";
343 case XAPIDDESTSHORTHAND_ALL_INCL_SELF: return "All including self";
344 case XAPICDESTSHORTHAND_ALL_EXCL_SELF: return "All excluding self";
345 default: break;
346 }
347 return "Invalid";
348}
349
350
351/**
352 * Gets the timer mode name.
353 *
354 * @returns The timer mode name.
355 * @param enmTimerMode The timer mode.
356 */
357const char *apicGetTimerModeName(XAPICTIMERMODE enmTimerMode)
358{
359 switch (enmTimerMode)
360 {
361 case XAPICTIMERMODE_ONESHOT: return "One-shot";
362 case XAPICTIMERMODE_PERIODIC: return "Periodic";
363 case XAPICTIMERMODE_TSC_DEADLINE: return "TSC deadline";
364 default: break;
365 }
366 return "Invalid";
367}
368
369
370/**
371 * Gets the APIC mode given the base MSR value.
372 *
373 * @returns The APIC mode.
374 * @param uApicBaseMsr The APIC Base MSR value.
375 */
376APICMODE apicGetMode(uint64_t uApicBaseMsr)
377{
378 uint32_t const uMode = MSR_APICBASE_GET_MODE(uApicBaseMsr);
379 APICMODE const enmMode = (APICMODE)uMode;
380#ifdef VBOX_STRICT
381 /* Paranoia. */
382 switch (uMode)
383 {
384 case APICMODE_DISABLED:
385 case APICMODE_INVALID:
386 case APICMODE_XAPIC:
387 case APICMODE_X2APIC:
388 break;
389 default:
390 AssertMsgFailed(("Invalid mode"));
391 }
392#endif
393 return enmMode;
394}
395
396
397/**
398 * Returns whether the APIC is hardware enabled or not.
399 *
400 * @returns true if enabled, false otherwise.
401 */
402DECLINLINE(bool) apicIsEnabled(PVMCPU pVCpu)
403{
404 PCAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
405 return MSR_APICBASE_IS_ENABLED(pApicCpu->uApicBaseMsr);
406}
407
408
409/**
410 * Finds the most significant set bit in an APIC 256-bit sparse register.
411 *
412 * @returns @a rcNotFound if no bit was set, 0-255 otherwise.
413 * @param pReg The APIC 256-bit sparse register.
414 * @param rcNotFound What to return when no bit is set.
415 */
416static int apicGetHighestSetBit(volatile const XAPIC256BITREG *pReg, int rcNotFound)
417{
418 ssize_t const cFragments = RT_ELEMENTS(pReg->u);
419 unsigned const uFragmentShift = 5;
420 AssertCompile(1 << uFragmentShift == sizeof(pReg->u[0].u32Reg) * 8);
421 for (ssize_t i = cFragments - 1; i >= 0; i--)
422 {
423 uint32_t const uFragment = pReg->u[i].u32Reg;
424 if (uFragment)
425 {
426 unsigned idxSetBit = ASMBitLastSetU32(uFragment);
427 --idxSetBit;
428 idxSetBit |= i << uFragmentShift;
429 return idxSetBit;
430 }
431 }
432 return rcNotFound;
433}
434
435
436/**
437 * Reads a 32-bit register at a specified offset.
438 *
439 * @returns The value at the specified offset.
440 * @param pXApicPage The xAPIC page.
441 * @param offReg The offset of the register being read.
442 */
443DECLINLINE(uint32_t) apicReadRaw32(PCXAPICPAGE pXApicPage, uint16_t offReg)
444{
445 Assert(offReg < sizeof(*pXApicPage) - sizeof(uint32_t));
446 uint8_t const *pbXApic = (const uint8_t *)pXApicPage;
447 uint32_t const uValue = *(const uint32_t *)(pbXApic + offReg);
448 return uValue;
449}
450
451
452/**
453 * Writes a 32-bit register at a specified offset.
454 *
455 * @param pXApicPage The xAPIC page.
456 * @param offReg The offset of the register being written.
457 * @param uReg The value of the register.
458 */
459DECLINLINE(void) apicWriteRaw32(PXAPICPAGE pXApicPage, uint16_t offReg, uint32_t uReg)
460{
461 Assert(offReg < sizeof(*pXApicPage) - sizeof(uint32_t));
462 uint8_t *pbXApic = (uint8_t *)pXApicPage;
463 *(uint32_t *)(pbXApic + offReg) = uReg;
464}
465
466
467/**
468 * Sets an error in the internal ESR of the specified APIC.
469 *
470 * @param pVCpu The cross context virtual CPU structure.
471 * @param uError The error.
472 * @thread Any.
473 */
474DECLINLINE(void) apicSetError(PVMCPU pVCpu, uint32_t uError)
475{
476 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
477 ASMAtomicOrU32(&pApicCpu->uEsrInternal, uError);
478}
479
480
481/**
482 * Clears all errors in the internal ESR.
483 *
484 * @returns The value of the internal ESR before clearing.
485 * @param pVCpu The cross context virtual CPU structure.
486 */
487DECLINLINE(uint32_t) apicClearAllErrors(PVMCPU pVCpu)
488{
489 VMCPU_ASSERT_EMT(pVCpu);
490 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
491 return ASMAtomicXchgU32(&pApicCpu->uEsrInternal, 0);
492}
493
494
495/**
496 * Signals the guest if a pending interrupt is ready to be serviced.
497 *
498 * @param pVCpu The cross context virtual CPU structure.
499 */
500static void apicSignalNextPendingIntr(PVMCPU pVCpu)
501{
502 VMCPU_ASSERT_EMT(pVCpu);
503
504 PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
505 if (pXApicPage->svr.u.fApicSoftwareEnable)
506 {
507 int const irrv = apicGetHighestSetBit(&pXApicPage->irr, -1 /* rcNotFound */);
508 if (irrv >= 0)
509 {
510 Assert(irrv <= (int)UINT8_MAX);
511 uint8_t const uVector = irrv;
512 uint8_t const uPpr = pXApicPage->ppr.u8Ppr;
513 if ( !uPpr
514 || XAPIC_PPR_GET_PP(uVector) > XAPIC_PPR_GET_PP(uPpr))
515 {
516 Log2(("APIC%u: apicSignalNextPendingIntr: Signaling pending interrupt\n", pVCpu->idCpu));
517 APICSetInterruptFF(pVCpu, PDMAPICIRQ_HARDWARE);
518 }
519 }
520 }
521 else
522 {
523 Log2(("APIC%u: apicSignalNextPendingIntr: APIC software-disabled, clearing pending interrupt\n", pVCpu->idCpu));
524 APICClearInterruptFF(pVCpu, PDMAPICIRQ_HARDWARE);
525 }
526}
527
528
529/**
530 * Sets the Spurious-Interrupt Vector Register (SVR).
531 *
532 * @returns Strict VBox status code.
533 * @param pVCpu The cross context virtual CPU structure.
534 * @param uSvr The SVR value.
535 */
536static VBOXSTRICTRC apicSetSvr(PVMCPU pVCpu, uint32_t uSvr)
537{
538 VMCPU_ASSERT_EMT(pVCpu);
539
540 uint32_t uValidMask = XAPIC_SVR;
541 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
542 if (pXApicPage->version.u.fEoiBroadcastSupression)
543 uValidMask |= XAPIC_SVR_SUPRESS_EOI_BROADCAST;
544
545 if ( XAPIC_IN_X2APIC_MODE(pVCpu)
546 && (uSvr & ~uValidMask))
547 return apicMsrAccessError(pVCpu, MSR_IA32_X2APIC_SVR, APICMSRACCESS_WRITE_RSVD_BITS);
548
549 apicWriteRaw32(pXApicPage, XAPIC_OFF_SVR, uSvr);
550 if (!pXApicPage->svr.u.fApicSoftwareEnable)
551 {
552 /** @todo CMCI. */
553 pXApicPage->lvt_timer.u.u1Mask = 1;
554#if XAPIC_HARDWARE_VERSION == XAPIC_HARDWARE_VERSION_P4
555 pXApicPage->lvt_thermal.u.u1Mask = 1;
556#endif
557 pXApicPage->lvt_perf.u.u1Mask = 1;
558 pXApicPage->lvt_lint0.u.u1Mask = 1;
559 pXApicPage->lvt_lint1.u.u1Mask = 1;
560 pXApicPage->lvt_error.u.u1Mask = 1;
561 }
562 return VINF_SUCCESS;
563}
564
565
566/**
567 * Sends an interrupt to one or more APICs.
568 *
569 * @returns Strict VBox status code.
570 * @param pVM The cross context VM structure.
571 * @param pVCpu The cross context virtual CPU structure, can be
572 * NULL if the source of the interrupt is not an
573 * APIC (for e.g. a bus).
574 * @param uVector The interrupt vector.
575 * @param enmTriggerMode The trigger mode.
576 * @param enmDeliveryMode The delivery mode.
577 * @param pDestCpuSet The destination CPU set.
578 * @param rcRZ The return code if the operation cannot be
579 * performed in the current context.
580 */
581static VBOXSTRICTRC apicSendIntr(PVM pVM, PVMCPU pVCpu, uint8_t uVector, XAPICTRIGGERMODE enmTriggerMode,
582 XAPICDELIVERYMODE enmDeliveryMode, PCVMCPUSET pDestCpuSet, int rcRZ)
583{
584 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
585 VMCPUID const cCpus = pVM->cCpus;
586 switch (enmDeliveryMode)
587 {
588 case XAPICDELIVERYMODE_FIXED:
589 {
590 for (VMCPUID idCpu = 0; idCpu < cCpus; idCpu++)
591 {
592 if ( VMCPUSET_IS_PRESENT(pDestCpuSet, idCpu)
593 && apicIsEnabled(&pVM->aCpus[idCpu]))
594 APICPostInterrupt(&pVM->aCpus[idCpu], uVector, enmTriggerMode);
595 }
596 break;
597 }
598
599 case XAPICDELIVERYMODE_LOWEST_PRIO:
600 {
601 VMCPUID const idCpu = VMCPUSET_FIND_FIRST_PRESENT(pDestCpuSet);
602 if ( idCpu < pVM->cCpus
603 && apicIsEnabled(&pVM->aCpus[idCpu]))
604 APICPostInterrupt(&pVM->aCpus[idCpu], uVector, enmTriggerMode);
605 else
606 Log2(("APIC: apicSendIntr: No CPU found for lowest-priority delivery mode!\n"));
607 break;
608 }
609
610 case XAPICDELIVERYMODE_SMI:
611 {
612 for (VMCPUID idCpu = 0; idCpu < cCpus; idCpu++)
613 {
614 if (VMCPUSET_IS_PRESENT(pDestCpuSet, idCpu))
615 {
616 Log2(("APIC: apicSendIntr: Raising SMI on VCPU%u\n", idCpu));
617 APICSetInterruptFF(&pVM->aCpus[idCpu], PDMAPICIRQ_SMI);
618 }
619 }
620 break;
621 }
622
623 case XAPICDELIVERYMODE_NMI:
624 {
625 for (VMCPUID idCpu = 0; idCpu < cCpus; idCpu++)
626 {
627 if ( VMCPUSET_IS_PRESENT(pDestCpuSet, idCpu)
628 && apicIsEnabled(&pVM->aCpus[idCpu]))
629 {
630 Log2(("APIC: apicSendIntr: Raising NMI on VCPU%u\n", idCpu));
631 APICSetInterruptFF(&pVM->aCpus[idCpu], PDMAPICIRQ_NMI);
632 }
633 }
634 break;
635 }
636
637 case XAPICDELIVERYMODE_INIT:
638 {
639#ifdef IN_RING3
640 for (VMCPUID idCpu = 0; idCpu < cCpus; idCpu++)
641 if (VMCPUSET_IS_PRESENT(pDestCpuSet, idCpu))
642 {
643 Log2(("APIC: apicSendIntr: Issuing INIT to VCPU%u\n", idCpu));
644 VMMR3SendInitIpi(pVM, idCpu);
645 }
646#else
647 /* We need to return to ring-3 to deliver the INIT. */
648 rcStrict = rcRZ;
649#endif
650 break;
651 }
652
653 case XAPICDELIVERYMODE_STARTUP:
654 {
655#ifdef IN_RING3
656 for (VMCPUID idCpu = 0; idCpu < cCpus; idCpu++)
657 if (VMCPUSET_IS_PRESENT(pDestCpuSet, idCpu))
658 {
659 Log2(("APIC: apicSendIntr: Issuing SIPI to VCPU%u\n", idCpu));
660 VMMR3SendStartupIpi(pVM, idCpu, uVector);
661 }
662#else
663 /* We need to return to ring-3 to deliver the SIPI. */
664 rcStrict = rcRZ;
665#endif
666 break;
667 }
668
669 case XAPICDELIVERYMODE_EXTINT:
670 {
671 for (VMCPUID idCpu = 0; idCpu < cCpus; idCpu++)
672 if (VMCPUSET_IS_PRESENT(pDestCpuSet, idCpu))
673 {
674 Log2(("APIC: apicSendIntr: Raising EXTINT on VCPU%u\n", idCpu));
675 APICSetInterruptFF(&pVM->aCpus[idCpu], PDMAPICIRQ_EXTINT);
676 }
677 break;
678 }
679
680 default:
681 {
682 AssertMsgFailed(("APIC: apicSendIntr: Unsupported delivery mode %#x (%s)\n", enmDeliveryMode,
683 apicGetDeliveryModeName(enmDeliveryMode)));
684 break;
685 }
686 }
687
688 /*
689 * If an illegal vector is programmed, set the 'send illegal vector' error here if the
690 * interrupt is being sent by an APIC.
691 *
692 * The 'receive illegal vector' will be set on the target APIC when the interrupt
693 * gets generated, see APICPostInterrupt().
694 *
695 * See Intel spec. 10.5.3 "Error Handling".
696 */
697 if ( rcStrict != rcRZ
698 && pVCpu)
699 {
700 if (RT_UNLIKELY(uVector <= XAPIC_ILLEGAL_VECTOR_END))
701 apicSetError(pVCpu, XAPIC_ESR_SEND_ILLEGAL_VECTOR);
702 }
703 return rcStrict;
704}
705
706
707/**
708 * Checks if this APIC belongs to a logical destination.
709 *
710 * @returns true if the APIC belongs to the logical
711 * destination, false otherwise.
712 * @param pVCpu The cross context virtual CPU structure.
713 * @param fDest The destination mask.
714 *
715 * @thread Any.
716 */
717static bool apicIsLogicalDest(PVMCPU pVCpu, uint32_t fDest)
718{
719 if (XAPIC_IN_X2APIC_MODE(pVCpu))
720 {
721 /*
722 * Flat logical mode is not supported in x2APIC mode.
723 * In clustered logical mode, the 32-bit logical ID in the LDR is interpreted as follows:
724 * - High 16 bits is the cluster ID.
725 * - Low 16 bits: each bit represents a unique APIC within the cluster.
726 */
727 PCX2APICPAGE pX2ApicPage = VMCPU_TO_CX2APICPAGE(pVCpu);
728 uint32_t const u32Ldr = pX2ApicPage->ldr.u32LogicalApicId;
729 if (X2APIC_LDR_GET_CLUSTER_ID(u32Ldr) == (fDest & X2APIC_LDR_CLUSTER_ID))
730 return RT_BOOL(u32Ldr & fDest & X2APIC_LDR_LOGICAL_ID);
731 return false;
732 }
733
734#if XAPIC_HARDWARE_VERSION == XAPIC_HARDWARE_VERSION_P4
735 /*
736 * In both flat and clustered logical mode, a destination mask of all set bits indicates a broadcast.
737 * See AMD spec. 16.6.1 "Receiving System and IPI Interrupts".
738 */
739 Assert(!XAPIC_IN_X2APIC_MODE(pVCpu));
740 if ((fDest & XAPIC_LDR_FLAT_LOGICAL_ID) == XAPIC_LDR_FLAT_LOGICAL_ID)
741 return true;
742
743 PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
744 XAPICDESTFORMAT enmDestFormat = (XAPICDESTFORMAT)pXApicPage->dfr.u.u4Model;
745 if (enmDestFormat == XAPICDESTFORMAT_FLAT)
746 {
747 /* The destination mask is interpreted as a bitmap of 8 unique logical APIC IDs. */
748 uint8_t const u8Ldr = pXApicPage->ldr.u.u8LogicalApicId;
749 return RT_BOOL(u8Ldr & fDest & XAPIC_LDR_FLAT_LOGICAL_ID);
750 }
751
752 /*
753 * In clustered logical mode, the 8-bit logical ID in the LDR is interpreted as follows:
754 * - High 4 bits is the cluster ID.
755 * - Low 4 bits: each bit represents a unique APIC within the cluster.
756 */
757 Assert(enmDestFormat == XAPICDESTFORMAT_CLUSTER);
758 uint8_t const u8Ldr = pXApicPage->ldr.u.u8LogicalApicId;
759 if (XAPIC_LDR_CLUSTERED_GET_CLUSTER_ID(u8Ldr) == (fDest & XAPIC_LDR_CLUSTERED_CLUSTER_ID))
760 return RT_BOOL(u8Ldr & fDest & XAPIC_LDR_CLUSTERED_LOGICAL_ID);
761 return false;
762#else
763# error "Implement Pentium and P6 family APIC architectures"
764#endif
765}
766
767
768/**
769 * Figures out the set of destination CPUs for a given destination mode, format
770 * and delivery mode setting.
771 *
772 * @param pVM The cross context VM structure.
773 * @param fDestMask The destination mask.
774 * @param fBroadcastMask The broadcast mask.
775 * @param enmDestMode The destination mode.
776 * @param enmDeliveryMode The delivery mode.
777 * @param pDestCpuSet The destination CPU set to update.
778 */
779static void apicGetDestCpuSet(PVM pVM, uint32_t fDestMask, uint32_t fBroadcastMask, XAPICDESTMODE enmDestMode,
780 XAPICDELIVERYMODE enmDeliveryMode, PVMCPUSET pDestCpuSet)
781{
782 VMCPUSET_EMPTY(pDestCpuSet);
783
784 /*
785 * Physical destination mode only supports either a broadcast or a single target.
786 * - Broadcast with lowest-priority delivery mode is not supported[1], we deliver it
787 * as a regular broadcast like in fixed delivery mode.
788 * - For a single target, lowest-priority delivery mode makes no sense. We deliver
789 * to the target like in fixed delivery mode.
790 *
791 * [1] See Intel spec. 10.6.2.1 "Physical Destination Mode".
792 */
793 if ( enmDestMode == XAPICDESTMODE_PHYSICAL
794 && enmDeliveryMode == XAPICDELIVERYMODE_LOWEST_PRIO)
795 {
796 AssertMsgFailed(("APIC: Lowest-priority delivery using physical destination mode!"));
797 enmDeliveryMode = XAPICDELIVERYMODE_FIXED;
798 }
799
800 uint32_t const cCpus = pVM->cCpus;
801 if (enmDeliveryMode == XAPICDELIVERYMODE_LOWEST_PRIO)
802 {
803 Assert(enmDestMode == XAPICDESTMODE_LOGICAL);
804#if XAPIC_HARDWARE_VERSION == XAPIC_HARDWARE_VERSION_P4
805 VMCPUID idCpuLowestTpr = NIL_VMCPUID;
806 uint8_t u8LowestTpr = UINT8_C(0xff);
807 for (VMCPUID idCpu = 0; idCpu < cCpus; idCpu++)
808 {
809 PVMCPU pVCpuDest = &pVM->aCpus[idCpu];
810 if (apicIsLogicalDest(pVCpuDest, fDestMask))
811 {
812 PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpuDest);
813 uint8_t const u8Tpr = pXApicPage->tpr.u8Tpr; /* PAV */
814
815 /*
816 * If there is a tie for lowest priority, the local APIC with the highest ID is chosen.
817 * Hence the use of "<=" in the check below.
818 * See AMD spec. 16.6.2 "Lowest Priority Messages and Arbitration".
819 */
820 if (u8Tpr <= u8LowestTpr)
821 {
822 u8LowestTpr = u8Tpr;
823 idCpuLowestTpr = idCpu;
824 }
825 }
826 }
827 if (idCpuLowestTpr != NIL_VMCPUID)
828 VMCPUSET_ADD(pDestCpuSet, idCpuLowestTpr);
829#else
830# error "Implement Pentium and P6 family APIC architectures"
831#endif
832 return;
833 }
834
835 /*
836 * x2APIC:
837 * - In both physical and logical destination mode, a destination mask of 0xffffffff implies a broadcast[1].
838 * xAPIC:
839 * - In physical destination mode, a destination mask of 0xff implies a broadcast[2].
840 * - In both flat and clustered logical mode, a destination mask of 0xff implies a broadcast[3].
841 *
842 * [1] See Intel spec. 10.12.9 "ICR Operation in x2APIC Mode".
843 * [2] See Intel spec. 10.6.2.1 "Physical Destination Mode".
844 * [2] See AMD spec. 16.6.1 "Receiving System and IPI Interrupts".
845 */
846 if ((fDestMask & fBroadcastMask) == fBroadcastMask)
847 {
848 VMCPUSET_FILL(pDestCpuSet);
849 return;
850 }
851
852 if (enmDestMode == XAPICDESTMODE_PHYSICAL)
853 {
854 /* The destination mask is interpreted as the physical APIC ID of a single target. */
855#if 1
856 /* Since our physical APIC ID is read-only to software, set the corresponding bit in the CPU set. */
857 if (RT_LIKELY(fDestMask < cCpus))
858 VMCPUSET_ADD(pDestCpuSet, fDestMask);
859#else
860 /* The physical APIC ID may not match our VCPU ID, search through the list of targets. */
861 for (VMCPUID idCpu = 0; idCpu < cCpus; idCpu++)
862 {
863 PVMCPU pVCpuDest = &pVM->aCpus[idCpu];
864 if (XAPIC_IN_X2APIC_MODE(pVCpuDest))
865 {
866 PCX2APICPAGE pX2ApicPage = VMCPU_TO_CX2APICPAGE(pVCpuDest);
867 if (pX2ApicPage->id.u32ApicId == fDestMask)
868 VMCPUSET_ADD(pDestCpuSet, pVCpuDest->idCpu);
869 }
870 else
871 {
872 PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpuDest);
873 if (pXApicPage->id.u8ApicId == (uint8_t)fDestMask)
874 VMCPUSET_ADD(pDestCpuSet, pVCpuDest->idCpu);
875 }
876 }
877#endif
878 }
879 else
880 {
881 Assert(enmDestMode == XAPICDESTMODE_LOGICAL);
882
883 /* A destination mask of all 0's implies no target APICs (since it's interpreted as a bitmap or partial bitmap). */
884 if (RT_UNLIKELY(!fDestMask))
885 return;
886
887 /* The destination mask is interpreted as a bitmap of software-programmable logical APIC ID of the target APICs. */
888 for (VMCPUID idCpu = 0; idCpu < cCpus; idCpu++)
889 {
890 PVMCPU pVCpuDest = &pVM->aCpus[idCpu];
891 if (apicIsLogicalDest(pVCpuDest, fDestMask))
892 VMCPUSET_ADD(pDestCpuSet, pVCpuDest->idCpu);
893 }
894 }
895}
896
897
898/**
899 * Sends an Interprocessor Interrupt (IPI) using values from the Interrupt
900 * Command Register (ICR).
901 *
902 * @returns VBox status code.
903 * @param pVCpu The cross context virtual CPU structure.
904 * @param rcRZ The return code if the operation cannot be
905 * performed in the current context.
906 */
907static VBOXSTRICTRC apicSendIpi(PVMCPU pVCpu, int rcRZ)
908{
909 VMCPU_ASSERT_EMT(pVCpu);
910
911 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
912 XAPICDELIVERYMODE const enmDeliveryMode = (XAPICDELIVERYMODE)pXApicPage->icr_lo.u.u3DeliveryMode;
913 XAPICDESTMODE const enmDestMode = (XAPICDESTMODE)pXApicPage->icr_lo.u.u1DestMode;
914 XAPICINITLEVEL const enmInitLevel = (XAPICINITLEVEL)pXApicPage->icr_lo.u.u1Level;
915 XAPICTRIGGERMODE const enmTriggerMode = (XAPICTRIGGERMODE)pXApicPage->icr_lo.u.u1TriggerMode;
916 XAPICDESTSHORTHAND const enmDestShorthand = (XAPICDESTSHORTHAND)pXApicPage->icr_lo.u.u2DestShorthand;
917 uint8_t const uVector = pXApicPage->icr_lo.u.u8Vector;
918
919 PX2APICPAGE pX2ApicPage = VMCPU_TO_X2APICPAGE(pVCpu);
920 uint32_t const fDest = XAPIC_IN_X2APIC_MODE(pVCpu) ? pX2ApicPage->icr_hi.u32IcrHi : pXApicPage->icr_hi.u.u8Dest;
921
922#if XAPIC_HARDWARE_VERSION == XAPIC_HARDWARE_VERSION_P4
923 /*
924 * INIT Level De-assert is not support on Pentium 4 and Xeon processors.
925 * See AMD spec. 16.5 "Interprocessor Interrupts (IPI)" for a table of valid ICR combinations.
926 */
927 if (RT_UNLIKELY( enmDeliveryMode == XAPICDELIVERYMODE_INIT_LEVEL_DEASSERT
928 && enmInitLevel == XAPICINITLEVEL_DEASSERT
929 && enmTriggerMode == XAPICTRIGGERMODE_LEVEL))
930 {
931 Log2(("APIC%u: INIT level de-assert unsupported, ignoring!\n", pVCpu->idCpu));
932 return VINF_SUCCESS;
933 }
934#else
935# error "Implement Pentium and P6 family APIC architectures"
936#endif
937
938 /*
939 * The destination and delivery modes are ignored/by-passed when a destination shorthand is specified.
940 * See Intel spec. 10.6.2.3 "Broadcast/Self Delivery Mode".
941 */
942 VMCPUSET DestCpuSet;
943 switch (enmDestShorthand)
944 {
945 case XAPICDESTSHORTHAND_NONE:
946 {
947 PVM pVM = pVCpu->CTX_SUFF(pVM);
948 uint32_t const fBroadcastMask = XAPIC_IN_X2APIC_MODE(pVCpu) ? X2APIC_ID_BROADCAST_MASK : XAPIC_ID_BROADCAST_MASK;
949 apicGetDestCpuSet(pVM, fDest, fBroadcastMask, enmDestMode, enmDeliveryMode, &DestCpuSet);
950 break;
951 }
952
953 case XAPICDESTSHORTHAND_SELF:
954 {
955 VMCPUSET_EMPTY(&DestCpuSet);
956 VMCPUSET_ADD(&DestCpuSet, pVCpu->idCpu);
957 break;
958 }
959
960 case XAPIDDESTSHORTHAND_ALL_INCL_SELF:
961 {
962 VMCPUSET_FILL(&DestCpuSet);
963 break;
964 }
965
966 case XAPICDESTSHORTHAND_ALL_EXCL_SELF:
967 {
968 VMCPUSET_FILL(&DestCpuSet);
969 VMCPUSET_DEL(&DestCpuSet, pVCpu->idCpu);
970 break;
971 }
972 }
973
974 return apicSendIntr(pVCpu->CTX_SUFF(pVM), pVCpu, uVector, enmTriggerMode, enmDeliveryMode, &DestCpuSet, rcRZ);
975}
976
977
978/**
979 * Sets the Interrupt Command Register (ICR) high dword.
980 *
981 * @returns Strict VBox status code.
982 * @param pVCpu The cross context virtual CPU structure.
983 * @param uIcrHi The ICR high dword.
984 */
985static VBOXSTRICTRC apicSetIcrHi(PVMCPU pVCpu, uint32_t uIcrHi)
986{
987 VMCPU_ASSERT_EMT(pVCpu);
988 Assert(!XAPIC_IN_X2APIC_MODE(pVCpu));
989
990 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
991 pXApicPage->icr_hi.all.u32IcrHi = uIcrHi & XAPIC_ICR_HI_DEST;
992 Log2(("APIC%u: apicSetIcrHi: uIcrHi=%#RX32\n", pVCpu->idCpu, pXApicPage->icr_hi.all.u32IcrHi));
993
994 return VINF_SUCCESS;
995}
996
997
998/**
999 * Sets the Interrupt Command Register (ICR) low dword.
1000 *
1001 * @returns Strict VBox status code.
1002 * @param pVCpu The cross context virtual CPU structure.
1003 * @param uIcrLo The ICR low dword.
1004 * @param rcRZ The return code if the operation cannot be performed
1005 * in the current context.
1006 */
1007static VBOXSTRICTRC apicSetIcrLo(PVMCPU pVCpu, uint32_t uIcrLo, int rcRZ)
1008{
1009 VMCPU_ASSERT_EMT(pVCpu);
1010
1011 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
1012 pXApicPage->icr_lo.all.u32IcrLo = uIcrLo & XAPIC_ICR_LO_WR;
1013 Log2(("APIC%u: apicSetIcrLo: uIcrLo=%#RX32\n", pVCpu->idCpu, pXApicPage->icr_lo.all.u32IcrLo));
1014
1015 return apicSendIpi(pVCpu, rcRZ);
1016}
1017
1018
1019/**
1020 * Sets the Interrupt Command Register (ICR).
1021 *
1022 * @returns Strict VBox status code.
1023 * @param pVCpu The cross context virtual CPU structure.
1024 * @param u64Icr The ICR (High and Low combined).
1025 * @param rcRZ The return code if the operation cannot be performed
1026 * in the current context.
1027 */
1028static VBOXSTRICTRC apicSetIcr(PVMCPU pVCpu, uint64_t u64Icr, int rcRZ)
1029{
1030 VMCPU_ASSERT_EMT(pVCpu);
1031 Assert(XAPIC_IN_X2APIC_MODE(pVCpu));
1032
1033 /* Validate. */
1034 uint32_t const uLo = RT_LO_U32(u64Icr);
1035 if (RT_LIKELY(!(uLo & ~XAPIC_ICR_LO_WR)))
1036 {
1037 /* Update high dword first, then update the low dword which sends the IPI. */
1038 PX2APICPAGE pX2ApicPage = VMCPU_TO_X2APICPAGE(pVCpu);
1039 pX2ApicPage->icr_hi.u32IcrHi = RT_HI_U32(u64Icr);
1040 return apicSetIcrLo(pVCpu, uLo, rcRZ);
1041 }
1042 return apicMsrAccessError(pVCpu, MSR_IA32_X2APIC_ICR, APICMSRACCESS_WRITE_RSVD_BITS);
1043}
1044
1045
1046/**
1047 * Sets the Error Status Register (ESR).
1048 *
1049 * @returns Strict VBox status code.
1050 * @param pVCpu The cross context virtual CPU structure.
1051 * @param uEsr The ESR value.
1052 */
1053static VBOXSTRICTRC apicSetEsr(PVMCPU pVCpu, uint32_t uEsr)
1054{
1055 VMCPU_ASSERT_EMT(pVCpu);
1056
1057 Log2(("APIC%u: apicSetEr: uEsr=%#RX32\n", pVCpu->idCpu, uEsr));
1058
1059 if ( XAPIC_IN_X2APIC_MODE(pVCpu)
1060 && (uEsr & ~XAPIC_ESR_WO))
1061 return apicMsrAccessError(pVCpu, MSR_IA32_X2APIC_ESR, APICMSRACCESS_WRITE_RSVD_BITS);
1062
1063 /*
1064 * Writes to the ESR causes the internal state to be updated in the register,
1065 * clearing the original state. See AMD spec. 16.4.6 "APIC Error Interrupts".
1066 */
1067 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
1068 pXApicPage->esr.all.u32Errors = apicClearAllErrors(pVCpu);
1069 return VINF_SUCCESS;
1070}
1071
1072
1073/**
1074 * Updates the Processor Priority Register (PPR).
1075 *
1076 * @param pVCpu The cross context virtual CPU structure.
1077 */
1078static void apicUpdatePpr(PVMCPU pVCpu)
1079{
1080 VMCPU_ASSERT_EMT(pVCpu);
1081
1082 /* See Intel spec 10.8.3.1 "Task and Processor Priorities". */
1083 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
1084 uint8_t const uIsrv = apicGetHighestSetBit(&pXApicPage->isr, 0 /* rcNotFound */);
1085 uint8_t uPpr;
1086 if (XAPIC_TPR_GET_TP(pXApicPage->tpr.u8Tpr) >= XAPIC_PPR_GET_PP(uIsrv))
1087 uPpr = pXApicPage->tpr.u8Tpr;
1088 else
1089 uPpr = XAPIC_PPR_GET_PP(uIsrv);
1090 pXApicPage->ppr.u8Ppr = uPpr;
1091}
1092
1093
1094/**
1095 * Gets the Processor Priority Register (PPR).
1096 *
1097 * @returns The PPR value.
1098 * @param pVCpu The cross context virtual CPU structure.
1099 */
1100static uint8_t apicGetPpr(PVMCPU pVCpu)
1101{
1102 VMCPU_ASSERT_EMT(pVCpu);
1103
1104 /*
1105 * With virtualized APIC registers or with TPR virtualization, the hardware may
1106 * update ISR/TPR transparently. We thus re-calculate the PPR which may be out of sync.
1107 * See Intel spec. 29.2.2 "Virtual-Interrupt Delivery".
1108 */
1109 PCAPIC pApic = VM_TO_APIC(pVCpu->CTX_SUFF(pVM));
1110 if (pApic->fVirtApicRegsEnabled) /** @todo re-think this */
1111 apicUpdatePpr(pVCpu);
1112 PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
1113 return pXApicPage->ppr.u8Ppr;
1114}
1115
1116
1117/**
1118 * Sets the Task Priority Register (TPR).
1119 *
1120 * @returns Strict VBox status code.
1121 * @param pVCpu The cross context virtual CPU structure.
1122 * @param uTpr The TPR value.
1123 */
1124static VBOXSTRICTRC apicSetTpr(PVMCPU pVCpu, uint32_t uTpr)
1125{
1126 VMCPU_ASSERT_EMT(pVCpu);
1127
1128 Log2(("APIC%u: apicSetTpr: uTpr=%#RX32\n", pVCpu->idCpu, uTpr));
1129
1130 if ( XAPIC_IN_X2APIC_MODE(pVCpu)
1131 && (uTpr & ~XAPIC_TPR))
1132 return apicMsrAccessError(pVCpu, MSR_IA32_X2APIC_TPR, APICMSRACCESS_WRITE_RSVD_BITS);
1133
1134 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
1135 pXApicPage->tpr.u8Tpr = uTpr;
1136 apicUpdatePpr(pVCpu);
1137 apicSignalNextPendingIntr(pVCpu);
1138 return VINF_SUCCESS;
1139}
1140
1141
1142/**
1143 * Sets the End-Of-Interrupt (EOI) register.
1144 *
1145 * @returns Strict VBox status code.
1146 * @param pVCpu The cross context virtual CPU structure.
1147 * @param uEoi The EOI value.
1148 */
1149static VBOXSTRICTRC apicSetEoi(PVMCPU pVCpu, uint32_t uEoi)
1150{
1151 VMCPU_ASSERT_EMT(pVCpu);
1152
1153 Log2(("APIC%u: apicSetEoi: uEoi=%#RX32\n", pVCpu->idCpu, uEoi));
1154
1155 if ( XAPIC_IN_X2APIC_MODE(pVCpu)
1156 && (uEoi & ~XAPIC_EOI_WO))
1157 return apicMsrAccessError(pVCpu, MSR_IA32_X2APIC_EOI, APICMSRACCESS_WRITE_RSVD_BITS);
1158
1159 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
1160 int isrv = apicGetHighestSetBit(&pXApicPage->isr, -1 /* rcNotFound */);
1161 if (isrv >= 0)
1162 {
1163 Assert(isrv <= (int)UINT8_MAX);
1164 uint8_t const uVector = isrv;
1165 apicClearVectorInReg(&pXApicPage->isr, uVector);
1166 apicUpdatePpr(pVCpu);
1167 Log2(("APIC%u: apicSetEoi: Cleared interrupt from ISR. uVector=%#x\n", pVCpu->idCpu, uVector));
1168
1169 bool fLevelTriggered = apicTestVectorInReg(&pXApicPage->tmr, uVector);
1170 if (fLevelTriggered)
1171 {
1172 /** @todo We need to broadcast EOI to IO APICs here. */
1173 apicClearVectorInReg(&pXApicPage->tmr, uVector);
1174 Log2(("APIC%u: apicSetEoi: Cleared level triggered interrupt from TMR. uVector=%#x\n", pVCpu->idCpu, uVector));
1175 }
1176
1177 apicSignalNextPendingIntr(pVCpu);
1178 }
1179
1180 return VINF_SUCCESS;
1181}
1182
1183
1184/**
1185 * Sets the Logical Destination Register (LDR).
1186 *
1187 * @returns Strict VBox status code.
1188 * @param pVCpu The cross context virtual CPU structure.
1189 * @param uLdr The LDR value.
1190 *
1191 * @remarks LDR is read-only in x2APIC mode.
1192 */
1193static VBOXSTRICTRC apicSetLdr(PVMCPU pVCpu, uint32_t uLdr)
1194{
1195 VMCPU_ASSERT_EMT(pVCpu);
1196 Assert(!XAPIC_IN_X2APIC_MODE(pVCpu));
1197
1198 Log2(("APIC%u: apicSetLdr: uLdr=%#RX32\n", pVCpu->idCpu, uLdr));
1199
1200 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
1201 apicWriteRaw32(pXApicPage, XAPIC_OFF_LDR, uLdr & XAPIC_LDR);
1202 return VINF_SUCCESS;
1203}
1204
1205
1206/**
1207 * Sets the Destination Format Register (DFR).
1208 *
1209 * @returns Strict VBox status code.
1210 * @param pVCpu The cross context virtual CPU structure.
1211 * @param uDfr The DFR value.
1212 *
1213 * @remarks DFR is not available in x2APIC mode.
1214 */
1215static VBOXSTRICTRC apicSetDfr(PVMCPU pVCpu, uint32_t uDfr)
1216{
1217 VMCPU_ASSERT_EMT(pVCpu);
1218 Assert(!XAPIC_IN_X2APIC_MODE(pVCpu));
1219
1220 uDfr &= XAPIC_DFR;
1221 uDfr |= XAPIC_DFR_RSVD_MB1;
1222
1223 Log2(("APIC%u: apicSetDfr: uDfr=%#RX32\n", pVCpu->idCpu, uDfr));
1224
1225 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
1226 apicWriteRaw32(pXApicPage, XAPIC_OFF_DFR, uDfr);
1227 return VINF_SUCCESS;
1228}
1229
1230
1231/**
1232 * Sets the Timer Divide Configuration Register (DCR).
1233 *
1234 * @returns Strict VBox status code.
1235 * @param pVCpu The cross context virtual CPU structure.
1236 * @param uTimerDcr The timer DCR value.
1237 */
1238static VBOXSTRICTRC apicSetTimerDcr(PVMCPU pVCpu, uint32_t uTimerDcr)
1239{
1240 VMCPU_ASSERT_EMT(pVCpu);
1241 if ( XAPIC_IN_X2APIC_MODE(pVCpu)
1242 && (uTimerDcr & ~XAPIC_TIMER_DCR))
1243 return apicMsrAccessError(pVCpu, MSR_IA32_X2APIC_TIMER_DCR, APICMSRACCESS_WRITE_RSVD_BITS);
1244
1245 Log2(("APIC%u: apicSetTimerDcr: uTimerDcr=%#RX32\n", pVCpu->idCpu, uTimerDcr));
1246
1247 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
1248 apicWriteRaw32(pXApicPage, XAPIC_OFF_TIMER_DCR, uTimerDcr);
1249 return VINF_SUCCESS;
1250}
1251
1252
1253/**
1254 * Gets the timer's Current Count Register (CCR).
1255 *
1256 * @returns VBox status code.
1257 * @param pVCpu The cross context virtual CPU structure.
1258 * @param rcBusy The busy return code for the timer critical section.
1259 * @param puValue Where to store the LVT timer CCR.
1260 */
1261static VBOXSTRICTRC apicGetTimerCcr(PVMCPU pVCpu, int rcBusy, uint32_t *puValue)
1262{
1263 VMCPU_ASSERT_EMT(pVCpu);
1264 Assert(puValue);
1265
1266 PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
1267 *puValue = 0;
1268
1269 /* In TSC-deadline mode, CCR returns 0, see Intel spec. 10.5.4.1 "TSC-Deadline Mode". */
1270 if (pXApicPage->lvt_timer.u.u2TimerMode == XAPIC_TIMER_MODE_TSC_DEADLINE)
1271 return VINF_SUCCESS;
1272
1273 /* If the initial-count register is 0, CCR returns 0 as it cannot exceed the ICR. */
1274 uint32_t const uInitialCount = pXApicPage->timer_icr.u32InitialCount;
1275 if (!uInitialCount)
1276 return VINF_SUCCESS;
1277
1278 /*
1279 * Reading the virtual-sync clock requires locking its timer because it's not
1280 * a simple atomic operation, see tmVirtualSyncGetEx().
1281 *
1282 * We also need to lock before reading the timer CCR, see apicR3TimerCallback().
1283 */
1284 PCAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
1285 PTMTIMER pTimer = pApicCpu->CTX_SUFF(pTimer);
1286
1287 int rc = TMTimerLock(pTimer, rcBusy);
1288 if (rc == VINF_SUCCESS)
1289 {
1290 /* If the current-count register is 0, it implies the timer expired. */
1291 uint32_t const uCurrentCount = pXApicPage->timer_ccr.u32CurrentCount;
1292 if (uCurrentCount)
1293 {
1294 uint64_t const cTicksElapsed = TMTimerGet(pApicCpu->CTX_SUFF(pTimer)) - pApicCpu->u64TimerInitial;
1295 TMTimerUnlock(pTimer);
1296 uint8_t const uTimerShift = apicGetTimerShift(pXApicPage);
1297 uint64_t const uDelta = cTicksElapsed >> uTimerShift;
1298 if (uInitialCount > uDelta)
1299 *puValue = uInitialCount - uDelta;
1300 }
1301 else
1302 TMTimerUnlock(pTimer);
1303 }
1304 return rc;
1305}
1306
1307
1308/**
1309 * Sets the timer's Initial-Count Register (ICR).
1310 *
1311 * @returns Strict VBox status code.
1312 * @param pVCpu The cross context virtual CPU structure.
1313 * @param rcBusy The busy return code for the timer critical section.
1314 * @param uInitialCount The timer ICR.
1315 */
1316static VBOXSTRICTRC apicSetTimerIcr(PVMCPU pVCpu, int rcBusy, uint32_t uInitialCount)
1317{
1318 VMCPU_ASSERT_EMT(pVCpu);
1319
1320 PAPIC pApic = VM_TO_APIC(pVCpu->CTX_SUFF(pVM));
1321 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
1322 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
1323 PTMTIMER pTimer = pApicCpu->CTX_SUFF(pTimer);
1324
1325 /* In TSC-deadline mode, timer ICR writes are ignored, see Intel spec. 10.5.4.1 "TSC-Deadline Mode". */
1326 if ( pApic->fSupportsTscDeadline
1327 && pXApicPage->lvt_timer.u.u2TimerMode == XAPIC_TIMER_MODE_TSC_DEADLINE)
1328 return VINF_SUCCESS;
1329
1330 Log2(("APIC%u: apicSetTimerIcr: uInitialCount=%#RX32\n", pVCpu->idCpu, uInitialCount));
1331
1332 /*
1333 * The timer CCR may be modified by apicR3TimerCallback() in parallel,
1334 * so obtain the lock -before- updating it here to be consistent with the
1335 * timer ICR. We rely on CCR being consistent in apicGetTimerCcr().
1336 */
1337 int rc = TMTimerLock(pTimer, rcBusy);
1338 if (rc == VINF_SUCCESS)
1339 {
1340 pXApicPage->timer_icr.u32InitialCount = uInitialCount;
1341 pXApicPage->timer_ccr.u32CurrentCount = uInitialCount;
1342 if (uInitialCount)
1343 APICStartTimer(pVCpu, uInitialCount);
1344 else
1345 APICStopTimer(pVCpu);
1346 TMTimerUnlock(pTimer);
1347 }
1348 return rc;
1349}
1350
1351
1352/**
1353 * Sets an LVT entry.
1354 *
1355 * @returns Strict VBox status code.
1356 * @param pVCpu The cross context virtual CPU structure.
1357 * @param offLvt The LVT entry offset in the xAPIC page.
1358 * @param uLvt The LVT value to set.
1359 */
1360static VBOXSTRICTRC apicSetLvtEntry(PVMCPU pVCpu, uint16_t offLvt, uint32_t uLvt)
1361{
1362 VMCPU_ASSERT_EMT(pVCpu);
1363
1364#if XAPIC_HARDWARE_VERSION == XAPIC_HARDWARE_VERSION_P4
1365 AssertMsg( offLvt == XAPIC_OFF_LVT_TIMER
1366 || offLvt == XAPIC_OFF_LVT_THERMAL
1367 || offLvt == XAPIC_OFF_LVT_PERF
1368 || offLvt == XAPIC_OFF_LVT_LINT0
1369 || offLvt == XAPIC_OFF_LVT_LINT1
1370 || offLvt == XAPIC_OFF_LVT_ERROR,
1371 ("APIC%u: apicSetLvtEntry: invalid offset, offLvt=%#RX16, uLvt=%#RX32\n", pVCpu->idCpu, offLvt, uLvt));
1372
1373 /*
1374 * If TSC-deadline mode isn't support, ignore the bit in xAPIC mode
1375 * and raise #GP(0) in x2APIC mode.
1376 */
1377 PCAPIC pApic = VM_TO_APIC(pVCpu->CTX_SUFF(pVM));
1378 if (offLvt == XAPIC_OFF_LVT_TIMER)
1379 {
1380 if ( !pApic->fSupportsTscDeadline
1381 && (uLvt & XAPIC_LVT_TIMER_TSCDEADLINE))
1382 {
1383 if (XAPIC_IN_X2APIC_MODE(pVCpu))
1384 return apicMsrAccessError(pVCpu, XAPIC_GET_X2APIC_MSR(offLvt), APICMSRACCESS_WRITE_RSVD_BITS);
1385 uLvt &= ~XAPIC_LVT_TIMER_TSCDEADLINE;
1386 /** @todo TSC-deadline timer mode transition */
1387 }
1388 }
1389
1390 /*
1391 * Validate rest of the LVT bits.
1392 */
1393 uint16_t const idxLvt = (offLvt - XAPIC_OFF_LVT_START) >> 4;
1394 AssertReturn(idxLvt < RT_ELEMENTS(g_au32LvtValidMasks), VERR_OUT_OF_RANGE);
1395
1396 if ( XAPIC_IN_X2APIC_MODE(pVCpu)
1397 && (uLvt & ~g_au32LvtValidMasks[idxLvt]))
1398 return apicMsrAccessError(pVCpu, XAPIC_GET_X2APIC_MSR(offLvt), APICMSRACCESS_WRITE_RSVD_BITS);
1399
1400 uLvt &= g_au32LvtValidMasks[idxLvt];
1401
1402 /*
1403 * In the software-disabled state, LVT mask-bit must remain set and attempts to clear the mask
1404 * bit must be ignored. See Intel spec. 10.4.7.2 "Local APIC State After It Has Been Software Disabled".
1405 */
1406 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
1407 AssertCompile(RT_OFFSETOF(XAPICPAGE, svr) == RT_OFFSETOF(X2APICPAGE, svr));
1408 if (!pXApicPage->svr.u.fApicSoftwareEnable)
1409 uLvt |= XAPIC_LVT_MASK;
1410
1411 /*
1412 * It is unclear whether we should signal a 'send illegal vector' error here and ignore updating
1413 * the LVT entry when the delivery mode is 'fixed'[1] or update it in addition to signaling the
1414 * error or not signal the error at all. For now, we'll allow setting illegal vectors into the LVT
1415 * but set the 'send illegal vector' error here. The 'receive illegal vector' error will be set if
1416 * the interrupt for the vector happens to be generated, see APICPostInterrupt().
1417 *
1418 * [1] See Intel spec. 10.5.2 "Valid Interrupt Vectors".
1419 */
1420 if (RT_UNLIKELY( XAPIC_LVT_GET_VECTOR(uLvt) <= XAPIC_ILLEGAL_VECTOR_END
1421 && XAPIC_LVT_GET_DELIVERY_MODE(uLvt) == XAPICDELIVERYMODE_FIXED))
1422 apicSetError(pVCpu, XAPIC_ESR_SEND_ILLEGAL_VECTOR);
1423
1424 Log2(("APIC%u: apicSetLvtEntry: offLvt=%#RX16 uLvt=%#RX32\n", pVCpu->idCpu, offLvt, uLvt));
1425
1426 apicWriteRaw32(pXApicPage, offLvt, uLvt);
1427 return VINF_SUCCESS;
1428#else
1429# error "Implement Pentium and P6 family APIC architectures"
1430#endif /* XAPIC_HARDWARE_VERSION == XAPIC_HARDWARE_VERSION_P4 */
1431}
1432
1433
1434#if 0
1435/**
1436 * Sets an LVT entry in the extended LVT range.
1437 *
1438 * @returns VBox status code.
1439 * @param pVCpu The cross context virtual CPU structure.
1440 * @param offLvt The LVT entry offset in the xAPIC page.
1441 * @param uValue The LVT value to set.
1442 */
1443static int apicSetLvtExtEntry(PVMCPU pVCpu, uint16_t offLvt, uint32_t uLvt)
1444{
1445 VMCPU_ASSERT_EMT(pVCpu);
1446 AssertMsg(offLvt == XAPIC_OFF_CMCI, ("APIC%u: apicSetLvt1Entry: invalid offset %#RX16\n", pVCpu->idCpu, offLvt));
1447
1448 /** @todo support CMCI. */
1449 return VERR_NOT_IMPLEMENTED;
1450}
1451#endif
1452
1453
1454/**
1455 * Hints TM about the APIC timer frequency.
1456 *
1457 * @param pApicCpu The APIC CPU state.
1458 * @param uInitialCount The new initial count.
1459 * @param uTimerShift The new timer shift.
1460 * @thread Any.
1461 */
1462void apicHintTimerFreq(PAPICCPU pApicCpu, uint32_t uInitialCount, uint8_t uTimerShift)
1463{
1464 Assert(pApicCpu);
1465
1466 if ( pApicCpu->uHintedTimerInitialCount != uInitialCount
1467 || pApicCpu->uHintedTimerShift != uTimerShift)
1468 {
1469 uint32_t uHz;
1470 if (uInitialCount)
1471 {
1472 uint64_t cTicksPerPeriod = (uint64_t)uInitialCount << uTimerShift;
1473 uHz = TMTimerGetFreq(pApicCpu->CTX_SUFF(pTimer)) / cTicksPerPeriod;
1474 }
1475 else
1476 uHz = 0;
1477
1478 TMTimerSetFrequencyHint(pApicCpu->CTX_SUFF(pTimer), uHz);
1479 pApicCpu->uHintedTimerInitialCount = uInitialCount;
1480 pApicCpu->uHintedTimerShift = uTimerShift;
1481 }
1482}
1483
1484
1485/**
1486 * Reads an APIC register.
1487 *
1488 * @returns VBox status code.
1489 * @param pApicDev The APIC device instance.
1490 * @param pVCpu The cross context virtual CPU structure.
1491 * @param offReg The offset of the register being read.
1492 * @param puValue Where to store the register value.
1493 */
1494static int apicReadRegister(PAPICDEV pApicDev, PVMCPU pVCpu, uint16_t offReg, uint32_t *puValue)
1495{
1496 VMCPU_ASSERT_EMT(pVCpu);
1497 Assert(offReg <= XAPIC_OFF_MAX_VALID);
1498
1499 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
1500 uint32_t uValue = 0;
1501 int rc = VINF_SUCCESS;
1502 switch (offReg)
1503 {
1504 case XAPIC_OFF_ID:
1505 case XAPIC_OFF_VERSION:
1506 case XAPIC_OFF_TPR:
1507 case XAPIC_OFF_EOI:
1508 case XAPIC_OFF_RRD:
1509 case XAPIC_OFF_LDR:
1510 case XAPIC_OFF_DFR:
1511 case XAPIC_OFF_SVR:
1512 case XAPIC_OFF_ISR0: case XAPIC_OFF_ISR1: case XAPIC_OFF_ISR2: case XAPIC_OFF_ISR3:
1513 case XAPIC_OFF_ISR4: case XAPIC_OFF_ISR5: case XAPIC_OFF_ISR6: case XAPIC_OFF_ISR7:
1514 case XAPIC_OFF_TMR0: case XAPIC_OFF_TMR1: case XAPIC_OFF_TMR2: case XAPIC_OFF_TMR3:
1515 case XAPIC_OFF_TMR4: case XAPIC_OFF_TMR5: case XAPIC_OFF_TMR6: case XAPIC_OFF_TMR7:
1516 case XAPIC_OFF_IRR0: case XAPIC_OFF_IRR1: case XAPIC_OFF_IRR2: case XAPIC_OFF_IRR3:
1517 case XAPIC_OFF_IRR4: case XAPIC_OFF_IRR5: case XAPIC_OFF_IRR6: case XAPIC_OFF_IRR7:
1518 case XAPIC_OFF_ESR:
1519 case XAPIC_OFF_ICR_LO:
1520 case XAPIC_OFF_ICR_HI:
1521 case XAPIC_OFF_LVT_TIMER:
1522#if XAPIC_HARDWARE_VERSION == XAPIC_HARDWARE_VERSION_P4
1523 case XAPIC_OFF_LVT_THERMAL:
1524#endif
1525 case XAPIC_OFF_LVT_PERF:
1526 case XAPIC_OFF_LVT_LINT0:
1527 case XAPIC_OFF_LVT_LINT1:
1528 case XAPIC_OFF_LVT_ERROR:
1529 case XAPIC_OFF_TIMER_ICR:
1530 case XAPIC_OFF_TIMER_DCR:
1531 {
1532 Assert( !XAPIC_IN_X2APIC_MODE(pVCpu)
1533 || ( offReg != XAPIC_OFF_DFR
1534 && offReg != XAPIC_OFF_ICR_HI
1535 && offReg != XAPIC_OFF_EOI));
1536 uValue = apicReadRaw32(pXApicPage, offReg);
1537 break;
1538 }
1539
1540 case XAPIC_OFF_PPR:
1541 {
1542 uValue = apicGetPpr(pVCpu);
1543 break;
1544 }
1545
1546 case XAPIC_OFF_TIMER_CCR:
1547 {
1548 Assert(!XAPIC_IN_X2APIC_MODE(pVCpu));
1549 rc = VBOXSTRICTRC_VAL(apicGetTimerCcr(pVCpu, VINF_IOM_R3_MMIO_READ, &uValue));
1550 break;
1551 }
1552
1553 case XAPIC_OFF_APR:
1554 {
1555#if XAPIC_HARDWARE_VERSION == XAPIC_HARDWARE_VERSION_P4
1556 /* Unsupported on Pentium 4 and Xeon CPUs, invalid in x2APIC mode. */
1557 Assert(!XAPIC_IN_X2APIC_MODE(pVCpu));
1558#else
1559# error "Implement Pentium and P6 family APIC architectures"
1560#endif
1561 break;
1562 }
1563
1564 default:
1565 {
1566 Assert(!XAPIC_IN_X2APIC_MODE(pVCpu));
1567 rc = PDMDevHlpDBGFStop(pApicDev->CTX_SUFF(pDevIns), RT_SRC_POS, "VCPU[%u]: offReg=%#RX16\n", pVCpu->idCpu, offReg);
1568 apicSetError(pVCpu, XAPIC_ESR_ILLEGAL_REG_ADDRESS);
1569 break;
1570 }
1571 }
1572
1573 *puValue = uValue;
1574 return rc;
1575}
1576
1577
1578/**
1579 * Writes an APIC register.
1580 *
1581 * @returns Strict VBox status code.
1582 * @param pApicDev The APIC device instance.
1583 * @param pVCpu The cross context virtual CPU structure.
1584 * @param offReg The offset of the register being written.
1585 * @param uValue The register value.
1586 */
1587static VBOXSTRICTRC apicWriteRegister(PAPICDEV pApicDev, PVMCPU pVCpu, uint16_t offReg, uint32_t uValue)
1588{
1589 VMCPU_ASSERT_EMT(pVCpu);
1590 Assert(offReg <= XAPIC_OFF_MAX_VALID);
1591 Assert(!XAPIC_IN_X2APIC_MODE(pVCpu));
1592
1593 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
1594 switch (offReg)
1595 {
1596 case XAPIC_OFF_TPR:
1597 {
1598 rcStrict = apicSetTpr(pVCpu, uValue);
1599 break;
1600 }
1601
1602 case XAPIC_OFF_LVT_TIMER:
1603#if XAPIC_HARDWARE_VERSION == XAPIC_HARDWARE_VERSION_P4
1604 case XAPIC_OFF_LVT_THERMAL:
1605#endif
1606 case XAPIC_OFF_LVT_PERF:
1607 case XAPIC_OFF_LVT_LINT0:
1608 case XAPIC_OFF_LVT_LINT1:
1609 case XAPIC_OFF_LVT_ERROR:
1610 {
1611 rcStrict = apicSetLvtEntry(pVCpu, offReg, uValue);
1612 break;
1613 }
1614
1615 case XAPIC_OFF_TIMER_ICR:
1616 {
1617 rcStrict = apicSetTimerIcr(pVCpu, VINF_IOM_R3_MMIO_WRITE, uValue);
1618 break;
1619 }
1620
1621 case XAPIC_OFF_EOI:
1622 {
1623 rcStrict = apicSetEoi(pVCpu, uValue);
1624 break;
1625 }
1626
1627 case XAPIC_OFF_LDR:
1628 {
1629 rcStrict = apicSetLdr(pVCpu, uValue);
1630 break;
1631 }
1632
1633 case XAPIC_OFF_DFR:
1634 {
1635 rcStrict = apicSetDfr(pVCpu, uValue);
1636 break;
1637 }
1638
1639 case XAPIC_OFF_SVR:
1640 {
1641 rcStrict = apicSetSvr(pVCpu, uValue);
1642 break;
1643 }
1644
1645 case XAPIC_OFF_ICR_LO:
1646 {
1647 rcStrict = apicSetIcrLo(pVCpu, uValue, VINF_IOM_R3_MMIO_WRITE);
1648 break;
1649 }
1650
1651 case XAPIC_OFF_ICR_HI:
1652 {
1653 rcStrict = apicSetIcrHi(pVCpu, uValue);
1654 break;
1655 }
1656
1657 case XAPIC_OFF_TIMER_DCR:
1658 {
1659 rcStrict = apicSetTimerDcr(pVCpu, uValue);
1660 break;
1661 }
1662
1663 case XAPIC_OFF_ESR:
1664 {
1665 rcStrict = apicSetEsr(pVCpu, uValue);
1666 break;
1667 }
1668
1669 case XAPIC_OFF_APR:
1670 case XAPIC_OFF_RRD:
1671 {
1672#if XAPIC_HARDWARE_VERSION == XAPIC_HARDWARE_VERSION_P4
1673 /* Unsupported on Pentium 4 and Xeon CPUs but writes do -not- set an illegal register access error. */
1674#else
1675# error "Implement Pentium and P6 family APIC architectures"
1676#endif
1677 break;
1678 }
1679
1680 /* Read-only, write ignored: */
1681 case XAPIC_OFF_VERSION:
1682 case XAPIC_OFF_ID:
1683 break;
1684
1685 /* Unavailable/reserved in xAPIC mode: */
1686 case X2APIC_OFF_SELF_IPI:
1687 /* Read-only registers: */
1688 case XAPIC_OFF_PPR:
1689 case XAPIC_OFF_ISR0: case XAPIC_OFF_ISR1: case XAPIC_OFF_ISR2: case XAPIC_OFF_ISR3:
1690 case XAPIC_OFF_ISR4: case XAPIC_OFF_ISR5: case XAPIC_OFF_ISR6: case XAPIC_OFF_ISR7:
1691 case XAPIC_OFF_TMR0: case XAPIC_OFF_TMR1: case XAPIC_OFF_TMR2: case XAPIC_OFF_TMR3:
1692 case XAPIC_OFF_TMR4: case XAPIC_OFF_TMR5: case XAPIC_OFF_TMR6: case XAPIC_OFF_TMR7:
1693 case XAPIC_OFF_IRR0: case XAPIC_OFF_IRR1: case XAPIC_OFF_IRR2: case XAPIC_OFF_IRR3:
1694 case XAPIC_OFF_IRR4: case XAPIC_OFF_IRR5: case XAPIC_OFF_IRR6: case XAPIC_OFF_IRR7:
1695 case XAPIC_OFF_TIMER_CCR:
1696 default:
1697 {
1698 rcStrict = PDMDevHlpDBGFStop(pApicDev->CTX_SUFF(pDevIns), RT_SRC_POS, "APIC%u: offReg=%#RX16\n", pVCpu->idCpu,
1699 offReg);
1700 apicSetError(pVCpu, XAPIC_ESR_ILLEGAL_REG_ADDRESS);
1701 break;
1702 }
1703 }
1704
1705 return rcStrict;
1706}
1707
1708
1709/**
1710 * @interface_method_impl{PDMAPICREG,pfnReadMsrR3}
1711 */
1712VMMDECL(VBOXSTRICTRC) APICReadMsr(PPDMDEVINS pDevIns, PVMCPU pVCpu, uint32_t u32Reg, uint64_t *pu64Value)
1713{
1714 /*
1715 * Validate.
1716 */
1717 VMCPU_ASSERT_EMT(pVCpu);
1718 Assert(u32Reg >= MSR_IA32_X2APIC_START && u32Reg <= MSR_IA32_X2APIC_END);
1719 Assert(pu64Value);
1720
1721 PCAPIC pApic = VM_TO_APIC(pVCpu->CTX_SUFF(pVM));
1722 if (pApic->fRZEnabled)
1723 { /* likely */}
1724 else
1725 return VINF_CPUM_R3_MSR_READ;
1726
1727 STAM_COUNTER_INC(&pVCpu->apic.s.CTX_SUFF(StatMsrRead));
1728
1729 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
1730 if (RT_LIKELY(XAPIC_IN_X2APIC_MODE(pVCpu)))
1731 {
1732 switch (u32Reg)
1733 {
1734 /* Special handling for x2APIC: */
1735 case MSR_IA32_X2APIC_ICR:
1736 {
1737 PCX2APICPAGE pX2ApicPage = VMCPU_TO_CX2APICPAGE(pVCpu);
1738 uint64_t const uHi = pX2ApicPage->icr_hi.u32IcrHi;
1739 uint64_t const uLo = pX2ApicPage->icr_lo.all.u32IcrLo;
1740 *pu64Value = RT_MAKE_U64(uLo, uHi);
1741 break;
1742 }
1743
1744 /* Special handling, compatible with xAPIC: */
1745 case MSR_IA32_X2APIC_TIMER_CCR:
1746 {
1747 uint32_t uValue;
1748 rcStrict = apicGetTimerCcr(pVCpu, VINF_CPUM_R3_MSR_READ, &uValue);
1749 *pu64Value = uValue;
1750 break;
1751 }
1752
1753 /* Special handling, compatible with xAPIC: */
1754 case MSR_IA32_X2APIC_PPR:
1755 {
1756 *pu64Value = apicGetPpr(pVCpu);
1757 break;
1758 }
1759
1760 /* Raw read, compatible with xAPIC: */
1761 case MSR_IA32_X2APIC_ID:
1762 case MSR_IA32_X2APIC_VERSION:
1763 case MSR_IA32_X2APIC_TPR:
1764 case MSR_IA32_X2APIC_LDR:
1765 case MSR_IA32_X2APIC_SVR:
1766 case MSR_IA32_X2APIC_ISR0: case MSR_IA32_X2APIC_ISR1: case MSR_IA32_X2APIC_ISR2: case MSR_IA32_X2APIC_ISR3:
1767 case MSR_IA32_X2APIC_ISR4: case MSR_IA32_X2APIC_ISR5: case MSR_IA32_X2APIC_ISR6: case MSR_IA32_X2APIC_ISR7:
1768 case MSR_IA32_X2APIC_TMR0: case MSR_IA32_X2APIC_TMR1: case MSR_IA32_X2APIC_TMR2: case MSR_IA32_X2APIC_TMR3:
1769 case MSR_IA32_X2APIC_TMR4: case MSR_IA32_X2APIC_TMR5: case MSR_IA32_X2APIC_TMR6: case MSR_IA32_X2APIC_TMR7:
1770 case MSR_IA32_X2APIC_IRR0: case MSR_IA32_X2APIC_IRR1: case MSR_IA32_X2APIC_IRR2: case MSR_IA32_X2APIC_IRR3:
1771 case MSR_IA32_X2APIC_IRR4: case MSR_IA32_X2APIC_IRR5: case MSR_IA32_X2APIC_IRR6: case MSR_IA32_X2APIC_IRR7:
1772 case MSR_IA32_X2APIC_ESR:
1773 case MSR_IA32_X2APIC_LVT_TIMER:
1774 case MSR_IA32_X2APIC_LVT_THERMAL:
1775 case MSR_IA32_X2APIC_LVT_PERF:
1776 case MSR_IA32_X2APIC_LVT_LINT0:
1777 case MSR_IA32_X2APIC_LVT_LINT1:
1778 case MSR_IA32_X2APIC_LVT_ERROR:
1779 case MSR_IA32_X2APIC_TIMER_ICR:
1780 case MSR_IA32_X2APIC_TIMER_DCR:
1781 {
1782 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
1783 uint16_t const offReg = X2APIC_GET_XAPIC_OFF(u32Reg);
1784 *pu64Value = apicReadRaw32(pXApicPage, offReg);
1785 break;
1786 }
1787
1788 /* Write-only MSRs: */
1789 case MSR_IA32_X2APIC_SELF_IPI:
1790 case MSR_IA32_X2APIC_EOI:
1791 {
1792 rcStrict = apicMsrAccessError(pVCpu, u32Reg, APICMSRACCESS_READ_WRITE_ONLY);
1793 break;
1794 }
1795
1796 /* Reserved MSRs: */
1797 case MSR_IA32_X2APIC_LVT_CMCI:
1798 default:
1799 {
1800 rcStrict = apicMsrAccessError(pVCpu, u32Reg, APICMSRACCESS_READ_RSVD_OR_UNKNOWN);
1801 break;
1802 }
1803 }
1804 }
1805 else
1806 rcStrict = apicMsrAccessError(pVCpu, u32Reg, APICMSRACCESS_INVALID_READ_MODE);
1807
1808 return rcStrict;
1809}
1810
1811
1812/**
1813 * @interface_method_impl{PDMAPICREG,pfnWriteMsrR3}
1814 */
1815VMMDECL(VBOXSTRICTRC) APICWriteMsr(PPDMDEVINS pDevIns, PVMCPU pVCpu, uint32_t u32Reg, uint64_t u64Value)
1816{
1817 /*
1818 * Validate.
1819 */
1820 VMCPU_ASSERT_EMT(pVCpu);
1821 Assert(u32Reg >= MSR_IA32_X2APIC_START && u32Reg <= MSR_IA32_X2APIC_END);
1822
1823 PCAPIC pApic = VM_TO_APIC(pVCpu->CTX_SUFF(pVM));
1824 if (pApic->fRZEnabled)
1825 { /* likely */ }
1826 else
1827 return VINF_CPUM_R3_MSR_WRITE;
1828
1829 STAM_COUNTER_INC(&pVCpu->apic.s.CTX_SUFF(StatMsrWrite));
1830
1831 /*
1832 * In x2APIC mode, we need to raise #GP(0) for writes to reserved bits, unlike MMIO
1833 * accesses where they are ignored. Hence, we need to validate each register before
1834 * invoking the generic/xAPIC write functions.
1835 *
1836 * Bits 63:32 of all registers except the ICR are reserved, we'll handle this common
1837 * case first and handle validating the remaining bits on a per-register basis.
1838 * See Intel spec. 10.12.1.2 "x2APIC Register Address Space".
1839 */
1840 if ( u32Reg != MSR_IA32_X2APIC_ICR
1841 && RT_HI_U32(u64Value))
1842 return apicMsrAccessError(pVCpu, u32Reg, APICMSRACCESS_WRITE_RSVD_BITS);
1843
1844 uint32_t u32Value = RT_LO_U32(u64Value);
1845 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
1846 if (RT_LIKELY(XAPIC_IN_X2APIC_MODE(pVCpu)))
1847 {
1848 switch (u32Reg)
1849 {
1850 case MSR_IA32_X2APIC_TPR:
1851 {
1852 rcStrict = apicSetTpr(pVCpu, u32Value);
1853 break;
1854 }
1855
1856 case MSR_IA32_X2APIC_ICR:
1857 {
1858 rcStrict = apicSetIcr(pVCpu, u64Value, VINF_CPUM_R3_MSR_WRITE);
1859 break;
1860 }
1861
1862 case MSR_IA32_X2APIC_SVR:
1863 {
1864 rcStrict = apicSetSvr(pVCpu, u32Value);
1865 break;
1866 }
1867
1868 case MSR_IA32_X2APIC_ESR:
1869 {
1870 rcStrict = apicSetEsr(pVCpu, u32Value);
1871 break;
1872 }
1873
1874 case MSR_IA32_X2APIC_TIMER_DCR:
1875 {
1876 rcStrict = apicSetTimerDcr(pVCpu, u32Value);
1877 break;
1878 }
1879
1880 case MSR_IA32_X2APIC_LVT_TIMER:
1881 case MSR_IA32_X2APIC_LVT_THERMAL:
1882 case MSR_IA32_X2APIC_LVT_PERF:
1883 case MSR_IA32_X2APIC_LVT_LINT0:
1884 case MSR_IA32_X2APIC_LVT_LINT1:
1885 case MSR_IA32_X2APIC_LVT_ERROR:
1886 {
1887 rcStrict = apicSetLvtEntry(pVCpu, X2APIC_GET_XAPIC_OFF(u32Reg), u32Value);
1888 break;
1889 }
1890
1891 case MSR_IA32_X2APIC_TIMER_ICR:
1892 {
1893 rcStrict = apicSetTimerIcr(pVCpu, VINF_CPUM_R3_MSR_WRITE, u32Value);
1894 break;
1895 }
1896
1897 /* Write-only MSRs: */
1898 case MSR_IA32_X2APIC_SELF_IPI:
1899 {
1900 uint8_t const uVector = XAPIC_SELF_IPI_GET_VECTOR(u32Value);
1901 APICPostInterrupt(pVCpu, uVector, XAPICTRIGGERMODE_EDGE);
1902 rcStrict = VINF_SUCCESS;
1903 break;
1904 }
1905
1906 case MSR_IA32_X2APIC_EOI:
1907 {
1908 rcStrict = apicSetEoi(pVCpu, u32Value);
1909 break;
1910 }
1911
1912 /* Read-only MSRs: */
1913 case MSR_IA32_X2APIC_ID:
1914 case MSR_IA32_X2APIC_VERSION:
1915 case MSR_IA32_X2APIC_PPR:
1916 case MSR_IA32_X2APIC_LDR:
1917 case MSR_IA32_X2APIC_ISR0: case MSR_IA32_X2APIC_ISR1: case MSR_IA32_X2APIC_ISR2: case MSR_IA32_X2APIC_ISR3:
1918 case MSR_IA32_X2APIC_ISR4: case MSR_IA32_X2APIC_ISR5: case MSR_IA32_X2APIC_ISR6: case MSR_IA32_X2APIC_ISR7:
1919 case MSR_IA32_X2APIC_TMR0: case MSR_IA32_X2APIC_TMR1: case MSR_IA32_X2APIC_TMR2: case MSR_IA32_X2APIC_TMR3:
1920 case MSR_IA32_X2APIC_TMR4: case MSR_IA32_X2APIC_TMR5: case MSR_IA32_X2APIC_TMR6: case MSR_IA32_X2APIC_TMR7:
1921 case MSR_IA32_X2APIC_IRR0: case MSR_IA32_X2APIC_IRR1: case MSR_IA32_X2APIC_IRR2: case MSR_IA32_X2APIC_IRR3:
1922 case MSR_IA32_X2APIC_IRR4: case MSR_IA32_X2APIC_IRR5: case MSR_IA32_X2APIC_IRR6: case MSR_IA32_X2APIC_IRR7:
1923 case MSR_IA32_X2APIC_TIMER_CCR:
1924 {
1925 rcStrict = apicMsrAccessError(pVCpu, u32Reg, APICMSRACCESS_WRITE_READ_ONLY);
1926 break;
1927 }
1928
1929 /* Reserved MSRs: */
1930 case MSR_IA32_X2APIC_LVT_CMCI:
1931 default:
1932 {
1933 rcStrict = apicMsrAccessError(pVCpu, u32Reg, APICMSRACCESS_WRITE_RSVD_OR_UNKNOWN);
1934 break;
1935 }
1936 }
1937 }
1938 else
1939 rcStrict = apicMsrAccessError(pVCpu, u32Reg, APICMSRACCESS_INVALID_WRITE_MODE);
1940
1941 return rcStrict;
1942}
1943
1944
1945/**
1946 * @interface_method_impl{PDMAPICREG,pfnSetBaseMsrR3}
1947 */
1948VMMDECL(VBOXSTRICTRC) APICSetBaseMsr(PPDMDEVINS pDevIns, PVMCPU pVCpu, uint64_t u64BaseMsr)
1949{
1950 Assert(pVCpu);
1951 NOREF(pDevIns);
1952
1953#ifdef IN_RING3
1954 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
1955 PAPIC pApic = VM_TO_APIC(pVCpu->CTX_SUFF(pVM));
1956 APICMODE enmOldMode = apicGetMode(pApicCpu->uApicBaseMsr);
1957 APICMODE enmNewMode = apicGetMode(u64BaseMsr);
1958 uint64_t uBaseMsr = pApicCpu->uApicBaseMsr;
1959
1960 Log2(("APIC%u: ApicSetBaseMsr: u64BaseMsr=%#RX64 enmNewMode=%s enmOldMode=%s\n", pVCpu->idCpu, u64BaseMsr,
1961 apicGetModeName(enmNewMode), apicGetModeName(enmOldMode)));
1962
1963 /*
1964 * We do not support re-mapping the APIC base address because:
1965 * - We'll have to manage all the mappings ourselves in the APIC (reference counting based unmapping etc.)
1966 * i.e. we can only unmap the MMIO region if no other APIC is mapped on that location.
1967 * - It's unclear how/if IOM can fallback to handling regions as regular memory (if the MMIO
1968 * region remains mapped but doesn't belong to the called VCPU's APIC).
1969 */
1970 /** @todo Handle per-VCPU APIC base relocation. */
1971 if (MSR_APICBASE_GET_PHYSADDR(uBaseMsr) != XAPIC_APICBASE_PHYSADDR)
1972 {
1973 LogRelMax(5, ("APIC%u: Attempt to relocate base to %#RGp, unsupported -> #GP(0)\n", pVCpu->idCpu,
1974 MSR_APICBASE_GET_PHYSADDR(uBaseMsr)));
1975 return VERR_CPUM_RAISE_GP_0;
1976 }
1977
1978 /* Don't allow enabling xAPIC/x2APIC if the VM is configured with the APIC disabled. */
1979 if (pApic->enmOriginalMode == APICMODE_DISABLED)
1980 {
1981 LogRel(("APIC%u: Disallowing APIC base MSR write as the VM config is configured with APIC disabled!\n"));
1982 return apicMsrAccessError(pVCpu, MSR_IA32_APICBASE, APICMSRACCESS_WRITE_DISALLOWED_CONFIG);
1983 }
1984
1985 /*
1986 * Act on state transition.
1987 */
1988 /** @todo We need to update the CPUID according to the state, which we
1989 * currently don't do as CPUMSetGuestCpuIdFeature() is setting
1990 * per-VM CPUID bits while we need per-VCPU specific bits. */
1991 if (enmNewMode != enmOldMode)
1992 {
1993 switch (enmNewMode)
1994 {
1995 case APICMODE_DISABLED:
1996 {
1997 /*
1998 * The APIC state needs to be reset (especially the APIC ID as x2APIC APIC ID bit layout
1999 * is different). We can start with a clean slate identical to the state after a power-up/reset.
2000 *
2001 * See Intel spec. 10.4.3 "Enabling or Disabling the Local APIC".
2002 *
2003 * We'll also manually manage the APIC base MSR here. We want a single-point of commit
2004 * at the end of this function rather than touching it in APICR3Reset. This means we also
2005 * need to update the CPUID leaf ourselves.
2006 */
2007 APICR3Reset(pVCpu, false /* fResetApicBaseMsr */);
2008 uBaseMsr &= ~(MSR_APICBASE_XAPIC_ENABLE_BIT | MSR_APICBASE_X2APIC_ENABLE_BIT);
2009 CPUMClearGuestCpuIdFeature(pVCpu->CTX_SUFF(pVM), CPUMCPUIDFEATURE_APIC);
2010 LogRel(("APIC%u: Switched mode to disabled\n", pVCpu->idCpu));
2011 break;
2012 }
2013
2014 case APICMODE_XAPIC:
2015 {
2016 if (enmOldMode != APICMODE_DISABLED)
2017 {
2018 LogRel(("APIC%u: Can only transition to xAPIC state from disabled state\n", pVCpu->idCpu));
2019 return apicMsrAccessError(pVCpu, MSR_IA32_APICBASE, APICMSRACCESS_WRITE_INVALID);
2020 }
2021
2022 uBaseMsr |= MSR_APICBASE_XAPIC_ENABLE_BIT;
2023 CPUMSetGuestCpuIdFeature(pVCpu->CTX_SUFF(pVM), CPUMCPUIDFEATURE_APIC);
2024 LogRel(("APIC%u: Switched mode to xAPIC\n", pVCpu->idCpu));
2025 break;
2026 }
2027
2028 case APICMODE_X2APIC:
2029 {
2030 if (enmOldMode != APICMODE_XAPIC)
2031 {
2032 LogRel(("APIC%u: Can only transition to x2APIC state from xAPIC state\n", pVCpu->idCpu));
2033 return apicMsrAccessError(pVCpu, MSR_IA32_APICBASE, APICMSRACCESS_WRITE_INVALID);
2034 }
2035
2036 /* Don't allow enabling x2APIC if the VM is configured with the APIC disabled. */
2037 uBaseMsr |= MSR_APICBASE_XAPIC_ENABLE_BIT | MSR_APICBASE_X2APIC_ENABLE_BIT;
2038
2039 /*
2040 * The APIC ID needs updating when entering x2APIC mode.
2041 * Software written APIC ID in xAPIC mode isn't preseved.
2042 * The APIC ID becomes read-only to software in x2APIC mode.
2043 *
2044 * See Intel spec. 10.12.5.1 "x2APIC States".
2045 */
2046 PX2APICPAGE pX2ApicPage = VMCPU_TO_X2APICPAGE(pVCpu);
2047 ASMMemZero32(&pX2ApicPage->id, sizeof(pX2ApicPage->id));
2048 pX2ApicPage->id.u32ApicId = pVCpu->idCpu;
2049
2050 /*
2051 * LDR initialization occurs when entering x2APIC mode.
2052 * See Intel spec. 10.12.10.2 "Deriving Logical x2APIC ID from the Local x2APIC ID".
2053 */
2054 pX2ApicPage->ldr.u32LogicalApicId = ((pX2ApicPage->id.u32ApicId & UINT32_C(0xffff0)) << 16)
2055 | (UINT32_C(1) << pX2ApicPage->id.u32ApicId & UINT32_C(0xf));
2056
2057 LogRel(("APIC%u: Switched mode to x2APIC\n", pVCpu->idCpu));
2058 break;
2059 }
2060
2061 case APICMODE_INVALID:
2062 default:
2063 {
2064 Log(("APIC%u: Invalid state transition attempted\n", pVCpu->idCpu));
2065 return apicMsrAccessError(pVCpu, MSR_IA32_APICBASE, APICMSRACCESS_WRITE_INVALID);
2066 }
2067 }
2068 }
2069
2070 ASMAtomicWriteU64(&pApicCpu->uApicBaseMsr, uBaseMsr);
2071 return VINF_SUCCESS;
2072#else /* !IN_RING3 */
2073 return VINF_CPUM_R3_MSR_WRITE;
2074#endif /* IN_RING3 */
2075}
2076
2077
2078/**
2079 * @interface_method_impl{PDMAPICREG,pfnGetBaseMsrR3}
2080 */
2081VMMDECL(uint64_t) APICGetBaseMsr(PPDMDEVINS pDevIns, PVMCPU pVCpu)
2082{
2083 VMCPU_ASSERT_EMT_OR_NOT_RUNNING(pVCpu);
2084
2085 PCAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
2086 return pApicCpu->uApicBaseMsr;
2087}
2088
2089
2090/**
2091 * @interface_method_impl{PDMAPICREG,pfnSetTprR3}
2092 */
2093VMMDECL(void) APICSetTpr(PPDMDEVINS pDevIns, PVMCPU pVCpu, uint8_t u8Tpr)
2094{
2095 apicSetTpr(pVCpu, u8Tpr);
2096}
2097
2098
2099/**
2100 * Gets the highest priority pending interrupt.
2101 *
2102 * @returns true if any interrupt is pending, false otherwise.
2103 * @param pVCpu The cross context virtual CPU structure.
2104 * @param pu8PendingIntr Where to store the interrupt vector if the
2105 * interrupt is pending (optional, can be NULL).
2106 */
2107static bool apicGetHighestPendingInterrupt(PVMCPU pVCpu, uint8_t *pu8PendingIntr)
2108{
2109 PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
2110 int const irrv = apicGetHighestSetBit(&pXApicPage->irr, -1);
2111 if (irrv >= 0)
2112 {
2113 Assert(irrv <= (int)UINT8_MAX);
2114 if (pu8PendingIntr)
2115 *pu8PendingIntr = (uint8_t)irrv;
2116 return true;
2117 }
2118 return false;
2119}
2120
2121
2122/**
2123 * @interface_method_impl{PDMAPICREG,pfnGetTprR3}
2124 */
2125VMMDECL(uint8_t) APICGetTpr(PPDMDEVINS pDevIns, PVMCPU pVCpu, bool *pfPending, uint8_t *pu8PendingIntr)
2126{
2127 VMCPU_ASSERT_EMT(pVCpu);
2128 PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
2129
2130 if (pfPending)
2131 {
2132 /*
2133 * Just return whatever the highest pending interrupt is in the IRR.
2134 * The caller is responsible for figuring out if it's masked by the TPR etc.
2135 */
2136 *pfPending = apicGetHighestPendingInterrupt(pVCpu, pu8PendingIntr);
2137 }
2138
2139 return pXApicPage->tpr.u8Tpr;
2140}
2141
2142
2143/**
2144 * @interface_method_impl{PDMAPICREG,pfnGetTimerFreqR3}
2145 */
2146VMMDECL(uint64_t) APICGetTimerFreq(PPDMDEVINS pDevIns)
2147{
2148 PVM pVM = PDMDevHlpGetVM(pDevIns);
2149 PVMCPU pVCpu = &pVM->aCpus[0];
2150 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
2151 uint64_t uTimer = TMTimerGetFreq(pApicCpu->CTX_SUFF(pTimer));
2152 return uTimer;
2153}
2154
2155
2156/**
2157 * @interface_method_impl{PDMAPICREG,pfnBusDeliverR3}
2158 * @remarks This is a private interface between the IOAPIC and the APIC.
2159 */
2160VMMDECL(int) APICBusDeliver(PPDMDEVINS pDevIns, uint8_t uDest, uint8_t uDestMode, uint8_t uDeliveryMode, uint8_t uVector,
2161 uint8_t uPolarity, uint8_t uTriggerMode, uint32_t uTagSrc)
2162{
2163 NOREF(uPolarity);
2164 NOREF(uTagSrc);
2165 PVM pVM = PDMDevHlpGetVM(pDevIns);
2166
2167 /*
2168 * The destination field (mask) in the IO APIC redirectable table entry is 8-bits.
2169 * Hence, the broadcast mask is 0xff.
2170 * See IO APIC spec. 3.2.4. "IOREDTBL[23:0] - I/O Redirectable Table Registers".
2171 */
2172 XAPICTRIGGERMODE enmTriggerMode = (XAPICTRIGGERMODE)uTriggerMode;
2173 XAPICDELIVERYMODE enmDeliveryMode = (XAPICDELIVERYMODE)uDeliveryMode;
2174 XAPICDESTMODE enmDestMode = (XAPICDESTMODE)uDestMode;
2175 uint32_t fDestMask = uDest;
2176 uint32_t fBroadcastMask = UINT32_C(0xff);
2177
2178 Log2(("APIC: apicBusDeliver: fDestMask=%#x enmDestMode=%s enmTriggerMode=%s enmDeliveryMode=%s\n", fDestMask,
2179 apicGetDestModeName(enmDestMode), apicGetTriggerModeName(enmTriggerMode), apicGetDeliveryModeName(enmDeliveryMode)));
2180
2181 VMCPUSET DestCpuSet;
2182 apicGetDestCpuSet(pVM, fDestMask, fBroadcastMask, enmDestMode, enmDeliveryMode, &DestCpuSet);
2183 VBOXSTRICTRC rcStrict = apicSendIntr(pVM, NULL /* pVCpu */, uVector, enmTriggerMode, enmDeliveryMode, &DestCpuSet,
2184 VINF_SUCCESS /* rcRZ */);
2185 return VBOXSTRICTRC_VAL(rcStrict);
2186}
2187
2188
2189/**
2190 * @interface_method_impl{PDMAPICREG,pfnLocalInterruptR3}
2191 * @remarks This is a private interface between the PIC and the APIC.
2192 */
2193VMMDECL(VBOXSTRICTRC) APICLocalInterrupt(PPDMDEVINS pDevIns, PVMCPU pVCpu, uint8_t u8Pin, uint8_t u8Level, int rcRZ)
2194{
2195 NOREF(pDevIns);
2196 AssertReturn(u8Pin <= 1, VERR_INVALID_PARAMETER);
2197 AssertReturn(u8Level <= 1, VERR_INVALID_PARAMETER);
2198
2199 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
2200
2201 /* If the APIC is enabled, the interrupt is subject to LVT programming. */
2202 if (apicIsEnabled(pVCpu))
2203 {
2204 PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
2205
2206 /* Pick the LVT entry corresponding to the interrupt pin. */
2207 static const uint16_t s_au16LvtOffsets[] =
2208 {
2209 XAPIC_OFF_LVT_LINT0,
2210 XAPIC_OFF_LVT_LINT1
2211 };
2212 Assert(u8Pin < RT_ELEMENTS(s_au16LvtOffsets));
2213 uint16_t const offLvt = s_au16LvtOffsets[u8Pin];
2214 uint32_t const uLvt = apicReadRaw32(pXApicPage, offLvt);
2215
2216 /* If software hasn't masked the interrupt in the LVT entry, proceed interrupt processing. */
2217 if (!XAPIC_LVT_IS_MASKED(uLvt))
2218 {
2219 XAPICDELIVERYMODE const enmDeliveryMode = XAPIC_LVT_GET_DELIVERY_MODE(uLvt);
2220 XAPICTRIGGERMODE enmTriggerMode = XAPIC_LVT_GET_TRIGGER_MODE(uLvt);
2221
2222 switch (enmDeliveryMode)
2223 {
2224 case XAPICDELIVERYMODE_INIT:
2225 {
2226 /** @todo won't work in R0/RC because callers don't care about rcRZ. */
2227 AssertMsgFailed(("INIT through LINT0/LINT1 is not yet supported\n"));
2228 /* fallthru */
2229 }
2230 case XAPICDELIVERYMODE_FIXED:
2231 {
2232 /* Level-sensitive interrupts are not supported for LINT1. See Intel spec. 10.5.1 "Local Vector Table". */
2233 if (offLvt == XAPIC_OFF_LVT_LINT1)
2234 enmTriggerMode = XAPICTRIGGERMODE_EDGE;
2235 /** @todo figure out what "If the local APIC is not used in conjunction with an I/O APIC and fixed
2236 delivery mode is selected; the Pentium 4, Intel Xeon, and P6 family processors will always
2237 use level-sensitive triggering, regardless if edge-sensitive triggering is selected."
2238 means. */
2239 /* fallthru */
2240 }
2241 case XAPICDELIVERYMODE_SMI:
2242 case XAPICDELIVERYMODE_NMI:
2243 {
2244 VMCPUSET DestCpuSet;
2245 VMCPUSET_EMPTY(&DestCpuSet);
2246 VMCPUSET_ADD(&DestCpuSet, pVCpu->idCpu);
2247 uint8_t const uVector = XAPIC_LVT_GET_VECTOR(uLvt);
2248 rcStrict = apicSendIntr(pVCpu->CTX_SUFF(pVM), pVCpu, uVector, enmTriggerMode, enmDeliveryMode, &DestCpuSet,
2249 rcRZ);
2250 break;
2251 }
2252
2253 case XAPICDELIVERYMODE_EXTINT:
2254 {
2255 Log2(("APIC%u: APICLocalInterrupt: %s ExtINT through LINT%u\n", pVCpu->idCpu,
2256 u8Level ? "Raising" : "Lowering", u8Pin));
2257 if (u8Level)
2258 APICSetInterruptFF(pVCpu, PDMAPICIRQ_EXTINT);
2259 else
2260 APICClearInterruptFF(pVCpu, PDMAPICIRQ_EXTINT);
2261 break;
2262 }
2263
2264 /* Reserved/unknown delivery modes: */
2265 case XAPICDELIVERYMODE_LOWEST_PRIO:
2266 case XAPICDELIVERYMODE_STARTUP:
2267 default:
2268 {
2269 rcStrict = VERR_INTERNAL_ERROR_3;
2270 AssertMsgFailed(("APIC%u: LocalInterrupt: Invalid delivery mode %#x (%s) on LINT%d\n", pVCpu->idCpu,
2271 enmDeliveryMode, apicGetDeliveryModeName(enmDeliveryMode), u8Pin));
2272 break;
2273 }
2274 }
2275 }
2276 }
2277 else
2278 {
2279 /* The APIC is hardware disabled. The CPU behaves as though there is no on-chip APIC. */
2280 if (u8Pin == 0)
2281 {
2282 /* LINT0 behaves as an external interrupt pin. */
2283 Log2(("APIC%u: APICLocalInterrupt: APIC hardware-disabled, %s INTR\n", pVCpu->idCpu,
2284 u8Level ? "raising" : "lowering"));
2285 if (u8Level)
2286 APICSetInterruptFF(pVCpu, PDMAPICIRQ_EXTINT);
2287 else
2288 APICClearInterruptFF(pVCpu, PDMAPICIRQ_EXTINT);
2289 }
2290 else
2291 {
2292 /* LINT1 behaves as NMI. */
2293 Log2(("APIC%u: APICLocalInterrupt: APIC hardware-disabled, raising NMI\n", pVCpu->idCpu));
2294 APICSetInterruptFF(pVCpu, PDMAPICIRQ_NMI);
2295 }
2296 }
2297
2298 return rcStrict;
2299}
2300
2301
2302/**
2303 * @interface_method_impl{PDMAPICREG,pfnGetInterruptR3}
2304 */
2305VMMDECL(int) APICGetInterrupt(PPDMDEVINS pDevIns, PVMCPU pVCpu, uint8_t *pu8Vector, uint32_t *pu32TagSrc)
2306{
2307 VMCPU_ASSERT_EMT(pVCpu);
2308 Assert(pu8Vector);
2309 NOREF(pu32TagSrc);
2310
2311 LogFlow(("APIC%u: APICGetInterrupt\n", pVCpu->idCpu));
2312
2313 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
2314 bool const fApicHwEnabled = apicIsEnabled(pVCpu);
2315 if ( fApicHwEnabled
2316 && pXApicPage->svr.u.fApicSoftwareEnable)
2317 {
2318 int const irrv = apicGetHighestSetBit(&pXApicPage->irr, -1);
2319 if (RT_LIKELY(irrv >= 0))
2320 {
2321 Assert(irrv <= (int)UINT8_MAX);
2322 uint8_t const uVector = irrv;
2323
2324 /*
2325 * This can happen if the APIC receives an interrupt when the CPU has interrupts
2326 * disabled but the TPR is raised by the guest before re-enabling interrupts.
2327 */
2328 uint8_t const uTpr = pXApicPage->tpr.u8Tpr;
2329 if (uTpr > 0 && XAPIC_TPR_GET_TP(uVector) <= XAPIC_TPR_GET_TP(uTpr))
2330 {
2331 Log2(("APIC%u: APICGetInterrupt: Interrupt masked. uVector=%#x uTpr=%#x SpuriousVector=%#x\n", pVCpu->idCpu,
2332 uVector, uTpr, pXApicPage->svr.u.u8SpuriousVector));
2333 *pu8Vector = uVector;
2334 return VERR_APIC_INTR_MASKED_BY_TPR;
2335 }
2336
2337 /*
2338 * The PPR should be up-to-date at this point and we're on EMT (so no parallel updates).
2339 * Subject the pending vector to PPR prioritization.
2340 */
2341 uint8_t const uPpr = pXApicPage->ppr.u8Ppr;
2342 if ( !uPpr
2343 || XAPIC_PPR_GET_PP(uVector) > XAPIC_PPR_GET_PP(uPpr))
2344 {
2345 apicClearVectorInReg(&pXApicPage->irr, uVector);
2346 apicSetVectorInReg(&pXApicPage->isr, uVector);
2347 apicUpdatePpr(pVCpu);
2348 apicSignalNextPendingIntr(pVCpu);
2349
2350 Log2(("APIC%u: APICGetInterrupt: Valid Interrupt. uVector=%#x\n", pVCpu->idCpu, uVector));
2351 *pu8Vector = uVector;
2352 return VINF_SUCCESS;
2353 }
2354 else
2355 Log2(("APIC%u: APICGetInterrupt: Interrupt's priority is not higher than the PPR. uVector=%#x PPR=%#x\n",
2356 pVCpu->idCpu, uVector, uPpr));
2357 }
2358 else
2359 Log2(("APIC%u: APICGetInterrupt: No pending bits in IRR\n", pVCpu->idCpu));
2360 }
2361 else
2362 Log2(("APIC%u: APICGetInterrupt: APIC %s disabled\n", pVCpu->idCpu, !fApicHwEnabled ? "hardware" : "software"));
2363
2364 return VERR_APIC_INTR_NOT_PENDING;
2365}
2366
2367
2368/**
2369 * @callback_method_impl{FNIOMMMIOREAD}
2370 */
2371VMMDECL(int) APICReadMmio(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
2372{
2373 NOREF(pvUser);
2374 Assert(!(GCPhysAddr & 0xf));
2375 Assert(cb == 4);
2376
2377 PAPICDEV pApicDev = PDMINS_2_DATA(pDevIns, PAPICDEV);
2378 PVMCPU pVCpu = PDMDevHlpGetVMCPU(pDevIns);
2379 uint16_t offReg = (GCPhysAddr & 0xff0);
2380 uint32_t uValue = 0;
2381
2382 STAM_COUNTER_INC(&pVCpu->apic.s.CTX_SUFF(StatMmioRead));
2383
2384 int rc = apicReadRegister(pApicDev, pVCpu, offReg, &uValue);
2385 *(uint32_t *)pv = uValue;
2386
2387 Log2(("APIC%u: APICReadMmio: offReg=%#RX16 uValue=%#RX32\n", pVCpu->idCpu, offReg, uValue));
2388 return rc;
2389}
2390
2391
2392/**
2393 * @callback_method_impl{FNIOMMMIOWRITE}
2394 */
2395VMMDECL(int) APICWriteMmio(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb)
2396{
2397 NOREF(pvUser);
2398 Assert(!(GCPhysAddr & 0xf));
2399 Assert(cb == 4);
2400
2401 PAPICDEV pApicDev = PDMINS_2_DATA(pDevIns, PAPICDEV);
2402 PVMCPU pVCpu = PDMDevHlpGetVMCPU(pDevIns);
2403 uint16_t offReg = (GCPhysAddr & 0xff0);
2404 uint32_t uValue = *(uint32_t *)pv;
2405
2406 STAM_COUNTER_INC(&pVCpu->apic.s.CTX_SUFF(StatMmioWrite));
2407
2408 Log2(("APIC%u: APICWriteMmio: offReg=%#RX16 uValue=%#RX32\n", pVCpu->idCpu, offReg, uValue));
2409
2410 int rc = VBOXSTRICTRC_VAL(apicWriteRegister(pApicDev, pVCpu, offReg, uValue));
2411 return rc;
2412}
2413
2414
2415/**
2416 * Sets the interrupt pending force-flag and pokes the EMT if required.
2417 *
2418 * @param pVCpu The cross context virtual CPU structure.
2419 * @param enmType The IRQ type.
2420 */
2421VMMDECL(void) APICSetInterruptFF(PVMCPU pVCpu, PDMAPICIRQ enmType)
2422{
2423 PVM pVM = pVCpu->CTX_SUFF(pVM);
2424 PAPICDEV pApicDev = VM_TO_APICDEV(pVM);
2425 CTX_SUFF(pApicDev->pApicHlp)->pfnSetInterruptFF(pApicDev->CTX_SUFF(pDevIns), enmType, pVCpu->idCpu);
2426}
2427
2428
2429/**
2430 * Clears the interrupt pending force-flag.
2431 *
2432 * @param pVCpu The cross context virtual CPU structure.
2433 * @param enmType The IRQ type.
2434 */
2435VMMDECL(void) APICClearInterruptFF(PVMCPU pVCpu, PDMAPICIRQ enmType)
2436{
2437 PVM pVM = pVCpu->CTX_SUFF(pVM);
2438 PAPICDEV pApicDev = VM_TO_APICDEV(pVM);
2439 pApicDev->CTX_SUFF(pApicHlp)->pfnClearInterruptFF(pApicDev->CTX_SUFF(pDevIns), enmType, pVCpu->idCpu);
2440}
2441
2442
2443/**
2444 * Posts an interrupt to a target APIC.
2445 *
2446 * This function handles interrupts received from the system bus or
2447 * interrupts generated locally from the LVT or via a self IPI.
2448 *
2449 * Don't use this function to try and deliver ExtINT style interrupts.
2450 *
2451 * @param pVCpu The cross context virtual CPU structure.
2452 * @param uVector The vector of the interrupt to be posted.
2453 * @param enmTriggerMode The trigger mode of the interrupt.
2454 *
2455 * @thread Any.
2456 */
2457VMM_INT_DECL(void) APICPostInterrupt(PVMCPU pVCpu, uint8_t uVector, XAPICTRIGGERMODE enmTriggerMode)
2458{
2459 Assert(pVCpu);
2460 Assert(uVector > XAPIC_ILLEGAL_VECTOR_END);
2461
2462 PCAPIC pApic = VM_TO_APIC(pVCpu->CTX_SUFF(pVM));
2463 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
2464
2465 STAM_PROFILE_START(&pApicCpu->StatPostIntr, a);
2466
2467 /*
2468 * Only post valid interrupt vectors.
2469 * See Intel spec. 10.5.2 "Valid Interrupt Vectors".
2470 */
2471 if (RT_LIKELY(uVector > XAPIC_ILLEGAL_VECTOR_END))
2472 {
2473 /*
2474 * If the interrupt is already pending in the vIRR we can skip the
2475 * potential expensive operation of poking the guest EMT out of execution.
2476 */
2477 PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
2478 if (!apicTestVectorInReg(&pXApicPage->irr, uVector)) /* PAV */
2479 {
2480 Log2(("APIC%u: APICPostInterrupt: uVector=%#x\n", pVCpu->idCpu, uVector));
2481 if (enmTriggerMode == XAPICTRIGGERMODE_EDGE)
2482 {
2483 if (pApic->fPostedIntrsEnabled)
2484 { /** @todo posted-interrupt call to hardware */ }
2485 else
2486 {
2487 apicSetVectorInPib(pApicCpu->CTX_SUFF(pvApicPib), uVector);
2488 uint32_t const fAlreadySet = apicSetNotificationBitInPib((PAPICPIB)pApicCpu->CTX_SUFF(pvApicPib));
2489 if (!fAlreadySet)
2490 APICSetInterruptFF(pVCpu, PDMAPICIRQ_HARDWARE);
2491 }
2492 }
2493 else
2494 {
2495 /*
2496 * Level-triggered interrupts requires updating of the TMR and thus cannot be
2497 * delivered asynchronously.
2498 */
2499 apicSetVectorInPib(&pApicCpu->ApicPibLevel, uVector);
2500 uint32_t const fAlreadySet = apicSetNotificationBitInPib(&pApicCpu->ApicPibLevel);
2501 if (!fAlreadySet)
2502 APICSetInterruptFF(pVCpu, PDMAPICIRQ_HARDWARE);
2503 }
2504 }
2505 else
2506 STAM_COUNTER_INC(&pApicCpu->StatPostIntrAlreadyPending);
2507 }
2508 else
2509 apicSetError(pVCpu, XAPIC_ESR_RECV_ILLEGAL_VECTOR);
2510
2511 STAM_PROFILE_STOP(&pApicCpu->StatPostIntr, a);
2512}
2513
2514
2515/**
2516 * Starts the APIC timer.
2517 *
2518 * @param pVCpu The cross context virtual CPU structure.
2519 * @param uInitialCount The timer's Initial-Count Register (ICR), must be >
2520 * 0.
2521 * @thread Any.
2522 */
2523VMM_INT_DECL(void) APICStartTimer(PVMCPU pVCpu, uint32_t uInitialCount)
2524{
2525 Assert(pVCpu);
2526 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
2527 Assert(TMTimerIsLockOwner(pApicCpu->CTX_SUFF(pTimer)));
2528 Assert(uInitialCount > 0);
2529
2530 PCXAPICPAGE pXApicPage = APICCPU_TO_CXAPICPAGE(pApicCpu);
2531 uint8_t const uTimerShift = apicGetTimerShift(pXApicPage);
2532 uint64_t const cTicksToNext = (uint64_t)uInitialCount << uTimerShift;
2533
2534 Log2(("APIC%u: APICStartTimer: uInitialCount=%#RX32 uTimerShift=%u cTicksToNext=%RU64\n", pVCpu->idCpu, uInitialCount,
2535 uTimerShift, cTicksToNext));
2536
2537 /*
2538 * The assumption here is that the timer doesn't tick during this call
2539 * and thus setting a relative time to fire next is accurate. The advantage
2540 * however is updating u64TimerInitial 'atomically' while setting the next
2541 * tick.
2542 */
2543 PTMTIMER pTimer = pApicCpu->CTX_SUFF(pTimer);
2544 TMTimerSetRelative(pTimer, cTicksToNext, &pApicCpu->u64TimerInitial);
2545 apicHintTimerFreq(pApicCpu, uInitialCount, uTimerShift);
2546}
2547
2548
2549/**
2550 * Stops the APIC timer.
2551 *
2552 * @param pVCpu The cross context virtual CPU structure.
2553 * @thread Any.
2554 */
2555VMM_INT_DECL(void) APICStopTimer(PVMCPU pVCpu)
2556{
2557 Assert(pVCpu);
2558 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
2559 Assert(TMTimerIsLockOwner(pApicCpu->CTX_SUFF(pTimer)));
2560
2561 Log2(("APIC%u: APICStopTimer\n", pVCpu->idCpu));
2562
2563 PTMTIMER pTimer = pApicCpu->CTX_SUFF(pTimer);
2564 TMTimerStop(pTimer); /* This will reset the hint, no need to explicitly call TMTimerSetFrequencyHint(). */
2565 pApicCpu->uHintedTimerInitialCount = 0;
2566 pApicCpu->uHintedTimerShift = 0;
2567}
2568
2569
2570/**
2571 * Queues a pending interrupt as in-service.
2572 *
2573 * This function should only be needed without virtualized APIC
2574 * registers. With virtualized APIC registers, it's sufficient to keep
2575 * the interrupts pending in the IRR as the hardware takes care of
2576 * virtual interrupt delivery.
2577 *
2578 * @returns true if the interrupt was queued to in-service interrupts,
2579 * false otherwise.
2580 * @param pVCpu The cross context virtual CPU structure.
2581 * @param u8PendingIntr The pending interrupt to queue as
2582 * in-service.
2583 *
2584 * @remarks This assumes the caller has done the necessary checks and
2585 * is ready to take actually service the interrupt (TPR,
2586 * interrupt shadow etc.)
2587 */
2588VMMDECL(bool) APICQueueInterruptToService(PVMCPU pVCpu, uint8_t u8PendingIntr)
2589{
2590 VMCPU_ASSERT_EMT(pVCpu);
2591
2592 PVM pVM = pVCpu->CTX_SUFF(pVM);
2593 PAPIC pApic = VM_TO_APIC(pVM);
2594 Assert(!pApic->fVirtApicRegsEnabled);
2595 NOREF(pApic);
2596
2597 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
2598 bool const fIsPending = apicTestVectorInReg(&pXApicPage->irr, u8PendingIntr);
2599 if (fIsPending)
2600 {
2601 apicClearVectorInReg(&pXApicPage->irr, u8PendingIntr);
2602 apicSetVectorInReg(&pXApicPage->isr, u8PendingIntr);
2603 apicUpdatePpr(pVCpu);
2604 return true;
2605 }
2606 return false;
2607}
2608
2609
2610/**
2611 * Dequeues a pending interrupt from in-service.
2612 *
2613 * This undoes APICQueueInterruptToService() for premature VM-exits before event
2614 * injection.
2615 *
2616 * @param pVCpu The cross context virtual CPU structure.
2617 * @param u8PendingIntr The pending interrupt to dequeue from
2618 * in-service.
2619 */
2620VMMDECL(void) APICDequeueInterruptFromService(PVMCPU pVCpu, uint8_t u8PendingIntr)
2621{
2622 VMCPU_ASSERT_EMT(pVCpu);
2623
2624 PVM pVM = pVCpu->CTX_SUFF(pVM);
2625 PAPIC pApic = VM_TO_APIC(pVM);
2626 Assert(!pApic->fVirtApicRegsEnabled);
2627 NOREF(pApic);
2628
2629 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
2630 bool const fInService = apicTestVectorInReg(&pXApicPage->isr, u8PendingIntr);
2631 if (fInService)
2632 {
2633 apicClearVectorInReg(&pXApicPage->isr, u8PendingIntr);
2634 apicSetVectorInReg(&pXApicPage->irr, u8PendingIntr);
2635 apicUpdatePpr(pVCpu);
2636 }
2637}
2638
2639
2640/**
2641 * Updates pending interrupts from the pending-interrupt bitmaps to the IRR.
2642 *
2643 * @param pVCpu The cross context virtual CPU structure.
2644 */
2645VMMDECL(void) APICUpdatePendingInterrupts(PVMCPU pVCpu)
2646{
2647 VMCPU_ASSERT_EMT(pVCpu);
2648
2649 PAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
2650 PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);
2651
2652 STAM_PROFILE_START(&pApicCpu->StatUpdatePendingIntrs, a);
2653
2654 /* Update edge-triggered pending interrupts. */
2655 for (;;)
2656 {
2657 uint32_t const fAlreadySet = apicClearNotificationBitInPib((PAPICPIB)pApicCpu->CTX_SUFF(pvApicPib));
2658 if (!fAlreadySet)
2659 break;
2660
2661 PAPICPIB pPib = (PAPICPIB)pApicCpu->CTX_SUFF(pvApicPib);
2662 AssertCompile(RT_ELEMENTS(pXApicPage->irr.u) == 2 * RT_ELEMENTS(pPib->aVectorBitmap));
2663
2664 for (size_t idxPib = 0, idxReg = 0; idxPib < RT_ELEMENTS(pPib->aVectorBitmap); idxPib++, idxReg += 2)
2665 {
2666 uint64_t const u64Fragment = ASMAtomicXchgU64(&pPib->aVectorBitmap[idxPib], 0);
2667 if (u64Fragment)
2668 {
2669 uint32_t const u32FragmentLo = RT_LO_U32(u64Fragment);
2670 uint32_t const u32FragmentHi = RT_HI_U32(u64Fragment);
2671
2672 pXApicPage->irr.u[idxReg].u32Reg |= u32FragmentLo;
2673 pXApicPage->irr.u[idxReg + 1].u32Reg |= u32FragmentHi;
2674
2675 pXApicPage->tmr.u[idxReg].u32Reg &= ~u32FragmentLo;
2676 pXApicPage->tmr.u[idxReg + 1].u32Reg &= ~u32FragmentHi;
2677 }
2678 }
2679 }
2680
2681 /* Update level-triggered pending interrupts. */
2682 for (;;)
2683 {
2684 uint32_t const fAlreadySet = apicClearNotificationBitInPib((PAPICPIB)&pApicCpu->ApicPibLevel);
2685 if (!fAlreadySet)
2686 break;
2687
2688 PAPICPIB pPib = (PAPICPIB)&pApicCpu->ApicPibLevel;
2689 AssertCompile(RT_ELEMENTS(pXApicPage->irr.u) == 2 * RT_ELEMENTS(pPib->aVectorBitmap));
2690
2691 for (size_t idxPib = 0, idxReg = 0; idxPib < RT_ELEMENTS(pPib->aVectorBitmap); idxPib++, idxReg += 2)
2692 {
2693 uint64_t const u64Fragment = ASMAtomicXchgU64(&pPib->aVectorBitmap[idxPib], 0);
2694 if (u64Fragment)
2695 {
2696 uint32_t const u32FragmentLo = RT_LO_U32(u64Fragment);
2697 uint32_t const u32FragmentHi = RT_HI_U32(u64Fragment);
2698
2699 pXApicPage->irr.u[idxReg].u32Reg |= u32FragmentLo;
2700 pXApicPage->irr.u[idxReg + 1].u32Reg |= u32FragmentHi;
2701
2702 pXApicPage->tmr.u[idxReg].u32Reg |= u32FragmentLo;
2703 pXApicPage->tmr.u[idxReg + 1].u32Reg |= u32FragmentHi;
2704 }
2705 }
2706 }
2707
2708 STAM_PROFILE_STOP(&pApicCpu->StatUpdatePendingIntrs, a);
2709}
2710
2711
2712/**
2713 * Gets the highest priority pending interrupt.
2714 *
2715 * @returns true if any interrupt is pending, false otherwise.
2716 * @param pVCpu The cross context virtual CPU structure.
2717 * @param pu8PendingIntr Where to store the interrupt vector if the
2718 * interrupt is pending.
2719 */
2720VMMDECL(bool) APICGetHighestPendingInterrupt(PVMCPU pVCpu, uint8_t *pu8PendingIntr)
2721{
2722 VMCPU_ASSERT_EMT(pVCpu);
2723 return apicGetHighestPendingInterrupt(pVCpu, pu8PendingIntr);
2724}
2725
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