VirtualBox

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

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

VMM/APIC: Set the 'receive' and not 'send' illegal vector error when LVT entry is incorrectly programmed, logging, 130 col.

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