VirtualBox

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

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

VMM: Fixed TPR thresholding and related PDM interfaces.
Cleaned up the PDM interface and merged apicHasPendingIrq with apicGetTpr.
Fixed raw-mode with the new APIC code due to busted GC mapping relocation.

This finally fixes the NT4 VM boot-up issue with the new APIC code.

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