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
Line 
1/* $Id: DevAPIC.cpp 40280 2012-02-28 19:47:00Z vboxsync $ */
2/** @file
3 * Advanced Programmable Interrupt Controller (APIC) Device.
4 */
5
6/*
7 * Copyright (C) 2006-2011 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 * --------------------------------------------------------------------
17 *
18 * This code is based on:
19 *
20 * apic.c revision 1.5 @@OSETODO
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
39 */
40
41/*******************************************************************************
42* Header Files *
43*******************************************************************************/
44#define LOG_GROUP LOG_GROUP_DEV_APIC
45#include <VBox/vmm/pdmdev.h>
46
47#include <VBox/log.h>
48#include <VBox/vmm/stam.h>
49#include <VBox/vmm/vmcpuset.h>
50#include <iprt/asm.h>
51#include <iprt/assert.h>
52
53#include <VBox/msi.h>
54
55#include "VBoxDD2.h"
56#include "DevApic.h"
57
58/*******************************************************************************
59* Defined Constants And Macros *
60*******************************************************************************/
61#define MSR_IA32_APICBASE 0x1b
62#define MSR_IA32_APICBASE_BSP (1<<8)
63#define MSR_IA32_APICBASE_ENABLE (1<<11)
64#define MSR_IA32_APICBASE_X2ENABLE (1<<10)
65#define MSR_IA32_APICBASE_BASE (0xfffff<<12)
66
67#ifdef _MSC_VER
68# pragma warning(disable:4244)
69#endif
70
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
79/* version 0x14: Pentium 4, Xeon; LVT count depends on that */
80#define APIC_HW_VERSION 0x14
81
82/** @def APIC_LOCK
83 * Acquires the PDM lock. */
84#define APIC_LOCK(a_pDev, rcBusy) \
85 do { \
86 int rc2 = PDMCritSectEnter((a_pDev)->CTX_SUFF(pCritSect), (rcBusy)); \
87 if (rc2 != VINF_SUCCESS) \
88 return rc2; \
89 } while (0)
90
91/** @def APIC_LOCK_VOID
92 * Acquires the PDM lock and does not expect failure (i.e. ring-3 only!). */
93#define APIC_LOCK_VOID(a_pDev, rcBusy) \
94 do { \
95 int rc2 = PDMCritSectEnter((a_pDev)->CTX_SUFF(pCritSect), (rcBusy)); \
96 AssertLogRelRCReturnVoid(rc2); \
97 } while (0)
98
99/** @def APIC_UNLOCK
100 * Releases the PDM lock. */
101#define APIC_UNLOCK(a_pDev) \
102 PDMCritSectLeave((a_pDev)->CTX_SUFF(pCritSect))
103
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
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 } \
162 } while (0)
163
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 */
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
183
184/* APIC destination mode */
185#define APIC_DESTMODE_FLAT 0xf
186#define APIC_DESTMODE_CLUSTER 0x0
187
188#define APIC_TRIGGER_EDGE 0
189#define APIC_TRIGGER_LEVEL 1
190
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)
197
198#define ESR_ILLEGAL_ADDRESS (1 << 7)
199
200#define APIC_SV_ENABLE (1 << 8)
201
202#define APIC_MAX_PATCH_ATTEMPTS 100
203
204typedef uint32_t PhysApicId;
205typedef uint32_t LogApicId;
206
207
208/*******************************************************************************
209* Structures and Typedefs *
210*******************************************************************************/
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{
297 uint32_t apicbase;
298 /* Task priority register (interrupt level) */
299 uint32_t tpr;
300 /* Logical APIC id - user programmable */
301 LogApicId id;
302 /* Physical APIC id - not visible to user, constant */
303 PhysApicId phys_id;
304 /** @todo: is it logical or physical? Not really used anyway now. */
305 PhysApicId arb_id;
306 uint32_t spurious_vec;
307 uint8_t log_dest;
308 uint8_t dest_mode;
309 APIC256BITREG isr; /**< in service register */
310 APIC256BITREG tmr; /**< trigger mode register */
311 APIC256BITREG irr; /**< interrupt request register */
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;
318 uint32_t Alignment0;
319
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;
324 /** The APIC timer - R3 Ptr. */
325 PTMTIMERR3 pTimerR3;
326 /** The APIC timer - R0 Ptr. */
327 PTMTIMERR0 pTimerR0;
328 /** The APIC timer - RC Ptr. */
329 PTMTIMERRC pTimerRC;
330 /** Whether the timer is armed or not */
331 bool fTimerArmed;
332 /** Alignment */
333 bool afAlignment[3];
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;
338 /** Timer description timer. */
339 R3PTRTYPE(char *) pszDesc;
340# ifdef VBOX_WITH_STATISTICS
341# if HC_ARCH_BITS == 32
342 uint32_t u32Alignment0;
343# endif
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
355
356} APICState;
357
358AssertCompileMemberAlignment(APICState, initial_count_load_time, 8);
359# ifdef VBOX_WITH_STATISTICS
360AssertCompileMemberAlignment(APICState, StatTimerSetInitialCount, 8);
361# endif
362
363typedef struct
364{
365 /** The device instance - R3 Ptr. */
366 PPDMDEVINSR3 pDevInsR3;
367 /** The APIC helpers - R3 Ptr. */
368 PCPDMAPICHLPR3 pApicHlpR3;
369 /** LAPICs states - R3 Ptr */
370 R3PTRTYPE(APICState *) paLapicsR3;
371 /** The critical section - R3 Ptr. */
372 R3PTRTYPE(PPDMCRITSECT) pCritSectR3;
373
374 /** The device instance - R0 Ptr. */
375 PPDMDEVINSR0 pDevInsR0;
376 /** The APIC helpers - R0 Ptr. */
377 PCPDMAPICHLPR0 pApicHlpR0;
378 /** LAPICs states - R0 Ptr */
379 R0PTRTYPE(APICState *) paLapicsR0;
380 /** The critical section - R3 Ptr. */
381 R0PTRTYPE(PPDMCRITSECT) pCritSectR0;
382
383 /** The device instance - RC Ptr. */
384 PPDMDEVINSRC pDevInsRC;
385 /** The APIC helpers - RC Ptr. */
386 PCPDMAPICHLPRC pApicHlpRC;
387 /** LAPICs states - RC Ptr */
388 RCPTRTYPE(APICState *) paLapicsRC;
389 /** The critical section - R3 Ptr. */
390 RCPTRTYPE(PPDMCRITSECT) pCritSectRC;
391
392 /** APIC specification version in this virtual hardware configuration. */
393 PDMAPICVERSION enmVersion;
394
395 /** Number of attempts made to optimize TPR accesses. */
396 uint32_t cTPRPatchAttempts;
397
398 /** Number of CPUs on the system (same as LAPIC count). */
399 uint32_t cCpus;
400 /** Whether we've got an IO APIC or not. */
401 bool fIoApic;
402 /** Alignment padding. */
403 bool afPadding[3];
404
405# ifdef VBOX_WITH_STATISTICS
406 STAMCOUNTER StatMMIOReadGC;
407 STAMCOUNTER StatMMIOReadHC;
408 STAMCOUNTER StatMMIOWriteGC;
409 STAMCOUNTER StatMMIOWriteHC;
410 STAMCOUNTER StatClearedActiveIrq;
411# endif
412} APICDeviceInfo;
413# ifdef VBOX_WITH_STATISTICS
414AssertCompileMemberAlignment(APICDeviceInfo, StatMMIOReadGC, 8);
415# endif
416
417#ifndef VBOX_DEVICE_STRUCT_TESTCASE
418
419/*******************************************************************************
420* Internal Functions *
421*******************************************************************************/
422static void apic_update_tpr(APICDeviceInfo *pDev, APICState* s, uint32_t val);
423
424static void apic_eoi(APICDeviceInfo *pDev, APICState* s); /* */
425static PVMCPUSET apic_get_delivery_bitmask(APICDeviceInfo* pDev, uint8_t dest, uint8_t dest_mode, PVMCPUSET pDstSet);
426static int apic_deliver(APICDeviceInfo* pDev, APICState *s,
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);
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);
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);
436
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);
440
441
442DECLINLINE(APICState*) getLapicById(APICDeviceInfo *pDev, VMCPUID id)
443{
444 AssertFatalMsg(id < pDev->cCpus, ("CPU id %d out of range\n", id));
445 return &pDev->CTX_SUFF(paLapics)[id];
446}
447
448DECLINLINE(APICState*) getLapic(APICDeviceInfo* pDev)
449{
450 /* LAPIC's array is indexed by CPU id */
451 VMCPUID id = pDev->CTX_SUFF(pApicHlp)->pfnGetCpuId(pDev->CTX_SUFF(pDevIns));
452 return getLapicById(pDev, id);
453}
454
455DECLINLINE(VMCPUID) getCpuFromLapic(APICDeviceInfo* pDev, APICState *s)
456{
457 /* for now we assume LAPIC physical id == CPU id */
458 return VMCPUID(s->phys_id);
459}
460
461DECLINLINE(void) cpuSetInterrupt(APICDeviceInfo* pDev, APICState *s, PDMAPICIRQ enmType = PDMAPICIRQ_HARDWARE)
462{
463 LogFlow(("apic: setting interrupt flag for cpu %d\n", getCpuFromLapic(pDev, s)));
464 pDev->CTX_SUFF(pApicHlp)->pfnSetInterruptFF(pDev->CTX_SUFF(pDevIns), enmType,
465 getCpuFromLapic(pDev, s));
466}
467
468DECLINLINE(void) cpuClearInterrupt(APICDeviceInfo* pDev, APICState *s, PDMAPICIRQ enmType = PDMAPICIRQ_HARDWARE)
469{
470 LogFlow(("apic: clear interrupt flag\n"));
471 pDev->CTX_SUFF(pApicHlp)->pfnClearInterruptFF(pDev->CTX_SUFF(pDevIns), enmType,
472 getCpuFromLapic(pDev, s));
473}
474
475# ifdef IN_RING3
476
477DECLINLINE(void) cpuSendSipi(APICDeviceInfo* pDev, APICState *s, int vector)
478{
479 Log2(("apic: send SIPI vector=%d\n", vector));
480
481 pDev->pApicHlpR3->pfnSendSipi(pDev->pDevInsR3,
482 getCpuFromLapic(pDev, s),
483 vector);
484}
485
486DECLINLINE(void) cpuSendInitIpi(APICDeviceInfo* pDev, APICState *s)
487{
488 Log2(("apic: send init IPI\n"));
489
490 pDev->pApicHlpR3->pfnSendInitIpi(pDev->pDevInsR3,
491 getCpuFromLapic(pDev, s));
492}
493
494# endif /* IN_RING3 */
495
496DECLINLINE(uint32_t) getApicEnableBits(APICDeviceInfo* pDev)
497{
498 switch (pDev->enmVersion)
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:
507 AssertMsgFailed(("Unsupported APIC version %d\n", pDev->enmVersion));
508 return 0;
509 }
510}
511
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
529static int apic_bus_deliver(APICDeviceInfo* pDev,
530 PCVMCPUSET pDstSet, uint8_t delivery_mode,
531 uint8_t vector_num, uint8_t polarity,
532 uint8_t trigger_mode)
533{
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 {
539 case APIC_DM_LOWPRI:
540 {
541 VMCPUID idDstCpu = VMCPUSET_FIND_FIRST_PRESENT(pDstSet);
542 if (idDstCpu != NIL_VMCPUID)
543 {
544 APICState *pApic = getLapicById(pDev, idDstCpu);
545 apic_set_irq(pDev, pApic, vector_num, trigger_mode);
546 }
547 return VINF_SUCCESS;
548 }
549
550 case APIC_DM_FIXED:
551 /** @todo XXX: arbitration */
552 break;
553
554 case APIC_DM_SMI:
555 APIC_FOREACH_IN_SET_BEGIN(pDev, pDstSet);
556 cpuSetInterrupt(pDev, pCurApic, PDMAPICIRQ_SMI);
557 APIC_FOREACH_END();
558 return VINF_SUCCESS;
559
560 case APIC_DM_NMI:
561 APIC_FOREACH_IN_SET_BEGIN(pDev, pDstSet);
562 cpuSetInterrupt(pDev, pCurApic, PDMAPICIRQ_NMI);
563 APIC_FOREACH_END();
564 return VINF_SUCCESS;
565
566 case APIC_DM_INIT:
567 /* normal INIT IPI sent to processors */
568#ifdef IN_RING3
569 APIC_FOREACH_IN_SET_BEGIN(pDev, pDstSet);
570 apicSendInitIpi(pDev, pCurApic);
571 APIC_FOREACH_END();
572 return VINF_SUCCESS;
573#else
574 /* We shall send init IPI only in R3. */
575 return VINF_IOM_R3_MMIO_READ_WRITE;
576#endif /* IN_RING3 */
577
578 case APIC_DM_EXTINT:
579 /* handled in I/O APIC code */
580 break;
581
582 default:
583 return VINF_SUCCESS;
584 }
585
586 APIC_FOREACH_IN_SET_BEGIN(pDev, pDstSet);
587 apic_set_irq(pDev, pCurApic, vector_num, trigger_mode);
588 APIC_FOREACH_END();
589 return VINF_SUCCESS;
590}
591
592
593PDMBOTHCBDECL(void) apicSetBase(PPDMDEVINS pDevIns, uint64_t val)
594{
595 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
596 Assert(PDMCritSectIsOwner(pDev->CTX_SUFF(pCritSect)));
597 APICState *s = getLapic(pDev); /** @todo fix interface */
598 Log(("apicSetBase: %016RX64\n", val));
599
600 /** @todo: do we need to lock here ? */
601 /* APIC_LOCK_VOID(pDev, VERR_INTERNAL_ERROR); */
602 /** @todo If this change is valid immediately, then we should change the MMIO registration! */
603 /* We cannot change if this CPU is BSP or not by writing to MSR - it's hardwired */
604 PDMAPICVERSION oldMode = getApicMode(s);
605 s->apicbase =
606 (val & 0xfffff000) | /* base */
607 (val & getApicEnableBits(pDev)) | /* mode */
608 (s->apicbase & MSR_IA32_APICBASE_BSP) /* keep BSP bit */;
609 PDMAPICVERSION newMode = getApicMode(s);
610
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. */
619 cpuClearInterrupt(pDev, s);
620 /** @todo: why do we do that? */
621 pDev->CTX_SUFF(pApicHlp)->pfnChangeFeature(pDevIns, PDMAPICVERSION_NONE);
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 }
633 }
634 /* APIC_UNLOCK(pDev); */
635}
636
637PDMBOTHCBDECL(uint64_t) apicGetBase(PPDMDEVINS pDevIns)
638{
639 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
640 Assert(PDMCritSectIsOwner(pDev->CTX_SUFF(pCritSect)));
641 APICState *s = getLapic(pDev); /** @todo fix interface */
642 LogFlow(("apicGetBase: %016llx\n", (uint64_t)s->apicbase));
643 return s->apicbase;
644}
645
646PDMBOTHCBDECL(void) apicSetTPR(PPDMDEVINS pDevIns, VMCPUID idCpu, uint8_t val)
647{
648 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
649 Assert(PDMCritSectIsOwner(pDev->CTX_SUFF(pCritSect)));
650 APICState *s = getLapicById(pDev, idCpu);
651 LogFlow(("apicSetTPR: val=%#x (trp %#x -> %#x)\n", val, s->tpr, val));
652 apic_update_tpr(pDev, s, val);
653}
654
655PDMBOTHCBDECL(uint8_t) apicGetTPR(PPDMDEVINS pDevIns, VMCPUID idCpu)
656{
657 /* We don't perform any locking here as that would cause a lot of contention for VT-x/AMD-V. */
658 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
659 APICState *s = getLapicById(pDev, idCpu);
660 Log2(("apicGetTPR: returns %#x\n", s->tpr));
661 return s->tpr;
662}
663
664
665/**
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/**
692 * Writes to an APIC register via MMIO or MSR.
693 *
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.
702 */
703static int apicWriteRegister(APICDeviceInfo *pDev, APICState *pApic, uint32_t iReg, uint64_t u64Value,
704 int rcBusy, bool fMsr)
705{
706 Assert(!PDMCritSectIsOwner(pDev->CTX_SUFF(pCritSect)));
707
708 int rc = VINF_SUCCESS;
709 switch (iReg)
710 {
711 case 0x02:
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);
715 break;
716
717 case 0x03:
718 /* read only, ignore write. */
719 break;
720
721 case 0x08:
722 APIC_LOCK(pDev, rcBusy);
723 apic_update_tpr(pDev, pApic, u64Value);
724 APIC_UNLOCK(pDev);
725 break;
726
727 case 0x09: case 0x0a:
728 Log(("apicWriteRegister: write to read-only register %d ignored\n", iReg));
729 break;
730
731 case 0x0b: /* EOI */
732 APIC_LOCK(pDev, rcBusy);
733 apic_eoi(pDev, pApic);
734 APIC_UNLOCK(pDev);
735 break;
736
737 case 0x0d:
738 APIC_LOCK(pDev, rcBusy);
739 pApic->log_dest = (u64Value >> 24) & 0xff;
740 APIC_UNLOCK(pDev);
741 break;
742
743 case 0x0e:
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);
747 break;
748
749 case 0x0f:
750 APIC_LOCK(pDev, rcBusy);
751 pApic->spurious_vec = u64Value & 0x1ff;
752 apic_update_irq(pDev, pApic);
753 APIC_UNLOCK(pDev);
754 break;
755
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:
760 Log(("apicWriteRegister: write to read-only register %d ignored\n", iReg));
761 break;
762
763 case 0x30:
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);
772 break;
773
774 case 0x31:
775 if (!fMsr)
776 {
777 APIC_LOCK(pDev, rcBusy);
778 pApic->icr[1] = (uint64_t)u64Value;
779 APIC_UNLOCK(pDev);
780 }
781 else
782 rc = apicWriteRegisterInvalid(pDev, pApic, iReg, u64Value, rcBusy, fMsr);
783 break;
784
785 case 0x32 + APIC_LVT_TIMER:
786 AssertCompile(APIC_LVT_TIMER == 0);
787 APIC_AND_TM_LOCK(pDev, pApic, rcBusy);
788 apicTimerSetLvt(pDev, pApic, u64Value);
789 APIC_AND_TM_UNLOCK(pDev, pApic);
790 break;
791
792 case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
793 APIC_LOCK(pDev, rcBusy);
794 pApic->lvt[iReg - 0x32] = u64Value;
795 APIC_UNLOCK(pDev);
796 break;
797
798 case 0x38:
799 APIC_AND_TM_LOCK(pDev, pApic, rcBusy);
800 apicTimerSetInitialCount(pDev, pApic, u64Value);
801 APIC_AND_TM_UNLOCK(pDev, pApic);
802 break;
803
804 case 0x39:
805 Log(("apicWriteRegister: write to read-only register %d ignored\n", iReg));
806 break;
807
808 case 0x3e:
809 {
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);
815 break;
816 }
817
818 case 0x3f:
819 if (fMsr)
820 {
821 /* Self IPI, see x2APIC book 2.4.5 */
822 APIC_LOCK(pDev, rcBusy);
823 int vector = u64Value & 0xff;
824 VMCPUSET SelfSet;
825 VMCPUSET_EMPTY(&SelfSet);
826 VMCPUSET_ADD(&SelfSet, pApic->id);
827 rc = apic_bus_deliver(pDev,
828 &SelfSet,
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 */
837
838 default:
839 rc = apicWriteRegisterInvalid(pDev, pApic, iReg, u64Value, rcBusy, fMsr);
840 break;
841 }
842
843 return rc;
844}
845
846
847/**
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.
858 */
859static int apicReadRegisterInvalid(APICDeviceInfo *pDev, APICState *pApic, uint32_t iReg, uint64_t *pu64Value,
860 int rcBusy, bool fMsr)
861{
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;
870}
871
872
873/**
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.
884 */
885static int apicReadRegister(APICDeviceInfo *pDev, APICState *pApic, uint32_t iReg, uint64_t *pu64Value,
886 int rcBusy, bool fMsr)
887{
888 Assert(!PDMCritSectIsOwner(pDev->CTX_SUFF(pCritSect)));
889
890 int rc = VINF_SUCCESS;
891 switch (iReg)
892 {
893 case 0x02: /* id */
894 APIC_LOCK(pDev, rcBusy);
895 *pu64Value = pApic->id << 24;
896 APIC_UNLOCK(pDev);
897 break;
898
899 case 0x03: /* version */
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);
908 break;
909
910 case 0x08:
911 APIC_LOCK(pDev, rcBusy);
912 *pu64Value = pApic->tpr;
913 APIC_UNLOCK(pDev);
914 break;
915
916 case 0x09:
917 *pu64Value = apic_get_arb_pri(pApic);
918 break;
919
920 case 0x0a:
921 /* ppr */
922 APIC_LOCK(pDev, rcBusy);
923 *pu64Value = apic_get_ppr(pApic);
924 APIC_UNLOCK(pDev);
925 break;
926
927 case 0x0b:
928 Log(("apicReadRegister: %x -> write only returning 0\n", iReg));
929 *pu64Value = 0;
930 break;
931
932 case 0x0d:
933 APIC_LOCK(pDev, rcBusy);
934 *pu64Value = (uint64_t)pApic->log_dest << 24;
935 APIC_UNLOCK(pDev);
936 break;
937
938 case 0x0e:
939 /* Bottom 28 bits are always 1 */
940 APIC_LOCK(pDev, rcBusy);
941 *pu64Value = ((uint64_t)pApic->dest_mode << 28) | UINT32_C(0xfffffff);
942 APIC_UNLOCK(pDev);
943 break;
944
945 case 0x0f:
946 APIC_LOCK(pDev, rcBusy);
947 *pu64Value = pApic->spurious_vec;
948 APIC_UNLOCK(pDev);
949 break;
950
951 case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
952 APIC_LOCK(pDev, rcBusy);
953 *pu64Value = pApic->isr.au32Bitmap[iReg & 7];
954 APIC_UNLOCK(pDev);
955 break;
956
957 case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
958 APIC_LOCK(pDev, rcBusy);
959 *pu64Value = pApic->tmr.au32Bitmap[iReg & 7];
960 APIC_UNLOCK(pDev);
961 break;
962
963 case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
964 APIC_LOCK(pDev, rcBusy);
965 *pu64Value = pApic->irr.au32Bitmap[iReg & 7];
966 APIC_UNLOCK(pDev);
967 break;
968
969 case 0x28:
970 APIC_LOCK(pDev, rcBusy);
971 *pu64Value = pApic->esr;
972 APIC_UNLOCK(pDev);
973 break;
974
975 case 0x30:
976 /* Here one of the differences with regular APIC: ICR is single 64-bit register */
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);
983 break;
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
996 case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
997 APIC_LOCK(pDev, rcBusy);
998 *pu64Value = pApic->lvt[iReg - 0x32];
999 APIC_UNLOCK(pDev);
1000 break;
1001
1002 case 0x38:
1003 APIC_LOCK(pDev, rcBusy);
1004 *pu64Value = pApic->initial_count;
1005 APIC_UNLOCK(pDev);
1006 break;
1007
1008 case 0x39:
1009 APIC_AND_TM_LOCK(pDev, pApic, rcBusy);
1010 *pu64Value = apic_get_current_count(pDev, pApic);
1011 APIC_AND_TM_UNLOCK(pDev, pApic);
1012 break;
1013
1014 case 0x3e:
1015 APIC_LOCK(pDev, rcBusy);
1016 *pu64Value = pApic->divide_conf;
1017 APIC_UNLOCK(pDev);
1018 break;
1019
1020 case 0x3f:
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);
1029 break;
1030 case 0x2f: /** @todo Correctable machine check exception vector, implement me! */
1031 default:
1032 /**
1033 * @todo: according to spec when APIC writes to ESR it msut raise error interrupt,
1034 * i.e. LVT[5]
1035 */
1036 rc = apicReadRegisterInvalid(pDev, pApic, iReg, pu64Value, rcBusy, fMsr);
1037 break;
1038 }
1039 return rc;
1040}
1041
1042/**
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/**
1074 * More or less private interface between IOAPIC, only PDM is responsible
1075 * for connecting the two devices.
1076 */
1077PDMBOTHCBDECL(int) apicBusDeliverCallback(PPDMDEVINS pDevIns, uint8_t u8Dest, uint8_t u8DestMode,
1078 uint8_t u8DeliveryMode, uint8_t iVector, uint8_t u8Polarity,
1079 uint8_t u8TriggerMode)
1080{
1081 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
1082 Assert(PDMCritSectIsOwner(pDev->CTX_SUFF(pCritSect)));
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));
1085 VMCPUSET DstSet;
1086 return apic_bus_deliver(pDev, apic_get_delivery_bitmask(pDev, u8Dest, u8DestMode, &DstSet),
1087 u8DeliveryMode, iVector, u8Polarity, u8TriggerMode);
1088}
1089
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{
1096 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
1097 APICState *s = getLapicById(pDev, 0);
1098
1099 Assert(PDMCritSectIsOwner(pDev->CTX_SUFF(pCritSect)));
1100 LogFlow(("apicLocalInterrupt: pDevIns=%p u8Pin=%x u8Level=%x\n", pDevIns, u8Pin, u8Level));
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)
1107 cpuSetInterrupt(pDev, s, PDMAPICIRQ_EXTINT);
1108 else
1109 cpuClearInterrupt(pDev, s, PDMAPICIRQ_EXTINT);
1110
1111 return VINF_SUCCESS;
1112 }
1113
1114 /* If LAPIC is enabled, interrupts are subject to LVT programming. */
1115
1116 /* There are only two local interrupt pins. */
1117 AssertMsgReturn(u8Pin <= 1, ("Invalid LAPIC pin %d\n", u8Pin), VERR_INVALID_PARAMETER);
1118
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;
1132 switch (u8Delivery)
1133 {
1134 case APIC_DM_EXTINT:
1135 Assert(u8Pin == 0); /* PIC should be wired to LINT0. */
1136 enmType = PDMAPICIRQ_EXTINT;
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)
1140 cpuSetInterrupt(pDev, s, enmType);
1141 else
1142 cpuClearInterrupt(pDev, s, enmType);
1143 return VINF_SUCCESS;
1144 case APIC_DM_NMI:
1145 /* External NMI should be wired to LINT1, but Linux sometimes programs
1146 * LVT0 to NMI delivery mode as well.
1147 */
1148 enmType = PDMAPICIRQ_NMI;
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;
1153 case APIC_DM_SMI:
1154 enmType = PDMAPICIRQ_SMI;
1155 break;
1156 case APIC_DM_FIXED:
1157 {
1158 /** @todo implement APIC_DM_FIXED! */
1159 static unsigned s_c = 0;
1160 if (s_c++ < 5)
1161 LogRel(("delivery type APIC_DM_FIXED not implemented. u8Pin=%d u8Level=%d\n", u8Pin, u8Level));
1162 return VINF_SUCCESS;
1163 }
1164 case APIC_DM_INIT:
1165 /** @todo implement APIC_DM_INIT? */
1166 default:
1167 {
1168 static unsigned s_c = 0;
1169 if (s_c++ < 100)
1170 AssertLogRelMsgFailed(("delivery type %d not implemented. u8Pin=%d u8Level=%d\n", u8Delivery, u8Pin, u8Level));
1171 return VERR_INTERNAL_ERROR_4;
1172 }
1173 }
1174 LogFlow(("apicLocalInterrupt: setting local interrupt type %d\n", enmType));
1175 cpuSetInterrupt(pDev, s, enmType);
1176 }
1177 return VINF_SUCCESS;
1178}
1179
1180static int apic_get_ppr(APICState const *s)
1181{
1182 int ppr;
1183
1184 int tpr = (s->tpr >> 4);
1185 int isrv = Apic256BitReg_FindLastSetBit(&s->isr, 0);
1186 isrv >>= 4;
1187 if (tpr >= isrv)
1188 ppr = s->tpr;
1189 else
1190 ppr = isrv << 4;
1191 return ppr;
1192}
1193
1194static int apic_get_ppr_zero_tpr(APICState *s)
1195{
1196 return Apic256BitReg_FindLastSetBit(&s->isr, 0);
1197}
1198
1199static int apic_get_arb_pri(APICState const *s)
1200{
1201 /** @todo XXX: arbitration */
1202 return 0;
1203}
1204
1205/* signal the CPU if an irq is pending */
1206static bool apic_update_irq(APICDeviceInfo *pDev, APICState* s)
1207{
1208 if (!(s->spurious_vec & APIC_SV_ENABLE))
1209 {
1210 /* Clear any pending APIC interrupt action flag. */
1211 cpuClearInterrupt(pDev, s);
1212 return false;
1213 }
1214
1215 int irrv = Apic256BitReg_FindLastSetBit(&s->irr, -1);
1216 if (irrv < 0)
1217 return false;
1218 int ppr = apic_get_ppr(s);
1219 if (ppr && (irrv & 0xf0) <= (ppr & 0xf0))
1220 return false;
1221 cpuSetInterrupt(pDev, s);
1222 return true;
1223}
1224
1225/* Check if the APIC has a pending interrupt/if a TPR change would active one. */
1226PDMBOTHCBDECL(bool) apicHasPendingIrq(PPDMDEVINS pDevIns)
1227{
1228 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
1229 if (!pDev)
1230 return false;
1231
1232 /* We don't perform any locking here as that would cause a lot of contention for VT-x/AMD-V. */
1233
1234 APICState *s = getLapic(pDev); /** @todo fix interface */
1235
1236 /*
1237 * All our callbacks now come from single IOAPIC, thus locking
1238 * seems to be excessive now
1239 */
1240 /** @todo check excessive locking whatever... */
1241 int irrv = Apic256BitReg_FindLastSetBit(&s->irr, -1);
1242 if (irrv < 0)
1243 return false;
1244
1245 int ppr = apic_get_ppr_zero_tpr(s);
1246
1247 if (ppr && (irrv & 0xf0) <= (ppr & 0xf0))
1248 return false;
1249
1250 return true;
1251}
1252
1253static void apic_update_tpr(APICDeviceInfo *pDev, APICState* s, uint32_t val)
1254{
1255 bool fIrqIsActive = false;
1256 bool fIrqWasActive = false;
1257
1258 fIrqWasActive = apic_update_irq(pDev, s);
1259 s->tpr = val;
1260 fIrqIsActive = apic_update_irq(pDev, s);
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));
1266 STAM_COUNTER_INC(&pDev->StatClearedActiveIrq);
1267 cpuClearInterrupt(pDev, s);
1268 }
1269}
1270
1271static void apic_set_irq(APICDeviceInfo *pDev, APICState* s, int vector_num, int trigger_mode)
1272{
1273 LogFlow(("CPU%d: apic_set_irq vector=%x, trigger_mode=%x\n", s->phys_id, vector_num, trigger_mode));
1274 Apic256BitReg_SetBit(&s->irr, vector_num);
1275 if (trigger_mode)
1276 Apic256BitReg_SetBit(&s->tmr, vector_num);
1277 else
1278 Apic256BitReg_ClearBit(&s->tmr, vector_num);
1279 apic_update_irq(pDev, s);
1280}
1281
1282static void apic_eoi(APICDeviceInfo *pDev, APICState* s)
1283{
1284 int isrv = Apic256BitReg_FindLastSetBit(&s->isr, -1);
1285 if (isrv < 0)
1286 return;
1287 Apic256BitReg_ClearBit(&s->isr, isrv);
1288 LogFlow(("CPU%d: apic_eoi isrv=%x\n", s->phys_id, isrv));
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. */
1291 apic_update_irq(pDev, s);
1292}
1293
1294static PVMCPUSET apic_get_delivery_bitmask(APICDeviceInfo *pDev, uint8_t dest, uint8_t dest_mode, PVMCPUSET pDstSet)
1295{
1296 VMCPUSET_EMPTY(pDstSet);
1297
1298 if (dest_mode == 0)
1299 {
1300 if (dest == 0xff) /* The broadcast ID. */
1301 VMCPUSET_FILL(pDstSet);
1302 else
1303 VMCPUSET_ADD(pDstSet, dest);
1304 }
1305 else
1306 {
1307 /** @todo XXX: cluster mode */
1308 APIC_FOREACH_BEGIN(pDev);
1309 if (pCurApic->dest_mode == APIC_DESTMODE_FLAT)
1310 {
1311 if (dest & pCurApic->log_dest)
1312 VMCPUSET_ADD(pDstSet, iCurApic);
1313 }
1314 else if (pCurApic->dest_mode == APIC_DESTMODE_CLUSTER)
1315 {
1316 if ( (dest & 0xf0) == (pCurApic->log_dest & 0xf0)
1317 && (dest & pCurApic->log_dest & 0x0f))
1318 VMCPUSET_ADD(pDstSet, iCurApic);
1319 }
1320 APIC_FOREACH_END();
1321 }
1322
1323 return pDstSet;
1324}
1325
1326#ifdef IN_RING3
1327static void apic_init_ipi(APICDeviceInfo* pDev, APICState *s)
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;
1336 s->dest_mode = 0xff; /** @todo 0xff???? */
1337 Apic256BitReg_Empty(&s->isr);
1338 Apic256BitReg_Empty(&s->tmr);
1339 Apic256BitReg_Empty(&s->irr);
1340 s->esr = 0;
1341 memset(s->icr, 0, sizeof(s->icr));
1342 s->divide_conf = 0;
1343 s->count_shift = 1;
1344 s->initial_count = 0;
1345 s->initial_count_load_time = 0;
1346 s->next_time = 0;
1347}
1348
1349
1350static void apicSendInitIpi(APICDeviceInfo* pDev, APICState *s)
1351{
1352 apic_init_ipi(pDev, s);
1353 cpuSendInitIpi(pDev, s);
1354}
1355
1356/* send a SIPI message to the CPU to start it */
1357static void apic_startup(APICDeviceInfo* pDev, APICState *s, int vector_num)
1358{
1359 Log(("[SMP] apic_startup: %d on CPUs %d\n", vector_num, s->phys_id));
1360 cpuSendSipi(pDev, s, vector_num);
1361}
1362#endif /* IN_RING3 */
1363
1364static int apic_deliver(APICDeviceInfo *pDev, APICState *s,
1365 uint8_t dest, uint8_t dest_mode,
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;
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));
1371
1372 VMCPUSET DstSet;
1373 switch (dest_shorthand)
1374 {
1375 case 0:
1376 apic_get_delivery_bitmask(pDev, dest, dest_mode, &DstSet);
1377 break;
1378 case 1:
1379 VMCPUSET_EMPTY(&DstSet);
1380 VMCPUSET_ADD(&DstSet, s->id);
1381 break;
1382 case 2:
1383 VMCPUSET_FILL(&DstSet);
1384 break;
1385 case 3:
1386 VMCPUSET_FILL(&DstSet);
1387 VMCPUSET_DEL(&DstSet, s->id);
1388 break;
1389 }
1390
1391 switch (delivery_mode)
1392 {
1393 case APIC_DM_INIT:
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)
1398 {
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;
1404 }
1405 break;
1406 }
1407
1408 case APIC_DM_SIPI:
1409# ifdef IN_RING3
1410 APIC_FOREACH_IN_SET_BEGIN(pDev, &DstSet);
1411 apic_startup(pDev, pCurApic, vector_num);
1412 APIC_FOREACH_END();
1413 return VINF_SUCCESS;
1414# else
1415 /* We shall send SIPI only in R3, R0 calls should be
1416 rescheduled to R3 */
1417 return VINF_IOM_R3_MMIO_WRITE;
1418# endif
1419 }
1420
1421 return apic_bus_deliver(pDev, &DstSet, delivery_mode, vector_num,
1422 polarity, trigger_mode);
1423}
1424
1425
1426PDMBOTHCBDECL(int) apicGetInterrupt(PPDMDEVINS pDevIns)
1427{
1428 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
1429 /* if the APIC is not installed or enabled, we let the 8259 handle the
1430 IRQs */
1431 if (!pDev)
1432 {
1433 Log(("apic_get_interrupt: returns -1 (!s)\n"));
1434 return -1;
1435 }
1436
1437 Assert(PDMCritSectIsOwner(pDev->CTX_SUFF(pCritSect)));
1438
1439 APICState *s = getLapic(pDev); /** @todo fix interface */
1440
1441 if (!(s->spurious_vec & APIC_SV_ENABLE))
1442 {
1443 Log(("CPU%d: apic_get_interrupt: returns -1 (APIC_SV_ENABLE)\n", s->phys_id));
1444 return -1;
1445 }
1446
1447 /** @todo XXX: spurious IRQ handling */
1448 int intno = Apic256BitReg_FindLastSetBit(&s->irr, -1);
1449 if (intno < 0)
1450 {
1451 Log(("CPU%d: apic_get_interrupt: returns -1 (irr)\n", s->phys_id));
1452 return -1;
1453 }
1454
1455 if (s->tpr && (uint32_t)intno <= s->tpr)
1456 {
1457 Log(("apic_get_interrupt: returns %d (sp)\n", s->spurious_vec & 0xff));
1458 return s->spurious_vec & 0xff;
1459 }
1460 Apic256BitReg_ClearBit(&s->irr, intno);
1461 Apic256BitReg_SetBit(&s->isr, intno);
1462 apic_update_irq(pDev, s);
1463 LogFlow(("CPU%d: apic_get_interrupt: returns %d\n", s->phys_id, intno));
1464 return intno;
1465}
1466
1467/**
1468 * @remarks Caller (apicReadRegister) takes both the TM and APIC locks before
1469 * calling this function.
1470 */
1471static uint32_t apic_get_current_count(APICDeviceInfo const *pDev, APICState const *pApic)
1472{
1473 int64_t d = (TMTimerGet(pApic->CTX_SUFF(pTimer)) - pApic->initial_count_load_time)
1474 >> pApic->count_shift;
1475
1476 uint32_t val;
1477 if (pApic->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC)
1478 /* periodic */
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;
1484
1485 return val;
1486}
1487
1488/**
1489 * Does the frequency hinting and logging.
1490 *
1491 * @param pApic The device state.
1492 */
1493DECLINLINE(void) apicDoFrequencyHinting(APICState *pApic)
1494{
1495 if ( pApic->uHintedInitialCount != pApic->initial_count
1496 || pApic->uHintedCountShift != (uint32_t)pApic->count_shift)
1497 {
1498 pApic->uHintedInitialCount = pApic->initial_count;
1499 pApic->uHintedCountShift = pApic->count_shift;
1500
1501 uint32_t uHz;
1502 if (pApic->initial_count > 0)
1503 {
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;
1507 }
1508 else
1509 uHz = 0;
1510 TMTimerSetFrequencyHint(pApic->CTX_SUFF(pTimer), uHz);
1511 Log(("apic: %u Hz\n", uHz));
1512 }
1513}
1514
1515/**
1516 * Implementation of the 0380h access: Timer reset + new initial count.
1517 *
1518 * @param pDev The device state.
1519 * @param pApic The APIC sub-device state.
1520 * @param u32NewInitialCount The new initial count for the timer.
1521 */
1522static void apicTimerSetInitialCount(APICDeviceInfo *pDev, APICState *pApic, uint32_t u32NewInitialCount)
1523{
1524 STAM_COUNTER_INC(&pApic->StatTimerSetInitialCount);
1525 pApic->initial_count = u32NewInitialCount;
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 */
1531 if ( !(pApic->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)
1532 && u32NewInitialCount > 0)
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;
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));
1548 }
1549 else
1550 {
1551 /* Stop it if necessary and record the load time for unmasking. */
1552 if (pApic->fTimerArmed)
1553 {
1554 STAM_COUNTER_INC(&pApic->StatTimerSetInitialCountDisarm);
1555 TMTimerStop(pApic->CTX_SUFF(pTimer));
1556 pApic->fTimerArmed = false;
1557 pApic->uHintedCountShift = pApic->uHintedInitialCount = 0;
1558 }
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));
1561 }
1562}
1563
1564/**
1565 * Implementation of the 0320h access: change the LVT flags.
1566 *
1567 * @param pDev The device state.
1568 * @param pApic The APIC sub-device state to operate on.
1569 * @param fNew The new flags.
1570 */
1571static void apicTimerSetLvt(APICDeviceInfo *pDev, APICState *pApic, uint32_t fNew)
1572{
1573 STAM_COUNTER_INC(&pApic->StatTimerSetLvt);
1574
1575 /*
1576 * Make the flag change, saving the old ones so we can avoid
1577 * unnecessary work.
1578 */
1579 uint32_t const fOld = pApic->lvt[APIC_LVT_TIMER];
1580 pApic->lvt[APIC_LVT_TIMER] = fNew;
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 {
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)
1599 {
1600 /* not first period, stop it. */
1601 TMTimerStop(pApic->CTX_SUFF(pTimer));
1602 pApic->fTimerArmed = false;
1603 pApic->uHintedCountShift = pApic->uHintedInitialCount = 0;
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.
1611 * (apicR3TimerCallback will stop it if still masked.)
1612 */
1613 if (fNew & APIC_LVT_MASKED)
1614 STAM_COUNTER_INC(&pApic->StatTimerSetLvtPostponed);
1615 else if (pApic->fTimerArmed)
1616 STAM_COUNTER_INC(&pApic->StatTimerSetLvtArmed);
1617 /*
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!
1623 */
1624 else if ( (fOld & APIC_LVT_MASKED)
1625 && pApic->initial_count > 0)
1626 {
1627 STAM_COUNTER_INC(&pApic->StatTimerSetLvtArm);
1628 for (unsigned cTries = 0; ; cTries++)
1629 {
1630 uint64_t NextTS;
1631 uint64_t cTicks = (TMTimerGet(pApic->CTX_SUFF(pTimer)) - pApic->initial_count_load_time) >> pApic->count_shift;
1632 if (fNew & APIC_LVT_TIMER_PERIODIC)
1633 NextTS = ((cTicks / ((uint64_t)pApic->initial_count + 1)) + 1) * ((uint64_t)pApic->initial_count + 1);
1634 else
1635 {
1636 if (cTicks >= pApic->initial_count)
1637 break;
1638 NextTS = (uint64_t)pApic->initial_count + 1;
1639 }
1640 NextTS <<= pApic->count_shift;
1641 NextTS += pApic->initial_count_load_time;
1642
1643 /* Try avoid the assertion in TM.cpp... this isn't perfect! */
1644 if ( NextTS > TMTimerGet(pApic->CTX_SUFF(pTimer))
1645 || cTries > 10)
1646 {
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));
1652 break;
1653 }
1654 STAM_COUNTER_INC(&pApic->StatTimerSetLvtArmRetries);
1655 }
1656 }
1657 }
1658 else
1659 STAM_COUNTER_INC(&pApic->StatTimerSetLvtNoRelevantChange);
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 */
1670static DECLCALLBACK(void) apicR3TimerCallback(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
1671{
1672 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
1673 APICState *pApic = (APICState *)pvUser;
1674 Assert(pApic->pTimerR3 == pTimer);
1675 Assert(pApic->fTimerArmed);
1676 Assert(PDMCritSectIsOwner(pDev->pCritSectR3));
1677 Assert(TMTimerIsLockOwner(pTimer));
1678
1679 if (!(pApic->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) {
1680 LogFlow(("apic_timer: trigger irq\n"));
1681 apic_set_irq(pDev, pApic, pApic->lvt[APIC_LVT_TIMER] & 0xff, APIC_TRIGGER_EDGE);
1682
1683 if ( (pApic->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC)
1684 && pApic->initial_count > 0) {
1685 /* new interval. */
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);
1690 Log2(("apicR3TimerCallback: ic=%#x sh=%#x nxt=%#llx\n", pApic->initial_count, pApic->count_shift, pApic->next_time));
1691 } else {
1692 /* single shot or disabled. */
1693 pApic->fTimerArmed = false;
1694 pApic->uHintedCountShift = pApic->uHintedInitialCount = 0;
1695 }
1696 } else {
1697 /* masked, do not rearm. */
1698 pApic->fTimerArmed = false;
1699 pApic->uHintedCountShift = pApic->uHintedInitialCount = 0;
1700 }
1701}
1702
1703static void apic_save(SSMHANDLE* f, void *opaque)
1704{
1705 APICState *s = (APICState*)opaque;
1706 int i;
1707
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);
1716 for (i = 0; i < 8; i++) {
1717 SSMR3PutU32(f, s->isr.au32Bitmap[i]);
1718 SSMR3PutU32(f, s->tmr.au32Bitmap[i]);
1719 SSMR3PutU32(f, s->irr.au32Bitmap[i]);
1720 }
1721 for (i = 0; i < APIC_LVT_NB; i++) {
1722 SSMR3PutU32(f, s->lvt[i]);
1723 }
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);
1732
1733 TMR3TimerSave(s->CTX_SUFF(pTimer), f);
1734}
1735
1736static int apic_load(SSMHANDLE *f, void *opaque, int version_id)
1737{
1738 APICState *s = (APICState*)opaque;
1739 int i;
1740
1741 /** @todo XXX: what if the base changes? (registered memory regions) */
1742 SSMR3GetU32(f, &s->apicbase);
1743
1744 switch (version_id)
1745 {
1746 case APIC_SAVED_STATE_VERSION_ANCIENT:
1747 {
1748 uint8_t val = 0;
1749 SSMR3GetU8(f, &val);
1750 s->id = val;
1751 /* UP only in old saved states */
1752 s->phys_id = 0;
1753 SSMR3GetU8(f, &val);
1754 s->arb_id = val;
1755 break;
1756 }
1757 case APIC_SAVED_STATE_VERSION:
1758 case APIC_SAVED_STATE_VERSION_VBOX_30:
1759 SSMR3GetU32(f, &s->id);
1760 SSMR3GetU32(f, &s->phys_id);
1761 SSMR3GetU32(f, &s->arb_id);
1762 break;
1763 default:
1764 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1765 }
1766 SSMR3GetU32(f, &s->tpr);
1767 SSMR3GetU32(f, &s->spurious_vec);
1768 SSMR3GetU8(f, &s->log_dest);
1769 SSMR3GetU8(f, &s->dest_mode);
1770 for (i = 0; i < 8; i++) {
1771 SSMR3GetU32(f, &s->isr.au32Bitmap[i]);
1772 SSMR3GetU32(f, &s->tmr.au32Bitmap[i]);
1773 SSMR3GetU32(f, &s->irr.au32Bitmap[i]);
1774 }
1775 for (i = 0; i < APIC_LVT_NB; i++) {
1776 SSMR3GetU32(f, &s->lvt[i]);
1777 }
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);
1786
1787 int rc = TMR3TimerLoad(s->CTX_SUFF(pTimer), f);
1788 AssertRCReturn(rc, rc);
1789 s->uHintedCountShift = s->uHintedInitialCount = 0;
1790 s->fTimerArmed = TMTimerIsActive(s->CTX_SUFF(pTimer));
1791 if (s->fTimerArmed)
1792 apicDoFrequencyHinting(s);
1793
1794 return VINF_SUCCESS; /** @todo darn mess! */
1795}
1796
1797#endif /* IN_RING3 */
1798
1799/* LAPIC */
1800PDMBOTHCBDECL(int) apicMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
1801{
1802 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
1803 APICState *s = getLapic(pDev);
1804
1805 Log(("CPU%d: apicMMIORead at %llx\n", s->phys_id, (uint64_t)GCPhysAddr));
1806
1807 /** @todo add LAPIC range validity checks (different LAPICs can
1808 * theoretically have different physical addresses, see #3092) */
1809
1810 STAM_COUNTER_INC(&CTXSUFF(pDev->StatMMIORead));
1811 switch (cb)
1812 {
1813 case 1:
1814 /** @todo this is not how recent APIC behave! We will fix
1815 * this via the IOM. */
1816 *(uint8_t *)pv = 0;
1817 break;
1818
1819 case 2:
1820 /** @todo this is not how recent APIC behave! */
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 */
1831 && ++s->cTPRPatchAttempts < APIC_MAX_PATCH_ATTEMPTS)
1832 {
1833#ifdef IN_RC
1834 pDevIns->pDevHlpGC->pfnPATMSetMMIOPatchInfo(pDevIns, GCPhysAddr, &s->tpr);
1835#else
1836 RTGCPTR pDevInsGC = PDMINS2DATA_GCPTR(pDevIns);
1837 pDevIns->pHlpR0->pfnPATMSetMMIOPatchInfo(pDevIns, GCPhysAddr, pDevIns + RT_OFFSETOF(APICState, tpr));
1838#endif
1839 return VINF_PATM_HC_MMIO_PATCH_READ;
1840 }
1841#endif
1842#endif /* experimental */
1843
1844 /* It does its own locking. */
1845 uint64_t u64Value = 0;
1846 int rc = apicReadRegister(pDev, s, (GCPhysAddr >> 4) & 0xff, &u64Value,
1847 VINF_IOM_R3_MMIO_READ, false /*fMsr*/);
1848 *(uint32_t *)pv = (uint32_t)u64Value;
1849 return rc;
1850 }
1851
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
1859PDMBOTHCBDECL(int) apicMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb)
1860{
1861 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
1862 APICState *s = getLapic(pDev);
1863
1864 Log(("CPU%d: apicMMIOWrite at %llx\n", s->phys_id, (uint64_t)GCPhysAddr));
1865
1866 /** @todo: add LAPIC range validity checks (multiple LAPICs can theoretically have
1867 different physical addresses, see #3092) */
1868
1869 STAM_COUNTER_INC(&CTXSUFF(pDev->StatMMIOWrite));
1870 switch (cb)
1871 {
1872 case 1:
1873 case 2:
1874 /* ignore */
1875 break;
1876
1877 case 4:
1878 /* It does its own locking. */
1879 return apicWriteRegister(pDev, s, (GCPhysAddr >> 4) & 0xff, *(uint32_t const *)pv,
1880 VINF_IOM_R3_MMIO_WRITE, false /*fMsr*/);
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
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)
1900{
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{
1918 for (uint32_t i = 0; i < 8; i++)
1919 pHlp->pfnPrintf(pHlp, "%08x", apicR3InfoReadReg(pDev, pApic, iStartReg + i));
1920 pHlp->pfnPrintf(pHlp, "\n");
1921}
1922
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)
1931{
1932 uint64_t u64;
1933
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));
1957 pHlp->pfnPrintf(pHlp, " ISR : ");
1958 apicR3DumpVec(pDev, pApic, pHlp, 0x10);
1959 int iMax = Apic256BitReg_FindLastSetBit(&pApic->isr, -1);
1960 pHlp->pfnPrintf(pHlp, " highest = %02x\n", iMax == -1 ? 0 : iMax);
1961 pHlp->pfnPrintf(pHlp, " IRR : ");
1962 apicR3DumpVec(pDev, pApic, pHlp, 0x20);
1963 iMax = Apic256BitReg_FindLastSetBit(&pApic->irr, -1);
1964 pHlp->pfnPrintf(pHlp, " highest = %02X\n", iMax == -1 ? 0 : iMax);
1965}
1966
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)
1976{
1977 static const char * const s_apszDeliveryModes[] =
1978 {
1979 "Fixed ", "Reserved", "SMI", "Reserved", "NMI", "INIT", "Reserved", "ExtINT"
1980 };
1981 uint64_t u64;
1982
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);
2007}
2008
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)
2018{
2019 pHlp->pfnPrintf(pHlp, "Local APIC timer:\n");
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);
2026}
2027
2028
2029/**
2030 * @callback_method_impl{FNDBGFHANDLERDEV,
2031 * Dumps the Local APIC state according to given argument.}
2032 */
2033static DECLCALLBACK(void) apicR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
2034{
2035 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2036 APICState *pApic = getLapic(pDev);
2037
2038 if (pszArgs == NULL || !strcmp(pszArgs, "basic"))
2039 apicR3InfoBasic(pDev, pApic, pHlp);
2040 else if (!strcmp(pszArgs, "lvt"))
2041 apicR3InfoLVT(pDev, pApic, pHlp);
2042 else if (!strcmp(pszArgs, "timer"))
2043 apicR3InfoTimer(pDev, pApic, pHlp);
2044 else
2045 pHlp->pfnPrintf(pHlp, "Invalid argument. Recognized arguments are 'basic', 'lvt', 'timer'.\n");
2046}
2047
2048
2049/**
2050 * @copydoc FNSSMDEVLIVEEXEC
2051 */
2052static DECLCALLBACK(int) apicR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
2053{
2054 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2055
2056 SSMR3PutU32( pSSM, pDev->cCpus);
2057 SSMR3PutBool(pSSM, pDev->fIoApic);
2058 SSMR3PutU32( pSSM, pDev->enmVersion);
2059 AssertCompile(PDMAPICVERSION_APIC == 2);
2060
2061 return VINF_SSM_DONT_CALL_AGAIN;
2062}
2063
2064
2065/**
2066 * @copydoc FNSSMDEVSAVEEXEC
2067 */
2068static DECLCALLBACK(int) apicR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
2069{
2070 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2071
2072 /* config */
2073 apicR3LiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
2074
2075 /* save all APICs data */ /** @todo: is it correct? */
2076 APIC_FOREACH_BEGIN(pDev);
2077 apic_save(pSSM, pCurApic);
2078 APIC_FOREACH_END();
2079
2080 return VINF_SUCCESS;
2081}
2082
2083/**
2084 * @copydoc FNSSMDEVLOADEXEC
2085 */
2086static DECLCALLBACK(int) apicR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
2087{
2088 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2089
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 */
2096 if (uVersion > APIC_SAVED_STATE_VERSION_VBOX_30)
2097 {
2098 uint32_t cCpus;
2099 int rc = SSMR3GetU32(pSSM, &cCpus); AssertRCReturn(rc, rc);
2100 if (cCpus != pDev->cCpus)
2101 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - cCpus: saved=%#x config=%#x"), cCpus, pDev->cCpus);
2102
2103 bool fIoApic;
2104 rc = SSMR3GetBool(pSSM, &fIoApic); AssertRCReturn(rc, rc);
2105 if (fIoApic != pDev->fIoApic)
2106 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - fIoApic: saved=%RTbool config=%RTbool"), fIoApic, pDev->fIoApic);
2107
2108 uint32_t uApicVersion;
2109 rc = SSMR3GetU32(pSSM, &uApicVersion); AssertRCReturn(rc, rc);
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);
2112 }
2113
2114 if (uPass != SSM_PASS_FINAL)
2115 return VINF_SUCCESS;
2116
2117 /* load all APICs data */ /** @todo: is it correct? */
2118 APIC_LOCK(pDev, VERR_INTERNAL_ERROR_3);
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
2127 APIC_UNLOCK(pDev);
2128 return rc;
2129}
2130
2131/**
2132 * @copydoc FNPDMDEVRESET
2133 */
2134static DECLCALLBACK(void) apicR3Reset(PPDMDEVINS pDevIns)
2135{
2136 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2137 TMTimerLock(pDev->paLapicsR3[0].pTimerR3, VERR_IGNORED);
2138 APIC_LOCK_VOID(pDev, VERR_IGNORED);
2139
2140 /* Reset all APICs. */
2141 for (VMCPUID i = 0; i < pDev->cCpus; i++)
2142 {
2143 APICState *pApic = &pDev->CTX_SUFF(paLapics)[i];
2144 TMTimerStop(pApic->CTX_SUFF(pTimer));
2145
2146 /* Clear LAPIC state as if an INIT IPI was sent. */
2147 apic_init_ipi(pDev, pApic);
2148
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. */
2152
2153 /* Reset should re-enable the APIC, see comment in msi.h */
2154 pApic->apicbase = VBOX_MSI_ADDR_BASE | MSR_IA32_APICBASE_ENABLE;
2155 if (pApic->phys_id == 0)
2156 pApic->apicbase |= MSR_IA32_APICBASE_BSP;
2157
2158 /* Clear any pending APIC interrupt action flag. */
2159 cpuClearInterrupt(pDev, pApic);
2160 }
2161 /** @todo r=bird: Why is this done everytime, while the constructor first
2162 * checks the CPUID? Who is right? */
2163 pDev->pApicHlpR3->pfnChangeFeature(pDev->pDevInsR3, pDev->enmVersion);
2164
2165 APIC_UNLOCK(pDev);
2166 TMTimerUnlock(pDev->paLapicsR3[0].pTimerR3);
2167}
2168
2169
2170/**
2171 * @copydoc FNPDMDEVRELOCATE
2172 */
2173static DECLCALLBACK(void) apicR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
2174{
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);
2182}
2183
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)
2192{
2193 memset(pApic, 0, sizeof(*pApic));
2194
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;
2206}
2207
2208
2209/**
2210 * @copydoc FNPDMDEVCONSTRUCT
2211 */
2212static DECLCALLBACK(int) apicR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
2213{
2214 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2215 uint32_t i;
2216
2217 /*
2218 * Only single device instance.
2219 */
2220 Assert(iInstance == 0);
2221
2222 /*
2223 * Validate configuration.
2224 */
2225 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "IOAPIC|RZEnabled|NumCPUs", "");
2226
2227 bool fIoApic;
2228 int rc = CFGMR3QueryBoolDef(pCfg, "IOAPIC", &fIoApic, true);
2229 if (RT_FAILURE(rc))
2230 return PDMDEV_SET_ERROR(pDevIns, rc,
2231 N_("Configuration error: Failed to read \"IOAPIC\""));
2232
2233 bool fRZEnabled;
2234 rc = CFGMR3QueryBoolDef(pCfg, "RZEnabled", &fRZEnabled, true);
2235 if (RT_FAILURE(rc))
2236 return PDMDEV_SET_ERROR(pDevIns, rc,
2237 N_("Configuration error: Failed to query boolean value \"RZEnabled\""));
2238
2239 uint32_t cCpus;
2240 rc = CFGMR3QueryU32Def(pCfg, "NumCPUs", &cCpus, 1);
2241 if (RT_FAILURE(rc))
2242 return PDMDEV_SET_ERROR(pDevIns, rc,
2243 N_("Configuration error: Failed to query integer value \"NumCPUs\""));
2244
2245 Log(("APIC: cCpus=%d fRZEnabled=%RTbool fIoApic=%RTbool\n", cCpus, fRZEnabled, fIoApic));
2246 if (cCpus > 255)
2247 return PDMDEV_SET_ERROR(pDevIns, rc,
2248 N_("Configuration error: Invalid value for \"NumCPUs\""));
2249
2250 /*
2251 * Init the data.
2252 */
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;
2258 /* Use PDMAPICVERSION_X2APIC to activate x2APIC mode */
2259 pDev->enmVersion = PDMAPICVERSION_APIC;
2260
2261 /* Disable locking in this device. */
2262 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
2263 AssertRCReturn(rc, rc);
2264
2265 PVM pVM = PDMDevHlpGetVM(pDevIns);
2266
2267 /*
2268 * We are not freeing this memory, as it's automatically released when guest exits.
2269 */
2270 rc = MMHyperAlloc(pVM, cCpus * sizeof(APICState), 1, MM_TAG_PDM_DEVICE_USER, (void **)&pDev->paLapicsR3);
2271 if (RT_FAILURE(rc))
2272 return VERR_NO_MEMORY;
2273 pDev->paLapicsR0 = MMHyperR3ToR0(pVM, pDev->paLapicsR3);
2274 pDev->paLapicsRC = MMHyperR3ToRC(pVM, pDev->paLapicsR3);
2275
2276 for (i = 0; i < cCpus; i++)
2277 initApicData(&pDev->paLapicsR3[i], i);
2278
2279 /*
2280 * Register the APIC.
2281 */
2282 PDMAPICREG ApicReg;
2283 ApicReg.u32Version = PDM_APICREG_VERSION;
2284 ApicReg.pfnGetInterruptR3 = apicGetInterrupt;
2285 ApicReg.pfnHasPendingIrqR3 = apicHasPendingIrq;
2286 ApicReg.pfnSetBaseR3 = apicSetBase;
2287 ApicReg.pfnGetBaseR3 = apicGetBase;
2288 ApicReg.pfnSetTPRR3 = apicSetTPR;
2289 ApicReg.pfnGetTPRR3 = apicGetTPR;
2290 ApicReg.pfnWriteMSRR3 = apicWriteMSR;
2291 ApicReg.pfnReadMSRR3 = apicReadMSR;
2292 ApicReg.pfnBusDeliverR3 = apicBusDeliverCallback;
2293 ApicReg.pfnLocalInterruptR3 = apicLocalInterrupt;
2294 if (fRZEnabled)
2295 {
2296 ApicReg.pszGetInterruptRC = "apicGetInterrupt";
2297 ApicReg.pszHasPendingIrqRC = "apicHasPendingIrq";
2298 ApicReg.pszSetBaseRC = "apicSetBase";
2299 ApicReg.pszGetBaseRC = "apicGetBase";
2300 ApicReg.pszSetTPRRC = "apicSetTPR";
2301 ApicReg.pszGetTPRRC = "apicGetTPR";
2302 ApicReg.pszWriteMSRRC = "apicWriteMSR";
2303 ApicReg.pszReadMSRRC = "apicReadMSR";
2304 ApicReg.pszBusDeliverRC = "apicBusDeliverCallback";
2305 ApicReg.pszLocalInterruptRC = "apicLocalInterrupt";
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 {
2320 ApicReg.pszGetInterruptRC = NULL;
2321 ApicReg.pszHasPendingIrqRC = NULL;
2322 ApicReg.pszSetBaseRC = NULL;
2323 ApicReg.pszGetBaseRC = NULL;
2324 ApicReg.pszSetTPRRC = NULL;
2325 ApicReg.pszGetTPRRC = NULL;
2326 ApicReg.pszWriteMSRRC = NULL;
2327 ApicReg.pszReadMSRRC = NULL;
2328 ApicReg.pszBusDeliverRC = NULL;
2329 ApicReg.pszLocalInterruptRC = NULL;
2330
2331 ApicReg.pszGetInterruptR0 = NULL;
2332 ApicReg.pszHasPendingIrqR0 = NULL;
2333 ApicReg.pszSetBaseR0 = NULL;
2334 ApicReg.pszGetBaseR0 = NULL;
2335 ApicReg.pszSetTPRR0 = NULL;
2336 ApicReg.pszGetTPRR0 = NULL;
2337 ApicReg.pszWriteMSRR0 = NULL;
2338 ApicReg.pszReadMSRR0 = NULL;
2339 ApicReg.pszBusDeliverR0 = NULL;
2340 ApicReg.pszLocalInterruptR0 = NULL;
2341 }
2342
2343 rc = PDMDevHlpAPICRegister(pDevIns, &ApicReg, &pDev->pApicHlpR3);
2344 AssertLogRelRCReturn(rc, rc);
2345 pDev->pCritSectR3 = pDev->pApicHlpR3->pfnGetR3CritSect(pDevIns);
2346
2347 /*
2348 * The the CPUID feature bit.
2349 */
2350 /** @todo r=bird: See remark in the apicR3Reset. */
2351 uint32_t u32Eax, u32Ebx, u32Ecx, u32Edx;
2352 PDMDevHlpGetCpuId(pDevIns, 0, &u32Eax, &u32Ebx, &u32Ecx, &u32Edx);
2353 if (u32Eax >= 1)
2354 {
2355 if ( fIoApic /* If IOAPIC is enabled, enable Local APIC in any case */
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
2361 && u32Edx == X86_CPUID_VENDOR_AMD_EDX /* AuthenticAMD */))
2362 {
2363 LogRel(("Activating Local APIC\n"));
2364 pDev->pApicHlpR3->pfnChangeFeature(pDevIns, pDev->enmVersion);
2365 }
2366 }
2367
2368 /*
2369 * Register the MMIO range.
2370 */
2371 /** @todo: shall reregister, if base changes. */
2372 uint32_t ApicBase = pDev->paLapicsR3[0].apicbase & ~0xfff;
2373 rc = PDMDevHlpMMIORegister(pDevIns, ApicBase, 0x1000, pDev,
2374 IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
2375 apicMMIOWrite, apicMMIORead, "APIC Memory");
2376 if (RT_FAILURE(rc))
2377 return rc;
2378
2379 if (fRZEnabled)
2380 {
2381 pDev->pApicHlpRC = pDev->pApicHlpR3->pfnGetRCHelpers(pDevIns);
2382 pDev->pCritSectRC = pDev->pApicHlpR3->pfnGetRCCritSect(pDevIns);
2383 rc = PDMDevHlpMMIORegisterRC(pDevIns, ApicBase, 0x1000, NIL_RTRCPTR /*pvUser*/, "apicMMIOWrite", "apicMMIORead");
2384 if (RT_FAILURE(rc))
2385 return rc;
2386
2387 pDev->pApicHlpR0 = pDev->pApicHlpR3->pfnGetR0Helpers(pDevIns);
2388 pDev->pCritSectR0 = pDev->pApicHlpR3->pfnGetR0CritSect(pDevIns);
2389 rc = PDMDevHlpMMIORegisterR0(pDevIns, ApicBase, 0x1000, NIL_RTR0PTR /*pvUser*/, "apicMMIOWrite", "apicMMIORead");
2390 if (RT_FAILURE(rc))
2391 return rc;
2392 }
2393
2394 /*
2395 * Create the APIC timers.
2396 */
2397 for (i = 0; i < cCpus; i++)
2398 {
2399 APICState *pApic = &pDev->paLapicsR3[i];
2400 pApic->pszDesc = MMR3HeapAPrintf(pVM, MM_TAG_PDM_DEVICE_USER, "APIC Timer #%u", i);
2401 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, apicR3TimerCallback, pApic,
2402 TMTIMER_FLAGS_NO_CRIT_SECT, pApic->pszDesc, &pApic->pTimerR3);
2403 if (RT_FAILURE(rc))
2404 return rc;
2405 pApic->pTimerR0 = TMTimerR0Ptr(pApic->pTimerR3);
2406 pApic->pTimerRC = TMTimerRCPtr(pApic->pTimerR3);
2407 TMR3TimerSetCritSect(pApic->pTimerR3, pDev->pCritSectR3);
2408 }
2409
2410 /*
2411 * Saved state.
2412 */
2413 rc = PDMDevHlpSSMRegister3(pDevIns, APIC_SAVED_STATE_VERSION, sizeof(*pDev),
2414 apicR3LiveExec, apicR3SaveExec, apicR3LoadExec);
2415 if (RT_FAILURE(rc))
2416 return rc;
2417
2418 /*
2419 * Register debugger info callback.
2420 */
2421 PDMDevHlpDBGFInfoRegister(pDevIns, "apic", "Display Local APIC state for current CPU. "
2422 "Recognizes 'basic', 'lvt', 'timer' as arguments, defaulting to 'basic'.", apicR3Info);
2423
2424#ifdef VBOX_WITH_STATISTICS
2425 /*
2426 * Statistics.
2427 */
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.");
2433 for (i = 0; i < cCpus; i++)
2434 {
2435 APICState *pApic = &pDev->paLapicsR3[i];
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 }
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,
2460 /* szName */
2461 "apic",
2462 /* szRCMod */
2463 "VBoxDD2GC.gc",
2464 /* szR0Mod */
2465 "VBoxDD2R0.r0",
2466 /* pszDescription */
2467 "Advanced Programmable Interrupt Controller (APIC) Device",
2468 /* fFlags */
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,
2470 /* fClass */
2471 PDM_DEVREG_CLASS_PIC,
2472 /* cMaxInstances */
2473 1,
2474 /* cbInstance */
2475 sizeof(APICState),
2476 /* pfnConstruct */
2477 apicR3Construct,
2478 /* pfnDestruct */
2479 NULL,
2480 /* pfnRelocate */
2481 apicR3Relocate,
2482 /* pfnIOCtl */
2483 NULL,
2484 /* pfnPowerOn */
2485 NULL,
2486 /* pfnReset */
2487 apicR3Reset,
2488 /* pfnSuspend */
2489 NULL,
2490 /* pfnResume */
2491 NULL,
2492 /* pfnAttach */
2493 NULL,
2494 /* pfnDetach */
2495 NULL,
2496 /* pfnQueryInterface. */
2497 NULL,
2498 /* pfnInitComplete */
2499 NULL,
2500 /* pfnPowerOff */
2501 NULL,
2502 /* pfnSoftReset */
2503 NULL,
2504 /* u32VersionEnd */
2505 PDM_DEVREG_VERSION
2506};
2507
2508#endif /* IN_RING3 */
2509#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
2510
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use