VirtualBox

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

Last change on this file since 65276 was 65135, checked in by vboxsync, 8 years ago

VMM/APIC: Interface for retrieving APIC pages in all contexts.

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

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