VirtualBox

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

Last change on this file since 40754 was 40280, checked in by vboxsync, 12 years ago

Corrected a bunch of HC and GC uses in status codes.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use