VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/DevAPIC.cpp@ 39314

Last change on this file since 39314 was 39306, checked in by vboxsync, 13 years ago

DevAPIC: > 32 CPUs, cleanups.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 88.6 KB
Line 
1/* $Id: DevAPIC.cpp 39306 2011-11-15 13:14:13Z vboxsync $ */
2/** @file
3 * Advanced Programmable Interrupt Controller (APIC) Device and
4 * I/O Advanced Programmable Interrupt Controller (IO-APIC) Device.
5 */
6
7/*
8 * Copyright (C) 2006-2011 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 * --------------------------------------------------------------------
18 *
19 * This code is based on:
20 *
21 * apic.c revision 1.5 @@OSETODO
22 *
23 * APIC support
24 *
25 * Copyright (c) 2004-2005 Fabrice Bellard
26 *
27 * This library is free software; you can redistribute it and/or
28 * modify it under the terms of the GNU Lesser General Public
29 * License as published by the Free Software Foundation; either
30 * version 2 of the License, or (at your option) any later version.
31 *
32 * This library is distributed in the hope that it will be useful,
33 * but WITHOUT ANY WARRANTY; without even the implied warranty of
34 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
35 * Lesser General Public License for more details.
36 *
37 * You should have received a copy of the GNU Lesser General Public
38 * License along with this library; if not, write to the Free Software
39 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
40 */
41
42/*******************************************************************************
43* Header Files *
44*******************************************************************************/
45#define LOG_GROUP LOG_GROUP_DEV_APIC
46#include <VBox/vmm/pdmdev.h>
47
48#include <VBox/log.h>
49#include <VBox/vmm/stam.h>
50#include <VBox/vmm/vmcpuset.h>
51#include <iprt/asm.h>
52#include <iprt/assert.h>
53
54#include <VBox/msi.h>
55
56#include "VBoxDD2.h"
57#include "DevApic.h"
58
59/*******************************************************************************
60* Defined Constants And Macros *
61*******************************************************************************/
62#define MSR_IA32_APICBASE 0x1b
63#define MSR_IA32_APICBASE_BSP (1<<8)
64#define MSR_IA32_APICBASE_ENABLE (1<<11)
65#define MSR_IA32_APICBASE_X2ENABLE (1<<10)
66#define MSR_IA32_APICBASE_BASE (0xfffff<<12)
67
68#ifdef _MSC_VER
69# pragma warning(disable:4244)
70#endif
71
72/** The current saved state version.*/
73#define APIC_SAVED_STATE_VERSION 3
74/** The saved state version used by VirtualBox v3 and earlier.
75 * This does not include the config. */
76#define APIC_SAVED_STATE_VERSION_VBOX_30 2
77/** Some ancient version... */
78#define APIC_SAVED_STATE_VERSION_ANCIENT 1
79
80/* version 0x14: Pentium 4, Xeon; LVT count depends on that */
81#define APIC_HW_VERSION 0x14
82
83/** @def APIC_LOCK
84 * Acquires the PDM lock. */
85#define APIC_LOCK(a_pDev, rcBusy) \
86 do { \
87 int rc2 = PDMCritSectEnter((a_pDev)->CTX_SUFF(pCritSect), (rcBusy)); \
88 if (rc2 != VINF_SUCCESS) \
89 return rc2; \
90 } while (0)
91
92/** @def APIC_LOCK_VOID
93 * Acquires the PDM lock and does not expect failure (i.e. ring-3 only!). */
94#define APIC_LOCK_VOID(a_pDev, rcBusy) \
95 do { \
96 int rc2 = PDMCritSectEnter((a_pDev)->CTX_SUFF(pCritSect), (rcBusy)); \
97 AssertLogRelRCReturnVoid(rc2); \
98 } while (0)
99
100/** @def APIC_UNLOCK
101 * Releases the PDM lock. */
102#define APIC_UNLOCK(a_pDev) \
103 PDMCritSectLeave((a_pDev)->CTX_SUFF(pCritSect))
104
105/** @def APIC_AND_TM_LOCK
106 * Acquires the virtual sync clock lock as well as the PDM lock. */
107#define APIC_AND_TM_LOCK(a_pDev, a_pAcpi, rcBusy) \
108 do { \
109 int rc2 = TMTimerLock((a_pAcpi)->CTX_SUFF(pTimer), (rcBusy)); \
110 if (rc2 != VINF_SUCCESS) \
111 return rc2; \
112 rc2 = PDMCritSectEnter((a_pDev)->CTX_SUFF(pCritSect), (rcBusy)); \
113 if (rc2 != VINF_SUCCESS) \
114 { \
115 TMTimerUnlock((a_pAcpi)->CTX_SUFF(pTimer)); \
116 return rc2; \
117 } \
118 } while (0)
119
120/** @def APIC_AND_TM_UNLOCK
121 * Releases the PDM lock as well as the TM virtual sync clock lock. */
122#define APIC_AND_TM_UNLOCK(a_pDev, a_pAcpi) \
123 do { \
124 TMTimerUnlock((a_pAcpi)->CTX_SUFF(pTimer)); \
125 PDMCritSectLeave((a_pDev)->CTX_SUFF(pCritSect)); \
126 } while (0)
127
128/**
129 * Begins an APIC enumeration block.
130 *
131 * Code placed between this and the APIC_FOREACH_END macro will be executed for
132 * each APIC instance present in the system.
133 *
134 * @param a_pDev The APIC device.
135 */
136#define APIC_FOREACH_BEGIN(a_pDev) \
137 do { \
138 VMCPUID const cApics = (a_pDev)->cCpus; \
139 APICState *pCurApic = (a_pDev)->CTX_SUFF(paLapics); \
140 for (VMCPUID iCurApic = 0; iCurApic < cApics; iCurApic++, pCurApic++) \
141 { \
142 do { } while (0)
143
144/**
145 * Begins an APIC enumeration block, given a destination set.
146 *
147 * Code placed between this and the APIC_FOREACH_END macro will be executed for
148 * each APIC instance present in @a a_pDstSet.
149 *
150 * @param a_pDev The APIC device.
151 * @param a_pDstSet The destination set.
152 */
153#define APIC_FOREACH_IN_SET_BEGIN(a_pDev, a_pDstSet) \
154 APIC_FOREACH_BEGIN(a_pDev); \
155 if (!VMCPUSET_IS_PRESENT((a_pDstSet), iCurApic)) \
156 continue; \
157 do { } while (0)
158
159
160/** Counterpart to APIC_FOREACH_IN_SET_BEGIN and APIC_FOREACH_BEGIN. */
161#define APIC_FOREACH_END() \
162 } \
163 } while (0)
164
165#define DEBUG_APIC
166
167/* APIC Local Vector Table */
168#define APIC_LVT_TIMER 0
169#define APIC_LVT_THERMAL 1
170#define APIC_LVT_PERFORM 2
171#define APIC_LVT_LINT0 3
172#define APIC_LVT_LINT1 4
173#define APIC_LVT_ERROR 5
174#define APIC_LVT_NB 6
175
176/* APIC delivery modes */
177#define APIC_DM_FIXED 0
178#define APIC_DM_LOWPRI 1
179#define APIC_DM_SMI 2
180#define APIC_DM_NMI 4
181#define APIC_DM_INIT 5
182#define APIC_DM_SIPI 6
183#define APIC_DM_EXTINT 7
184
185/* APIC destination mode */
186#define APIC_DESTMODE_FLAT 0xf
187#define APIC_DESTMODE_CLUSTER 0x0
188
189#define APIC_TRIGGER_EDGE 0
190#define APIC_TRIGGER_LEVEL 1
191
192#define APIC_LVT_TIMER_PERIODIC (1<<17)
193#define APIC_LVT_MASKED (1<<16)
194#define APIC_LVT_LEVEL_TRIGGER (1<<15)
195#define APIC_LVT_REMOTE_IRR (1<<14)
196#define APIC_INPUT_POLARITY (1<<13)
197#define APIC_SEND_PENDING (1<<12)
198
199#define ESR_ILLEGAL_ADDRESS (1 << 7)
200
201#define APIC_SV_ENABLE (1 << 8)
202
203#define APIC_MAX_PATCH_ATTEMPTS 100
204
205typedef uint32_t PhysApicId;
206typedef uint32_t LogApicId;
207
208
209/*******************************************************************************
210* Structures and Typedefs *
211*******************************************************************************/
212typedef struct APIC256BITREG
213{
214 /** The bitmap data. */
215 uint32_t au32Bitmap[8 /*256/32*/];
216} APIC256BITREG;
217typedef APIC256BITREG *PAPIC256BITREG;
218typedef APIC256BITREG const *PCAPIC256BITREG;
219
220/**
221 * Tests if a bit in the 256-bit APIC register is set.
222 *
223 * @returns true if set, false if clear.
224 *
225 * @param pReg The register.
226 * @param iBit The bit to test for.
227 */
228DECLINLINE(bool) Apic256BitReg_IsBitSet(PCAPIC256BITREG pReg, unsigned iBit)
229{
230 Assert(iBit < 256);
231 return ASMBitTest(&pReg->au32Bitmap[0], iBit);
232}
233
234
235/**
236 * Sets a bit in the 256-bit APIC register is set.
237 *
238 * @param pReg The register.
239 * @param iBit The bit to set.
240 */
241DECLINLINE(void) Apic256BitReg_SetBit(PAPIC256BITREG pReg, unsigned iBit)
242{
243 Assert(iBit < 256);
244 return ASMBitSet(&pReg->au32Bitmap[0], iBit);
245}
246
247
248/**
249 * Clears a bit in the 256-bit APIC register is set.
250 *
251 * @param pReg The register.
252 * @param iBit The bit to clear.
253 */
254DECLINLINE(void) Apic256BitReg_ClearBit(PAPIC256BITREG pReg, unsigned iBit)
255{
256 Assert(iBit < 256);
257 return ASMBitClear(&pReg->au32Bitmap[0], iBit);
258}
259
260/**
261 * Clears all bits in the 256-bit APIC register set.
262 *
263 * @param pReg The register.
264 */
265DECLINLINE(void) Apic256BitReg_Empty(PAPIC256BITREG pReg)
266{
267 memset(&pReg->au32Bitmap[0], 0, sizeof(pReg->au32Bitmap));
268}
269
270/**
271 * Finds the last bit set in the register, i.e. the highest priority interrupt.
272 *
273 * @returns The index of the found bit, @a iRetAllClear if none was found.
274 *
275 * @param pReg The register.
276 * @param iRetAllClear What to return if all bits are clear.
277 */
278static int Apic256BitReg_FindLastSetBit(PCAPIC256BITREG pReg, int iRetAllClear)
279{
280 uint32_t i = RT_ELEMENTS(pReg->au32Bitmap);
281 while (i-- > 0)
282 {
283 uint32_t u = pReg->au32Bitmap[i];
284 if (u)
285 {
286 u = ASMBitLastSetU32(u);
287 u--;
288 u |= i << 5;
289 return (int)u;
290 }
291 }
292 return iRetAllClear;
293}
294
295
296typedef struct APICState
297{
298 uint32_t apicbase;
299 /* Task priority register (interrupt level) */
300 uint32_t tpr;
301 /* Logical APIC id - user programmable */
302 LogApicId id;
303 /* Physical APIC id - not visible to user, constant */
304 PhysApicId phys_id;
305 /** @todo: is it logical or physical? Not really used anyway now. */
306 PhysApicId arb_id;
307 uint32_t spurious_vec;
308 uint8_t log_dest;
309 uint8_t dest_mode;
310 APIC256BITREG isr; /**< in service register */
311 APIC256BITREG tmr; /**< trigger mode register */
312 APIC256BITREG irr; /**< interrupt request register */
313 uint32_t lvt[APIC_LVT_NB];
314 uint32_t esr; /* error register */
315 uint32_t icr[2];
316 uint32_t divide_conf;
317 int count_shift;
318 uint32_t initial_count;
319 uint32_t Alignment0;
320
321 /** The time stamp of the initial_count load, i.e. when it was started. */
322 uint64_t initial_count_load_time;
323 /** The time stamp of the next timer callback. */
324 uint64_t next_time;
325 /** The APIC timer - R3 Ptr. */
326 PTMTIMERR3 pTimerR3;
327 /** The APIC timer - R0 Ptr. */
328 PTMTIMERR0 pTimerR0;
329 /** The APIC timer - RC Ptr. */
330 PTMTIMERRC pTimerRC;
331 /** Whether the timer is armed or not */
332 bool fTimerArmed;
333 /** Alignment */
334 bool afAlignment[3];
335 /** The initial_count value used for the current frequency hint. */
336 uint32_t uHintedInitialCount;
337 /** The count_shift value used for the current frequency hint. */
338 uint32_t uHintedCountShift;
339 /** Timer description timer. */
340 R3PTRTYPE(char *) pszDesc;
341# ifdef VBOX_WITH_STATISTICS
342# if HC_ARCH_BITS == 32
343 uint32_t u32Alignment0;
344# endif
345 STAMCOUNTER StatTimerSetInitialCount;
346 STAMCOUNTER StatTimerSetInitialCountArm;
347 STAMCOUNTER StatTimerSetInitialCountDisarm;
348 STAMCOUNTER StatTimerSetLvt;
349 STAMCOUNTER StatTimerSetLvtClearPeriodic;
350 STAMCOUNTER StatTimerSetLvtPostponed;
351 STAMCOUNTER StatTimerSetLvtArmed;
352 STAMCOUNTER StatTimerSetLvtArm;
353 STAMCOUNTER StatTimerSetLvtArmRetries;
354 STAMCOUNTER StatTimerSetLvtNoRelevantChange;
355# endif
356
357} APICState;
358
359AssertCompileMemberAlignment(APICState, initial_count_load_time, 8);
360# ifdef VBOX_WITH_STATISTICS
361AssertCompileMemberAlignment(APICState, StatTimerSetInitialCount, 8);
362# endif
363
364typedef struct
365{
366 /** The device instance - R3 Ptr. */
367 PPDMDEVINSR3 pDevInsR3;
368 /** The APIC helpers - R3 Ptr. */
369 PCPDMAPICHLPR3 pApicHlpR3;
370 /** LAPICs states - R3 Ptr */
371 R3PTRTYPE(APICState *) paLapicsR3;
372 /** The critical section - R3 Ptr. */
373 R3PTRTYPE(PPDMCRITSECT) pCritSectR3;
374
375 /** The device instance - R0 Ptr. */
376 PPDMDEVINSR0 pDevInsR0;
377 /** The APIC helpers - R0 Ptr. */
378 PCPDMAPICHLPR0 pApicHlpR0;
379 /** LAPICs states - R0 Ptr */
380 R0PTRTYPE(APICState *) paLapicsR0;
381 /** The critical section - R3 Ptr. */
382 R0PTRTYPE(PPDMCRITSECT) pCritSectR0;
383
384 /** The device instance - RC Ptr. */
385 PPDMDEVINSRC pDevInsRC;
386 /** The APIC helpers - RC Ptr. */
387 PCPDMAPICHLPRC pApicHlpRC;
388 /** LAPICs states - RC Ptr */
389 RCPTRTYPE(APICState *) paLapicsRC;
390 /** The critical section - R3 Ptr. */
391 RCPTRTYPE(PPDMCRITSECT) pCritSectRC;
392
393 /** APIC specification version in this virtual hardware configuration. */
394 PDMAPICVERSION enmVersion;
395
396 /** Number of attempts made to optimize TPR accesses. */
397 uint32_t cTPRPatchAttempts;
398
399 /** Number of CPUs on the system (same as LAPIC count). */
400 uint32_t cCpus;
401 /** Whether we've got an IO APIC or not. */
402 bool fIoApic;
403 /** Alignment padding. */
404 bool afPadding[3];
405
406# ifdef VBOX_WITH_STATISTICS
407 STAMCOUNTER StatMMIOReadGC;
408 STAMCOUNTER StatMMIOReadHC;
409 STAMCOUNTER StatMMIOWriteGC;
410 STAMCOUNTER StatMMIOWriteHC;
411 STAMCOUNTER StatClearedActiveIrq;
412# endif
413} APICDeviceInfo;
414# ifdef VBOX_WITH_STATISTICS
415AssertCompileMemberAlignment(APICDeviceInfo, StatMMIOReadGC, 8);
416# endif
417
418#ifndef VBOX_DEVICE_STRUCT_TESTCASE
419
420/*******************************************************************************
421* Internal Functions *
422*******************************************************************************/
423static void apic_update_tpr(APICDeviceInfo *pDev, APICState* s, uint32_t val);
424
425static void apic_eoi(APICDeviceInfo *pDev, APICState* s); /* */
426static PVMCPUSET apic_get_delivery_bitmask(APICDeviceInfo* pDev, uint8_t dest, uint8_t dest_mode, PVMCPUSET pDstSet);
427static int apic_deliver(APICDeviceInfo* pDev, APICState *s,
428 uint8_t dest, uint8_t dest_mode,
429 uint8_t delivery_mode, uint8_t vector_num,
430 uint8_t polarity, uint8_t trigger_mode);
431static int apic_get_arb_pri(APICState const *s);
432static int apic_get_ppr(APICState const *s);
433static uint32_t apic_get_current_count(APICDeviceInfo const *pDev, APICState const *s);
434static void apicTimerSetInitialCount(APICDeviceInfo *pDev, APICState *s, uint32_t initial_count);
435static void apicTimerSetLvt(APICDeviceInfo *pDev, APICState *pApic, uint32_t fNew);
436static void apicSendInitIpi(APICDeviceInfo* pDev, APICState *s);
437
438static void apic_init_ipi(APICDeviceInfo* pDev, APICState *s);
439static void apic_set_irq(APICDeviceInfo* pDev, APICState *s, int vector_num, int trigger_mode);
440static bool apic_update_irq(APICDeviceInfo* pDev, APICState *s);
441
442
443DECLINLINE(APICState*) getLapicById(APICDeviceInfo *pDev, VMCPUID id)
444{
445 AssertFatalMsg(id < pDev->cCpus, ("CPU id %d out of range\n", id));
446 return &pDev->CTX_SUFF(paLapics)[id];
447}
448
449DECLINLINE(APICState*) getLapic(APICDeviceInfo* pDev)
450{
451 /* LAPIC's array is indexed by CPU id */
452 VMCPUID id = pDev->CTX_SUFF(pApicHlp)->pfnGetCpuId(pDev->CTX_SUFF(pDevIns));
453 return getLapicById(pDev, id);
454}
455
456DECLINLINE(VMCPUID) getCpuFromLapic(APICDeviceInfo* pDev, APICState *s)
457{
458 /* for now we assume LAPIC physical id == CPU id */
459 return VMCPUID(s->phys_id);
460}
461
462DECLINLINE(void) cpuSetInterrupt(APICDeviceInfo* pDev, APICState *s, PDMAPICIRQ enmType = PDMAPICIRQ_HARDWARE)
463{
464 LogFlow(("apic: setting interrupt flag for cpu %d\n", getCpuFromLapic(pDev, s)));
465 pDev->CTX_SUFF(pApicHlp)->pfnSetInterruptFF(pDev->CTX_SUFF(pDevIns), enmType,
466 getCpuFromLapic(pDev, s));
467}
468
469DECLINLINE(void) cpuClearInterrupt(APICDeviceInfo* pDev, APICState *s, PDMAPICIRQ enmType = PDMAPICIRQ_HARDWARE)
470{
471 LogFlow(("apic: clear interrupt flag\n"));
472 pDev->CTX_SUFF(pApicHlp)->pfnClearInterruptFF(pDev->CTX_SUFF(pDevIns), enmType,
473 getCpuFromLapic(pDev, s));
474}
475
476# ifdef IN_RING3
477
478DECLINLINE(void) cpuSendSipi(APICDeviceInfo* pDev, APICState *s, int vector)
479{
480 Log2(("apic: send SIPI vector=%d\n", vector));
481
482 pDev->pApicHlpR3->pfnSendSipi(pDev->pDevInsR3,
483 getCpuFromLapic(pDev, s),
484 vector);
485}
486
487DECLINLINE(void) cpuSendInitIpi(APICDeviceInfo* pDev, APICState *s)
488{
489 Log2(("apic: send init IPI\n"));
490
491 pDev->pApicHlpR3->pfnSendInitIpi(pDev->pDevInsR3,
492 getCpuFromLapic(pDev, s));
493}
494
495# endif /* IN_RING3 */
496
497DECLINLINE(uint32_t) getApicEnableBits(APICDeviceInfo* pDev)
498{
499 switch (pDev->enmVersion)
500 {
501 case PDMAPICVERSION_NONE:
502 return 0;
503 case PDMAPICVERSION_APIC:
504 return MSR_IA32_APICBASE_ENABLE;
505 case PDMAPICVERSION_X2APIC:
506 return MSR_IA32_APICBASE_ENABLE | MSR_IA32_APICBASE_X2ENABLE ;
507 default:
508 AssertMsgFailed(("Unsupported APIC version %d\n", pDev->enmVersion));
509 return 0;
510 }
511}
512
513DECLINLINE(PDMAPICVERSION) getApicMode(APICState *apic)
514{
515 switch (((apic->apicbase) >> 10) & 0x3)
516 {
517 case 0:
518 return PDMAPICVERSION_NONE;
519 case 1:
520 default:
521 /* Invalid */
522 return PDMAPICVERSION_NONE;
523 case 2:
524 return PDMAPICVERSION_APIC;
525 case 3:
526 return PDMAPICVERSION_X2APIC;
527 }
528}
529
530static int apic_bus_deliver(APICDeviceInfo* pDev,
531 PCVMCPUSET pDstSet, uint8_t delivery_mode,
532 uint8_t vector_num, uint8_t polarity,
533 uint8_t trigger_mode)
534{
535 LogFlow(("apic_bus_deliver mask=%R[vmcpuset] mode=%x vector=%x polarity=%x trigger_mode=%x\n",
536 pDstSet, delivery_mode, vector_num, polarity, trigger_mode));
537
538 switch (delivery_mode)
539 {
540 case APIC_DM_LOWPRI:
541 {
542 VMCPUID idDstCpu = VMCPUSET_FIND_FIRST_PRESENT(pDstSet);
543 if (idDstCpu != NIL_VMCPUID)
544 {
545 APICState *pApic = getLapicById(pDev, idDstCpu);
546 apic_set_irq(pDev, pApic, vector_num, trigger_mode);
547 }
548 return VINF_SUCCESS;
549 }
550
551 case APIC_DM_FIXED:
552 /** @todo XXX: arbitration */
553 break;
554
555 case APIC_DM_SMI:
556 APIC_FOREACH_IN_SET_BEGIN(pDev, pDstSet);
557 cpuSetInterrupt(pDev, pCurApic, PDMAPICIRQ_SMI);
558 APIC_FOREACH_END();
559 return VINF_SUCCESS;
560
561 case APIC_DM_NMI:
562 APIC_FOREACH_IN_SET_BEGIN(pDev, pDstSet);
563 cpuSetInterrupt(pDev, pCurApic, PDMAPICIRQ_NMI);
564 APIC_FOREACH_END();
565 return VINF_SUCCESS;
566
567 case APIC_DM_INIT:
568 /* normal INIT IPI sent to processors */
569#ifdef IN_RING3
570 APIC_FOREACH_IN_SET_BEGIN(pDev, pDstSet);
571 apicSendInitIpi(pDev, pCurApic);
572 APIC_FOREACH_END();
573 return VINF_SUCCESS;
574#else
575 /* We shall send init IPI only in R3. */
576 return VINF_IOM_HC_MMIO_READ_WRITE;
577#endif /* IN_RING3 */
578
579 case APIC_DM_EXTINT:
580 /* handled in I/O APIC code */
581 break;
582
583 default:
584 return VINF_SUCCESS;
585 }
586
587 APIC_FOREACH_IN_SET_BEGIN(pDev, pDstSet);
588 apic_set_irq(pDev, pCurApic, vector_num, trigger_mode);
589 APIC_FOREACH_END();
590 return VINF_SUCCESS;
591}
592
593
594PDMBOTHCBDECL(void) apicSetBase(PPDMDEVINS pDevIns, uint64_t val)
595{
596 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
597 Assert(PDMCritSectIsOwner(pDev->CTX_SUFF(pCritSect)));
598 APICState *s = getLapic(pDev); /** @todo fix interface */
599 Log(("apicSetBase: %016RX64\n", val));
600
601 /** @todo: do we need to lock here ? */
602 /* APIC_LOCK_VOID(pDev, VERR_INTERNAL_ERROR); */
603 /** @todo If this change is valid immediately, then we should change the MMIO registration! */
604 /* We cannot change if this CPU is BSP or not by writing to MSR - it's hardwired */
605 PDMAPICVERSION oldMode = getApicMode(s);
606 s->apicbase =
607 (val & 0xfffff000) | /* base */
608 (val & getApicEnableBits(pDev)) | /* mode */
609 (s->apicbase & MSR_IA32_APICBASE_BSP) /* keep BSP bit */;
610 PDMAPICVERSION newMode = getApicMode(s);
611
612 if (oldMode != newMode)
613 {
614 switch (newMode)
615 {
616 case PDMAPICVERSION_NONE:
617 {
618 s->spurious_vec &= ~APIC_SV_ENABLE;
619 /* Clear any pending APIC interrupt action flag. */
620 cpuClearInterrupt(pDev, s);
621 /** @todo: why do we do that? */
622 pDev->CTX_SUFF(pApicHlp)->pfnChangeFeature(pDevIns, PDMAPICVERSION_NONE);
623 break;
624 }
625 case PDMAPICVERSION_APIC:
626 /** @todo: map MMIO ranges, if needed */
627 break;
628 case PDMAPICVERSION_X2APIC:
629 /** @todo: unmap MMIO ranges of this APIC, according to the spec */
630 break;
631 default:
632 break;
633 }
634 }
635 /* APIC_UNLOCK(pDev); */
636}
637
638PDMBOTHCBDECL(uint64_t) apicGetBase(PPDMDEVINS pDevIns)
639{
640 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
641 Assert(PDMCritSectIsOwner(pDev->CTX_SUFF(pCritSect)));
642 APICState *s = getLapic(pDev); /** @todo fix interface */
643 LogFlow(("apicGetBase: %016llx\n", (uint64_t)s->apicbase));
644 return s->apicbase;
645}
646
647PDMBOTHCBDECL(void) apicSetTPR(PPDMDEVINS pDevIns, VMCPUID idCpu, uint8_t val)
648{
649 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
650 Assert(PDMCritSectIsOwner(pDev->CTX_SUFF(pCritSect)));
651 APICState *s = getLapicById(pDev, idCpu);
652 LogFlow(("apicSetTPR: val=%#x (trp %#x -> %#x)\n", val, s->tpr, val));
653 apic_update_tpr(pDev, s, val);
654}
655
656PDMBOTHCBDECL(uint8_t) apicGetTPR(PPDMDEVINS pDevIns, VMCPUID idCpu)
657{
658 /* We don't perform any locking here as that would cause a lot of contention for VT-x/AMD-V. */
659 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
660 APICState *s = getLapicById(pDev, idCpu);
661 Log2(("apicGetTPR: returns %#x\n", s->tpr));
662 return s->tpr;
663}
664
665
666/**
667 * apicWriteRegister helper for dealing with invalid register access.
668 *
669 * @returns Strict VBox status code.
670 * @param pDev The PDM device instance.
671 * @param pApic The APIC being written to.
672 * @param iReg The APIC register index.
673 * @param u64Value The value being written.
674 * @param rcBusy The busy return code to employ. See
675 * PDMCritSectEnter for a description.
676 * @param fMsr Set if called via MSR, clear if MMIO.
677 */
678static int apicWriteRegisterInvalid(APICDeviceInfo *pDev, APICState *pApic, uint32_t iReg, uint64_t u64Value,
679 int rcBusy, bool fMsr)
680{
681 Log(("apicWriteRegisterInvalid/%u: iReg=%#x fMsr=%RTbool u64Value=%#llx\n", pApic->phys_id, iReg, fMsr, u64Value));
682 int rc = PDMDevHlpDBGFStop(pDev->CTX_SUFF(pDevIns), RT_SRC_POS,
683 "iReg=%#x fMsr=%RTbool u64Value=%#llx id=%u\n", iReg, fMsr, u64Value, pApic->phys_id);
684 APIC_LOCK(pDev, rcBusy);
685 pApic->esr |= ESR_ILLEGAL_ADDRESS;
686 APIC_UNLOCK(pDev);
687 return rc;
688}
689
690
691
692/**
693 * Writes to an APIC register via MMIO or MSR.
694 *
695 * @returns Strict VBox status code.
696 * @param pDev The PDM device instance.
697 * @param pApic The APIC being written to.
698 * @param iReg The APIC register index.
699 * @param u64Value The value being written.
700 * @param rcBusy The busy return code to employ. See
701 * PDMCritSectEnter for a description.
702 * @param fMsr Set if called via MSR, clear if MMIO.
703 */
704static int apicWriteRegister(APICDeviceInfo *pDev, APICState *pApic, uint32_t iReg, uint64_t u64Value,
705 int rcBusy, bool fMsr)
706{
707 Assert(!PDMCritSectIsOwner(pDev->CTX_SUFF(pCritSect)));
708
709 int rc = VINF_SUCCESS;
710 switch (iReg)
711 {
712 case 0x02:
713 APIC_LOCK(pDev, rcBusy);
714 pApic->id = (u64Value >> 24); /** @todo r=bird: Is the range supposed to be 40 bits??? */
715 APIC_UNLOCK(pDev);
716 break;
717
718 case 0x03:
719 /* read only, ignore write. */
720 break;
721
722 case 0x08:
723 APIC_LOCK(pDev, rcBusy);
724 apic_update_tpr(pDev, pApic, u64Value);
725 APIC_UNLOCK(pDev);
726 break;
727
728 case 0x09: case 0x0a:
729 Log(("apicWriteRegister: write to read-only register %d ignored\n", iReg));
730 break;
731
732 case 0x0b: /* EOI */
733 APIC_LOCK(pDev, rcBusy);
734 apic_eoi(pDev, pApic);
735 APIC_UNLOCK(pDev);
736 break;
737
738 case 0x0d:
739 APIC_LOCK(pDev, rcBusy);
740 pApic->log_dest = (u64Value >> 24) & 0xff;
741 APIC_UNLOCK(pDev);
742 break;
743
744 case 0x0e:
745 APIC_LOCK(pDev, rcBusy);
746 pApic->dest_mode = u64Value >> 28; /** @todo r=bird: range? This used to be 32-bit before morphed into an MSR handler. */
747 APIC_UNLOCK(pDev);
748 break;
749
750 case 0x0f:
751 APIC_LOCK(pDev, rcBusy);
752 pApic->spurious_vec = u64Value & 0x1ff;
753 apic_update_irq(pDev, pApic);
754 APIC_UNLOCK(pDev);
755 break;
756
757 case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
758 case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
759 case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
760 case 0x28:
761 Log(("apicWriteRegister: write to read-only register %d ignored\n", iReg));
762 break;
763
764 case 0x30:
765 APIC_LOCK(pDev, rcBusy);
766 pApic->icr[0] = (uint32_t)u64Value;
767 if (fMsr) /* Here one of the differences with regular APIC: ICR is single 64-bit register */
768 pApic->icr[1] = (uint32_t)(u64Value >> 32);
769 rc = apic_deliver(pDev, pApic, (pApic->icr[1] >> 24) & 0xff, (pApic->icr[0] >> 11) & 1,
770 (pApic->icr[0] >> 8) & 7, (pApic->icr[0] & 0xff),
771 (pApic->icr[0] >> 14) & 1, (pApic->icr[0] >> 15) & 1);
772 APIC_UNLOCK(pDev);
773 break;
774
775 case 0x31:
776 if (!fMsr)
777 {
778 APIC_LOCK(pDev, rcBusy);
779 pApic->icr[1] = (uint64_t)u64Value;
780 APIC_UNLOCK(pDev);
781 }
782 else
783 rc = apicWriteRegisterInvalid(pDev, pApic, iReg, u64Value, rcBusy, fMsr);
784 break;
785
786 case 0x32 + APIC_LVT_TIMER:
787 AssertCompile(APIC_LVT_TIMER == 0);
788 APIC_AND_TM_LOCK(pDev, pApic, rcBusy);
789 apicTimerSetLvt(pDev, pApic, u64Value);
790 APIC_AND_TM_UNLOCK(pDev, pApic);
791 break;
792
793 case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
794 APIC_LOCK(pDev, rcBusy);
795 pApic->lvt[iReg - 0x32] = u64Value;
796 APIC_UNLOCK(pDev);
797 break;
798
799 case 0x38:
800 APIC_AND_TM_LOCK(pDev, pApic, rcBusy);
801 apicTimerSetInitialCount(pDev, pApic, u64Value);
802 APIC_AND_TM_UNLOCK(pDev, pApic);
803 break;
804
805 case 0x39:
806 Log(("apicWriteRegister: write to read-only register %d ignored\n", iReg));
807 break;
808
809 case 0x3e:
810 {
811 APIC_LOCK(pDev, rcBusy);
812 pApic->divide_conf = u64Value & 0xb;
813 int v = (pApic->divide_conf & 3) | ((pApic->divide_conf >> 1) & 4);
814 pApic->count_shift = (v + 1) & 7;
815 APIC_UNLOCK(pDev);
816 break;
817 }
818
819 case 0x3f:
820 if (fMsr)
821 {
822 /* Self IPI, see x2APIC book 2.4.5 */
823 APIC_LOCK(pDev, rcBusy);
824 int vector = u64Value & 0xff;
825 VMCPUSET SelfSet;
826 VMCPUSET_EMPTY(&SelfSet);
827 VMCPUSET_ADD(&SelfSet, pApic->id);
828 rc = apic_bus_deliver(pDev,
829 &SelfSet,
830 0 /* Delivery mode - fixed */,
831 vector,
832 0 /* Polarity - conform to the bus */,
833 0 /* Trigger mode - edge */);
834 APIC_UNLOCK(pDev);
835 break;
836 }
837 /* else: fall thru */
838
839 default:
840 rc = apicWriteRegisterInvalid(pDev, pApic, iReg, u64Value, rcBusy, fMsr);
841 break;
842 }
843
844 return rc;
845}
846
847
848/**
849 * apicReadRegister helper for dealing with invalid register access.
850 *
851 * @returns Strict VBox status code.
852 * @param pDev The PDM device instance.
853 * @param pApic The APIC being read to.
854 * @param iReg The APIC register index.
855 * @param pu64Value Where to store the value we've read.
856 * @param rcBusy The busy return code to employ. See
857 * PDMCritSectEnter for a description.
858 * @param fMsr Set if called via MSR, clear if MMIO.
859 */
860static int apicReadRegisterInvalid(APICDeviceInfo *pDev, APICState *pApic, uint32_t iReg, uint64_t *pu64Value,
861 int rcBusy, bool fMsr)
862{
863 Log(("apicReadRegisterInvalid/%u: iReg=%#x fMsr=%RTbool\n", pApic->phys_id, iReg, fMsr));
864 int rc = PDMDevHlpDBGFStop(pDev->CTX_SUFF(pDevIns), RT_SRC_POS,
865 "iReg=%#x fMsr=%RTbool id=%u\n", iReg, fMsr, pApic->phys_id);
866 APIC_LOCK(pDev, rcBusy);
867 pApic->esr |= ESR_ILLEGAL_ADDRESS;
868 APIC_UNLOCK(pDev);
869 *pu64Value = 0;
870 return rc;
871}
872
873
874/**
875 * Read from an APIC register via MMIO or MSR.
876 *
877 * @returns Strict VBox status code.
878 * @param pDev The PDM device instance.
879 * @param pApic The APIC being read to.
880 * @param iReg The APIC register index.
881 * @param pu64Value Where to store the value we've read.
882 * @param rcBusy The busy return code to employ. See
883 * PDMCritSectEnter for a description.
884 * @param fMsr Set if called via MSR, clear if MMIO.
885 */
886static int apicReadRegister(APICDeviceInfo *pDev, APICState *pApic, uint32_t iReg, uint64_t *pu64Value,
887 int rcBusy, bool fMsr)
888{
889 Assert(!PDMCritSectIsOwner(pDev->CTX_SUFF(pCritSect)));
890
891 int rc = VINF_SUCCESS;
892 switch (iReg)
893 {
894 case 0x02: /* id */
895 APIC_LOCK(pDev, rcBusy);
896 *pu64Value = pApic->id << 24;
897 APIC_UNLOCK(pDev);
898 break;
899
900 case 0x03: /* version */
901 APIC_LOCK(pDev, rcBusy);
902 *pu64Value = APIC_HW_VERSION
903 | ((APIC_LVT_NB - 1) << 16) /* Max LVT index */
904#if 0
905 | (0 << 24) /* Support for EOI broadcast suppression */
906#endif
907 ;
908 APIC_UNLOCK(pDev);
909 break;
910
911 case 0x08:
912 APIC_LOCK(pDev, rcBusy);
913 *pu64Value = pApic->tpr;
914 APIC_UNLOCK(pDev);
915 break;
916
917 case 0x09:
918 *pu64Value = apic_get_arb_pri(pApic);
919 break;
920
921 case 0x0a:
922 /* ppr */
923 APIC_LOCK(pDev, rcBusy);
924 *pu64Value = apic_get_ppr(pApic);
925 APIC_UNLOCK(pDev);
926 break;
927
928 case 0x0b:
929 Log(("apicReadRegister: %x -> write only returning 0\n", iReg));
930 *pu64Value = 0;
931 break;
932
933 case 0x0d:
934 APIC_LOCK(pDev, rcBusy);
935 *pu64Value = (uint64_t)pApic->log_dest << 24;
936 APIC_UNLOCK(pDev);
937 break;
938
939 case 0x0e:
940 /* Bottom 28 bits are always 1 */
941 APIC_LOCK(pDev, rcBusy);
942 *pu64Value = ((uint64_t)pApic->dest_mode << 28) | UINT32_C(0xfffffff);
943 APIC_UNLOCK(pDev);
944 break;
945
946 case 0x0f:
947 APIC_LOCK(pDev, rcBusy);
948 *pu64Value = pApic->spurious_vec;
949 APIC_UNLOCK(pDev);
950 break;
951
952 case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
953 APIC_LOCK(pDev, rcBusy);
954 *pu64Value = pApic->isr.au32Bitmap[iReg & 7];
955 APIC_UNLOCK(pDev);
956 break;
957
958 case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
959 APIC_LOCK(pDev, rcBusy);
960 *pu64Value = pApic->tmr.au32Bitmap[iReg & 7];
961 APIC_UNLOCK(pDev);
962 break;
963
964 case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
965 APIC_LOCK(pDev, rcBusy);
966 *pu64Value = pApic->irr.au32Bitmap[iReg & 7];
967 APIC_UNLOCK(pDev);
968 break;
969
970 case 0x28:
971 APIC_LOCK(pDev, rcBusy);
972 *pu64Value = pApic->esr;
973 APIC_UNLOCK(pDev);
974 break;
975
976 case 0x30:
977 /* Here one of the differences with regular APIC: ICR is single 64-bit register */
978 APIC_LOCK(pDev, rcBusy);
979 if (fMsr)
980 *pu64Value = RT_MAKE_U64(pApic->icr[0], pApic->icr[1]);
981 else
982 *pu64Value = pApic->icr[0];
983 APIC_UNLOCK(pDev);
984 break;
985
986 case 0x31:
987 if (fMsr)
988 rc = apicReadRegisterInvalid(pDev, pApic, iReg, pu64Value, rcBusy, fMsr);
989 else
990 {
991 APIC_LOCK(pDev, rcBusy);
992 *pu64Value = pApic->icr[1];
993 APIC_UNLOCK(pDev);
994 }
995 break;
996
997 case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
998 APIC_LOCK(pDev, rcBusy);
999 *pu64Value = pApic->lvt[iReg - 0x32];
1000 APIC_UNLOCK(pDev);
1001 break;
1002
1003 case 0x38:
1004 APIC_LOCK(pDev, rcBusy);
1005 *pu64Value = pApic->initial_count;
1006 APIC_UNLOCK(pDev);
1007 break;
1008
1009 case 0x39:
1010 APIC_AND_TM_LOCK(pDev, pApic, rcBusy);
1011 *pu64Value = apic_get_current_count(pDev, pApic);
1012 APIC_AND_TM_UNLOCK(pDev, pApic);
1013 break;
1014
1015 case 0x3e:
1016 APIC_LOCK(pDev, rcBusy);
1017 *pu64Value = pApic->divide_conf;
1018 APIC_UNLOCK(pDev);
1019 break;
1020
1021 case 0x3f:
1022 if (fMsr)
1023 {
1024 /* Self IPI register is write only */
1025 Log(("apicReadMSR: read from write-only register %d ignored\n", iReg));
1026 *pu64Value = 0;
1027 }
1028 else
1029 rc = apicReadRegisterInvalid(pDev, pApic, iReg, pu64Value, rcBusy, fMsr);
1030 break;
1031 case 0x2f: /** @todo Correctable machine check exception vector, implement me! */
1032 default:
1033 /**
1034 * @todo: according to spec when APIC writes to ESR it msut raise error interrupt,
1035 * i.e. LVT[5]
1036 */
1037 rc = apicReadRegisterInvalid(pDev, pApic, iReg, pu64Value, rcBusy, fMsr);
1038 break;
1039 }
1040 return rc;
1041}
1042
1043/**
1044 * @interface_method_impl{PDMAPICREG,pfnWriteMSRR3}
1045 */
1046PDMBOTHCBDECL(int) apicWriteMSR(PPDMDEVINS pDevIns, VMCPUID idCpu, uint32_t u32Reg, uint64_t u64Value)
1047{
1048 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
1049 if (pDev->enmVersion < PDMAPICVERSION_X2APIC)
1050 return VERR_EM_INTERPRETER; /** @todo tell the caller to raise hell (\#GP(0)). */
1051
1052 APICState *pApic = getLapicById(pDev, idCpu);
1053 uint32_t iReg = (u32Reg - MSR_IA32_APIC_START) & 0xff;
1054 return apicWriteRegister(pDev, pApic, iReg, u64Value, VINF_SUCCESS /*rcBusy*/, true /*fMsr*/);
1055}
1056
1057
1058/**
1059 * @interface_method_impl{PDMAPICREG,pfnReadMSRR3}
1060 */
1061PDMBOTHCBDECL(int) apicReadMSR(PPDMDEVINS pDevIns, VMCPUID idCpu, uint32_t u32Reg, uint64_t *pu64Value)
1062{
1063 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
1064 Assert(PDMCritSectIsOwner(pDev->CTX_SUFF(pCritSect)));
1065
1066 if (pDev->enmVersion < PDMAPICVERSION_X2APIC)
1067 return VERR_EM_INTERPRETER;
1068
1069 APICState *pApic = getLapicById(pDev, idCpu);
1070 uint32_t iReg = (u32Reg - MSR_IA32_APIC_START) & 0xff;
1071 return apicReadRegister(pDev, pApic, iReg, pu64Value, VINF_SUCCESS /*rcBusy*/, true /*fMsr*/);
1072}
1073
1074/**
1075 * More or less private interface between IOAPIC, only PDM is responsible
1076 * for connecting the two devices.
1077 */
1078PDMBOTHCBDECL(int) apicBusDeliverCallback(PPDMDEVINS pDevIns, uint8_t u8Dest, uint8_t u8DestMode,
1079 uint8_t u8DeliveryMode, uint8_t iVector, uint8_t u8Polarity,
1080 uint8_t u8TriggerMode)
1081{
1082 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
1083 Assert(PDMCritSectIsOwner(pDev->CTX_SUFF(pCritSect)));
1084 LogFlow(("apicBusDeliverCallback: pDevIns=%p u8Dest=%#x u8DestMode=%#x u8DeliveryMode=%#x iVector=%#x u8Polarity=%#x u8TriggerMode=%#x\n",
1085 pDevIns, u8Dest, u8DestMode, u8DeliveryMode, iVector, u8Polarity, u8TriggerMode));
1086 VMCPUSET DstSet;
1087 return apic_bus_deliver(pDev, apic_get_delivery_bitmask(pDev, u8Dest, u8DestMode, &DstSet),
1088 u8DeliveryMode, iVector, u8Polarity, u8TriggerMode);
1089}
1090
1091/**
1092 * Local interrupt delivery, for devices attached to the CPU's LINT0/LINT1 pin.
1093 * Normally used for 8259A PIC and NMI.
1094 */
1095PDMBOTHCBDECL(int) apicLocalInterrupt(PPDMDEVINS pDevIns, uint8_t u8Pin, uint8_t u8Level)
1096{
1097 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
1098 APICState *s = getLapicById(pDev, 0);
1099
1100 Assert(PDMCritSectIsOwner(pDev->CTX_SUFF(pCritSect)));
1101 LogFlow(("apicLocalInterrupt: pDevIns=%p u8Pin=%x u8Level=%x\n", pDevIns, u8Pin, u8Level));
1102
1103 /* If LAPIC is disabled, go straight to the CPU. */
1104 if (!(s->spurious_vec & APIC_SV_ENABLE))
1105 {
1106 LogFlow(("apicLocalInterrupt: LAPIC disabled, delivering directly to CPU core.\n"));
1107 if (u8Level)
1108 cpuSetInterrupt(pDev, s, PDMAPICIRQ_EXTINT);
1109 else
1110 cpuClearInterrupt(pDev, s, PDMAPICIRQ_EXTINT);
1111
1112 return VINF_SUCCESS;
1113 }
1114
1115 /* If LAPIC is enabled, interrupts are subject to LVT programming. */
1116
1117 /* There are only two local interrupt pins. */
1118 AssertMsgReturn(u8Pin <= 1, ("Invalid LAPIC pin %d\n", u8Pin), VERR_INVALID_PARAMETER);
1119
1120 /* NB: We currently only deliver local interrupts to the first CPU. In theory they
1121 * should be delivered to all CPUs and it is the guest's responsibility to ensure
1122 * no more than one CPU has the interrupt unmasked.
1123 */
1124 uint32_t u32Lvec;
1125
1126 u32Lvec = s->lvt[APIC_LVT_LINT0 + u8Pin]; /* Fetch corresponding LVT entry. */
1127 /* Drop int if entry is masked. May not be correct for level-triggered interrupts. */
1128 if (!(u32Lvec & APIC_LVT_MASKED))
1129 { uint8_t u8Delivery;
1130 PDMAPICIRQ enmType;
1131
1132 u8Delivery = (u32Lvec >> 8) & 7;
1133 switch (u8Delivery)
1134 {
1135 case APIC_DM_EXTINT:
1136 Assert(u8Pin == 0); /* PIC should be wired to LINT0. */
1137 enmType = PDMAPICIRQ_EXTINT;
1138 /* ExtINT can be both set and cleared, NMI/SMI/INIT can only be set. */
1139 LogFlow(("apicLocalInterrupt: %s ExtINT interrupt\n", u8Level ? "setting" : "clearing"));
1140 if (u8Level)
1141 cpuSetInterrupt(pDev, s, enmType);
1142 else
1143 cpuClearInterrupt(pDev, s, enmType);
1144 return VINF_SUCCESS;
1145 case APIC_DM_NMI:
1146 /* External NMI should be wired to LINT1, but Linux sometimes programs
1147 * LVT0 to NMI delivery mode as well.
1148 */
1149 enmType = PDMAPICIRQ_NMI;
1150 /* Currently delivering NMIs through here causes problems with NMI watchdogs
1151 * on certain Linux kernels, e.g. 64-bit CentOS 5.3. Disable NMIs for now.
1152 */
1153 return VINF_SUCCESS;
1154 case APIC_DM_SMI:
1155 enmType = PDMAPICIRQ_SMI;
1156 break;
1157 case APIC_DM_FIXED:
1158 {
1159 /** @todo implement APIC_DM_FIXED! */
1160 static unsigned s_c = 0;
1161 if (s_c++ < 5)
1162 LogRel(("delivery type APIC_DM_FIXED not implemented. u8Pin=%d u8Level=%d\n", u8Pin, u8Level));
1163 return VINF_SUCCESS;
1164 }
1165 case APIC_DM_INIT:
1166 /** @todo implement APIC_DM_INIT? */
1167 default:
1168 {
1169 static unsigned s_c = 0;
1170 if (s_c++ < 100)
1171 AssertLogRelMsgFailed(("delivery type %d not implemented. u8Pin=%d u8Level=%d\n", u8Delivery, u8Pin, u8Level));
1172 return VERR_INTERNAL_ERROR_4;
1173 }
1174 }
1175 LogFlow(("apicLocalInterrupt: setting local interrupt type %d\n", enmType));
1176 cpuSetInterrupt(pDev, s, enmType);
1177 }
1178 return VINF_SUCCESS;
1179}
1180
1181static int apic_get_ppr(APICState const *s)
1182{
1183 int ppr;
1184
1185 int tpr = (s->tpr >> 4);
1186 int isrv = Apic256BitReg_FindLastSetBit(&s->isr, 0);
1187 isrv >>= 4;
1188 if (tpr >= isrv)
1189 ppr = s->tpr;
1190 else
1191 ppr = isrv << 4;
1192 return ppr;
1193}
1194
1195static int apic_get_ppr_zero_tpr(APICState *s)
1196{
1197 return Apic256BitReg_FindLastSetBit(&s->isr, 0);
1198}
1199
1200static int apic_get_arb_pri(APICState const *s)
1201{
1202 /** @todo XXX: arbitration */
1203 return 0;
1204}
1205
1206/* signal the CPU if an irq is pending */
1207static bool apic_update_irq(APICDeviceInfo *pDev, APICState* s)
1208{
1209 if (!(s->spurious_vec & APIC_SV_ENABLE))
1210 {
1211 /* Clear any pending APIC interrupt action flag. */
1212 cpuClearInterrupt(pDev, s);
1213 return false;
1214 }
1215
1216 int irrv = Apic256BitReg_FindLastSetBit(&s->irr, -1);
1217 if (irrv < 0)
1218 return false;
1219 int ppr = apic_get_ppr(s);
1220 if (ppr && (irrv & 0xf0) <= (ppr & 0xf0))
1221 return false;
1222 cpuSetInterrupt(pDev, s);
1223 return true;
1224}
1225
1226/* Check if the APIC has a pending interrupt/if a TPR change would active one. */
1227PDMBOTHCBDECL(bool) apicHasPendingIrq(PPDMDEVINS pDevIns)
1228{
1229 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
1230 if (!pDev)
1231 return false;
1232
1233 /* We don't perform any locking here as that would cause a lot of contention for VT-x/AMD-V. */
1234
1235 APICState *s = getLapic(pDev); /** @todo fix interface */
1236
1237 /*
1238 * All our callbacks now come from single IOAPIC, thus locking
1239 * seems to be excessive now
1240 */
1241 /** @todo check excessive locking whatever... */
1242 int irrv = Apic256BitReg_FindLastSetBit(&s->irr, -1);
1243 if (irrv < 0)
1244 return false;
1245
1246 int ppr = apic_get_ppr_zero_tpr(s);
1247
1248 if (ppr && (irrv & 0xf0) <= (ppr & 0xf0))
1249 return false;
1250
1251 return true;
1252}
1253
1254static void apic_update_tpr(APICDeviceInfo *pDev, APICState* s, uint32_t val)
1255{
1256 bool fIrqIsActive = false;
1257 bool fIrqWasActive = false;
1258
1259 fIrqWasActive = apic_update_irq(pDev, s);
1260 s->tpr = val;
1261 fIrqIsActive = apic_update_irq(pDev, s);
1262
1263 /* If an interrupt is pending and now masked, then clear the FF flag. */
1264 if (fIrqWasActive && !fIrqIsActive)
1265 {
1266 Log(("apic_update_tpr: deactivate interrupt that was masked by the TPR update (%x)\n", val));
1267 STAM_COUNTER_INC(&pDev->StatClearedActiveIrq);
1268 cpuClearInterrupt(pDev, s);
1269 }
1270}
1271
1272static void apic_set_irq(APICDeviceInfo *pDev, APICState* s, int vector_num, int trigger_mode)
1273{
1274 LogFlow(("CPU%d: apic_set_irq vector=%x, trigger_mode=%x\n", s->phys_id, vector_num, trigger_mode));
1275 Apic256BitReg_SetBit(&s->irr, vector_num);
1276 if (trigger_mode)
1277 Apic256BitReg_SetBit(&s->tmr, vector_num);
1278 else
1279 Apic256BitReg_ClearBit(&s->tmr, vector_num);
1280 apic_update_irq(pDev, s);
1281}
1282
1283static void apic_eoi(APICDeviceInfo *pDev, APICState* s)
1284{
1285 int isrv = Apic256BitReg_FindLastSetBit(&s->isr, -1);
1286 if (isrv < 0)
1287 return;
1288 Apic256BitReg_ClearBit(&s->isr, isrv);
1289 LogFlow(("CPU%d: apic_eoi isrv=%x\n", s->phys_id, isrv));
1290 /** @todo XXX: send the EOI packet to the APIC bus to allow the I/O APIC to
1291 * set the remote IRR bit for level triggered interrupts. */
1292 apic_update_irq(pDev, s);
1293}
1294
1295static PVMCPUSET apic_get_delivery_bitmask(APICDeviceInfo *pDev, uint8_t dest, uint8_t dest_mode, PVMCPUSET pDstSet)
1296{
1297 VMCPUSET_EMPTY(pDstSet);
1298
1299 if (dest_mode == 0)
1300 {
1301 if (dest == 0xff)
1302 {
1303 /* was: mask = 0xff; - weird */ /** @todo check this; could this (1) differ on X2APIC and (2) actully mean a broadcast? */
1304 for (VMCPUID iCpu = 0; iCpu < 8; iCpu++)
1305 VMCPUSET_ADD(pDstSet, iCpu);
1306 }
1307 else
1308 VMCPUSET_ADD(pDstSet, dest);
1309 }
1310 else
1311 {
1312 /** @todo XXX: cluster mode */
1313 APIC_FOREACH_BEGIN(pDev);
1314 if (pCurApic->dest_mode == APIC_DESTMODE_FLAT)
1315 {
1316 if (dest & pCurApic->log_dest)
1317 VMCPUSET_ADD(pDstSet, iCurApic);
1318 }
1319 else if (pCurApic->dest_mode == APIC_DESTMODE_CLUSTER)
1320 {
1321 if ( (dest & 0xf0) == (pCurApic->log_dest & 0xf0)
1322 && (dest & pCurApic->log_dest & 0x0f))
1323 VMCPUSET_ADD(pDstSet, iCurApic);
1324 }
1325 APIC_FOREACH_END();
1326 }
1327
1328 return pDstSet;
1329}
1330
1331#ifdef IN_RING3
1332static void apic_init_ipi(APICDeviceInfo* pDev, APICState *s)
1333{
1334 int i;
1335
1336 for(i = 0; i < APIC_LVT_NB; i++)
1337 s->lvt[i] = 1 << 16; /* mask LVT */
1338 s->tpr = 0;
1339 s->spurious_vec = 0xff;
1340 s->log_dest = 0;
1341 s->dest_mode = 0xff; /** @todo 0xff???? */
1342 Apic256BitReg_Empty(&s->isr);
1343 Apic256BitReg_Empty(&s->tmr);
1344 Apic256BitReg_Empty(&s->irr);
1345 s->esr = 0;
1346 memset(s->icr, 0, sizeof(s->icr));
1347 s->divide_conf = 0;
1348 s->count_shift = 1;
1349 s->initial_count = 0;
1350 s->initial_count_load_time = 0;
1351 s->next_time = 0;
1352}
1353
1354
1355static void apicSendInitIpi(APICDeviceInfo* pDev, APICState *s)
1356{
1357 apic_init_ipi(pDev, s);
1358 cpuSendInitIpi(pDev, s);
1359}
1360
1361/* send a SIPI message to the CPU to start it */
1362static void apic_startup(APICDeviceInfo* pDev, APICState *s, int vector_num)
1363{
1364 Log(("[SMP] apic_startup: %d on CPUs %d\n", vector_num, s->phys_id));
1365 cpuSendSipi(pDev, s, vector_num);
1366}
1367#endif /* IN_RING3 */
1368
1369static int apic_deliver(APICDeviceInfo *pDev, APICState *s,
1370 uint8_t dest, uint8_t dest_mode,
1371 uint8_t delivery_mode, uint8_t vector_num,
1372 uint8_t polarity, uint8_t trigger_mode)
1373{
1374 int dest_shorthand = (s->icr[0] >> 18) & 3;
1375 LogFlow(("apic_deliver dest=%x dest_mode=%x dest_shorthand=%x delivery_mode=%x vector_num=%x polarity=%x trigger_mode=%x\n", dest, dest_mode, dest_shorthand, delivery_mode, vector_num, polarity, trigger_mode));
1376
1377 VMCPUSET DstSet;
1378 switch (dest_shorthand)
1379 {
1380 case 0:
1381 apic_get_delivery_bitmask(pDev, dest, dest_mode, &DstSet);
1382 break;
1383 case 1:
1384 VMCPUSET_EMPTY(&DstSet);
1385 VMCPUSET_ADD(&DstSet, s->id);
1386 break;
1387 case 2:
1388 VMCPUSET_FILL(&DstSet);
1389 break;
1390 case 3:
1391 VMCPUSET_FILL(&DstSet);
1392 VMCPUSET_DEL(&DstSet, s->id);
1393 break;
1394 }
1395
1396 switch (delivery_mode)
1397 {
1398 case APIC_DM_INIT:
1399 {
1400 uint32_t const trig_mode = (s->icr[0] >> 15) & 1;
1401 uint32_t const level = (s->icr[0] >> 14) & 1;
1402 if (level == 0 && trig_mode == 1)
1403 {
1404 APIC_FOREACH_IN_SET_BEGIN(pDev, &DstSet);
1405 pCurApic->arb_id = pCurApic->id;
1406 APIC_FOREACH_END();
1407 Log(("CPU%d: APIC_DM_INIT arbitration id(s) set\n", s->phys_id));
1408 return VINF_SUCCESS;
1409 }
1410 break;
1411 }
1412
1413 case APIC_DM_SIPI:
1414# ifdef IN_RING3
1415 APIC_FOREACH_IN_SET_BEGIN(pDev, &DstSet);
1416 apic_startup(pDev, pCurApic, vector_num);
1417 APIC_FOREACH_END();
1418 return VINF_SUCCESS;
1419# else
1420 /* We shall send SIPI only in R3, R0 calls should be
1421 rescheduled to R3 */
1422 return VINF_IOM_HC_MMIO_WRITE;
1423# endif
1424 }
1425
1426 return apic_bus_deliver(pDev, &DstSet, delivery_mode, vector_num,
1427 polarity, trigger_mode);
1428}
1429
1430
1431PDMBOTHCBDECL(int) apicGetInterrupt(PPDMDEVINS pDevIns)
1432{
1433 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
1434 /* if the APIC is not installed or enabled, we let the 8259 handle the
1435 IRQs */
1436 if (!pDev)
1437 {
1438 Log(("apic_get_interrupt: returns -1 (!s)\n"));
1439 return -1;
1440 }
1441
1442 Assert(PDMCritSectIsOwner(pDev->CTX_SUFF(pCritSect)));
1443
1444 APICState *s = getLapic(pDev); /** @todo fix interface */
1445
1446 if (!(s->spurious_vec & APIC_SV_ENABLE))
1447 {
1448 Log(("CPU%d: apic_get_interrupt: returns -1 (APIC_SV_ENABLE)\n", s->phys_id));
1449 return -1;
1450 }
1451
1452 /** @todo XXX: spurious IRQ handling */
1453 int intno = Apic256BitReg_FindLastSetBit(&s->irr, -1);
1454 if (intno < 0)
1455 {
1456 Log(("CPU%d: apic_get_interrupt: returns -1 (irr)\n", s->phys_id));
1457 return -1;
1458 }
1459
1460 if (s->tpr && (uint32_t)intno <= s->tpr)
1461 {
1462 Log(("apic_get_interrupt: returns %d (sp)\n", s->spurious_vec & 0xff));
1463 return s->spurious_vec & 0xff;
1464 }
1465 Apic256BitReg_ClearBit(&s->irr, intno);
1466 Apic256BitReg_SetBit(&s->isr, intno);
1467 apic_update_irq(pDev, s);
1468 LogFlow(("CPU%d: apic_get_interrupt: returns %d\n", s->phys_id, intno));
1469 return intno;
1470}
1471
1472/**
1473 * @remarks Caller (apicReadRegister) takes both the TM and APIC locks before
1474 * calling this function.
1475 */
1476static uint32_t apic_get_current_count(APICDeviceInfo const *pDev, APICState const *pApic)
1477{
1478 int64_t d = (TMTimerGet(pApic->CTX_SUFF(pTimer)) - pApic->initial_count_load_time)
1479 >> pApic->count_shift;
1480
1481 uint32_t val;
1482 if (pApic->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC)
1483 /* periodic */
1484 val = pApic->initial_count - (d % ((uint64_t)pApic->initial_count + 1));
1485 else if (d >= pApic->initial_count)
1486 val = 0;
1487 else
1488 val = pApic->initial_count - d;
1489
1490 return val;
1491}
1492
1493/**
1494 * Does the frequency hinting and logging.
1495 *
1496 * @param pApic The device state.
1497 */
1498DECLINLINE(void) apicDoFrequencyHinting(APICState *pApic)
1499{
1500 if ( pApic->uHintedInitialCount != pApic->initial_count
1501 || pApic->uHintedCountShift != (uint32_t)pApic->count_shift)
1502 {
1503 pApic->uHintedInitialCount = pApic->initial_count;
1504 pApic->uHintedCountShift = pApic->count_shift;
1505
1506 uint32_t uHz;
1507 if (pApic->initial_count > 0)
1508 {
1509 Assert((unsigned)pApic->count_shift < 30);
1510 uint64_t cTickPerPeriod = ((uint64_t)pApic->initial_count + 1) << pApic->count_shift;
1511 uHz = TMTimerGetFreq(pApic->CTX_SUFF(pTimer)) / cTickPerPeriod;
1512 }
1513 else
1514 uHz = 0;
1515 TMTimerSetFrequencyHint(pApic->CTX_SUFF(pTimer), uHz);
1516 Log(("apic: %u Hz\n", uHz));
1517 }
1518}
1519
1520/**
1521 * Implementation of the 0380h access: Timer reset + new initial count.
1522 *
1523 * @param pDev The device state.
1524 * @param pApic The APIC sub-device state.
1525 * @param u32NewInitialCount The new initial count for the timer.
1526 */
1527static void apicTimerSetInitialCount(APICDeviceInfo *pDev, APICState *pApic, uint32_t u32NewInitialCount)
1528{
1529 STAM_COUNTER_INC(&pApic->StatTimerSetInitialCount);
1530 pApic->initial_count = u32NewInitialCount;
1531
1532 /*
1533 * Don't (re-)arm the timer if the it's masked or if it's
1534 * a zero length one-shot timer.
1535 */
1536 if ( !(pApic->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)
1537 && u32NewInitialCount > 0)
1538 {
1539 /*
1540 * Calculate the relative next time and perform a combined timer get/set
1541 * operation. This avoids racing the clock between get and set.
1542 */
1543 uint64_t cTicksNext = u32NewInitialCount;
1544 cTicksNext += 1;
1545 cTicksNext <<= pApic->count_shift;
1546 TMTimerSetRelative(pApic->CTX_SUFF(pTimer), cTicksNext, &pApic->initial_count_load_time);
1547 pApic->next_time = pApic->initial_count_load_time + cTicksNext;
1548 pApic->fTimerArmed = true;
1549 apicDoFrequencyHinting(pApic);
1550 STAM_COUNTER_INC(&pApic->StatTimerSetInitialCountArm);
1551 Log(("apicTimerSetInitialCount: cTicksNext=%'llu (%#llx) ic=%#x sh=%#x nxt=%#llx\n",
1552 cTicksNext, cTicksNext, u32NewInitialCount, pApic->count_shift, pApic->next_time));
1553 }
1554 else
1555 {
1556 /* Stop it if necessary and record the load time for unmasking. */
1557 if (pApic->fTimerArmed)
1558 {
1559 STAM_COUNTER_INC(&pApic->StatTimerSetInitialCountDisarm);
1560 TMTimerStop(pApic->CTX_SUFF(pTimer));
1561 pApic->fTimerArmed = false;
1562 pApic->uHintedCountShift = pApic->uHintedInitialCount = 0;
1563 }
1564 pApic->initial_count_load_time = TMTimerGet(pApic->CTX_SUFF(pTimer));
1565 Log(("apicTimerSetInitialCount: ic=%#x sh=%#x iclt=%#llx\n", u32NewInitialCount, pApic->count_shift, pApic->initial_count_load_time));
1566 }
1567}
1568
1569/**
1570 * Implementation of the 0320h access: change the LVT flags.
1571 *
1572 * @param pDev The device state.
1573 * @param pApic The APIC sub-device state to operate on.
1574 * @param fNew The new flags.
1575 */
1576static void apicTimerSetLvt(APICDeviceInfo *pDev, APICState *pApic, uint32_t fNew)
1577{
1578 STAM_COUNTER_INC(&pApic->StatTimerSetLvt);
1579
1580 /*
1581 * Make the flag change, saving the old ones so we can avoid
1582 * unnecessary work.
1583 */
1584 uint32_t const fOld = pApic->lvt[APIC_LVT_TIMER];
1585 pApic->lvt[APIC_LVT_TIMER] = fNew;
1586
1587 /* Only the masked and peridic bits are relevant (see apic_timer_update). */
1588 if ( (fOld & (APIC_LVT_MASKED | APIC_LVT_TIMER_PERIODIC))
1589 != (fNew & (APIC_LVT_MASKED | APIC_LVT_TIMER_PERIODIC)))
1590 {
1591 /*
1592 * If changed to one-shot from periodic, stop the timer if we're not
1593 * in the first period.
1594 */
1595 /** @todo check how clearing the periodic flag really should behave when not
1596 * in period 1. The current code just mirrors the behavior of the
1597 * original implementation. */
1598 if ( (fOld & APIC_LVT_TIMER_PERIODIC)
1599 && !(fNew & APIC_LVT_TIMER_PERIODIC))
1600 {
1601 STAM_COUNTER_INC(&pApic->StatTimerSetLvtClearPeriodic);
1602 uint64_t cTicks = (pApic->next_time - pApic->initial_count_load_time) >> pApic->count_shift;
1603 if (cTicks >= pApic->initial_count)
1604 {
1605 /* not first period, stop it. */
1606 TMTimerStop(pApic->CTX_SUFF(pTimer));
1607 pApic->fTimerArmed = false;
1608 pApic->uHintedCountShift = pApic->uHintedInitialCount = 0;
1609 }
1610 /* else: first period, let it fire normally. */
1611 }
1612
1613 /*
1614 * We postpone stopping the timer when it's masked, this way we can
1615 * avoid some timer work when the guest temporarily masks the timer.
1616 * (apicR3TimerCallback will stop it if still masked.)
1617 */
1618 if (fNew & APIC_LVT_MASKED)
1619 STAM_COUNTER_INC(&pApic->StatTimerSetLvtPostponed);
1620 else if (pApic->fTimerArmed)
1621 STAM_COUNTER_INC(&pApic->StatTimerSetLvtArmed);
1622 /*
1623 * If unmasked, not armed and with a valid initial count value (according
1624 * to our interpretation of the spec), we will have to rearm the timer so
1625 * it will fire at the end of the current period.
1626 *
1627 * N.B. This is code is currently RACING the virtual sync clock!
1628 */
1629 else if ( (fOld & APIC_LVT_MASKED)
1630 && pApic->initial_count > 0)
1631 {
1632 STAM_COUNTER_INC(&pApic->StatTimerSetLvtArm);
1633 for (unsigned cTries = 0; ; cTries++)
1634 {
1635 uint64_t NextTS;
1636 uint64_t cTicks = (TMTimerGet(pApic->CTX_SUFF(pTimer)) - pApic->initial_count_load_time) >> pApic->count_shift;
1637 if (fNew & APIC_LVT_TIMER_PERIODIC)
1638 NextTS = ((cTicks / ((uint64_t)pApic->initial_count + 1)) + 1) * ((uint64_t)pApic->initial_count + 1);
1639 else
1640 {
1641 if (cTicks >= pApic->initial_count)
1642 break;
1643 NextTS = (uint64_t)pApic->initial_count + 1;
1644 }
1645 NextTS <<= pApic->count_shift;
1646 NextTS += pApic->initial_count_load_time;
1647
1648 /* Try avoid the assertion in TM.cpp... this isn't perfect! */
1649 if ( NextTS > TMTimerGet(pApic->CTX_SUFF(pTimer))
1650 || cTries > 10)
1651 {
1652 TMTimerSet(pApic->CTX_SUFF(pTimer), NextTS);
1653 pApic->next_time = NextTS;
1654 pApic->fTimerArmed = true;
1655 apicDoFrequencyHinting(pApic);
1656 Log(("apicTimerSetLvt: ic=%#x sh=%#x nxt=%#llx\n", pApic->initial_count, pApic->count_shift, pApic->next_time));
1657 break;
1658 }
1659 STAM_COUNTER_INC(&pApic->StatTimerSetLvtArmRetries);
1660 }
1661 }
1662 }
1663 else
1664 STAM_COUNTER_INC(&pApic->StatTimerSetLvtNoRelevantChange);
1665}
1666
1667# ifdef IN_RING3
1668/**
1669 * Timer callback function.
1670 *
1671 * @param pDevIns The device state.
1672 * @param pTimer The timer handle.
1673 * @param pvUser User argument pointing to the APIC instance.
1674 */
1675static DECLCALLBACK(void) apicR3TimerCallback(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
1676{
1677 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
1678 APICState *pApic = (APICState *)pvUser;
1679 Assert(pApic->pTimerR3 == pTimer);
1680 Assert(pApic->fTimerArmed);
1681 Assert(PDMCritSectIsOwner(pDev->pCritSectR3));
1682 Assert(TMTimerIsLockOwner(pTimer));
1683
1684 if (!(pApic->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) {
1685 LogFlow(("apic_timer: trigger irq\n"));
1686 apic_set_irq(pDev, pApic, pApic->lvt[APIC_LVT_TIMER] & 0xff, APIC_TRIGGER_EDGE);
1687
1688 if ( (pApic->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC)
1689 && pApic->initial_count > 0) {
1690 /* new interval. */
1691 pApic->next_time += (((uint64_t)pApic->initial_count + 1) << pApic->count_shift);
1692 TMTimerSet(pApic->CTX_SUFF(pTimer), pApic->next_time);
1693 pApic->fTimerArmed = true;
1694 apicDoFrequencyHinting(pApic);
1695 Log2(("apicR3TimerCallback: ic=%#x sh=%#x nxt=%#llx\n", pApic->initial_count, pApic->count_shift, pApic->next_time));
1696 } else {
1697 /* single shot or disabled. */
1698 pApic->fTimerArmed = false;
1699 pApic->uHintedCountShift = pApic->uHintedInitialCount = 0;
1700 }
1701 } else {
1702 /* masked, do not rearm. */
1703 pApic->fTimerArmed = false;
1704 pApic->uHintedCountShift = pApic->uHintedInitialCount = 0;
1705 }
1706}
1707
1708static void apic_save(SSMHANDLE* f, void *opaque)
1709{
1710 APICState *s = (APICState*)opaque;
1711 int i;
1712
1713 SSMR3PutU32(f, s->apicbase);
1714 SSMR3PutU32(f, s->id);
1715 SSMR3PutU32(f, s->phys_id);
1716 SSMR3PutU32(f, s->arb_id);
1717 SSMR3PutU32(f, s->tpr);
1718 SSMR3PutU32(f, s->spurious_vec);
1719 SSMR3PutU8(f, s->log_dest);
1720 SSMR3PutU8(f, s->dest_mode);
1721 for (i = 0; i < 8; i++) {
1722 SSMR3PutU32(f, s->isr.au32Bitmap[i]);
1723 SSMR3PutU32(f, s->tmr.au32Bitmap[i]);
1724 SSMR3PutU32(f, s->irr.au32Bitmap[i]);
1725 }
1726 for (i = 0; i < APIC_LVT_NB; i++) {
1727 SSMR3PutU32(f, s->lvt[i]);
1728 }
1729 SSMR3PutU32(f, s->esr);
1730 SSMR3PutU32(f, s->icr[0]);
1731 SSMR3PutU32(f, s->icr[1]);
1732 SSMR3PutU32(f, s->divide_conf);
1733 SSMR3PutU32(f, s->count_shift);
1734 SSMR3PutU32(f, s->initial_count);
1735 SSMR3PutU64(f, s->initial_count_load_time);
1736 SSMR3PutU64(f, s->next_time);
1737
1738 TMR3TimerSave(s->CTX_SUFF(pTimer), f);
1739}
1740
1741static int apic_load(SSMHANDLE *f, void *opaque, int version_id)
1742{
1743 APICState *s = (APICState*)opaque;
1744 int i;
1745
1746 /** @todo XXX: what if the base changes? (registered memory regions) */
1747 SSMR3GetU32(f, &s->apicbase);
1748
1749 switch (version_id)
1750 {
1751 case APIC_SAVED_STATE_VERSION_ANCIENT:
1752 {
1753 uint8_t val = 0;
1754 SSMR3GetU8(f, &val);
1755 s->id = val;
1756 /* UP only in old saved states */
1757 s->phys_id = 0;
1758 SSMR3GetU8(f, &val);
1759 s->arb_id = val;
1760 break;
1761 }
1762 case APIC_SAVED_STATE_VERSION:
1763 case APIC_SAVED_STATE_VERSION_VBOX_30:
1764 SSMR3GetU32(f, &s->id);
1765 SSMR3GetU32(f, &s->phys_id);
1766 SSMR3GetU32(f, &s->arb_id);
1767 break;
1768 default:
1769 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1770 }
1771 SSMR3GetU32(f, &s->tpr);
1772 SSMR3GetU32(f, &s->spurious_vec);
1773 SSMR3GetU8(f, &s->log_dest);
1774 SSMR3GetU8(f, &s->dest_mode);
1775 for (i = 0; i < 8; i++) {
1776 SSMR3GetU32(f, &s->isr.au32Bitmap[i]);
1777 SSMR3GetU32(f, &s->tmr.au32Bitmap[i]);
1778 SSMR3GetU32(f, &s->irr.au32Bitmap[i]);
1779 }
1780 for (i = 0; i < APIC_LVT_NB; i++) {
1781 SSMR3GetU32(f, &s->lvt[i]);
1782 }
1783 SSMR3GetU32(f, &s->esr);
1784 SSMR3GetU32(f, &s->icr[0]);
1785 SSMR3GetU32(f, &s->icr[1]);
1786 SSMR3GetU32(f, &s->divide_conf);
1787 SSMR3GetU32(f, (uint32_t *)&s->count_shift);
1788 SSMR3GetU32(f, (uint32_t *)&s->initial_count);
1789 SSMR3GetU64(f, (uint64_t *)&s->initial_count_load_time);
1790 SSMR3GetU64(f, (uint64_t *)&s->next_time);
1791
1792 int rc = TMR3TimerLoad(s->CTX_SUFF(pTimer), f);
1793 AssertRCReturn(rc, rc);
1794 s->uHintedCountShift = s->uHintedInitialCount = 0;
1795 s->fTimerArmed = TMTimerIsActive(s->CTX_SUFF(pTimer));
1796 if (s->fTimerArmed)
1797 apicDoFrequencyHinting(s);
1798
1799 return VINF_SUCCESS; /** @todo darn mess! */
1800}
1801
1802#endif /* IN_RING3 */
1803
1804/* LAPIC */
1805PDMBOTHCBDECL(int) apicMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
1806{
1807 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
1808 APICState *s = getLapic(pDev);
1809
1810 Log(("CPU%d: apicMMIORead at %llx\n", s->phys_id, (uint64_t)GCPhysAddr));
1811
1812 /** @todo add LAPIC range validity checks (different LAPICs can
1813 * theoretically have different physical addresses, see #3092) */
1814
1815 STAM_COUNTER_INC(&CTXSUFF(pDev->StatMMIORead));
1816 switch (cb)
1817 {
1818 case 1:
1819 /** @todo this is not how recent APIC behave! We will fix
1820 * this via the IOM. */
1821 *(uint8_t *)pv = 0;
1822 break;
1823
1824 case 2:
1825 /** @todo this is not how recent APIC behave! */
1826 *(uint16_t *)pv = 0;
1827 break;
1828
1829 case 4:
1830 {
1831#if 0 /** @note experimental */
1832#ifndef IN_RING3
1833 uint32_t index = (GCPhysAddr >> 4) & 0xff;
1834
1835 if ( index == 0x08 /* TPR */
1836 && ++s->cTPRPatchAttempts < APIC_MAX_PATCH_ATTEMPTS)
1837 {
1838#ifdef IN_RC
1839 pDevIns->pDevHlpGC->pfnPATMSetMMIOPatchInfo(pDevIns, GCPhysAddr, &s->tpr);
1840#else
1841 RTGCPTR pDevInsGC = PDMINS2DATA_GCPTR(pDevIns);
1842 pDevIns->pHlpR0->pfnPATMSetMMIOPatchInfo(pDevIns, GCPhysAddr, pDevIns + RT_OFFSETOF(APICState, tpr));
1843#endif
1844 return VINF_PATM_HC_MMIO_PATCH_READ;
1845 }
1846#endif
1847#endif /* experimental */
1848
1849 /* It does its own locking. */
1850 uint64_t u64Value = 0;
1851 int rc = apicReadRegister(pDev, s, (GCPhysAddr >> 4) & 0xff, &u64Value,
1852 VINF_IOM_HC_MMIO_READ, false /*fMsr*/);
1853 *(uint32_t *)pv = (uint32_t)u64Value;
1854 return rc;
1855 }
1856
1857 default:
1858 AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */
1859 return VERR_INTERNAL_ERROR;
1860 }
1861 return VINF_SUCCESS;
1862}
1863
1864PDMBOTHCBDECL(int) apicMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb)
1865{
1866 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
1867 APICState *s = getLapic(pDev);
1868
1869 Log(("CPU%d: apicMMIOWrite at %llx\n", s->phys_id, (uint64_t)GCPhysAddr));
1870
1871 /** @todo: add LAPIC range validity checks (multiple LAPICs can theoretically have
1872 different physical addresses, see #3092) */
1873
1874 STAM_COUNTER_INC(&CTXSUFF(pDev->StatMMIOWrite));
1875 switch (cb)
1876 {
1877 case 1:
1878 case 2:
1879 /* ignore */
1880 break;
1881
1882 case 4:
1883 /* It does its own locking. */
1884 return apicWriteRegister(pDev, s, (GCPhysAddr >> 4) & 0xff, *(uint32_t const *)pv,
1885 VINF_IOM_HC_MMIO_WRITE, false /*fMsr*/);
1886
1887 default:
1888 AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */
1889 return VERR_INTERNAL_ERROR;
1890 }
1891 return VINF_SUCCESS;
1892}
1893
1894#ifdef IN_RING3
1895
1896/**
1897 * Wrapper around apicReadRegister.
1898 *
1899 * @returns 64-bit register value.
1900 * @param pDev The PDM device instance.
1901 * @param pApic The Local APIC in question.
1902 * @param iReg The APIC register index.
1903 */
1904static uint64_t apicR3InfoReadReg(APICDeviceInfo *pDev, APICState *pApic, uint32_t iReg)
1905{
1906 uint64_t u64Value;
1907 int rc = apicReadRegister(pDev, pApic, iReg, &u64Value, VINF_SUCCESS, true /*fMsr*/);
1908 AssertRCReturn(rc, UINT64_MAX);
1909 return u64Value;
1910}
1911
1912
1913/**
1914 * Print a 8-DWORD Local APIC bit map (256 bits).
1915 *
1916 * @param pDev The PDM device instance.
1917 * @param pApic The Local APIC in question.
1918 * @param pHlp The output helper.
1919 * @param iStartReg The register to start at.
1920 */
1921static void apicR3DumpVec(APICDeviceInfo *pDev, APICState *pApic, PCDBGFINFOHLP pHlp, uint32_t iStartReg)
1922{
1923 for (uint32_t i = 0; i < 8; i++)
1924 pHlp->pfnPrintf(pHlp, "%08x", apicR3InfoReadReg(pDev, pApic, iStartReg + i));
1925 pHlp->pfnPrintf(pHlp, "\n");
1926}
1927
1928/**
1929 * Print basic Local APIC state.
1930 *
1931 * @param pDev The PDM device instance.
1932 * @param pApic The Local APIC in question.
1933 * @param pHlp The output helper.
1934 */
1935static void apicR3InfoBasic(APICDeviceInfo *pDev, APICState *pApic, PCDBGFINFOHLP pHlp)
1936{
1937 uint64_t u64;
1938
1939 pHlp->pfnPrintf(pHlp, "Local APIC at %08llx:\n", pApic->apicbase);
1940 u64 = apicR3InfoReadReg(pDev, pApic, 0x2);
1941 pHlp->pfnPrintf(pHlp, " LAPIC ID : %08llx\n", u64);
1942 pHlp->pfnPrintf(pHlp, " APIC ID = %02llx\n", (u64 >> 24) & 0xff);
1943 u64 = apicR3InfoReadReg(pDev, pApic, 0x3);
1944 pHlp->pfnPrintf(pHlp, " APIC VER : %08llx\n", u64);
1945 pHlp->pfnPrintf(pHlp, " version = %02x\n", (int)RT_BYTE1(u64));
1946 pHlp->pfnPrintf(pHlp, " lvts = %d\n", (int)RT_BYTE3(u64) + 1);
1947 u64 = apicR3InfoReadReg(pDev, pApic, 0x8);
1948 pHlp->pfnPrintf(pHlp, " TPR : %08llx\n", u64);
1949 pHlp->pfnPrintf(pHlp, " task pri = %lld/%lld\n", (u64 >> 4) & 0xf, u64 & 0xf);
1950 u64 = apicR3InfoReadReg(pDev, pApic, 0xA);
1951 pHlp->pfnPrintf(pHlp, " PPR : %08llx\n", u64);
1952 pHlp->pfnPrintf(pHlp, " cpu pri = %lld/%lld\n", (u64 >> 4) & 0xf, u64 & 0xf);
1953 u64 = apicR3InfoReadReg(pDev, pApic, 0xD);
1954 pHlp->pfnPrintf(pHlp, " LDR : %08llx\n", u64);
1955 pHlp->pfnPrintf(pHlp, " log id = %02llx\n", (u64 >> 24) & 0xff);
1956 pHlp->pfnPrintf(pHlp, " DFR : %08llx\n", apicR3InfoReadReg(pDev, pApic, 0xE));
1957 u64 = apicR3InfoReadReg(pDev, pApic, 0xF);
1958 pHlp->pfnPrintf(pHlp, " SVR : %08llx\n", u64);
1959 pHlp->pfnPrintf(pHlp, " focus = %s\n", u64 & RT_BIT(9) ? "check off" : "check on");
1960 pHlp->pfnPrintf(pHlp, " lapic = %s\n", u64 & RT_BIT(8) ? "ENABLED" : "DISABLED");
1961 pHlp->pfnPrintf(pHlp, " vector = %02x\n", (unsigned)RT_BYTE1(u64));
1962 pHlp->pfnPrintf(pHlp, " ISR : ");
1963 apicR3DumpVec(pDev, pApic, pHlp, 0x10);
1964 int iMax = Apic256BitReg_FindLastSetBit(&pApic->isr, -1);
1965 pHlp->pfnPrintf(pHlp, " highest = %02x\n", iMax == -1 ? 0 : iMax);
1966 pHlp->pfnPrintf(pHlp, " IRR : ");
1967 apicR3DumpVec(pDev, pApic, pHlp, 0x20);
1968 iMax = Apic256BitReg_FindLastSetBit(&pApic->irr, -1);
1969 pHlp->pfnPrintf(pHlp, " highest = %02X\n", iMax == -1 ? 0 : iMax);
1970}
1971
1972
1973/**
1974 * Print the more interesting Local APIC LVT entries.
1975 *
1976 * @param pDev The PDM device instance.
1977 * @param pApic The Local APIC in question.
1978 * @param pHlp The output helper.
1979 */
1980static void apicR3InfoLVT(APICDeviceInfo *pDev, APICState *pApic, PCDBGFINFOHLP pHlp)
1981{
1982 static const char * const s_apszDeliveryModes[] =
1983 {
1984 "Fixed ", "Reserved", "SMI", "Reserved", "NMI", "INIT", "Reserved", "ExtINT"
1985 };
1986 uint64_t u64;
1987
1988 u64 = apicR3InfoReadReg(pDev, pApic, 0x32);
1989 pHlp->pfnPrintf(pHlp, " LVT Timer : %08llx\n", u64);
1990 pHlp->pfnPrintf(pHlp, " mode = %s\n", u64 & RT_BIT(17) ? "periodic" : "one-shot");
1991 pHlp->pfnPrintf(pHlp, " mask = %llu\n", (u64 >> 16) & 1);
1992 pHlp->pfnPrintf(pHlp, " status = %s\n", u64 & RT_BIT(12) ? "pending" : "idle");
1993 pHlp->pfnPrintf(pHlp, " vector = %02llx\n", u64 & 0xff);
1994 u64 = apicR3InfoReadReg(pDev, pApic, 0x35);
1995 pHlp->pfnPrintf(pHlp, " LVT LINT0 : %08llx\n", u64);
1996 pHlp->pfnPrintf(pHlp, " mask = %llu\n", (u64 >> 16) & 1);
1997 pHlp->pfnPrintf(pHlp, " trigger = %s\n", u64 & RT_BIT(15) ? "level" : "edge");
1998 pHlp->pfnPrintf(pHlp, " rem irr = %llu\n", (u64 >> 14) & 1);
1999 pHlp->pfnPrintf(pHlp, " polarty = %llu\n", (u64 >> 13) & 1);
2000 pHlp->pfnPrintf(pHlp, " status = %s\n", u64 & RT_BIT(12) ? "pending" : "idle");
2001 pHlp->pfnPrintf(pHlp, " delivry = %s\n", s_apszDeliveryModes[(u64 >> 8) & 7]);
2002 pHlp->pfnPrintf(pHlp, " vector = %02llx\n", u64 & 0xff);
2003 u64 = apicR3InfoReadReg(pDev, pApic, 0x36);
2004 pHlp->pfnPrintf(pHlp, " LVT LINT1 : %08llx\n", u64);
2005 pHlp->pfnPrintf(pHlp, " mask = %llu\n", (u64 >> 16) & 1);
2006 pHlp->pfnPrintf(pHlp, " trigger = %s\n", u64 & RT_BIT(15) ? "level" : "edge");
2007 pHlp->pfnPrintf(pHlp, " rem irr = %lld\n", (u64 >> 14) & 1);
2008 pHlp->pfnPrintf(pHlp, " polarty = %lld\n", (u64 >> 13) & 1);
2009 pHlp->pfnPrintf(pHlp, " status = %s\n", u64 & RT_BIT(12) ? "pending" : "idle");
2010 pHlp->pfnPrintf(pHlp, " delivry = %s\n", s_apszDeliveryModes[(u64 >> 8) & 7]);
2011 pHlp->pfnPrintf(pHlp, " vector = %02llx\n", u64 & 0xff);
2012}
2013
2014
2015/**
2016 * Print LAPIC timer state.
2017 *
2018 * @param pDev The PDM device instance.
2019 * @param pApic The Local APIC in question.
2020 * @param pHlp The output helper.
2021 */
2022static void apicR3InfoTimer(APICDeviceInfo *pDev, APICState *pApic, PCDBGFINFOHLP pHlp)
2023{
2024 pHlp->pfnPrintf(pHlp, "Local APIC timer:\n");
2025 pHlp->pfnPrintf(pHlp, " Initial count : %08llx\n", apicR3InfoReadReg(pDev, pApic, 0x38));
2026 pHlp->pfnPrintf(pHlp, " Current count : %08llx\n", apicR3InfoReadReg(pDev, pApic, 0x39));
2027 uint64_t u64 = apicR3InfoReadReg(pDev, pApic, 0x3e);
2028 pHlp->pfnPrintf(pHlp, " Divide config : %08llx\n", u64);
2029 unsigned uDivider = ((u64 >> 1) & 0x04) | (u64 & 0x03);
2030 pHlp->pfnPrintf(pHlp, " divider = %u\n", uDivider == 7 ? 1 : 2 << uDivider);
2031}
2032
2033
2034/**
2035 * @callback_method_impl{FNDBGFHANDLERDEV,
2036 * Dumps the Local APIC state according to given argument.}
2037 */
2038static DECLCALLBACK(void) apicR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
2039{
2040 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2041 APICState *pApic = getLapic(pDev);
2042
2043 if (pszArgs == NULL || !strcmp(pszArgs, "basic"))
2044 apicR3InfoBasic(pDev, pApic, pHlp);
2045 else if (!strcmp(pszArgs, "lvt"))
2046 apicR3InfoLVT(pDev, pApic, pHlp);
2047 else if (!strcmp(pszArgs, "timer"))
2048 apicR3InfoTimer(pDev, pApic, pHlp);
2049 else
2050 pHlp->pfnPrintf(pHlp, "Invalid argument. Recognized arguments are 'basic', 'lvt', 'timer'.\n");
2051}
2052
2053
2054/**
2055 * @copydoc FNSSMDEVLIVEEXEC
2056 */
2057static DECLCALLBACK(int) apicR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
2058{
2059 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2060
2061 SSMR3PutU32( pSSM, pDev->cCpus);
2062 SSMR3PutBool(pSSM, pDev->fIoApic);
2063 SSMR3PutU32( pSSM, pDev->enmVersion);
2064 AssertCompile(PDMAPICVERSION_APIC == 2);
2065
2066 return VINF_SSM_DONT_CALL_AGAIN;
2067}
2068
2069
2070/**
2071 * @copydoc FNSSMDEVSAVEEXEC
2072 */
2073static DECLCALLBACK(int) apicR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
2074{
2075 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2076
2077 /* config */
2078 apicR3LiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
2079
2080 /* save all APICs data */ /** @todo: is it correct? */
2081 APIC_FOREACH_BEGIN(pDev);
2082 apic_save(pSSM, pCurApic);
2083 APIC_FOREACH_END();
2084
2085 return VINF_SUCCESS;
2086}
2087
2088/**
2089 * @copydoc FNSSMDEVLOADEXEC
2090 */
2091static DECLCALLBACK(int) apicR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
2092{
2093 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2094
2095 if ( uVersion != APIC_SAVED_STATE_VERSION
2096 && uVersion != APIC_SAVED_STATE_VERSION_VBOX_30
2097 && uVersion != APIC_SAVED_STATE_VERSION_ANCIENT)
2098 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
2099
2100 /* config */
2101 if (uVersion > APIC_SAVED_STATE_VERSION_VBOX_30)
2102 {
2103 uint32_t cCpus;
2104 int rc = SSMR3GetU32(pSSM, &cCpus); AssertRCReturn(rc, rc);
2105 if (cCpus != pDev->cCpus)
2106 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - cCpus: saved=%#x config=%#x"), cCpus, pDev->cCpus);
2107
2108 bool fIoApic;
2109 rc = SSMR3GetBool(pSSM, &fIoApic); AssertRCReturn(rc, rc);
2110 if (fIoApic != pDev->fIoApic)
2111 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - fIoApic: saved=%RTbool config=%RTbool"), fIoApic, pDev->fIoApic);
2112
2113 uint32_t uApicVersion;
2114 rc = SSMR3GetU32(pSSM, &uApicVersion); AssertRCReturn(rc, rc);
2115 if (uApicVersion != (uint32_t)pDev->enmVersion)
2116 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - uApicVersion: saved=%#x config=%#x"), uApicVersion, pDev->enmVersion);
2117 }
2118
2119 if (uPass != SSM_PASS_FINAL)
2120 return VINF_SUCCESS;
2121
2122 /* load all APICs data */ /** @todo: is it correct? */
2123 APIC_LOCK(pDev, VERR_INTERNAL_ERROR_3);
2124
2125 int rc = VINF_SUCCESS;
2126 APIC_FOREACH_BEGIN(pDev);
2127 rc = apic_load(pSSM, pCurApic, uVersion);
2128 if (RT_FAILURE(rc))
2129 break;
2130 APIC_FOREACH_END();
2131
2132 APIC_UNLOCK(pDev);
2133 return rc;
2134}
2135
2136/**
2137 * @copydoc FNPDMDEVRESET
2138 */
2139static DECLCALLBACK(void) apicR3Reset(PPDMDEVINS pDevIns)
2140{
2141 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2142 TMTimerLock(pDev->paLapicsR3[0].pTimerR3, VERR_IGNORED);
2143 APIC_LOCK_VOID(pDev, VERR_IGNORED);
2144
2145 /* Reset all APICs. */
2146 for (VMCPUID i = 0; i < pDev->cCpus; i++)
2147 {
2148 APICState *pApic = &pDev->CTX_SUFF(paLapics)[i];
2149 TMTimerStop(pApic->CTX_SUFF(pTimer));
2150
2151 /* Clear LAPIC state as if an INIT IPI was sent. */
2152 apic_init_ipi(pDev, pApic);
2153
2154 /* The IDs are not touched by apic_init_ipi() and must be reset now. */
2155 pApic->arb_id = pApic->id = i;
2156 Assert(pApic->id == pApic->phys_id); /* The two should match again. */
2157
2158 /* Reset should re-enable the APIC, see comment in msi.h */
2159 pApic->apicbase = VBOX_MSI_ADDR_BASE | MSR_IA32_APICBASE_ENABLE;
2160 if (pApic->phys_id == 0)
2161 pApic->apicbase |= MSR_IA32_APICBASE_BSP;
2162
2163 /* Clear any pending APIC interrupt action flag. */
2164 cpuClearInterrupt(pDev, pApic);
2165 }
2166 /** @todo r=bird: Why is this done everytime, while the constructor first
2167 * checks the CPUID? Who is right? */
2168 pDev->pApicHlpR3->pfnChangeFeature(pDev->pDevInsR3, pDev->enmVersion);
2169
2170 APIC_UNLOCK(pDev);
2171 TMTimerUnlock(pDev->paLapicsR3[0].pTimerR3);
2172}
2173
2174
2175/**
2176 * @copydoc FNPDMDEVRELOCATE
2177 */
2178static DECLCALLBACK(void) apicR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
2179{
2180 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2181 pDev->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2182 pDev->pApicHlpRC = pDev->pApicHlpR3->pfnGetRCHelpers(pDevIns);
2183 pDev->paLapicsRC = MMHyperR3ToRC(PDMDevHlpGetVM(pDevIns), pDev->paLapicsR3);
2184 pDev->pCritSectRC = pDev->pApicHlpR3->pfnGetRCCritSect(pDevIns);
2185 for (uint32_t i = 0; i < pDev->cCpus; i++)
2186 pDev->paLapicsR3[i].pTimerRC = TMTimerRCPtr(pDev->paLapicsR3[i].pTimerR3);
2187}
2188
2189
2190/**
2191 * Initializes the state of one local APIC.
2192 *
2193 * @param pApic The Local APIC state to init.
2194 * @param id The Local APIC ID.
2195 */
2196DECLINLINE(void) initApicData(APICState *pApic, uint8_t id)
2197{
2198 memset(pApic, 0, sizeof(*pApic));
2199
2200 /* See comment in msi.h for LAPIC base info. */
2201 pApic->apicbase = VBOX_MSI_ADDR_BASE | MSR_IA32_APICBASE_ENABLE;
2202 if (id == 0) /* Mark first CPU as BSP. */
2203 pApic->apicbase |= MSR_IA32_APICBASE_BSP;
2204
2205 for (int i = 0; i < APIC_LVT_NB; i++)
2206 pApic->lvt[i] = RT_BIT_32(16); /* mask LVT */
2207
2208 pApic->spurious_vec = 0xff;
2209 pApic->phys_id = id;
2210 pApic->id = id;
2211}
2212
2213
2214/**
2215 * @copydoc FNPDMDEVCONSTRUCT
2216 */
2217static DECLCALLBACK(int) apicR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
2218{
2219 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2220 uint32_t i;
2221
2222 /*
2223 * Only single device instance.
2224 */
2225 Assert(iInstance == 0);
2226
2227 /*
2228 * Validate configuration.
2229 */
2230 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "IOAPIC|RZEnabled|NumCPUs", "");
2231
2232 bool fIoApic;
2233 int rc = CFGMR3QueryBoolDef(pCfg, "IOAPIC", &fIoApic, true);
2234 if (RT_FAILURE(rc))
2235 return PDMDEV_SET_ERROR(pDevIns, rc,
2236 N_("Configuration error: Failed to read \"IOAPIC\""));
2237
2238 bool fRZEnabled;
2239 rc = CFGMR3QueryBoolDef(pCfg, "RZEnabled", &fRZEnabled, true);
2240 if (RT_FAILURE(rc))
2241 return PDMDEV_SET_ERROR(pDevIns, rc,
2242 N_("Configuration error: Failed to query boolean value \"RZEnabled\""));
2243
2244 uint32_t cCpus;
2245 rc = CFGMR3QueryU32Def(pCfg, "NumCPUs", &cCpus, 1);
2246 if (RT_FAILURE(rc))
2247 return PDMDEV_SET_ERROR(pDevIns, rc,
2248 N_("Configuration error: Failed to query integer value \"NumCPUs\""));
2249
2250 Log(("APIC: cCpus=%d fRZEnabled=%RTbool fIoApic=%RTbool\n", cCpus, fRZEnabled, fIoApic));
2251 if (cCpus > 255)
2252 return PDMDEV_SET_ERROR(pDevIns, rc,
2253 N_("Configuration error: Invalid value for \"NumCPUs\""));
2254
2255 /*
2256 * Init the data.
2257 */
2258 pDev->pDevInsR3 = pDevIns;
2259 pDev->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
2260 pDev->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2261 pDev->cCpus = cCpus;
2262 pDev->fIoApic = fIoApic;
2263 /* Use PDMAPICVERSION_X2APIC to activate x2APIC mode */
2264 pDev->enmVersion = PDMAPICVERSION_APIC;
2265
2266 /* Disable locking in this device. */
2267 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
2268 AssertRCReturn(rc, rc);
2269
2270 PVM pVM = PDMDevHlpGetVM(pDevIns);
2271
2272 /*
2273 * We are not freeing this memory, as it's automatically released when guest exits.
2274 */
2275 rc = MMHyperAlloc(pVM, cCpus * sizeof(APICState), 1, MM_TAG_PDM_DEVICE_USER, (void **)&pDev->paLapicsR3);
2276 if (RT_FAILURE(rc))
2277 return VERR_NO_MEMORY;
2278 pDev->paLapicsR0 = MMHyperR3ToR0(pVM, pDev->paLapicsR3);
2279 pDev->paLapicsRC = MMHyperR3ToRC(pVM, pDev->paLapicsR3);
2280
2281 for (i = 0; i < cCpus; i++)
2282 initApicData(&pDev->paLapicsR3[i], i);
2283
2284 /*
2285 * Register the APIC.
2286 */
2287 PDMAPICREG ApicReg;
2288 ApicReg.u32Version = PDM_APICREG_VERSION;
2289 ApicReg.pfnGetInterruptR3 = apicGetInterrupt;
2290 ApicReg.pfnHasPendingIrqR3 = apicHasPendingIrq;
2291 ApicReg.pfnSetBaseR3 = apicSetBase;
2292 ApicReg.pfnGetBaseR3 = apicGetBase;
2293 ApicReg.pfnSetTPRR3 = apicSetTPR;
2294 ApicReg.pfnGetTPRR3 = apicGetTPR;
2295 ApicReg.pfnWriteMSRR3 = apicWriteMSR;
2296 ApicReg.pfnReadMSRR3 = apicReadMSR;
2297 ApicReg.pfnBusDeliverR3 = apicBusDeliverCallback;
2298 ApicReg.pfnLocalInterruptR3 = apicLocalInterrupt;
2299 if (fRZEnabled)
2300 {
2301 ApicReg.pszGetInterruptRC = "apicGetInterrupt";
2302 ApicReg.pszHasPendingIrqRC = "apicHasPendingIrq";
2303 ApicReg.pszSetBaseRC = "apicSetBase";
2304 ApicReg.pszGetBaseRC = "apicGetBase";
2305 ApicReg.pszSetTPRRC = "apicSetTPR";
2306 ApicReg.pszGetTPRRC = "apicGetTPR";
2307 ApicReg.pszWriteMSRRC = "apicWriteMSR";
2308 ApicReg.pszReadMSRRC = "apicReadMSR";
2309 ApicReg.pszBusDeliverRC = "apicBusDeliverCallback";
2310 ApicReg.pszLocalInterruptRC = "apicLocalInterrupt";
2311
2312 ApicReg.pszGetInterruptR0 = "apicGetInterrupt";
2313 ApicReg.pszHasPendingIrqR0 = "apicHasPendingIrq";
2314 ApicReg.pszSetBaseR0 = "apicSetBase";
2315 ApicReg.pszGetBaseR0 = "apicGetBase";
2316 ApicReg.pszSetTPRR0 = "apicSetTPR";
2317 ApicReg.pszGetTPRR0 = "apicGetTPR";
2318 ApicReg.pszWriteMSRR0 = "apicWriteMSR";
2319 ApicReg.pszReadMSRR0 = "apicReadMSR";
2320 ApicReg.pszBusDeliverR0 = "apicBusDeliverCallback";
2321 ApicReg.pszLocalInterruptR0 = "apicLocalInterrupt";
2322 }
2323 else
2324 {
2325 ApicReg.pszGetInterruptRC = NULL;
2326 ApicReg.pszHasPendingIrqRC = NULL;
2327 ApicReg.pszSetBaseRC = NULL;
2328 ApicReg.pszGetBaseRC = NULL;
2329 ApicReg.pszSetTPRRC = NULL;
2330 ApicReg.pszGetTPRRC = NULL;
2331 ApicReg.pszWriteMSRRC = NULL;
2332 ApicReg.pszReadMSRRC = NULL;
2333 ApicReg.pszBusDeliverRC = NULL;
2334 ApicReg.pszLocalInterruptRC = NULL;
2335
2336 ApicReg.pszGetInterruptR0 = NULL;
2337 ApicReg.pszHasPendingIrqR0 = NULL;
2338 ApicReg.pszSetBaseR0 = NULL;
2339 ApicReg.pszGetBaseR0 = NULL;
2340 ApicReg.pszSetTPRR0 = NULL;
2341 ApicReg.pszGetTPRR0 = NULL;
2342 ApicReg.pszWriteMSRR0 = NULL;
2343 ApicReg.pszReadMSRR0 = NULL;
2344 ApicReg.pszBusDeliverR0 = NULL;
2345 ApicReg.pszLocalInterruptR0 = NULL;
2346 }
2347
2348 rc = PDMDevHlpAPICRegister(pDevIns, &ApicReg, &pDev->pApicHlpR3);
2349 AssertLogRelRCReturn(rc, rc);
2350 pDev->pCritSectR3 = pDev->pApicHlpR3->pfnGetR3CritSect(pDevIns);
2351
2352 /*
2353 * The the CPUID feature bit.
2354 */
2355 /** @todo r=bird: See remark in the apicR3Reset. */
2356 uint32_t u32Eax, u32Ebx, u32Ecx, u32Edx;
2357 PDMDevHlpGetCpuId(pDevIns, 0, &u32Eax, &u32Ebx, &u32Ecx, &u32Edx);
2358 if (u32Eax >= 1)
2359 {
2360 if ( fIoApic /* If IOAPIC is enabled, enable Local APIC in any case */
2361 || ( u32Ebx == X86_CPUID_VENDOR_INTEL_EBX
2362 && u32Ecx == X86_CPUID_VENDOR_INTEL_ECX
2363 && u32Edx == X86_CPUID_VENDOR_INTEL_EDX /* GenuineIntel */)
2364 || ( u32Ebx == X86_CPUID_VENDOR_AMD_EBX
2365 && u32Ecx == X86_CPUID_VENDOR_AMD_ECX
2366 && u32Edx == X86_CPUID_VENDOR_AMD_EDX /* AuthenticAMD */))
2367 {
2368 LogRel(("Activating Local APIC\n"));
2369 pDev->pApicHlpR3->pfnChangeFeature(pDevIns, pDev->enmVersion);
2370 }
2371 }
2372
2373 /*
2374 * Register the MMIO range.
2375 */
2376 /** @todo: shall reregister, if base changes. */
2377 uint32_t ApicBase = pDev->paLapicsR3[0].apicbase & ~0xfff;
2378 rc = PDMDevHlpMMIORegister(pDevIns, ApicBase, 0x1000, pDev,
2379 IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
2380 apicMMIOWrite, apicMMIORead, "APIC Memory");
2381 if (RT_FAILURE(rc))
2382 return rc;
2383
2384 if (fRZEnabled)
2385 {
2386 pDev->pApicHlpRC = pDev->pApicHlpR3->pfnGetRCHelpers(pDevIns);
2387 pDev->pCritSectRC = pDev->pApicHlpR3->pfnGetRCCritSect(pDevIns);
2388 rc = PDMDevHlpMMIORegisterRC(pDevIns, ApicBase, 0x1000, NIL_RTRCPTR /*pvUser*/, "apicMMIOWrite", "apicMMIORead");
2389 if (RT_FAILURE(rc))
2390 return rc;
2391
2392 pDev->pApicHlpR0 = pDev->pApicHlpR3->pfnGetR0Helpers(pDevIns);
2393 pDev->pCritSectR0 = pDev->pApicHlpR3->pfnGetR0CritSect(pDevIns);
2394 rc = PDMDevHlpMMIORegisterR0(pDevIns, ApicBase, 0x1000, NIL_RTR0PTR /*pvUser*/, "apicMMIOWrite", "apicMMIORead");
2395 if (RT_FAILURE(rc))
2396 return rc;
2397 }
2398
2399 /*
2400 * Create the APIC timers.
2401 */
2402 for (i = 0; i < cCpus; i++)
2403 {
2404 APICState *pApic = &pDev->paLapicsR3[i];
2405 pApic->pszDesc = MMR3HeapAPrintf(pVM, MM_TAG_PDM_DEVICE_USER, "APIC Timer #%u", i);
2406 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, apicR3TimerCallback, pApic,
2407 TMTIMER_FLAGS_NO_CRIT_SECT, pApic->pszDesc, &pApic->pTimerR3);
2408 if (RT_FAILURE(rc))
2409 return rc;
2410 pApic->pTimerR0 = TMTimerR0Ptr(pApic->pTimerR3);
2411 pApic->pTimerRC = TMTimerRCPtr(pApic->pTimerR3);
2412 TMR3TimerSetCritSect(pApic->pTimerR3, pDev->pCritSectR3);
2413 }
2414
2415 /*
2416 * Saved state.
2417 */
2418 rc = PDMDevHlpSSMRegister3(pDevIns, APIC_SAVED_STATE_VERSION, sizeof(*pDev),
2419 apicR3LiveExec, apicR3SaveExec, apicR3LoadExec);
2420 if (RT_FAILURE(rc))
2421 return rc;
2422
2423 /*
2424 * Register debugger info callback.
2425 */
2426 PDMDevHlpDBGFInfoRegister(pDevIns, "apic", "Display Local APIC state for current CPU. "
2427 "Recognizes 'basic', 'lvt', 'timer' as arguments, defaulting to 'basic'.", apicR3Info);
2428
2429#ifdef VBOX_WITH_STATISTICS
2430 /*
2431 * Statistics.
2432 */
2433 PDMDevHlpSTAMRegister(pDevIns, &pDev->StatMMIOReadGC, STAMTYPE_COUNTER, "/Devices/APIC/MMIOReadGC", STAMUNIT_OCCURENCES, "Number of APIC MMIO reads in GC.");
2434 PDMDevHlpSTAMRegister(pDevIns, &pDev->StatMMIOReadHC, STAMTYPE_COUNTER, "/Devices/APIC/MMIOReadHC", STAMUNIT_OCCURENCES, "Number of APIC MMIO reads in HC.");
2435 PDMDevHlpSTAMRegister(pDevIns, &pDev->StatMMIOWriteGC, STAMTYPE_COUNTER, "/Devices/APIC/MMIOWriteGC", STAMUNIT_OCCURENCES, "Number of APIC MMIO writes in GC.");
2436 PDMDevHlpSTAMRegister(pDevIns, &pDev->StatMMIOWriteHC, STAMTYPE_COUNTER, "/Devices/APIC/MMIOWriteHC", STAMUNIT_OCCURENCES, "Number of APIC MMIO writes in HC.");
2437 PDMDevHlpSTAMRegister(pDevIns, &pDev->StatClearedActiveIrq,STAMTYPE_COUNTER, "/Devices/APIC/MaskedActiveIRQ", STAMUNIT_OCCURENCES, "Number of cleared irqs.");
2438 for (i = 0; i < cCpus; i++)
2439 {
2440 APICState *pApic = &pDev->paLapicsR3[i];
2441 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetInitialCount, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Calls to apicTimerSetInitialCount.", "/Devices/APIC/%u/TimerSetInitialCount", i);
2442 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetInitialCountArm, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerSetRelative calls.", "/Devices/APIC/%u/TimerSetInitialCount/Arm", i);
2443 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetInitialCountDisarm, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerStop calls.", "/Devices/APIC/%u/TimerSetInitialCount/Disasm", i);
2444 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvt, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Calls to apicTimerSetLvt.", "/Devices/APIC/%u/TimerSetLvt", i);
2445 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtClearPeriodic, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Clearing APIC_LVT_TIMER_PERIODIC.", "/Devices/APIC/%u/TimerSetLvt/ClearPeriodic", i);
2446 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtPostponed, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerStop postponed.", "/Devices/APIC/%u/TimerSetLvt/Postponed", i);
2447 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtArmed, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerSet avoided.", "/Devices/APIC/%u/TimerSetLvt/Armed", i);
2448 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtArm, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerSet necessary.", "/Devices/APIC/%u/TimerSetLvt/Arm", i);
2449 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtArmRetries, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerSet retries.", "/Devices/APIC/%u/TimerSetLvt/ArmRetries", i);
2450 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtNoRelevantChange,STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "No relevant flags changed.", "/Devices/APIC/%u/TimerSetLvt/NoRelevantChange", i);
2451 }
2452#endif
2453
2454 return VINF_SUCCESS;
2455}
2456
2457
2458/**
2459 * APIC device registration structure.
2460 */
2461const PDMDEVREG g_DeviceAPIC =
2462{
2463 /* u32Version */
2464 PDM_DEVREG_VERSION,
2465 /* szName */
2466 "apic",
2467 /* szRCMod */
2468 "VBoxDD2GC.gc",
2469 /* szR0Mod */
2470 "VBoxDD2R0.r0",
2471 /* pszDescription */
2472 "Advanced Programmable Interrupt Controller (APIC) Device",
2473 /* fFlags */
2474 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64 | PDM_DEVREG_FLAGS_PAE36 | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
2475 /* fClass */
2476 PDM_DEVREG_CLASS_PIC,
2477 /* cMaxInstances */
2478 1,
2479 /* cbInstance */
2480 sizeof(APICState),
2481 /* pfnConstruct */
2482 apicR3Construct,
2483 /* pfnDestruct */
2484 NULL,
2485 /* pfnRelocate */
2486 apicR3Relocate,
2487 /* pfnIOCtl */
2488 NULL,
2489 /* pfnPowerOn */
2490 NULL,
2491 /* pfnReset */
2492 apicR3Reset,
2493 /* pfnSuspend */
2494 NULL,
2495 /* pfnResume */
2496 NULL,
2497 /* pfnAttach */
2498 NULL,
2499 /* pfnDetach */
2500 NULL,
2501 /* pfnQueryInterface. */
2502 NULL,
2503 /* pfnInitComplete */
2504 NULL,
2505 /* pfnPowerOff */
2506 NULL,
2507 /* pfnSoftReset */
2508 NULL,
2509 /* u32VersionEnd */
2510 PDM_DEVREG_VERSION
2511};
2512
2513#endif /* IN_RING3 */
2514#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
2515
Note: See TracBrowser for help on using the repository browser.

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