VirtualBox

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

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

VMM/APIC: naming.

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