VirtualBox

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

Last change on this file since 62534 was 62460, checked in by vboxsync, 8 years ago

VMM: scm

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

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