VirtualBox

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

Last change on this file since 39135 was 39135, checked in by vboxsync, 14 years ago

Changed PDMDevHlpMMIORegister to take flags and drop pfnFill. Added PDMDevHlpMMIORegisterEx for the one user of pfnFill.

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

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