VirtualBox

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

Last change on this file since 73281 was 73281, checked in by vboxsync, 7 years ago

APIC: Made APICSetBaseMsr work in ring-0 and raw-mode context without requiring returns to ring-3. This uncomplicates NEM/win (not done yet). bugref:9044

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

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