VirtualBox

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

最後變更 在這個檔案從80317是 80253,由 vboxsync 提交於 6 年 前

VMM: Started refactoring VMMAll/* for bugref:9217

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette