VirtualBox

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

Last change on this file since 25776 was 25058, checked in by vboxsync, 15 years ago

EFI: safe part of tables changes (rest to come after branch), required for ACPI work

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 109.9 KB
Line 
1#ifdef VBOX
2/* $Id: DevAPIC.cpp 25058 2009-11-27 17:55:17Z vboxsync $ */
3/** @file
4 * Advanced Programmable Interrupt Controller (APIC) Device and
5 * I/O Advanced Programmable Interrupt Controller (IO-APIC) Device.
6 */
7
8/*
9 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 *
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
20 * Clara, CA 95054 USA or visit http://www.sun.com if you need
21 * additional information or have any questions.
22 * --------------------------------------------------------------------
23 *
24 * This code is based on:
25 *
26 * apic.c revision 1.5 @@OSETODO
27 */
28
29/*******************************************************************************
30* Header Files *
31*******************************************************************************/
32#define LOG_GROUP LOG_GROUP_DEV_APIC
33#include <VBox/pdmdev.h>
34
35#include <VBox/log.h>
36#include <VBox/stam.h>
37#include <iprt/assert.h>
38#include <iprt/asm.h>
39
40#include "Builtins2.h"
41#include "vl_vbox.h"
42
43#define MSR_IA32_APICBASE 0x1b
44#define MSR_IA32_APICBASE_BSP (1<<8)
45#define MSR_IA32_APICBASE_ENABLE (1<<11)
46#ifdef VBOX
47#define MSR_IA32_APICBASE_X2ENABLE (1<<10)
48#endif
49#define MSR_IA32_APICBASE_BASE (0xfffff<<12)
50
51#ifndef EINVAL
52# define EINVAL 1
53#endif
54
55#ifdef _MSC_VER
56# pragma warning(disable:4244)
57#endif
58
59/** The current saved state version.*/
60#define APIC_SAVED_STATE_VERSION 3
61/** The saved state version used by VirtualBox v3 and earlier.
62 * This does not include the config. */
63#define APIC_SAVED_STATE_VERSION_VBOX_30 2
64/** Some ancient version... */
65#define APIC_SAVED_STATE_VERSION_ANCIENT 1
66
67
68/** @def APIC_LOCK
69 * Acquires the PDM lock. */
70#define APIC_LOCK(pThis, rcBusy) \
71 do { \
72 int rc2 = PDMCritSectEnter((pThis)->CTX_SUFF(pCritSect), (rcBusy)); \
73 if (rc2 != VINF_SUCCESS) \
74 return rc2; \
75 } while (0)
76
77/** @def APIC_LOCK_VOID
78 * Acquires the PDM lock and does not expect failure (i.e. ring-3 only!). */
79#define APIC_LOCK_VOID(pThis, rcBusy) \
80 do { \
81 int rc2 = PDMCritSectEnter((pThis)->CTX_SUFF(pCritSect), (rcBusy)); \
82 AssertLogRelRCReturnVoid(rc2); \
83 } while (0)
84
85/** @def APIC_UNLOCK
86 * Releases the PDM lock. */
87#define APIC_UNLOCK(pThis) \
88 PDMCritSectLeave((pThis)->CTX_SUFF(pCritSect))
89
90/** @def IOAPIC_LOCK
91 * Acquires the PDM lock. */
92#define IOAPIC_LOCK(pThis, rc) \
93 do { \
94 int rc2 = (pThis)->CTX_SUFF(pIoApicHlp)->pfnLock((pThis)->CTX_SUFF(pDevIns), rc); \
95 if (rc2 != VINF_SUCCESS) \
96 return rc2; \
97 } while (0)
98
99/** @def IOAPIC_UNLOCK
100 * Releases the PDM lock. */
101#define IOAPIC_UNLOCK(pThis) (pThis)->CTX_SUFF(pIoApicHlp)->pfnUnlock((pThis)->CTX_SUFF(pDevIns))
102
103
104#define foreach_apic(dev, mask, code) \
105 do { \
106 uint32_t i; \
107 APICState *apic = (dev)->CTX_SUFF(paLapics); \
108 for (i = 0; i < (dev)->cCpus; i++) \
109 { \
110 if (mask & (1 << (apic->id))) \
111 { \
112 code; \
113 } \
114 apic++; \
115 } \
116 } while (0)
117
118# define set_bit(pvBitmap, iBit) ASMBitSet(pvBitmap, iBit)
119# define reset_bit(pvBitmap, iBit) ASMBitClear(pvBitmap, iBit)
120# define fls_bit(value) (ASMBitLastSetU32(value) - 1)
121# define ffs_bit(value) (ASMBitFirstSetU32(value) - 1)
122
123#endif /* VBOX */
124
125/*
126 * APIC support
127 *
128 * Copyright (c) 2004-2005 Fabrice Bellard
129 *
130 * This library is free software; you can redistribute it and/or
131 * modify it under the terms of the GNU Lesser General Public
132 * License as published by the Free Software Foundation; either
133 * version 2 of the License, or (at your option) any later version.
134 *
135 * This library is distributed in the hope that it will be useful,
136 * but WITHOUT ANY WARRANTY; without even the implied warranty of
137 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
138 * Lesser General Public License for more details.
139 *
140 * You should have received a copy of the GNU Lesser General Public
141 * License along with this library; if not, write to the Free Software
142 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
143 */
144#ifndef VBOX
145#include "vl.h"
146#endif
147
148#define DEBUG_APIC
149#define DEBUG_IOAPIC
150
151/* APIC Local Vector Table */
152#define APIC_LVT_TIMER 0
153#define APIC_LVT_THERMAL 1
154#define APIC_LVT_PERFORM 2
155#define APIC_LVT_LINT0 3
156#define APIC_LVT_LINT1 4
157#define APIC_LVT_ERROR 5
158#define APIC_LVT_NB 6
159
160/* APIC delivery modes */
161#define APIC_DM_FIXED 0
162#define APIC_DM_LOWPRI 1
163#define APIC_DM_SMI 2
164#define APIC_DM_NMI 4
165#define APIC_DM_INIT 5
166#define APIC_DM_SIPI 6
167#define APIC_DM_EXTINT 7
168
169/* APIC destination mode */
170#define APIC_DESTMODE_FLAT 0xf
171#define APIC_DESTMODE_CLUSTER 1
172
173#define APIC_TRIGGER_EDGE 0
174#define APIC_TRIGGER_LEVEL 1
175
176#define APIC_LVT_TIMER_PERIODIC (1<<17)
177#define APIC_LVT_MASKED (1<<16)
178#define APIC_LVT_LEVEL_TRIGGER (1<<15)
179#define APIC_LVT_REMOTE_IRR (1<<14)
180#define APIC_INPUT_POLARITY (1<<13)
181#define APIC_SEND_PENDING (1<<12)
182
183#define IOAPIC_NUM_PINS 0x18
184
185#define ESR_ILLEGAL_ADDRESS (1 << 7)
186
187#define APIC_SV_ENABLE (1 << 8)
188
189#ifdef VBOX
190#define APIC_MAX_PATCH_ATTEMPTS 100
191
192typedef uint32_t PhysApicId;
193typedef uint32_t LogApicId;
194#endif
195
196typedef struct APICState {
197#ifndef VBOX
198 CPUState *cpu_env;
199#endif /* !VBOX */
200 uint32_t apicbase;
201#ifdef VBOX
202 /* Task priority register (interrupt level) */
203 uint32_t tpr;
204 /* Logical APIC id - user programmable */
205 LogApicId id;
206 /* Physical APIC id - not visible to user, constant */
207 PhysApicId phys_id;
208 /** @todo: is it logical or physical? Not really used anyway now. */
209 PhysApicId arb_id;
210#else
211 uint8_t tpr;
212 uint8_t id;
213 uint8_t arb_id;
214#endif
215 uint32_t spurious_vec;
216 uint8_t log_dest;
217 uint8_t dest_mode;
218 uint32_t isr[8]; /* in service register */
219 uint32_t tmr[8]; /* trigger mode register */
220 uint32_t irr[8]; /* interrupt request register */
221 uint32_t lvt[APIC_LVT_NB];
222 uint32_t esr; /* error register */
223 uint32_t icr[2];
224 uint32_t divide_conf;
225 int count_shift;
226 uint32_t initial_count;
227#ifdef VBOX
228 uint32_t Alignment0;
229#endif
230#ifndef VBOX
231 int64_t initial_count_load_time, next_time;
232 QEMUTimer *timer;
233 struct APICState *next_apic;
234#else
235 /** The time stamp of the initial_count load, i.e. when it was started. */
236 uint64_t initial_count_load_time;
237 /** The time stamp of the next timer callback. */
238 uint64_t next_time;
239 /** The APIC timer - R3 Ptr. */
240 PTMTIMERR3 pTimerR3;
241 /** The APIC timer - R0 Ptr. */
242 PTMTIMERR0 pTimerR0;
243 /** The APIC timer - RC Ptr. */
244 PTMTIMERRC pTimerRC;
245 /** Whether the timer is armed or not */
246 bool fTimerArmed;
247 /** Alignment */
248 bool afAlignment[3];
249 /** Timer description timer. */
250 R3PTRTYPE(char *) pszDesc;
251# ifdef VBOX_WITH_STATISTICS
252# if HC_ARCH_BITS == 32
253 uint32_t u32Alignment0;
254# endif
255 STAMCOUNTER StatTimerSetInitialCount;
256 STAMCOUNTER StatTimerSetInitialCountArm;
257 STAMCOUNTER StatTimerSetInitialCountDisarm;
258 STAMCOUNTER StatTimerSetLvt;
259 STAMCOUNTER StatTimerSetLvtClearPeriodic;
260 STAMCOUNTER StatTimerSetLvtPostponed;
261 STAMCOUNTER StatTimerSetLvtArmed;
262 STAMCOUNTER StatTimerSetLvtArm;
263 STAMCOUNTER StatTimerSetLvtArmRetries;
264 STAMCOUNTER StatTimerSetLvtNoRelevantChange;
265# endif
266#endif /* VBOX */
267} APICState;
268#ifdef VBOX
269AssertCompileMemberAlignment(APICState, initial_count_load_time, 8);
270# ifdef VBOX_WITH_STATISTICS
271AssertCompileMemberAlignment(APICState, StatTimerSetInitialCount, 8);
272# endif
273#endif
274
275struct IOAPICState {
276 uint8_t id;
277 uint8_t ioregsel;
278
279 uint32_t irr;
280 uint64_t ioredtbl[IOAPIC_NUM_PINS];
281
282#ifdef VBOX
283 /** The device instance - R3 Ptr. */
284 PPDMDEVINSR3 pDevInsR3;
285 /** The IOAPIC helpers - R3 Ptr. */
286 PCPDMIOAPICHLPR3 pIoApicHlpR3;
287
288 /** The device instance - R0 Ptr. */
289 PPDMDEVINSR0 pDevInsR0;
290 /** The IOAPIC helpers - R0 Ptr. */
291 PCPDMIOAPICHLPR0 pIoApicHlpR0;
292
293 /** The device instance - RC Ptr. */
294 PPDMDEVINSRC pDevInsRC;
295 /** The IOAPIC helpers - RC Ptr. */
296 PCPDMIOAPICHLPRC pIoApicHlpRC;
297
298# ifdef VBOX_WITH_STATISTICS
299 STAMCOUNTER StatMMIOReadGC;
300 STAMCOUNTER StatMMIOReadHC;
301 STAMCOUNTER StatMMIOWriteGC;
302 STAMCOUNTER StatMMIOWriteHC;
303 STAMCOUNTER StatSetIrqGC;
304 STAMCOUNTER StatSetIrqHC;
305# endif
306#endif /* VBOX */
307};
308
309#ifdef VBOX
310typedef struct IOAPICState IOAPICState;
311
312typedef struct
313{
314 /** The device instance - R3 Ptr. */
315 PPDMDEVINSR3 pDevInsR3;
316 /** The APIC helpers - R3 Ptr. */
317 PCPDMAPICHLPR3 pApicHlpR3;
318 /** LAPICs states - R3 Ptr */
319 R3PTRTYPE(APICState *) paLapicsR3;
320 /** The critical section - R3 Ptr. */
321 R3PTRTYPE(PPDMCRITSECT) pCritSectR3;
322
323 /** The device instance - R0 Ptr. */
324 PPDMDEVINSR0 pDevInsR0;
325 /** The APIC helpers - R0 Ptr. */
326 PCPDMAPICHLPR0 pApicHlpR0;
327 /** LAPICs states - R0 Ptr */
328 R0PTRTYPE(APICState *) paLapicsR0;
329 /** The critical section - R3 Ptr. */
330 R0PTRTYPE(PPDMCRITSECT) pCritSectR0;
331
332 /** The device instance - RC Ptr. */
333 PPDMDEVINSRC pDevInsRC;
334 /** The APIC helpers - RC Ptr. */
335 PCPDMAPICHLPRC pApicHlpRC;
336 /** LAPICs states - RC Ptr */
337 RCPTRTYPE(APICState *) paLapicsRC;
338 /** The critical section - R3 Ptr. */
339 RCPTRTYPE(PPDMCRITSECT) pCritSectRC;
340
341 /** APIC specification version in this virtual hardware configuration. */
342 PDMAPICVERSION enmVersion;
343
344 /** Number of attempts made to optimize TPR accesses. */
345 uint32_t cTPRPatchAttempts;
346
347 /** Number of CPUs on the system (same as LAPIC count). */
348 uint32_t cCpus;
349 /** Whether we've got an IO APIC or not. */
350 bool fIoApic;
351 /** Alignment padding. */
352 bool afPadding[3];
353
354# ifdef VBOX_WITH_STATISTICS
355 STAMCOUNTER StatMMIOReadGC;
356 STAMCOUNTER StatMMIOReadHC;
357 STAMCOUNTER StatMMIOWriteGC;
358 STAMCOUNTER StatMMIOWriteHC;
359 STAMCOUNTER StatClearedActiveIrq;
360# endif
361} APICDeviceInfo;
362# ifdef VBOX_WITH_STATISTICS
363AssertCompileMemberAlignment(APICDeviceInfo, StatMMIOReadGC, 8);
364# endif
365#endif /* VBOX */
366
367#ifndef VBOX_DEVICE_STRUCT_TESTCASE
368
369#ifndef VBOX
370static int apic_io_memory;
371static APICState *first_local_apic = NULL;
372static int last_apic_id = 0;
373#endif /* !VBOX */
374
375
376#ifdef VBOX
377/*******************************************************************************
378* Internal Functions *
379*******************************************************************************/
380RT_C_DECLS_BEGIN
381PDMBOTHCBDECL(int) apicMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
382PDMBOTHCBDECL(int) apicMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
383PDMBOTHCBDECL(int) apicGetInterrupt(PPDMDEVINS pDevIns);
384PDMBOTHCBDECL(bool) apicHasPendingIrq(PPDMDEVINS pDevIns);
385PDMBOTHCBDECL(void) apicSetBase(PPDMDEVINS pDevIns, uint64_t val);
386PDMBOTHCBDECL(uint64_t) apicGetBase(PPDMDEVINS pDevIns);
387PDMBOTHCBDECL(void) apicSetTPR(PPDMDEVINS pDevIns, VMCPUID idCpu, uint8_t val);
388PDMBOTHCBDECL(uint8_t) apicGetTPR(PPDMDEVINS pDevIns, VMCPUID idCpu);
389PDMBOTHCBDECL(int) apicBusDeliverCallback(PPDMDEVINS pDevIns, uint8_t u8Dest, uint8_t u8DestMode,
390 uint8_t u8DeliveryMode, uint8_t iVector, uint8_t u8Polarity,
391 uint8_t u8TriggerMode);
392PDMBOTHCBDECL(int) apicLocalInterrupt(PPDMDEVINS pDevIns, uint8_t u8Pin, uint8_t u8Level);
393PDMBOTHCBDECL(int) apicWriteMSR(PPDMDEVINS pDevIns, VMCPUID iCpu, uint32_t u32Reg, uint64_t u64Value);
394PDMBOTHCBDECL(int) apicReadMSR(PPDMDEVINS pDevIns, VMCPUID iCpu, uint32_t u32Reg, uint64_t *pu64Value);
395PDMBOTHCBDECL(int) ioapicMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
396PDMBOTHCBDECL(int) ioapicMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
397PDMBOTHCBDECL(void) ioapicSetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel);
398
399static void apic_update_tpr(APICDeviceInfo *dev, APICState* s, uint32_t val);
400RT_C_DECLS_END
401
402static void apic_eoi(APICDeviceInfo *dev, APICState* s); /* */
403static uint32_t apic_get_delivery_bitmask(APICDeviceInfo* dev, uint8_t dest, uint8_t dest_mode);
404static int apic_deliver(APICDeviceInfo* dev, APICState *s,
405 uint8_t dest, uint8_t dest_mode,
406 uint8_t delivery_mode, uint8_t vector_num,
407 uint8_t polarity, uint8_t trigger_mode);
408static int apic_get_arb_pri(APICState *s);
409static int apic_get_ppr(APICState *s);
410static uint32_t apic_get_current_count(APICDeviceInfo* dev, APICState *s);
411static void apicTimerSetInitialCount(APICDeviceInfo *dev, APICState *s, uint32_t initial_count);
412static void apicTimerSetLvt(APICDeviceInfo *dev, APICState *pThis, uint32_t fNew);
413static void apicSendInitIpi(APICDeviceInfo* dev, APICState *s);
414
415#endif /* VBOX */
416
417static void apic_init_ipi(APICDeviceInfo* dev, APICState *s);
418static void apic_set_irq(APICDeviceInfo* dev, APICState *s, int vector_num, int trigger_mode);
419static bool apic_update_irq(APICDeviceInfo* dev, APICState *s);
420
421
422#ifdef VBOX
423
424DECLINLINE(APICState*) getLapicById(APICDeviceInfo* dev, VMCPUID id)
425{
426 AssertFatalMsg(id < dev->cCpus, ("CPU id %d out of range\n", id));
427 return &dev->CTX_SUFF(paLapics)[id];
428}
429
430DECLINLINE(APICState*) getLapic(APICDeviceInfo* dev)
431{
432 /* LAPIC's array is indexed by CPU id */
433 VMCPUID id = dev->CTX_SUFF(pApicHlp)->pfnGetCpuId(dev->CTX_SUFF(pDevIns));
434 return getLapicById(dev, id);
435}
436
437DECLINLINE(VMCPUID) getCpuFromLapic(APICDeviceInfo* dev, APICState *s)
438{
439 /* for now we assume LAPIC physical id == CPU id */
440 return VMCPUID(s->phys_id);
441}
442
443DECLINLINE(void) cpuSetInterrupt(APICDeviceInfo* dev, APICState *s, PDMAPICIRQ enmType = PDMAPICIRQ_HARDWARE)
444{
445 LogFlow(("apic: setting interrupt flag for cpu %d\n", getCpuFromLapic(dev, s)));
446 dev->CTX_SUFF(pApicHlp)->pfnSetInterruptFF(dev->CTX_SUFF(pDevIns), enmType,
447 getCpuFromLapic(dev, s));
448}
449
450DECLINLINE(void) cpuClearInterrupt(APICDeviceInfo* dev, APICState *s, PDMAPICIRQ enmType = PDMAPICIRQ_HARDWARE)
451{
452 LogFlow(("apic: clear interrupt flag\n"));
453 dev->CTX_SUFF(pApicHlp)->pfnClearInterruptFF(dev->CTX_SUFF(pDevIns), enmType,
454 getCpuFromLapic(dev, s));
455}
456
457# ifdef IN_RING3
458
459DECLINLINE(void) cpuSendSipi(APICDeviceInfo* dev, APICState *s, int vector)
460{
461 Log2(("apic: send SIPI vector=%d\n", vector));
462
463 dev->pApicHlpR3->pfnSendSipi(dev->pDevInsR3,
464 getCpuFromLapic(dev, s),
465 vector);
466}
467
468DECLINLINE(void) cpuSendInitIpi(APICDeviceInfo* dev, APICState *s)
469{
470 Log2(("apic: send init IPI\n"));
471
472 dev->pApicHlpR3->pfnSendInitIpi(dev->pDevInsR3,
473 getCpuFromLapic(dev, s));
474}
475
476# endif /* IN_RING3 */
477
478DECLINLINE(uint32_t) getApicEnableBits(APICDeviceInfo* dev)
479{
480 switch (dev->enmVersion)
481 {
482 case PDMAPICVERSION_NONE:
483 return 0;
484 case PDMAPICVERSION_APIC:
485 return MSR_IA32_APICBASE_ENABLE;
486 case PDMAPICVERSION_X2APIC:
487 return MSR_IA32_APICBASE_ENABLE | MSR_IA32_APICBASE_X2ENABLE ;
488 default:
489 AssertMsgFailed(("Unsuported APIC version %d\n", dev->enmVersion));
490 return 0;
491 }
492}
493
494DECLINLINE(PDMAPICVERSION) getApicMode(APICState *apic)
495{
496 switch (((apic->apicbase) >> 10) & 0x3)
497 {
498 case 0:
499 return PDMAPICVERSION_NONE;
500 case 1:
501 default:
502 /* Invalid */
503 return PDMAPICVERSION_NONE;
504 case 2:
505 return PDMAPICVERSION_APIC;
506 case 3:
507 return PDMAPICVERSION_X2APIC;
508 }
509}
510
511#endif /* VBOX */
512
513#ifndef VBOX
514static void apic_bus_deliver(uint32_t deliver_bitmask, uint8_t delivery_mode,
515 uint8_t vector_num, uint8_t polarity,
516 uint8_t trigger_mode)
517{
518 APICState *apic_iter;
519#else /* VBOX */
520static int apic_bus_deliver(APICDeviceInfo* dev,
521 uint32_t deliver_bitmask, uint8_t delivery_mode,
522 uint8_t vector_num, uint8_t polarity,
523 uint8_t trigger_mode)
524{
525#endif /* VBOX */
526
527 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));
528 switch (delivery_mode) {
529 case APIC_DM_LOWPRI:
530 {
531 int d = -1;
532 if (deliver_bitmask)
533 d = ffs_bit(deliver_bitmask);
534 if (d >= 0)
535 {
536 APICState* apic = getLapicById(dev, d);
537 apic_set_irq(dev, apic, vector_num, trigger_mode);
538 }
539 return VINF_SUCCESS;
540 }
541 case APIC_DM_FIXED:
542 /* XXX: arbitration */
543 break;
544
545 case APIC_DM_SMI:
546 foreach_apic(dev, deliver_bitmask,
547 cpuSetInterrupt(dev, apic, PDMAPICIRQ_SMI));
548 return VINF_SUCCESS;
549
550 case APIC_DM_NMI:
551 foreach_apic(dev, deliver_bitmask,
552 cpuSetInterrupt(dev, apic, PDMAPICIRQ_NMI));
553 return VINF_SUCCESS;
554
555 case APIC_DM_INIT:
556 /* normal INIT IPI sent to processors */
557#ifdef VBOX
558#ifdef IN_RING3
559 foreach_apic(dev, deliver_bitmask,
560 apicSendInitIpi(dev, apic));
561 return VINF_SUCCESS;
562#else
563 /* We shall send init IPI only in R3, R0 calls should be
564 rescheduled to R3 */
565 return VINF_IOM_HC_MMIO_READ_WRITE;
566#endif /* IN_RING3 */
567
568#else
569 for (apic_iter = first_local_apic; apic_iter != NULL;
570 apic_iter = apic_iter->next_apic) {
571 apic_init_ipi(apic_iter);
572 }
573#endif
574
575 case APIC_DM_EXTINT:
576 /* handled in I/O APIC code */
577 break;
578
579 default:
580 return VINF_SUCCESS;
581 }
582
583#ifdef VBOX
584 foreach_apic(dev, deliver_bitmask,
585 apic_set_irq (dev, apic, vector_num, trigger_mode));
586 return VINF_SUCCESS;
587#else /* VBOX */
588 for (apic_iter = first_local_apic; apic_iter != NULL;
589 apic_iter = apic_iter->next_apic) {
590 if (deliver_bitmask & (1 << apic_iter->id))
591 apic_set_irq(apic_iter, vector_num, trigger_mode);
592 }
593#endif /* VBOX */
594}
595
596#ifndef VBOX
597void cpu_set_apic_base(CPUState *env, uint64_t val)
598{
599 APICState *s = env->apic_state;
600#ifdef DEBUG_APIC
601 Log(("cpu_set_apic_base: %016llx\n", val));
602#endif
603
604 s->apicbase = (val & 0xfffff000) |
605 (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
606 /* if disabled, cannot be enabled again */
607 if (!(val & MSR_IA32_APICBASE_ENABLE)) {
608 s->apicbase &= ~MSR_IA32_APICBASE_ENABLE;
609 env->cpuid_features &= ~CPUID_APIC;
610 s->spurious_vec &= ~APIC_SV_ENABLE;
611 }
612}
613#else /* VBOX */
614PDMBOTHCBDECL(void) apicSetBase(PPDMDEVINS pDevIns, uint64_t val)
615{
616 APICDeviceInfo *dev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
617 Assert(PDMCritSectIsOwner(dev->CTX_SUFF(pCritSect)));
618 APICState *s = getLapic(dev); /** @todo fix interface */
619 Log(("cpu_set_apic_base: %016RX64\n", val));
620
621 /** @todo: do we need to lock here ? */
622 /* APIC_LOCK_VOID(dev, VERR_INTERNAL_ERROR); */
623 /** @todo If this change is valid immediately, then we should change the MMIO registration! */
624 /* We cannot change if this CPU is BSP or not by writing to MSR - it's hardwired */
625 PDMAPICVERSION oldMode = getApicMode(s);
626 s->apicbase =
627 (val & 0xfffff000) | /* base */
628 (val & getApicEnableBits(dev)) | /* mode */
629 (s->apicbase & MSR_IA32_APICBASE_BSP) /* keep BSP bit */;
630 PDMAPICVERSION newMode = getApicMode(s);
631
632 if (oldMode != newMode)
633 {
634 switch (newMode)
635 {
636 case PDMAPICVERSION_NONE:
637 {
638 s->spurious_vec &= ~APIC_SV_ENABLE;
639 /* Clear any pending APIC interrupt action flag. */
640 cpuClearInterrupt(dev, s);
641 /** @todo: why do we do that? */
642 dev->CTX_SUFF(pApicHlp)->pfnChangeFeature(pDevIns, PDMAPICVERSION_NONE);
643 break;
644 }
645 case PDMAPICVERSION_APIC:
646 /** @todo: map MMIO ranges, if needed */
647 break;
648 case PDMAPICVERSION_X2APIC:
649 /** @todo: unmap MMIO ranges of this APIC, according to the spec */
650 break;
651 default:
652 break;
653 }
654 }
655 /* APIC_UNLOCK(dev); */
656}
657#endif /* VBOX */
658
659#ifndef VBOX
660
661uint64_t cpu_get_apic_base(CPUState *env)
662{
663 APICState *s = env->apic_state;
664#ifdef DEBUG_APIC
665 Log(("cpu_get_apic_base: %016llx\n", (uint64_t)s->apicbase));
666#endif
667 return s->apicbase;
668}
669
670void cpu_set_apic_tpr(CPUX86State *env, uint8_t val)
671{
672 APICState *s = env->apic_state;
673 s->tpr = (val & 0x0f) << 4;
674 apic_update_irq(s);
675}
676
677uint8_t cpu_get_apic_tpr(CPUX86State *env)
678{
679 APICState *s = env->apic_state;
680 return s->tpr >> 4;
681}
682
683static int fls_bit(int value)
684{
685 unsigned int ret = 0;
686
687#ifdef HOST_I386
688 __asm__ __volatile__ ("bsr %1, %0\n" : "+r" (ret) : "rm" (value));
689 return ret;
690#else
691 if (value > 0xffff)
692 value >>= 16, ret = 16;
693 if (value > 0xff)
694 value >>= 8, ret += 8;
695 if (value > 0xf)
696 value >>= 4, ret += 4;
697 if (value > 0x3)
698 value >>= 2, ret += 2;
699 return ret + (value >> 1);
700#endif
701}
702
703static inline void set_bit(uint32_t *tab, int index)
704{
705 int i, mask;
706 i = index >> 5;
707 mask = 1 << (index & 0x1f);
708 tab[i] |= mask;
709}
710
711static inline void reset_bit(uint32_t *tab, int index)
712{
713 int i, mask;
714 i = index >> 5;
715 mask = 1 << (index & 0x1f);
716 tab[i] &= ~mask;
717}
718
719
720#else /* VBOX */
721
722PDMBOTHCBDECL(uint64_t) apicGetBase(PPDMDEVINS pDevIns)
723{
724 APICDeviceInfo *dev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
725 Assert(PDMCritSectIsOwner(dev->CTX_SUFF(pCritSect)));
726 APICState *s = getLapic(dev); /** @todo fix interface */
727 LogFlow(("apicGetBase: %016llx\n", (uint64_t)s->apicbase));
728 return s->apicbase;
729}
730
731PDMBOTHCBDECL(void) apicSetTPR(PPDMDEVINS pDevIns, VMCPUID idCpu, uint8_t val)
732{
733 APICDeviceInfo *dev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
734 Assert(PDMCritSectIsOwner(dev->CTX_SUFF(pCritSect)));
735 APICState *s = getLapicById(dev, idCpu);
736 LogFlow(("apicSetTPR: val=%#x (trp %#x -> %#x)\n", val, s->tpr, val));
737 apic_update_tpr(dev, s, val);
738}
739
740PDMBOTHCBDECL(uint8_t) apicGetTPR(PPDMDEVINS pDevIns, VMCPUID idCpu)
741{
742 /* We don't perform any locking here as that would cause a lot of contention for VT-x/AMD-V. */
743 APICDeviceInfo *dev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
744 APICState *s = getLapicById(dev, idCpu);
745 Log2(("apicGetTPR: returns %#x\n", s->tpr));
746 return s->tpr;
747}
748
749/**
750 * x2APIC MSR write interface.
751 *
752 * @returns VBox status code.
753 *
754 * @param pDevIns The device instance.
755 * @param idCpu The ID of the virtual CPU and thereby APIC index.
756 * @param u32Reg Register to write (ecx).
757 * @param u64Value The value to write (eax:edx / rax).
758 *
759 */
760PDMBOTHCBDECL(int) apicWriteMSR(PPDMDEVINS pDevIns, VMCPUID idCpu, uint32_t u32Reg, uint64_t u64Value)
761{
762 APICDeviceInfo *dev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
763 Assert(PDMCritSectIsOwner(dev->CTX_SUFF(pCritSect)));
764 int rc = VINF_SUCCESS;
765
766 if (dev->enmVersion < PDMAPICVERSION_X2APIC)
767 return VERR_EM_INTERPRETER;
768
769 APICState *pThis = getLapicById(dev, idCpu);
770
771 uint32_t index = (u32Reg - MSR_IA32_APIC_START) & 0xff;
772 switch (index)
773 {
774 case 0x02:
775 pThis->id = (u64Value >> 24);
776 break;
777 case 0x03:
778 break;
779 case 0x08:
780 apic_update_tpr(dev, pThis, u64Value);
781 break;
782 case 0x09: case 0x0a:
783 Log(("apicWriteMSR: write to read-only register %d ignored\n", index));
784 break;
785 case 0x0b: /* EOI */
786 apic_eoi(dev, pThis);
787 break;
788 case 0x0d:
789 pThis->log_dest = u64Value >> 24;
790 break;
791 case 0x0e:
792 pThis->dest_mode = u64Value >> 28;
793 break;
794 case 0x0f:
795 pThis->spurious_vec = u64Value & 0x1ff;
796 apic_update_irq(dev, pThis);
797 break;
798 case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
799 case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
800 case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
801 case 0x28:
802 Log(("apicWriteMSR: write to read-only register %d ignored\n", index));
803 break;
804
805 case 0x30:
806 /* Here one of the differences with regular APIC: ICR is single 64-bit register */
807 pThis->icr[0] = (uint32_t)u64Value;
808 pThis->icr[1] = (uint32_t)(u64Value >> 32);
809 rc = apic_deliver(dev, pThis, (pThis->icr[1] >> 24) & 0xff, (pThis->icr[0] >> 11) & 1,
810 (pThis->icr[0] >> 8) & 7, (pThis->icr[0] & 0xff),
811 (pThis->icr[0] >> 14) & 1, (pThis->icr[0] >> 15) & 1);
812 break;
813 case 0x32 + APIC_LVT_TIMER:
814 AssertCompile(APIC_LVT_TIMER == 0);
815 apicTimerSetLvt(dev, pThis, u64Value);
816 break;
817
818 case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
819 pThis->lvt[index - 0x32] = u64Value;
820 break;
821 case 0x38:
822 apicTimerSetInitialCount(dev, pThis, u64Value);
823 break;
824 case 0x39:
825 Log(("apicWriteMSR: write to read-only register %d ignored\n", index));
826 break;
827 case 0x3e:
828 {
829 int v;
830 pThis->divide_conf = u64Value & 0xb;
831 v = (pThis->divide_conf & 3) | ((pThis->divide_conf >> 1) & 4);
832 pThis->count_shift = (v + 1) & 7;
833 break;
834 }
835 case 0x3f:
836 {
837 /* Self IPI, see x2APIC book 2.4.5 */
838 int vector = u64Value & 0xff;
839 rc = apic_bus_deliver(dev,
840 1 << getLapicById(dev, idCpu)->id /* Self */,
841 0 /* Delivery mode - fixed */,
842 vector,
843 0 /* Polarity - conform to the bus */,
844 0 /* Trigger mode - edge */);
845 break;
846 }
847 default:
848 AssertMsgFailed(("apicWriteMSR: unknown index %x\n", index));
849 pThis->esr |= ESR_ILLEGAL_ADDRESS;
850 break;
851 }
852
853 return rc;
854}
855
856/**
857 * x2APIC MSR read interface.
858 *
859 * @returns VBox status code.
860 *
861 * @param pDevIns The device instance.
862 * @param idCpu The ID of the virtual CPU and thereby APIC index.
863 * @param u32Reg Register to write (ecx).
864 * @param pu64Value Where to return the value (eax:edx / rax).
865 */
866PDMBOTHCBDECL(int) apicReadMSR(PPDMDEVINS pDevIns, VMCPUID idCpu, uint32_t u32Reg, uint64_t *pu64Value)
867{
868 APICDeviceInfo *dev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
869 Assert(PDMCritSectIsOwner(dev->CTX_SUFF(pCritSect)));
870
871 if (dev->enmVersion < PDMAPICVERSION_X2APIC)
872 return VERR_EM_INTERPRETER;
873
874 uint32_t index = (u32Reg - MSR_IA32_APIC_START) & 0xff;
875 APICState* apic = getLapicById(dev, idCpu);
876 uint64_t val = 0;
877
878 switch (index)
879 {
880 case 0x02: /* id */
881 val = apic->id << 24;
882 break;
883 case 0x03: /* version */
884 val = 0x11 | ((APIC_LVT_NB - 1) << 16); /* version 0x11 */
885 break;
886 case 0x08:
887 val = apic->tpr;
888 break;
889 case 0x09:
890 val = apic_get_arb_pri(apic);
891 break;
892 case 0x0a:
893 /* ppr */
894 val = apic_get_ppr(apic);
895 break;
896 case 0x0b:
897 val = 0;
898 break;
899 case 0x0d:
900 val = apic->log_dest << 24;
901 break;
902 case 0x0e:
903 /* Bottom 28 bits are always 1 */
904 val = (apic->dest_mode << 28) | 0xfffffff;
905 break;
906 case 0x0f:
907 val = apic->spurious_vec;
908 break;
909 case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
910 val = apic->isr[index & 7];
911 break;
912 case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
913 val = apic->tmr[index & 7];
914 break;
915 case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
916 val = apic->irr[index & 7];
917 break;
918 case 0x28:
919 val = apic->esr;
920 break;
921 case 0x30:
922 /* Here one of the differences with regular APIC: ICR is single 64-bit register */
923 val = ((uint64_t)apic->icr[0x31] << 32) | apic->icr[0x30];
924 break;
925 case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
926 val = apic->lvt[index - 0x32];
927 break;
928 case 0x38:
929 val = apic->initial_count;
930 break;
931 case 0x39:
932 val = apic_get_current_count(dev, apic);
933 break;
934 case 0x3e:
935 val = apic->divide_conf;
936 break;
937 case 0x3f:
938 /* Self IPI register is write only */
939 Log(("apicReadMSR: read from write-only register %d ignored\n", index));
940 break;
941 default:
942 AssertMsgFailed(("apicReadMSR: unknown index %x\n", index));
943 apic->esr |= ESR_ILLEGAL_ADDRESS;
944 val = 0;
945 break;
946 }
947 *pu64Value = val;
948 return VINF_SUCCESS;
949}
950
951/**
952 * More or less private interface between IOAPIC, only PDM is responsible
953 * for connecting the two devices.
954 */
955PDMBOTHCBDECL(int) apicBusDeliverCallback(PPDMDEVINS pDevIns, uint8_t u8Dest, uint8_t u8DestMode,
956 uint8_t u8DeliveryMode, uint8_t iVector, uint8_t u8Polarity,
957 uint8_t u8TriggerMode)
958{
959 APICDeviceInfo *dev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
960 Assert(PDMCritSectIsOwner(dev->CTX_SUFF(pCritSect)));
961 LogFlow(("apicBusDeliverCallback: pDevIns=%p u8Dest=%#x u8DestMode=%#x u8DeliveryMode=%#x iVector=%#x u8Polarity=%#x u8TriggerMode=%#x\n",
962 pDevIns, u8Dest, u8DestMode, u8DeliveryMode, iVector, u8Polarity, u8TriggerMode));
963 return apic_bus_deliver(dev, apic_get_delivery_bitmask(dev, u8Dest, u8DestMode),
964 u8DeliveryMode, iVector, u8Polarity, u8TriggerMode);
965}
966
967/**
968 * Local interrupt delivery, for devices attached to the CPU's LINT0/LINT1 pin.
969 * Normally used for 8259A PIC and NMI.
970 */
971PDMBOTHCBDECL(int) apicLocalInterrupt(PPDMDEVINS pDevIns, uint8_t u8Pin, uint8_t u8Level)
972{
973 APICDeviceInfo *dev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
974 APICState *s = getLapicById(dev, 0);
975
976 Assert(PDMCritSectIsOwner(dev->CTX_SUFF(pCritSect)));
977 LogFlow(("apicLocalInterrupt: pDevIns=%p u8Pin=%x\n", pDevIns, u8Pin));
978
979 /* If LAPIC is disabled, go straight to the CPU. */
980 if (!(s->spurious_vec & APIC_SV_ENABLE))
981 {
982 LogFlow(("apicLocalInterrupt: LAPIC disabled, delivering directly to CPU core.\n"));
983 if (u8Level)
984 cpuSetInterrupt(dev, s, PDMAPICIRQ_EXTINT);
985 else
986 cpuClearInterrupt(dev, s, PDMAPICIRQ_EXTINT);
987
988 return VINF_SUCCESS;
989 }
990
991 /* If LAPIC is enabled, interrupts are subject to LVT programming. */
992
993 /* There are only two local interrupt pins. */
994 AssertMsgReturn(u8Pin <= 1, ("Invalid LAPIC pin %d\n", u8Pin), VERR_INVALID_PARAMETER);
995
996 /* NB: We currently only deliver local interrupts to the first CPU. In theory they
997 * should be delivered to all CPUs and it is the guest's responsibility to ensure
998 * no more than one CPU has the interrupt unmasked.
999 */
1000 uint32_t u32Lvec;
1001
1002 u32Lvec = s->lvt[APIC_LVT_LINT0 + u8Pin]; /* Fetch corresponding LVT entry. */
1003 /* Drop int if entry is masked. May not be correct for level-triggered interrupts. */
1004 if (!(u32Lvec & APIC_LVT_MASKED))
1005 { uint8_t u8Delivery;
1006 PDMAPICIRQ enmType;
1007
1008 u8Delivery = (u32Lvec >> 8) & 7;
1009 switch (u8Delivery)
1010 {
1011 case APIC_DM_EXTINT:
1012 Assert(u8Pin == 0); /* PIC should be wired to LINT0. */
1013 enmType = PDMAPICIRQ_EXTINT;
1014 /* ExtINT can be both set and cleared, NMI/SMI/INIT can only be set. */
1015 LogFlow(("apicLocalInterrupt: %s ExtINT interrupt\n", u8Level ? "setting" : "clearing"));
1016 if (u8Level)
1017 cpuSetInterrupt(dev, s, enmType);
1018 else
1019 cpuClearInterrupt(dev, s, enmType);
1020 return VINF_SUCCESS;
1021 case APIC_DM_NMI:
1022 /* External NMI should be wired to LINT1, but Linux sometimes programs
1023 * LVT0 to NMI delivery mode as well.
1024 */
1025 enmType = PDMAPICIRQ_NMI;
1026 /* Currently delivering NMIs through here causes problems with NMI watchdogs
1027 * on certain Linux kernels, e.g. 64-bit CentOS 5.3. Disable NMIs for now.
1028 */
1029 return VINF_SUCCESS;
1030 case APIC_DM_SMI:
1031 enmType = PDMAPICIRQ_SMI;
1032 break;
1033 case APIC_DM_FIXED:
1034 {
1035 /** @todo implement APIC_DM_FIXED! */
1036 static unsigned s_c = 0;
1037 if (s_c++ < 5)
1038 LogRel(("delivery type APIC_DM_FIXED not implemented. u8Pin=%d u8Level=%d", u8Pin, u8Level));
1039 return VINF_SUCCESS;
1040 }
1041 case APIC_DM_INIT:
1042 /** @todo implement APIC_DM_INIT? */
1043 default:
1044 {
1045 static unsigned s_c = 0;
1046 if (s_c++ < 100)
1047 AssertLogRelMsgFailed(("delivery type %d not implemented. u8Pin=%d u8Level=%d", u8Delivery, u8Pin, u8Level));
1048 return VERR_INTERNAL_ERROR_4;
1049 }
1050 }
1051 LogFlow(("apicLocalInterrupt: setting local interrupt type %d\n", enmType));
1052 cpuSetInterrupt(dev, s, enmType);
1053 }
1054 return VINF_SUCCESS;
1055}
1056
1057#endif /* VBOX */
1058
1059/* return -1 if no bit is set */
1060static int get_highest_priority_int(uint32_t *tab)
1061{
1062 int i;
1063 for(i = 7; i >= 0; i--) {
1064 if (tab[i] != 0) {
1065 return i * 32 + fls_bit(tab[i]);
1066 }
1067 }
1068 return -1;
1069}
1070
1071static int apic_get_ppr(APICState *s)
1072{
1073 int tpr, isrv, ppr;
1074
1075 tpr = (s->tpr >> 4);
1076 isrv = get_highest_priority_int(s->isr);
1077 if (isrv < 0)
1078 isrv = 0;
1079 isrv >>= 4;
1080 if (tpr >= isrv)
1081 ppr = s->tpr;
1082 else
1083 ppr = isrv << 4;
1084 return ppr;
1085}
1086
1087static int apic_get_ppr_zero_tpr(APICState *s)
1088{
1089 int isrv;
1090
1091 isrv = get_highest_priority_int(s->isr);
1092 if (isrv < 0)
1093 isrv = 0;
1094 return isrv;
1095}
1096
1097static int apic_get_arb_pri(APICState *s)
1098{
1099 /* XXX: arbitration */
1100 return 0;
1101}
1102
1103/* signal the CPU if an irq is pending */
1104static bool apic_update_irq(APICDeviceInfo *dev, APICState* s)
1105{
1106 int irrv, ppr;
1107 if (!(s->spurious_vec & APIC_SV_ENABLE))
1108#ifdef VBOX
1109 {
1110 /* Clear any pending APIC interrupt action flag. */
1111 cpuClearInterrupt(dev, s);
1112 return false;
1113 }
1114#else
1115 return false;
1116#endif /* VBOX */
1117 irrv = get_highest_priority_int(s->irr);
1118 if (irrv < 0)
1119 return false;
1120 ppr = apic_get_ppr(s);
1121 if (ppr && (irrv & 0xf0) <= (ppr & 0xf0))
1122 return false;
1123#ifndef VBOX
1124 cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
1125#else
1126 cpuSetInterrupt(dev, s);
1127 return true;
1128#endif
1129}
1130
1131#ifdef VBOX
1132
1133/* Check if the APIC has a pending interrupt/if a TPR change would active one. */
1134PDMBOTHCBDECL(bool) apicHasPendingIrq(PPDMDEVINS pDevIns)
1135{
1136 int irrv, ppr;
1137 APICDeviceInfo *dev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
1138 if (!dev)
1139 return false;
1140
1141 /* We don't perform any locking here as that would cause a lot of contention for VT-x/AMD-V. */
1142
1143 APICState *s = getLapic(dev); /** @todo fix interface */
1144
1145 /*
1146 * All our callbacks now come from single IOAPIC, thus locking
1147 * seems to be excessive now (@todo: check)
1148 */
1149 irrv = get_highest_priority_int(s->irr);
1150 if (irrv < 0)
1151 return false;
1152
1153 ppr = apic_get_ppr_zero_tpr(s);
1154
1155 if (ppr && (irrv & 0xf0) <= (ppr & 0xf0))
1156 return false;
1157
1158 return true;
1159}
1160
1161static void apic_update_tpr(APICDeviceInfo *dev, APICState* s, uint32_t val)
1162{
1163 bool fIrqIsActive = false;
1164 bool fIrqWasActive = false;
1165
1166 fIrqWasActive = apic_update_irq(dev, s);
1167 s->tpr = val;
1168 fIrqIsActive = apic_update_irq(dev, s);
1169
1170 /* If an interrupt is pending and now masked, then clear the FF flag. */
1171 if (fIrqWasActive && !fIrqIsActive)
1172 {
1173 Log(("apic_update_tpr: deactivate interrupt that was masked by the TPR update (%x)\n", val));
1174 STAM_COUNTER_INC(&dev->StatClearedActiveIrq);
1175 cpuClearInterrupt(dev, s);
1176 }
1177}
1178#endif
1179
1180static void apic_set_irq(APICDeviceInfo *dev, APICState* s, int vector_num, int trigger_mode)
1181{
1182 LogFlow(("CPU%d: apic_set_irq vector=%x, trigger_mode=%x\n", s->phys_id, vector_num, trigger_mode));
1183 set_bit(s->irr, vector_num);
1184 if (trigger_mode)
1185 set_bit(s->tmr, vector_num);
1186 else
1187 reset_bit(s->tmr, vector_num);
1188 apic_update_irq(dev, s);
1189}
1190
1191static void apic_eoi(APICDeviceInfo *dev, APICState* s)
1192{
1193 int isrv;
1194 isrv = get_highest_priority_int(s->isr);
1195 if (isrv < 0)
1196 return;
1197 reset_bit(s->isr, isrv);
1198 LogFlow(("CPU%d: apic_eoi isrv=%x\n", s->phys_id, isrv));
1199 /* XXX: send the EOI packet to the APIC bus to allow the I/O APIC to
1200 set the remote IRR bit for level triggered interrupts. */
1201 apic_update_irq(dev, s);
1202}
1203
1204#ifndef VBOX
1205static uint32_t apic_get_delivery_bitmask(uint8_t dest, uint8_t dest_mode)
1206#else /* VBOX */
1207static uint32_t apic_get_delivery_bitmask(APICDeviceInfo *dev, uint8_t dest, uint8_t dest_mode)
1208#endif /* VBOX */
1209{
1210 uint32_t mask = 0;
1211
1212 if (dest_mode == 0)
1213 {
1214 if (dest == 0xff)
1215 mask = 0xff;
1216 else
1217 mask = 1 << dest;
1218 }
1219 else
1220 {
1221 APICState *apic = dev->CTX_SUFF(paLapics);
1222 uint32_t i;
1223
1224 /* XXX: cluster mode */
1225 for(i = 0; i < dev->cCpus; i++)
1226 {
1227 if (apic->dest_mode == 0xf)
1228 {
1229 if (dest & apic->log_dest)
1230 mask |= (1 << apic->id);
1231 }
1232 else if (apic->dest_mode == 0x0)
1233 {
1234 if ((dest & 0xf0) == (apic->log_dest & 0xf0)
1235 &&
1236 (dest & apic->log_dest & 0x0f))
1237 {
1238 mask |= (1 << i);
1239 }
1240 }
1241 apic++;
1242 }
1243 }
1244
1245 return mask;
1246}
1247
1248#ifdef IN_RING3
1249static void apic_init_ipi(APICDeviceInfo* dev, APICState *s)
1250{
1251 int i;
1252
1253 for(i = 0; i < APIC_LVT_NB; i++)
1254 s->lvt[i] = 1 << 16; /* mask LVT */
1255 s->tpr = 0;
1256 s->spurious_vec = 0xff;
1257 s->log_dest = 0;
1258 s->dest_mode = 0xff;
1259 memset(s->isr, 0, sizeof(s->isr));
1260 memset(s->tmr, 0, sizeof(s->tmr));
1261 memset(s->irr, 0, sizeof(s->irr));
1262 s->esr = 0;
1263 memset(s->icr, 0, sizeof(s->icr));
1264 s->divide_conf = 0;
1265 s->count_shift = 0;
1266 s->initial_count = 0;
1267 s->initial_count_load_time = 0;
1268 s->next_time = 0;
1269}
1270
1271
1272#ifdef VBOX
1273static void apicSendInitIpi(APICDeviceInfo* dev, APICState *s)
1274{
1275 apic_init_ipi(dev, s);
1276 cpuSendInitIpi(dev, s);
1277}
1278#endif
1279
1280/* send a SIPI message to the CPU to start it */
1281static void apic_startup(APICDeviceInfo* dev, APICState *s, int vector_num)
1282{
1283#ifndef VBOX
1284 CPUState *env = s->cpu_env;
1285 if (!env->halted)
1286 return;
1287 env->eip = 0;
1288 cpu_x86_load_seg_cache(env, R_CS, vector_num << 8, vector_num << 12,
1289 0xffff, 0);
1290 env->halted = 0;
1291#else
1292 Log(("[SMP] apic_startup: %d on CPUs %d\n", vector_num, s->phys_id));
1293 cpuSendSipi(dev, s, vector_num);
1294#endif
1295}
1296#endif /* IN_RING3 */
1297
1298static int apic_deliver(APICDeviceInfo* dev, APICState *s,
1299 uint8_t dest, uint8_t dest_mode,
1300 uint8_t delivery_mode, uint8_t vector_num,
1301 uint8_t polarity, uint8_t trigger_mode)
1302{
1303 uint32_t deliver_bitmask = 0;
1304 int dest_shorthand = (s->icr[0] >> 18) & 3;
1305#ifndef VBOX
1306 APICState *apic_iter;
1307#endif /* !VBOX */
1308
1309 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));
1310
1311 switch (dest_shorthand) {
1312 case 0:
1313#ifndef VBOX
1314 deliver_bitmask = apic_get_delivery_bitmask(dest, dest_mode);
1315#else /* VBOX */
1316 deliver_bitmask = apic_get_delivery_bitmask(dev, dest, dest_mode);
1317#endif /* !VBOX */
1318 break;
1319 case 1:
1320 deliver_bitmask = (1 << s->id);
1321 break;
1322 case 2:
1323 deliver_bitmask = 0xffffffff;
1324 break;
1325 case 3:
1326 deliver_bitmask = 0xffffffff & ~(1 << s->id);
1327 break;
1328 }
1329
1330 switch (delivery_mode) {
1331 case APIC_DM_INIT:
1332 {
1333 int trig_mode = (s->icr[0] >> 15) & 1;
1334 int level = (s->icr[0] >> 14) & 1;
1335 if (level == 0 && trig_mode == 1) {
1336 foreach_apic(dev, deliver_bitmask,
1337 apic->arb_id = apic->id);
1338#ifndef VBOX
1339 return;
1340#else
1341 Log(("CPU%d: APIC_DM_INIT arbitration id(s) set\n", s->phys_id));
1342 return VINF_SUCCESS;
1343#endif
1344 }
1345 }
1346 break;
1347
1348 case APIC_DM_SIPI:
1349#ifndef VBOX
1350 for (apic_iter = first_local_apic; apic_iter != NULL;
1351 apic_iter = apic_iter->next_apic) {
1352 if (deliver_bitmask & (1 << apic_iter->id)) {
1353 /* XXX: SMP support */
1354 /* apic_startup(apic_iter); */
1355 }
1356 }
1357 return;
1358#else
1359# ifdef IN_RING3
1360 foreach_apic(dev, deliver_bitmask,
1361 apic_startup(dev, apic, vector_num));
1362 return VINF_SUCCESS;
1363# else
1364 /* We shall send SIPI only in R3, R0 calls should be
1365 rescheduled to R3 */
1366 return VINF_IOM_HC_MMIO_WRITE;
1367# endif
1368#endif /* !VBOX */
1369 }
1370
1371#ifndef VBOX
1372 apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, polarity,
1373 trigger_mode);
1374#else /* VBOX */
1375 return apic_bus_deliver(dev, deliver_bitmask, delivery_mode, vector_num,
1376 polarity, trigger_mode);
1377#endif /* VBOX */
1378}
1379
1380
1381PDMBOTHCBDECL(int) apicGetInterrupt(PPDMDEVINS pDevIns)
1382{
1383 APICDeviceInfo *dev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
1384 /* if the APIC is not installed or enabled, we let the 8259 handle the
1385 IRQs */
1386 if (!dev)
1387 {
1388 Log(("apic_get_interrupt: returns -1 (!s)\n"));
1389 return -1;
1390 }
1391
1392 Assert(PDMCritSectIsOwner(dev->CTX_SUFF(pCritSect)));
1393
1394 APICState *s = getLapic(dev); /** @todo fix interface */
1395 int intno;
1396
1397 if (!(s->spurious_vec & APIC_SV_ENABLE)) {
1398 Log(("CPU%d: apic_get_interrupt: returns -1 (APIC_SV_ENABLE)\n", s->phys_id));
1399 return -1;
1400 }
1401
1402 /* XXX: spurious IRQ handling */
1403 intno = get_highest_priority_int(s->irr);
1404 if (intno < 0) {
1405 Log(("CPU%d: apic_get_interrupt: returns -1 (irr)\n", s->phys_id));
1406 return -1;
1407 }
1408 if (s->tpr && (uint32_t)intno <= s->tpr) {
1409 Log(("apic_get_interrupt: returns %d (sp)\n", s->spurious_vec & 0xff));
1410 return s->spurious_vec & 0xff;
1411 }
1412 reset_bit(s->irr, intno);
1413 set_bit(s->isr, intno);
1414 apic_update_irq(dev, s);
1415 LogFlow(("CPU%d: apic_get_interrupt: returns %d\n", s->phys_id, intno));
1416 return intno;
1417}
1418
1419static uint32_t apic_get_current_count(APICDeviceInfo *dev, APICState *s)
1420{
1421 int64_t d;
1422 uint32_t val;
1423#ifndef VBOX
1424 d = (qemu_get_clock(vm_clock) - s->initial_count_load_time) >>
1425 s->count_shift;
1426#else /* VBOX */
1427 d = (TMTimerGet(s->CTX_SUFF(pTimer)) - s->initial_count_load_time) >>
1428 s->count_shift;
1429#endif /* VBOX */
1430 if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
1431 /* periodic */
1432 val = s->initial_count - (d % ((uint64_t)s->initial_count + 1));
1433 } else {
1434 if (d >= s->initial_count)
1435 val = 0;
1436 else
1437 val = s->initial_count - d;
1438 }
1439 return val;
1440}
1441
1442#ifndef VBOX /* we've replaced all the code working the APIC timer. */
1443
1444static void apic_timer_update(APICDeviceInfo* dev, APICState *s, int64_t current_time)
1445{
1446 int64_t next_time, d;
1447
1448 if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) {
1449 d = (current_time - s->initial_count_load_time) >>
1450 s->count_shift;
1451 if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
1452 d = ((d / ((uint64_t)s->initial_count + 1)) + 1) * ((uint64_t)s->initial_count + 1);
1453 } else {
1454 if (d >= s->initial_count)
1455 goto no_timer;
1456 d = (uint64_t)s->initial_count + 1;
1457 }
1458 next_time = s->initial_count_load_time + (d << s->count_shift);
1459# ifndef VBOX
1460 qemu_mod_timer(s->timer, next_time);
1461# else
1462 TMTimerSet(s->CTX_SUFF(pTimer), next_time);
1463 s->fTimerArmed = true;
1464# endif
1465 s->next_time = next_time;
1466 } else {
1467 no_timer:
1468# ifndef VBOX
1469 qemu_del_timer(s->timer);
1470# else
1471 TMTimerStop(s->CTX_SUFF(pTimer));
1472 s->fTimerArmed = false;
1473# endif
1474 }
1475}
1476
1477static void apic_timer(void *opaque)
1478{
1479 APICState *s = opaque;
1480
1481 if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) {
1482 LogFlow(("apic_timer: trigger irq\n"));
1483 apic_set_irq(dev, s, s->lvt[APIC_LVT_TIMER] & 0xff, APIC_TRIGGER_EDGE);
1484 }
1485 apic_timer_update(dev, s, s->next_time);
1486}
1487
1488#else /* VBOX */
1489
1490/**
1491 * Implementation of the 0380h access: Timer reset + new initial count.
1492 *
1493 * @param dev The device state.
1494 * @param pThis The APIC sub-device state.
1495 * @param u32NewInitialCount The new initial count for the timer.
1496 */
1497static void apicTimerSetInitialCount(APICDeviceInfo *dev, APICState *pThis, uint32_t u32NewInitialCount)
1498{
1499 STAM_COUNTER_INC(&pThis->StatTimerSetInitialCount);
1500 pThis->initial_count = u32NewInitialCount;
1501
1502 /*
1503 * Don't (re-)arm the timer if the it's masked or if it's
1504 * a zero length one-shot timer.
1505 */
1506 /** @todo check the correct behavior of setting a 0 initial_count for a one-shot
1507 * timer. This is just copying the behavior of the original code. */
1508 if ( !(pThis->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)
1509 && ( (pThis->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC)
1510 || u32NewInitialCount != 0))
1511 {
1512 /*
1513 * Calculate the relative next time and perform a combined timer get/set
1514 * operation. This avoids racing the clock between get and set.
1515 */
1516 uint64_t cTicksNext = u32NewInitialCount;
1517 cTicksNext += 1;
1518 cTicksNext <<= pThis->count_shift;
1519 TMTimerSetRelative(pThis->CTX_SUFF(pTimer), cTicksNext, &pThis->initial_count_load_time);
1520 pThis->next_time = pThis->initial_count_load_time + cTicksNext;
1521 pThis->fTimerArmed = true;
1522 STAM_COUNTER_INC(&pThis->StatTimerSetInitialCountArm);
1523 }
1524 else
1525 {
1526 /* Stop it if necessary and record the load time for unmasking. */
1527 if (pThis->fTimerArmed)
1528 {
1529 STAM_COUNTER_INC(&pThis->StatTimerSetInitialCountDisarm);
1530 TMTimerStop(pThis->CTX_SUFF(pTimer));
1531 pThis->fTimerArmed = false;
1532 }
1533 pThis->initial_count_load_time = TMTimerGet(pThis->CTX_SUFF(pTimer));
1534 }
1535}
1536
1537/**
1538 * Implementation of the 0320h access: change the LVT flags.
1539 *
1540 * @param dev The device state.
1541 * @param pThis The APIC sub-device state to operate on.
1542 * @param fNew The new flags.
1543 */
1544static void apicTimerSetLvt(APICDeviceInfo *dev, APICState *pThis, uint32_t fNew)
1545{
1546 STAM_COUNTER_INC(&pThis->StatTimerSetLvt);
1547
1548 /*
1549 * Make the flag change, saving the old ones so we can avoid
1550 * unnecessary work.
1551 */
1552 uint32_t const fOld = pThis->lvt[APIC_LVT_TIMER];
1553 pThis->lvt[APIC_LVT_TIMER] = fNew;
1554
1555 /* Only the masked and peridic bits are relevant (see apic_timer_update). */
1556 if ( (fOld & (APIC_LVT_MASKED | APIC_LVT_TIMER_PERIODIC))
1557 != (fNew & (APIC_LVT_MASKED | APIC_LVT_TIMER_PERIODIC)))
1558 {
1559 /*
1560 * If changed to one-shot from periodic, stop the timer if we're not
1561 * in the first period.
1562 */
1563 /** @todo check how clearing the periodic flag really should behave when not
1564 * in period 1. The current code just mirrors the behavior of the
1565 * original implementation. */
1566 if ( (fOld & APIC_LVT_TIMER_PERIODIC)
1567 && !(fNew & APIC_LVT_TIMER_PERIODIC))
1568 {
1569 STAM_COUNTER_INC(&pThis->StatTimerSetLvtClearPeriodic);
1570 uint64_t cTicks = (pThis->next_time - pThis->initial_count_load_time) >> pThis->count_shift;
1571 if (cTicks >= pThis->initial_count)
1572 {
1573 /* not first period, stop it. */
1574 TMTimerStop(pThis->CTX_SUFF(pTimer));
1575 pThis->fTimerArmed = false;
1576 }
1577 /* else: first period, let it fire normally. */
1578 }
1579
1580 /*
1581 * We postpone stopping the timer when it's masked, this way we can
1582 * avoid some timer work when the guest temporarily masks the timer.
1583 * (apicTimerCallback will stop it if still masked.)
1584 */
1585 if (fNew & APIC_LVT_MASKED)
1586 STAM_COUNTER_INC(&pThis->StatTimerSetLvtPostponed);
1587 else if (pThis->fTimerArmed)
1588 STAM_COUNTER_INC(&pThis->StatTimerSetLvtArmed);
1589 /*
1590 * If unmasked and not armed, we have to rearm the timer so it will
1591 * fire at the end of the current period.
1592 * This is code is currently RACING the virtual sync clock!
1593 */
1594 else if (fOld & APIC_LVT_MASKED)
1595 {
1596 STAM_COUNTER_INC(&pThis->StatTimerSetLvtArm);
1597 for (unsigned cTries = 0; ; cTries++)
1598 {
1599 uint64_t NextTS;
1600 uint64_t cTicks = (TMTimerGet(pThis->CTX_SUFF(pTimer)) - pThis->initial_count_load_time) >> pThis->count_shift;
1601 if (fNew & APIC_LVT_TIMER_PERIODIC)
1602 NextTS = ((cTicks / ((uint64_t)pThis->initial_count + 1)) + 1) * ((uint64_t)pThis->initial_count + 1);
1603 else
1604 {
1605 if (cTicks >= pThis->initial_count)
1606 break;
1607 NextTS = (uint64_t)pThis->initial_count + 1;
1608 }
1609 NextTS <<= pThis->count_shift;
1610 NextTS += pThis->initial_count_load_time;
1611
1612 /* Try avoid the assertion in TM.cpp... this isn't perfect! */
1613 if ( NextTS > TMTimerGet(pThis->CTX_SUFF(pTimer))
1614 || cTries > 10)
1615 {
1616 TMTimerSet(pThis->CTX_SUFF(pTimer), NextTS);
1617 pThis->next_time = NextTS;
1618 pThis->fTimerArmed = true;
1619 break;
1620 }
1621 STAM_COUNTER_INC(&pThis->StatTimerSetLvtArmRetries);
1622 }
1623 }
1624 }
1625 else
1626 STAM_COUNTER_INC(&pThis->StatTimerSetLvtNoRelevantChange);
1627}
1628
1629# ifdef IN_RING3
1630/**
1631 * Timer callback function.
1632 *
1633 * @param pDevIns The device state.
1634 * @param pTimer The timer handle.
1635 * @param pvUser User argument pointing to the APIC instance.
1636 */
1637static DECLCALLBACK(void) apicTimerCallback(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
1638{
1639 APICDeviceInfo *dev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
1640 APICState *pThis = (APICState *)pvUser;
1641 Assert(pThis->pTimerR3 == pTimer);
1642 Assert(pThis->fTimerArmed);
1643
1644 if (!(pThis->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) {
1645 LogFlow(("apic_timer: trigger irq\n"));
1646 apic_set_irq(dev, pThis, pThis->lvt[APIC_LVT_TIMER] & 0xff, APIC_TRIGGER_EDGE);
1647
1648 if (pThis->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
1649 /* new interval. */
1650 pThis->next_time += (((uint64_t)pThis->initial_count + 1) << pThis->count_shift);
1651 TMTimerSet(pThis->CTX_SUFF(pTimer), pThis->next_time);
1652 pThis->fTimerArmed = true;
1653 } else {
1654 /* single shot. */
1655 pThis->fTimerArmed = false;
1656 }
1657 } else {
1658 /* masked, do not rearm. */
1659 pThis->fTimerArmed = false;
1660 }
1661}
1662# endif /* IN_RING3 */
1663
1664#endif /* VBOX */
1665
1666#ifndef VBOX
1667static uint32_t apic_mem_readb(void *opaque, target_phys_addr_t addr)
1668{
1669 return 0;
1670}
1671static uint32_t apic_mem_readw(void *opaque, target_phys_addr_t addr)
1672{
1673 return 0;
1674}
1675
1676static void apic_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
1677{
1678}
1679
1680static void apic_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
1681{
1682}
1683#endif /* !VBOX */
1684
1685
1686#ifndef VBOX
1687static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr)
1688{
1689 CPUState *env;
1690 APICState *s;
1691#else /* VBOX */
1692static uint32_t apic_mem_readl(APICDeviceInfo* dev, APICState *s, target_phys_addr_t addr)
1693{
1694#endif /* VBOX */
1695 uint32_t val;
1696 int index;
1697
1698#ifndef VBOX
1699 env = cpu_single_env;
1700 if (!env)
1701 return 0;
1702 s = env->apic_state;
1703#endif /* !VBOX */
1704
1705 index = (addr >> 4) & 0xff;
1706 switch(index) {
1707 case 0x02: /* id */
1708 val = s->id << 24;
1709 break;
1710 case 0x03: /* version */
1711 val = 0x11 | ((APIC_LVT_NB - 1) << 16); /* version 0x11 */
1712 break;
1713 case 0x08:
1714 val = s->tpr;
1715 break;
1716 case 0x09:
1717 val = apic_get_arb_pri(s);
1718 break;
1719 case 0x0a:
1720 /* ppr */
1721 val = apic_get_ppr(s);
1722 break;
1723 case 0x0b:
1724 Log(("apic_mem_readl %x %x -> write only returning 0\n", addr, index));
1725 val = 0;
1726 break;
1727 case 0x0d:
1728 val = s->log_dest << 24;
1729 break;
1730 case 0x0e:
1731#ifdef VBOX
1732 /* Bottom 28 bits are always 1 */
1733 val = (s->dest_mode << 28) | 0xfffffff;
1734#else
1735 val = s->dest_mode << 28;
1736#endif
1737 break;
1738 case 0x0f:
1739 val = s->spurious_vec;
1740 break;
1741#ifndef VBOX
1742 case 0x10 ... 0x17:
1743#else /* VBOX */
1744 case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
1745#endif /* VBOX */
1746 val = s->isr[index & 7];
1747 break;
1748#ifndef VBOX
1749 case 0x18 ... 0x1f:
1750#else /* VBOX */
1751 case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
1752#endif /* VBOX */
1753 val = s->tmr[index & 7];
1754 break;
1755#ifndef VBOX
1756 case 0x20 ... 0x27:
1757#else /* VBOX */
1758 case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
1759#endif /* VBOX */
1760 val = s->irr[index & 7];
1761 break;
1762 case 0x28:
1763 val = s->esr;
1764 break;
1765 case 0x30:
1766 case 0x31:
1767 val = s->icr[index & 1];
1768 break;
1769#ifndef VBOX
1770 case 0x32 ... 0x37:
1771#else /* VBOX */
1772 case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
1773#endif /* VBOX */
1774 val = s->lvt[index - 0x32];
1775 break;
1776 case 0x38:
1777 val = s->initial_count;
1778 break;
1779 case 0x39:
1780 val = apic_get_current_count(dev, s);
1781 break;
1782 case 0x3e:
1783 val = s->divide_conf;
1784 break;
1785 default:
1786 AssertMsgFailed(("apic_mem_readl: unknown index %x\n", index));
1787 s->esr |= ESR_ILLEGAL_ADDRESS;
1788 val = 0;
1789 break;
1790 }
1791#ifdef DEBUG_APIC
1792 Log(("CPU%d: APIC read: %08x = %08x\n", s->phys_id, (uint32_t)addr, val));
1793#endif
1794 return val;
1795}
1796
1797#ifndef VBOX
1798static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
1799{
1800 CPUState *env;
1801 APICState *s;
1802#else /* VBOX */
1803static int apic_mem_writel(APICDeviceInfo* dev, APICState *s, target_phys_addr_t addr, uint32_t val)
1804{
1805 int rc = VINF_SUCCESS;
1806#endif /* VBOX */
1807 int index;
1808
1809#ifndef VBOX
1810 env = cpu_single_env;
1811 if (!env)
1812 return;
1813 s = env->apic_state;
1814#endif /* !VBOX */
1815
1816#ifdef DEBUG_APIC
1817 Log(("CPU%d: APIC write: %08x = %08x\n", s->phys_id, (uint32_t)addr, val));
1818#endif
1819
1820 index = (addr >> 4) & 0xff;
1821 switch(index) {
1822 case 0x02:
1823 s->id = (val >> 24);
1824 break;
1825 case 0x03:
1826 Log(("apic_mem_writel: write to version register; ignored\n"));
1827 break;
1828 case 0x08:
1829#ifdef VBOX
1830 apic_update_tpr(dev, s, val);
1831#else
1832 s->tpr = val;
1833 apic_update_irq(s);
1834#endif
1835 break;
1836 case 0x09:
1837 case 0x0a:
1838 Log(("apic_mem_writel: write to read-only register %d ignored\n", index));
1839 break;
1840 case 0x0b: /* EOI */
1841 apic_eoi(dev, s);
1842 break;
1843 case 0x0d:
1844 s->log_dest = val >> 24;
1845 break;
1846 case 0x0e:
1847 s->dest_mode = val >> 28;
1848 break;
1849 case 0x0f:
1850 s->spurious_vec = val & 0x1ff;
1851 apic_update_irq(dev, s);
1852 break;
1853#ifndef VBOX
1854 case 0x10 ... 0x17:
1855 case 0x18 ... 0x1f:
1856 case 0x20 ... 0x27:
1857 case 0x28:
1858#else
1859 case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
1860 case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
1861 case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
1862 case 0x28:
1863 Log(("apic_mem_writel: write to read-only register %d ignored\n", index));
1864#endif
1865 break;
1866
1867 case 0x30:
1868 s->icr[0] = val;
1869 rc = apic_deliver(dev, s, (s->icr[1] >> 24) & 0xff,
1870 (s->icr[0] >> 11) & 1,
1871 (s->icr[0] >> 8) & 7, (s->icr[0] & 0xff),
1872 (s->icr[0] >> 14) & 1, (s->icr[0] >> 15) & 1);
1873 break;
1874 case 0x31:
1875 s->icr[1] = val;
1876 break;
1877#ifndef VBOX
1878 case 0x32 ... 0x37:
1879#else /* VBOX */
1880 case 0x32 + APIC_LVT_TIMER:
1881 AssertCompile(APIC_LVT_TIMER == 0);
1882 apicTimerSetLvt(dev, s, val);
1883 break;
1884 case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
1885#endif /* VBOX */
1886 {
1887 int n = index - 0x32;
1888 s->lvt[n] = val;
1889#ifndef VBOX
1890 if (n == APIC_LVT_TIMER)
1891 apic_timer_update(s, qemu_get_clock(vm_clock));
1892#endif /* !VBOX*/
1893 }
1894 break;
1895 case 0x38:
1896#ifndef VBOX
1897 s->initial_count = val;
1898 s->initial_count_load_time = qemu_get_clock(vm_clock);
1899 apic_timer_update(dev, s, s->initial_count_load_time);
1900#else /* VBOX */
1901 apicTimerSetInitialCount(dev, s, val);
1902#endif /* VBOX*/
1903 break;
1904 case 0x39:
1905 Log(("apic_mem_writel: write to read-only register %d ignored\n", index));
1906 break;
1907 case 0x3e:
1908 {
1909 int v;
1910 s->divide_conf = val & 0xb;
1911 v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4);
1912 s->count_shift = (v + 1) & 7;
1913 }
1914 break;
1915 default:
1916 AssertMsgFailed(("apic_mem_writel: unknown index %x\n", index));
1917 s->esr |= ESR_ILLEGAL_ADDRESS;
1918 break;
1919 }
1920#ifdef VBOX
1921 return rc;
1922#endif
1923}
1924
1925#ifdef IN_RING3
1926
1927static void apic_save(QEMUFile *f, void *opaque)
1928{
1929 APICState *s = (APICState*)opaque;
1930 int i;
1931
1932 qemu_put_be32s(f, &s->apicbase);
1933#ifdef VBOX
1934 qemu_put_be32s(f, &s->id);
1935 qemu_put_be32s(f, &s->phys_id);
1936 qemu_put_be32s(f, &s->arb_id);
1937 qemu_put_be32s(f, &s->tpr);
1938#else
1939 qemu_put_8s(f, &s->id);
1940 qemu_put_8s(f, &s->arb_id);
1941 qemu_put_8s(f, &s->tpr);
1942#endif
1943 qemu_put_be32s(f, &s->spurious_vec);
1944 qemu_put_8s(f, &s->log_dest);
1945 qemu_put_8s(f, &s->dest_mode);
1946 for (i = 0; i < 8; i++) {
1947 qemu_put_be32s(f, &s->isr[i]);
1948 qemu_put_be32s(f, &s->tmr[i]);
1949 qemu_put_be32s(f, &s->irr[i]);
1950 }
1951 for (i = 0; i < APIC_LVT_NB; i++) {
1952 qemu_put_be32s(f, &s->lvt[i]);
1953 }
1954 qemu_put_be32s(f, &s->esr);
1955 qemu_put_be32s(f, &s->icr[0]);
1956 qemu_put_be32s(f, &s->icr[1]);
1957 qemu_put_be32s(f, &s->divide_conf);
1958 qemu_put_be32s(f, &s->count_shift);
1959 qemu_put_be32s(f, &s->initial_count);
1960 qemu_put_be64s(f, &s->initial_count_load_time);
1961 qemu_put_be64s(f, &s->next_time);
1962
1963#ifdef VBOX
1964 TMR3TimerSave(s->CTX_SUFF(pTimer), f);
1965#endif
1966}
1967
1968static int apic_load(QEMUFile *f, void *opaque, int version_id)
1969{
1970 APICState *s = (APICState*)opaque;
1971 int i;
1972
1973#ifdef VBOX
1974 /* XXX: what if the base changes? (registered memory regions) */
1975 qemu_get_be32s(f, &s->apicbase);
1976
1977 switch (version_id)
1978 {
1979 case APIC_SAVED_STATE_VERSION_ANCIENT:
1980 {
1981 uint8_t val = 0;
1982 qemu_get_8s(f, &val);
1983 s->id = val;
1984 /* UP only in old saved states */
1985 s->phys_id = 0;
1986 qemu_get_8s(f, &val);
1987 s->arb_id = val;
1988 break;
1989 }
1990 case APIC_SAVED_STATE_VERSION:
1991 case APIC_SAVED_STATE_VERSION_VBOX_30:
1992 qemu_get_be32s(f, &s->id);
1993 qemu_get_be32s(f, &s->phys_id);
1994 qemu_get_be32s(f, &s->arb_id);
1995 break;
1996 default:
1997 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1998 }
1999 qemu_get_be32s(f, &s->tpr);
2000#else
2001 if (version_id != 1)
2002 return -EINVAL;
2003
2004 /* XXX: what if the base changes? (registered memory regions) */
2005 qemu_get_be32s(f, &s->apicbase);
2006 qemu_get_8s(f, &s->id);
2007 qemu_get_8s(f, &s->arb_id);
2008 qemu_get_8s(f, &s->tpr);
2009#endif
2010 qemu_get_be32s(f, &s->spurious_vec);
2011 qemu_get_8s(f, &s->log_dest);
2012 qemu_get_8s(f, &s->dest_mode);
2013 for (i = 0; i < 8; i++) {
2014 qemu_get_be32s(f, &s->isr[i]);
2015 qemu_get_be32s(f, &s->tmr[i]);
2016 qemu_get_be32s(f, &s->irr[i]);
2017 }
2018 for (i = 0; i < APIC_LVT_NB; i++) {
2019 qemu_get_be32s(f, &s->lvt[i]);
2020 }
2021 qemu_get_be32s(f, &s->esr);
2022 qemu_get_be32s(f, &s->icr[0]);
2023 qemu_get_be32s(f, &s->icr[1]);
2024 qemu_get_be32s(f, &s->divide_conf);
2025 qemu_get_be32s(f, (uint32_t *)&s->count_shift);
2026 qemu_get_be32s(f, (uint32_t *)&s->initial_count);
2027 qemu_get_be64s(f, (uint64_t *)&s->initial_count_load_time);
2028 qemu_get_be64s(f, (uint64_t *)&s->next_time);
2029
2030#ifdef VBOX
2031 int rc = TMR3TimerLoad(s->CTX_SUFF(pTimer), f);
2032 s->fTimerArmed = TMTimerIsActive(s->CTX_SUFF(pTimer));
2033#endif
2034
2035 return VINF_SUCCESS; /** @todo darn mess! */
2036}
2037#ifndef VBOX
2038static void apic_reset(void *opaque)
2039{
2040 APICState *s = (APICState*)opaque;
2041 apic_init_ipi(s);
2042}
2043#endif
2044
2045#endif /* IN_RING3 */
2046
2047#ifndef VBOX
2048static CPUReadMemoryFunc *apic_mem_read[3] = {
2049 apic_mem_readb,
2050 apic_mem_readw,
2051 apic_mem_readl,
2052};
2053
2054static CPUWriteMemoryFunc *apic_mem_write[3] = {
2055 apic_mem_writeb,
2056 apic_mem_writew,
2057 apic_mem_writel,
2058};
2059
2060int apic_init(CPUState *env)
2061{
2062 APICState *s;
2063
2064 s = qemu_mallocz(sizeof(APICState));
2065 if (!s)
2066 return -1;
2067 env->apic_state = s;
2068 apic_init_ipi(s);
2069 s->id = last_apic_id++;
2070 s->cpu_env = env;
2071 s->apicbase = 0xfee00000 |
2072 (s->id ? 0 : MSR_IA32_APICBASE_BSP) | MSR_IA32_APICBASE_ENABLE;
2073
2074 /* XXX: mapping more APICs at the same memory location */
2075 if (apic_io_memory == 0) {
2076 /* NOTE: the APIC is directly connected to the CPU - it is not
2077 on the global memory bus. */
2078 apic_io_memory = cpu_register_io_memory(0, apic_mem_read,
2079 apic_mem_write, NULL);
2080 cpu_register_physical_memory(s->apicbase & ~0xfff, 0x1000,
2081 apic_io_memory);
2082 }
2083 s->timer = qemu_new_timer(vm_clock, apic_timer, s);
2084
2085 register_savevm("apic", 0, 1, apic_save, apic_load, s);
2086 qemu_register_reset(apic_reset, s);
2087
2088 s->next_apic = first_local_apic;
2089 first_local_apic = s;
2090
2091 return 0;
2092}
2093#endif /* !VBOX */
2094
2095static void ioapic_service(IOAPICState *s)
2096{
2097 uint8_t i;
2098 uint8_t trig_mode;
2099 uint8_t vector;
2100 uint8_t delivery_mode;
2101 uint32_t mask;
2102 uint64_t entry;
2103 uint8_t dest;
2104 uint8_t dest_mode;
2105 uint8_t polarity;
2106
2107 for (i = 0; i < IOAPIC_NUM_PINS; i++) {
2108 mask = 1 << i;
2109 if (s->irr & mask) {
2110 entry = s->ioredtbl[i];
2111 if (!(entry & APIC_LVT_MASKED)) {
2112 trig_mode = ((entry >> 15) & 1);
2113 dest = entry >> 56;
2114 dest_mode = (entry >> 11) & 1;
2115 delivery_mode = (entry >> 8) & 7;
2116 polarity = (entry >> 13) & 1;
2117 if (trig_mode == APIC_TRIGGER_EDGE)
2118 s->irr &= ~mask;
2119 if (delivery_mode == APIC_DM_EXTINT)
2120#ifndef VBOX /* malc: i'm still not so sure about ExtINT delivery */
2121 vector = pic_read_irq(isa_pic);
2122#else /* VBOX */
2123 {
2124 AssertMsgFailed(("Delivery mode ExtINT"));
2125 vector = 0xff; /* incorrect but shuts up gcc. */
2126 }
2127#endif /* VBOX */
2128 else
2129 vector = entry & 0xff;
2130
2131#ifndef VBOX
2132 apic_bus_deliver(apic_get_delivery_bitmask(dest, dest_mode),
2133 delivery_mode, vector, polarity, trig_mode);
2134#else /* VBOX */
2135 int rc = s->CTX_SUFF(pIoApicHlp)->pfnApicBusDeliver(s->CTX_SUFF(pDevIns),
2136 dest,
2137 dest_mode,
2138 delivery_mode,
2139 vector,
2140 polarity,
2141 trig_mode);
2142 /* We must be sure that attempts to reschedule in R3
2143 never get here */
2144 Assert(rc == VINF_SUCCESS);
2145#endif /* VBOX */
2146 }
2147 }
2148 }
2149}
2150
2151#ifdef VBOX
2152static
2153#endif
2154void ioapic_set_irq(void *opaque, int vector, int level)
2155{
2156 IOAPICState *s = (IOAPICState*)opaque;
2157
2158 if (vector >= 0 && vector < IOAPIC_NUM_PINS) {
2159 uint32_t mask = 1 << vector;
2160 uint64_t entry = s->ioredtbl[vector];
2161
2162 if ((entry >> 15) & 1) {
2163 /* level triggered */
2164 if (level) {
2165 s->irr |= mask;
2166 ioapic_service(s);
2167#ifdef VBOX
2168 if ((level & PDM_IRQ_LEVEL_FLIP_FLOP) == PDM_IRQ_LEVEL_FLIP_FLOP) {
2169 s->irr &= ~mask;
2170 }
2171#endif
2172 } else {
2173 s->irr &= ~mask;
2174 }
2175 } else {
2176 /* edge triggered */
2177 if (level) {
2178 s->irr |= mask;
2179 ioapic_service(s);
2180 }
2181 }
2182 }
2183}
2184
2185static uint32_t ioapic_mem_readl(void *opaque, target_phys_addr_t addr)
2186{
2187 IOAPICState *s = (IOAPICState*)opaque;
2188 int index;
2189 uint32_t val = 0;
2190
2191 addr &= 0xff;
2192 if (addr == 0x00) {
2193 val = s->ioregsel;
2194 } else if (addr == 0x10) {
2195 switch (s->ioregsel) {
2196 case 0x00:
2197 val = s->id << 24;
2198 break;
2199 case 0x01:
2200 val = 0x11 | ((IOAPIC_NUM_PINS - 1) << 16); /* version 0x11 */
2201 break;
2202 case 0x02:
2203 val = 0;
2204 break;
2205 default:
2206 index = (s->ioregsel - 0x10) >> 1;
2207 if (index >= 0 && index < IOAPIC_NUM_PINS) {
2208 if (s->ioregsel & 1)
2209 val = s->ioredtbl[index] >> 32;
2210 else
2211 val = s->ioredtbl[index] & 0xffffffff;
2212 }
2213 }
2214#ifdef DEBUG_IOAPIC
2215 Log(("I/O APIC read: %08x = %08x\n", s->ioregsel, val));
2216#endif
2217 }
2218 return val;
2219}
2220
2221static void ioapic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
2222{
2223 IOAPICState *s = (IOAPICState*)opaque;
2224 int index;
2225
2226 addr &= 0xff;
2227 if (addr == 0x00) {
2228 s->ioregsel = val;
2229 return;
2230 } else if (addr == 0x10) {
2231#ifdef DEBUG_IOAPIC
2232 Log(("I/O APIC write: %08x = %08x\n", s->ioregsel, val));
2233#endif
2234 switch (s->ioregsel) {
2235 case 0x00:
2236 s->id = (val >> 24) & 0xff;
2237 return;
2238 case 0x01:
2239 case 0x02:
2240 return;
2241 default:
2242 index = (s->ioregsel - 0x10) >> 1;
2243 if (index >= 0 && index < IOAPIC_NUM_PINS) {
2244 if (s->ioregsel & 1) {
2245 s->ioredtbl[index] &= 0xffffffff;
2246 s->ioredtbl[index] |= (uint64_t)val << 32;
2247 } else {
2248#ifdef VBOX
2249 /* According to IOAPIC spec, vectors should be from 0x10 to 0xfe */
2250 uint8_t vec = val & 0xff;
2251 if ((val & APIC_LVT_MASKED) ||
2252 ((vec >= 0x10) && (vec < 0xff)))
2253 {
2254 s->ioredtbl[index] &= ~0xffffffffULL;
2255 s->ioredtbl[index] |= val;
2256 }
2257 else
2258 {
2259 /*
2260 * Linux 2.6 kernels has pretty strange function
2261 * unlock_ExtINT_logic() which writes
2262 * absolutely bogus (all 0) value into the vector
2263 * with pretty vague explanation why.
2264 * So we just ignore such writes.
2265 */
2266 LogRel(("IOAPIC GUEST BUG: bad vector writing %x(sel=%x) to %d\n", val, s->ioregsel, index));
2267 }
2268 }
2269#else
2270 s->ioredtbl[index] &= ~0xffffffffULL;
2271 s->ioredtbl[index] |= val;
2272#endif
2273 ioapic_service(s);
2274 }
2275 }
2276 }
2277}
2278
2279#ifdef IN_RING3
2280
2281static void ioapic_save(QEMUFile *f, void *opaque)
2282{
2283 IOAPICState *s = (IOAPICState*)opaque;
2284 int i;
2285
2286 qemu_put_8s(f, &s->id);
2287 qemu_put_8s(f, &s->ioregsel);
2288 for (i = 0; i < IOAPIC_NUM_PINS; i++) {
2289 qemu_put_be64s(f, &s->ioredtbl[i]);
2290 }
2291}
2292
2293static int ioapic_load(QEMUFile *f, void *opaque, int version_id)
2294{
2295 IOAPICState *s = (IOAPICState*)opaque;
2296 int i;
2297
2298 if (version_id != 1)
2299 return -EINVAL;
2300
2301 qemu_get_8s(f, &s->id);
2302 qemu_get_8s(f, &s->ioregsel);
2303 for (i = 0; i < IOAPIC_NUM_PINS; i++) {
2304 qemu_get_be64s(f, &s->ioredtbl[i]);
2305 }
2306 return 0;
2307}
2308
2309static void ioapic_reset(void *opaque)
2310{
2311 IOAPICState *s = (IOAPICState*)opaque;
2312#ifdef VBOX
2313 PPDMDEVINSR3 pDevIns = s->pDevInsR3;
2314 PCPDMIOAPICHLPR3 pIoApicHlp = s->pIoApicHlpR3;
2315#endif
2316 int i;
2317
2318 memset(s, 0, sizeof(*s));
2319 for(i = 0; i < IOAPIC_NUM_PINS; i++)
2320 s->ioredtbl[i] = 1 << 16; /* mask LVT */
2321
2322#ifdef VBOX
2323 if (pDevIns)
2324 {
2325 s->pDevInsR3 = pDevIns;
2326 s->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2327 s->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
2328 }
2329 if (pIoApicHlp)
2330 {
2331 s->pIoApicHlpR3 = pIoApicHlp;
2332 s->pIoApicHlpRC = s->pIoApicHlpR3->pfnGetRCHelpers(pDevIns);
2333 s->pIoApicHlpR0 = s->pIoApicHlpR3->pfnGetR0Helpers(pDevIns);
2334 }
2335#endif
2336}
2337
2338#endif /* IN_RING3 */
2339
2340#ifndef VBOX
2341static CPUReadMemoryFunc *ioapic_mem_read[3] = {
2342 ioapic_mem_readl,
2343 ioapic_mem_readl,
2344 ioapic_mem_readl,
2345};
2346
2347static CPUWriteMemoryFunc *ioapic_mem_write[3] = {
2348 ioapic_mem_writel,
2349 ioapic_mem_writel,
2350 ioapic_mem_writel,
2351};
2352
2353IOAPICState *ioapic_init(void)
2354{
2355 IOAPICState *s;
2356 int io_memory;
2357
2358 s = qemu_mallocz(sizeof(IOAPICState));
2359 if (!s)
2360 return NULL;
2361 ioapic_reset(s);
2362 s->id = last_apic_id++;
2363
2364 io_memory = cpu_register_io_memory(0, ioapic_mem_read,
2365 ioapic_mem_write, s);
2366 cpu_register_physical_memory(0xfec00000, 0x1000, io_memory);
2367
2368 register_savevm("ioapic", 0, 1, ioapic_save, ioapic_load, s);
2369 qemu_register_reset(ioapic_reset, s);
2370
2371 return s;
2372}
2373#endif /* !VBOX */
2374
2375/* LAPIC */
2376PDMBOTHCBDECL(int) apicMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
2377{
2378 APICDeviceInfo *dev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2379 APICState *s = getLapic(dev);
2380
2381 Log(("CPU%d: apicMMIORead at %llx\n", s->phys_id, (uint64_t)GCPhysAddr));
2382
2383 /** @todo: add LAPIC range validity checks (different LAPICs can theoretically have
2384 different physical addresses, see #3092) */
2385
2386 STAM_COUNTER_INC(&CTXSUFF(dev->StatMMIORead));
2387 switch (cb)
2388 {
2389 case 1:
2390 *(uint8_t *)pv = 0;
2391 break;
2392
2393 case 2:
2394 *(uint16_t *)pv = 0;
2395 break;
2396
2397 case 4:
2398 {
2399#if 0 /** @note experimental */
2400#ifndef IN_RING3
2401 uint32_t index = (GCPhysAddr >> 4) & 0xff;
2402
2403 if ( index == 0x08 /* TPR */
2404 && ++s->cTPRPatchAttempts < APIC_MAX_PATCH_ATTEMPTS)
2405 {
2406#ifdef IN_RC
2407 pDevIns->pDevHlpGC->pfnPATMSetMMIOPatchInfo(pDevIns, GCPhysAddr, &s->tpr);
2408#else
2409 RTGCPTR pDevInsGC = PDMINS2DATA_GCPTR(pDevIns);
2410 pDevIns->pDevHlpR0->pfnPATMSetMMIOPatchInfo(pDevIns, GCPhysAddr, pDevIns + RT_OFFSETOF(APICState, tpr));
2411#endif
2412 return VINF_PATM_HC_MMIO_PATCH_READ;
2413 }
2414#endif
2415#endif /* experimental */
2416 APIC_LOCK(dev, VINF_IOM_HC_MMIO_READ);
2417 *(uint32_t *)pv = apic_mem_readl(dev, s, GCPhysAddr);
2418 APIC_UNLOCK(dev);
2419 break;
2420 }
2421 default:
2422 AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */
2423 return VERR_INTERNAL_ERROR;
2424 }
2425 return VINF_SUCCESS;
2426}
2427
2428PDMBOTHCBDECL(int) apicMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
2429{
2430 APICDeviceInfo *dev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2431 APICState *s = getLapic(dev);
2432
2433 Log(("CPU%d: apicMMIOWrite at %llx\n", s->phys_id, (uint64_t)GCPhysAddr));
2434
2435 /** @todo: add LAPIC range validity checks (multiple LAPICs can theoretically have
2436 different physical addresses, see #3092) */
2437
2438 STAM_COUNTER_INC(&CTXSUFF(dev->StatMMIOWrite));
2439 switch (cb)
2440 {
2441 case 1:
2442 case 2:
2443 /* ignore */
2444 break;
2445
2446 case 4:
2447 {
2448 int rc;
2449 APIC_LOCK(dev, VINF_IOM_HC_MMIO_WRITE);
2450 rc = apic_mem_writel(dev, s, GCPhysAddr, *(uint32_t *)pv);
2451 APIC_UNLOCK(dev);
2452 return rc;
2453 }
2454
2455 default:
2456 AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */
2457 return VERR_INTERNAL_ERROR;
2458 }
2459 return VINF_SUCCESS;
2460}
2461
2462#ifdef IN_RING3
2463
2464/* Print a 8-dword LAPIC bit map (256 bits). */
2465static void lapicDumpVec(APICDeviceInfo *dev, APICState *lapic, PCDBGFINFOHLP pHlp, unsigned start)
2466{
2467 unsigned i;
2468 uint32_t val;
2469
2470 for (i = 0; i < 8; ++i)
2471 {
2472 val = apic_mem_readl(dev, lapic, start + (i << 4));
2473 pHlp->pfnPrintf(pHlp, "%08X", val);
2474 }
2475 pHlp->pfnPrintf(pHlp, "\n");
2476}
2477
2478/* Print basic LAPIC state. */
2479static DECLCALLBACK(void) lapicInfoBasic(APICDeviceInfo *dev, APICState *lapic, PCDBGFINFOHLP pHlp)
2480{
2481 uint32_t val;
2482 unsigned max_lvt;
2483
2484 pHlp->pfnPrintf(pHlp, "Local APIC at %08X:\n", lapic->apicbase);
2485 val = apic_mem_readl(dev, lapic, 0x20);
2486 pHlp->pfnPrintf(pHlp, " LAPIC ID : %08X\n", val);
2487 pHlp->pfnPrintf(pHlp, " APIC ID = %02X\n", (val >> 24) & 0xff);
2488 val = apic_mem_readl(dev, lapic, 0x30);
2489 max_lvt = (val >> 16) & 0xff;
2490 pHlp->pfnPrintf(pHlp, " APIC VER : %08X\n", val);
2491 pHlp->pfnPrintf(pHlp, " version = %02X\n", val & 0xff);
2492 pHlp->pfnPrintf(pHlp, " lvts = %d\n", ((val >> 16) & 0xff) + 1);
2493 val = apic_mem_readl(dev, lapic, 0x80);
2494 pHlp->pfnPrintf(pHlp, " TPR : %08X\n", val);
2495 pHlp->pfnPrintf(pHlp, " task pri = %d/%d\n", (val >> 4) & 0xf, val & 0xf);
2496 val = apic_mem_readl(dev, lapic, 0xA0);
2497 pHlp->pfnPrintf(pHlp, " PPR : %08X\n", val);
2498 pHlp->pfnPrintf(pHlp, " cpu pri = %d/%d\n", (val >> 4) & 0xf, val & 0xf);
2499 val = apic_mem_readl(dev, lapic, 0xD0);
2500 pHlp->pfnPrintf(pHlp, " LDR : %08X\n", val);
2501 pHlp->pfnPrintf(pHlp, " log id = %02X\n", (val >> 24) & 0xff);
2502 val = apic_mem_readl(dev, lapic, 0xE0);
2503 pHlp->pfnPrintf(pHlp, " DFR : %08X\n", val);
2504 val = apic_mem_readl(dev, lapic, 0xF0);
2505 pHlp->pfnPrintf(pHlp, " SVR : %08X\n", val);
2506 pHlp->pfnPrintf(pHlp, " focus = %s\n", val & (1 << 9) ? "check off" : "check on");
2507 pHlp->pfnPrintf(pHlp, " lapic = %s\n", val & (1 << 8) ? "ENABLED" : "DISABLED");
2508 pHlp->pfnPrintf(pHlp, " vector = %02X\n", val & 0xff);
2509 pHlp->pfnPrintf(pHlp, " ISR : ");
2510 lapicDumpVec(dev, lapic, pHlp, 0x100);
2511 val = get_highest_priority_int(lapic->isr);
2512 pHlp->pfnPrintf(pHlp, " highest = %02X\n", val == ~0U ? 0 : val);
2513 pHlp->pfnPrintf(pHlp, " IRR : ");
2514 lapicDumpVec(dev, lapic, pHlp, 0x200);
2515 val = get_highest_priority_int(lapic->irr);
2516 pHlp->pfnPrintf(pHlp, " highest = %02X\n", val == ~0U ? 0 : val);
2517 val = apic_mem_readl(dev, lapic, 0x320);
2518}
2519
2520/* Print the more interesting LAPIC LVT entries. */
2521static DECLCALLBACK(void) lapicInfoLVT(APICDeviceInfo *dev, APICState *lapic, PCDBGFINFOHLP pHlp)
2522{
2523 uint32_t val;
2524 static const char *dmodes[] = { "Fixed ", "Reserved", "SMI", "Reserved",
2525 "NMI", "INIT", "Reserved", "ExtINT" };
2526
2527 val = apic_mem_readl(dev, lapic, 0x320);
2528 pHlp->pfnPrintf(pHlp, " LVT Timer : %08X\n", val);
2529 pHlp->pfnPrintf(pHlp, " mode = %s\n", val & (1 << 17) ? "periodic" : "one-shot");
2530 pHlp->pfnPrintf(pHlp, " mask = %d\n", (val >> 16) & 1);
2531 pHlp->pfnPrintf(pHlp, " status = %s\n", val & (1 << 12) ? "pending" : "idle");
2532 pHlp->pfnPrintf(pHlp, " vector = %02X\n", val & 0xff);
2533 val = apic_mem_readl(dev, lapic, 0x350);
2534 pHlp->pfnPrintf(pHlp, " LVT LINT0 : %08X\n", val);
2535 pHlp->pfnPrintf(pHlp, " mask = %d\n", (val >> 16) & 1);
2536 pHlp->pfnPrintf(pHlp, " trigger = %s\n", val & (1 << 15) ? "level" : "edge");
2537 pHlp->pfnPrintf(pHlp, " rem irr = %d\n", (val >> 14) & 1);
2538 pHlp->pfnPrintf(pHlp, " polarty = %d\n", (val >> 13) & 1);
2539 pHlp->pfnPrintf(pHlp, " status = %s\n", val & (1 << 12) ? "pending" : "idle");
2540 pHlp->pfnPrintf(pHlp, " delivry = %s\n", dmodes[(val >> 8) & 7]);
2541 pHlp->pfnPrintf(pHlp, " vector = %02X\n", val & 0xff);
2542 val = apic_mem_readl(dev, lapic, 0x360);
2543 pHlp->pfnPrintf(pHlp, " LVT LINT1 : %08X\n", val);
2544 pHlp->pfnPrintf(pHlp, " mask = %d\n", (val >> 16) & 1);
2545 pHlp->pfnPrintf(pHlp, " trigger = %s\n", val & (1 << 15) ? "level" : "edge");
2546 pHlp->pfnPrintf(pHlp, " rem irr = %d\n", (val >> 14) & 1);
2547 pHlp->pfnPrintf(pHlp, " polarty = %d\n", (val >> 13) & 1);
2548 pHlp->pfnPrintf(pHlp, " status = %s\n", val & (1 << 12) ? "pending" : "idle");
2549 pHlp->pfnPrintf(pHlp, " delivry = %s\n", dmodes[(val >> 8) & 7]);
2550 pHlp->pfnPrintf(pHlp, " vector = %02X\n", val & 0xff);
2551}
2552
2553/* Print LAPIC timer state. */
2554static DECLCALLBACK(void) lapicInfoTimer(APICDeviceInfo *dev, APICState *lapic, PCDBGFINFOHLP pHlp)
2555{
2556 uint32_t val;
2557 unsigned divider;
2558
2559 pHlp->pfnPrintf(pHlp, "Local APIC timer:\n");
2560 val = apic_mem_readl(dev, lapic, 0x380);
2561 pHlp->pfnPrintf(pHlp, " Initial count : %08X\n", val);
2562 val = apic_mem_readl(dev, lapic, 0x390);
2563 pHlp->pfnPrintf(pHlp, " Current count : %08X\n", val);
2564 val = apic_mem_readl(dev, lapic, 0x3E0);
2565 pHlp->pfnPrintf(pHlp, " Divide config : %08X\n", val);
2566 divider = ((val >> 1) & 0x04) | (val & 0x03);
2567 pHlp->pfnPrintf(pHlp, " divider = %d\n", divider == 7 ? 1 : 2 << divider);
2568}
2569
2570/**
2571 * Info handler, device version. Dumps Local APIC(s) state according to given argument.
2572 *
2573 * @param pDevIns Device instance which registered the info.
2574 * @param pHlp Callback functions for doing output.
2575 * @param pszArgs Argument string. Optional.
2576 */
2577static DECLCALLBACK(void) lapicInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
2578{
2579 APICDeviceInfo *dev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2580 APICState *lapic;
2581
2582 lapic = getLapic(dev);
2583
2584 if (pszArgs == NULL || !strcmp(pszArgs, "basic"))
2585 {
2586 lapicInfoBasic(dev, lapic, pHlp);
2587 }
2588 else if (!strcmp(pszArgs, "lvt"))
2589 {
2590 lapicInfoLVT(dev, lapic, pHlp);
2591 }
2592 else if (!strcmp(pszArgs, "timer"))
2593 {
2594 lapicInfoTimer(dev, lapic, pHlp);
2595 }
2596 else
2597 {
2598 pHlp->pfnPrintf(pHlp, "Invalid argument. Recognized arguments are 'basic', 'lvt', 'timer'.\n");
2599 }
2600}
2601
2602/**
2603 * @copydoc FNSSMDEVLIVEEXEC
2604 */
2605static DECLCALLBACK(int) apicLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
2606{
2607 APICDeviceInfo *pThis = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2608
2609 SSMR3PutU32( pSSM, pThis->cCpus);
2610 SSMR3PutBool(pSSM, pThis->fIoApic);
2611 SSMR3PutU32( pSSM, pThis->enmVersion);
2612 AssertCompile(PDMAPICVERSION_APIC == 2);
2613
2614 return VINF_SSM_DONT_CALL_AGAIN;
2615}
2616
2617/**
2618 * @copydoc FNSSMDEVSAVEEXEC
2619 */
2620static DECLCALLBACK(int) apicSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
2621{
2622 APICDeviceInfo *dev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2623
2624 /* config */
2625 apicLiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
2626
2627 /* save all APICs data, @todo: is it correct? */
2628 foreach_apic(dev, 0xffffffff, apic_save(pSSM, apic));
2629
2630 return VINF_SUCCESS;
2631}
2632
2633/**
2634 * @copydoc FNSSMDEVLOADEXEC
2635 */
2636static DECLCALLBACK(int) apicLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
2637{
2638 APICDeviceInfo *pThis = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2639
2640 if ( uVersion != APIC_SAVED_STATE_VERSION
2641 && uVersion != APIC_SAVED_STATE_VERSION_VBOX_30
2642 && uVersion != APIC_SAVED_STATE_VERSION_ANCIENT)
2643 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
2644
2645 /* config */
2646 if (uVersion > APIC_SAVED_STATE_VERSION_VBOX_30) {
2647 uint32_t cCpus;
2648 int rc = SSMR3GetU32(pSSM, &cCpus); AssertRCReturn(rc, rc);
2649 if (cCpus != pThis->cCpus)
2650 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - cCpus: saved=%#x config=%#x"), cCpus, pThis->cCpus);
2651 bool fIoApic;
2652 rc = SSMR3GetBool(pSSM, &fIoApic); AssertRCReturn(rc, rc);
2653 if (fIoApic != pThis->fIoApic)
2654 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - fIoApic: saved=%RTbool config=%RTbool"), fIoApic, pThis->fIoApic);
2655 uint32_t uApicVersion;
2656 rc = SSMR3GetU32(pSSM, &uApicVersion); AssertRCReturn(rc, rc);
2657 if (uApicVersion != (uint32_t)pThis->enmVersion)
2658 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - uApicVersion: saved=%#x config=%#x"), uApicVersion, pThis->enmVersion);
2659 }
2660
2661 if (uPass != SSM_PASS_FINAL)
2662 return VINF_SUCCESS;
2663
2664 /* load all APICs data */ /** @todo: is it correct? */
2665 foreach_apic(pThis, 0xffffffff,
2666 if (apic_load(pSSM, apic, uVersion)) {
2667 AssertFailed();
2668 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
2669 }
2670 );
2671 return VINF_SUCCESS;
2672}
2673
2674/**
2675 * @copydoc FNPDMDEVRESET
2676 */
2677static DECLCALLBACK(void) apicReset(PPDMDEVINS pDevIns)
2678{
2679 APICDeviceInfo *dev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2680 unsigned i;
2681
2682 APIC_LOCK_VOID(dev, VERR_INTERNAL_ERROR);
2683
2684 /* Reset all APICs. */
2685 for (i = 0; i < dev->cCpus; i++) {
2686 APICState *pApic = &dev->CTX_SUFF(paLapics)[i];
2687 TMTimerStop(pApic->CTX_SUFF(pTimer));
2688
2689 /* Clear LAPIC state as if an INIT IPI was sent. */
2690 apic_init_ipi(dev, pApic);
2691 /* The IDs are not touched by apic_init_ipi() and must be reset now. */
2692 pApic->arb_id = pApic->id = i;
2693 Assert(pApic->id == pApic->phys_id); /* The two should match again. */
2694 /* Reset should re-enable the APIC. */
2695 pApic->apicbase = 0xfee00000 | MSR_IA32_APICBASE_ENABLE;
2696 if (pApic->phys_id == 0)
2697 pApic->apicbase |= MSR_IA32_APICBASE_BSP;
2698
2699 /* Clear any pending APIC interrupt action flag. */
2700 cpuClearInterrupt(dev, pApic);
2701 }
2702 /** @todo r=bird: Why is this done everytime, while the constructor first
2703 * checks the CPUID? Who is right? */
2704 dev->pApicHlpR3->pfnChangeFeature(dev->pDevInsR3, dev->enmVersion);
2705
2706 APIC_UNLOCK(dev);
2707}
2708
2709/**
2710 * @copydoc FNPDMDEVRELOCATE
2711 */
2712static DECLCALLBACK(void) apicRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
2713{
2714 APICDeviceInfo *pThis = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2715 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2716 pThis->pApicHlpRC = pThis->pApicHlpR3->pfnGetRCHelpers(pDevIns);
2717 pThis->paLapicsRC = MMHyperR3ToRC(PDMDevHlpGetVM(pDevIns), pThis->paLapicsR3);
2718 pThis->pCritSectRC = pThis->pApicHlpR3->pfnGetRCCritSect(pDevIns);
2719 for (uint32_t i = 0; i < pThis->cCpus; i++)
2720 pThis->paLapicsR3[i].pTimerRC = TMTimerRCPtr(pThis->paLapicsR3[i].pTimerR3);
2721}
2722
2723DECLINLINE(void) initApicData(APICState* apic, uint8_t id)
2724{
2725 int i;
2726 memset(apic, 0, sizeof(*apic));
2727 apic->apicbase = UINT32_C(0xfee00000) | MSR_IA32_APICBASE_ENABLE;
2728 /* Mark first CPU as BSP */
2729 if (id == 0)
2730 apic->apicbase |= MSR_IA32_APICBASE_BSP;
2731 for (i = 0; i < APIC_LVT_NB; i++)
2732 apic->lvt[i] = 1 << 16; /* mask LVT */
2733 apic->spurious_vec = 0xff;
2734 apic->phys_id = apic->id = id;
2735}
2736
2737/**
2738 * @copydoc FNPDMDEVCONSTRUCT
2739 */
2740static DECLCALLBACK(int) apicConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
2741{
2742 PDMAPICREG ApicReg;
2743 int rc;
2744 uint32_t i;
2745 bool fIoApic;
2746 bool fGCEnabled;
2747 bool fR0Enabled;
2748 APICDeviceInfo *pThis = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2749 uint32_t cCpus;
2750
2751 /*
2752 * Only single device instance.
2753 */
2754 Assert(iInstance == 0);
2755
2756 /*
2757 * Validate configuration.
2758 */
2759 if (!CFGMR3AreValuesValid(pCfgHandle,
2760 "IOAPIC\0"
2761 "GCEnabled\0"
2762 "R0Enabled\0"
2763 "NumCPUs\0"))
2764 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
2765
2766 rc = CFGMR3QueryBoolDef(pCfgHandle, "IOAPIC", &fIoApic, true);
2767 if (RT_FAILURE(rc))
2768 return PDMDEV_SET_ERROR(pDevIns, rc,
2769 N_("Configuration error: Failed to read \"IOAPIC\""));
2770
2771 rc = CFGMR3QueryBoolDef(pCfgHandle, "GCEnabled", &fGCEnabled, true);
2772 if (RT_FAILURE(rc))
2773 return PDMDEV_SET_ERROR(pDevIns, rc,
2774 N_("Configuration error: Failed to query boolean value \"GCEnabled\""));
2775
2776 rc = CFGMR3QueryBoolDef(pCfgHandle, "R0Enabled", &fR0Enabled, true);
2777 if (RT_FAILURE(rc))
2778 return PDMDEV_SET_ERROR(pDevIns, rc,
2779 N_("Configuration error: Failed to query boolean value \"R0Enabled\""));
2780
2781 rc = CFGMR3QueryU32Def(pCfgHandle, "NumCPUs", &cCpus, 1);
2782 if (RT_FAILURE(rc))
2783 return PDMDEV_SET_ERROR(pDevIns, rc,
2784 N_("Configuration error: Failed to query integer value \"NumCPUs\""));
2785
2786 Log(("APIC: cCpus=%d fR0Enabled=%RTbool fGCEnabled=%RTbool fIoApic=%RTbool\n", cCpus, fR0Enabled, fGCEnabled, fIoApic));
2787
2788 /** @todo Current implementation is limited to 32 CPUs due to the use of 32
2789 * bits bitmasks. */
2790 if (cCpus > 32)
2791 return PDMDEV_SET_ERROR(pDevIns, rc,
2792 N_("Configuration error: Invalid value for \"NumCPUs\""));
2793
2794 /*
2795 * Init the data.
2796 */
2797 pThis->pDevInsR3 = pDevIns;
2798 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
2799 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2800 pThis->cCpus = cCpus;
2801 pThis->fIoApic = fIoApic;
2802 /* Use PDMAPICVERSION_X2APIC to activate x2APIC mode */
2803 pThis->enmVersion = PDMAPICVERSION_APIC;
2804
2805 PVM pVM = PDMDevHlpGetVM(pDevIns);
2806 /*
2807 * We are not freeing this memory, as it's automatically released when guest exits.
2808 */
2809 rc = MMHyperAlloc(pVM, cCpus * sizeof(APICState), 1, MM_TAG_PDM_DEVICE_USER, (void **)&pThis->paLapicsR3);
2810 if (RT_FAILURE(rc))
2811 return VERR_NO_MEMORY;
2812 pThis->paLapicsR0 = MMHyperR3ToR0(pVM, pThis->paLapicsR3);
2813 pThis->paLapicsRC = MMHyperR3ToRC(pVM, pThis->paLapicsR3);
2814
2815 for (i = 0; i < cCpus; i++)
2816 initApicData(&pThis->paLapicsR3[i], i);
2817
2818 /*
2819 * Register the APIC.
2820 */
2821 ApicReg.u32Version = PDM_APICREG_VERSION;
2822 ApicReg.pfnGetInterruptR3 = apicGetInterrupt;
2823 ApicReg.pfnHasPendingIrqR3 = apicHasPendingIrq;
2824 ApicReg.pfnSetBaseR3 = apicSetBase;
2825 ApicReg.pfnGetBaseR3 = apicGetBase;
2826 ApicReg.pfnSetTPRR3 = apicSetTPR;
2827 ApicReg.pfnGetTPRR3 = apicGetTPR;
2828 ApicReg.pfnWriteMSRR3 = apicWriteMSR;
2829 ApicReg.pfnReadMSRR3 = apicReadMSR;
2830 ApicReg.pfnBusDeliverR3 = apicBusDeliverCallback;
2831 ApicReg.pfnLocalInterruptR3 = apicLocalInterrupt;
2832 if (fGCEnabled) {
2833 ApicReg.pszGetInterruptRC = "apicGetInterrupt";
2834 ApicReg.pszHasPendingIrqRC = "apicHasPendingIrq";
2835 ApicReg.pszSetBaseRC = "apicSetBase";
2836 ApicReg.pszGetBaseRC = "apicGetBase";
2837 ApicReg.pszSetTPRRC = "apicSetTPR";
2838 ApicReg.pszGetTPRRC = "apicGetTPR";
2839 ApicReg.pszWriteMSRRC = "apicWriteMSR";
2840 ApicReg.pszReadMSRRC = "apicReadMSR";
2841 ApicReg.pszBusDeliverRC = "apicBusDeliverCallback";
2842 ApicReg.pszLocalInterruptRC = "apicLocalInterrupt";
2843 } else {
2844 ApicReg.pszGetInterruptRC = NULL;
2845 ApicReg.pszHasPendingIrqRC = NULL;
2846 ApicReg.pszSetBaseRC = NULL;
2847 ApicReg.pszGetBaseRC = NULL;
2848 ApicReg.pszSetTPRRC = NULL;
2849 ApicReg.pszGetTPRRC = NULL;
2850 ApicReg.pszWriteMSRRC = NULL;
2851 ApicReg.pszReadMSRRC = NULL;
2852 ApicReg.pszBusDeliverRC = NULL;
2853 ApicReg.pszLocalInterruptRC = NULL;
2854 }
2855 if (fR0Enabled) {
2856 ApicReg.pszGetInterruptR0 = "apicGetInterrupt";
2857 ApicReg.pszHasPendingIrqR0 = "apicHasPendingIrq";
2858 ApicReg.pszSetBaseR0 = "apicSetBase";
2859 ApicReg.pszGetBaseR0 = "apicGetBase";
2860 ApicReg.pszSetTPRR0 = "apicSetTPR";
2861 ApicReg.pszGetTPRR0 = "apicGetTPR";
2862 ApicReg.pszWriteMSRR0 = "apicWriteMSR";
2863 ApicReg.pszReadMSRR0 = "apicReadMSR";
2864 ApicReg.pszBusDeliverR0 = "apicBusDeliverCallback";
2865 ApicReg.pszLocalInterruptR0 = "apicLocalInterrupt";
2866 } else {
2867 ApicReg.pszGetInterruptR0 = NULL;
2868 ApicReg.pszHasPendingIrqR0 = NULL;
2869 ApicReg.pszSetBaseR0 = NULL;
2870 ApicReg.pszGetBaseR0 = NULL;
2871 ApicReg.pszSetTPRR0 = NULL;
2872 ApicReg.pszGetTPRR0 = NULL;
2873 ApicReg.pszWriteMSRR0 = NULL;
2874 ApicReg.pszReadMSRR0 = NULL;
2875 ApicReg.pszBusDeliverR0 = NULL;
2876 ApicReg.pszLocalInterruptR0 = NULL;
2877 }
2878
2879 Assert(pDevIns->pDevHlpR3->pfnAPICRegister);
2880 rc = pDevIns->pDevHlpR3->pfnAPICRegister(pDevIns, &ApicReg, &pThis->pApicHlpR3);
2881 AssertLogRelRCReturn(rc, rc);
2882 pThis->pCritSectR3 = pThis->pApicHlpR3->pfnGetR3CritSect(pDevIns);
2883
2884 /*
2885 * The the CPUID feature bit.
2886 */
2887 /** @todo r=bird: See remark in the apicReset. */
2888 uint32_t u32Eax, u32Ebx, u32Ecx, u32Edx;
2889 PDMDevHlpGetCpuId(pDevIns, 0, &u32Eax, &u32Ebx, &u32Ecx, &u32Edx);
2890 if (u32Eax >= 1) {
2891 if ( fIoApic /* If IOAPIC is enabled, enable Local APIC in any case */
2892 || ( u32Ebx == X86_CPUID_VENDOR_INTEL_EBX
2893 && u32Ecx == X86_CPUID_VENDOR_INTEL_ECX
2894 && u32Edx == X86_CPUID_VENDOR_INTEL_EDX /* GenuineIntel */)
2895 || ( u32Ebx == X86_CPUID_VENDOR_AMD_EBX
2896 && u32Ecx == X86_CPUID_VENDOR_AMD_ECX
2897 && u32Edx == X86_CPUID_VENDOR_AMD_EDX /* AuthenticAMD */)) {
2898 LogRel(("Activating Local APIC\n"));
2899 pThis->pApicHlpR3->pfnChangeFeature(pDevIns, pThis->enmVersion);
2900 }
2901 }
2902
2903 /*
2904 * Register the MMIO range.
2905 */
2906 uint32_t ApicBase = pThis->paLapicsR3[0].apicbase & ~0xfff;
2907 rc = PDMDevHlpMMIORegister(pDevIns, ApicBase, 0x1000, pThis,
2908 apicMMIOWrite, apicMMIORead, NULL, "APIC Memory");
2909 if (RT_FAILURE(rc))
2910 return rc;
2911
2912 if (fGCEnabled) {
2913 pThis->pApicHlpRC = pThis->pApicHlpR3->pfnGetRCHelpers(pDevIns);
2914 pThis->pCritSectRC = pThis->pApicHlpR3->pfnGetRCCritSect(pDevIns);
2915
2916 rc = PDMDevHlpMMIORegisterGC(pDevIns, ApicBase, 0x1000, 0,
2917 "apicMMIOWrite", "apicMMIORead", NULL);
2918 if (RT_FAILURE(rc))
2919 return rc;
2920 }
2921
2922 if (fR0Enabled) {
2923 pThis->pApicHlpR0 = pThis->pApicHlpR3->pfnGetR0Helpers(pDevIns);
2924 pThis->pCritSectR0 = pThis->pApicHlpR3->pfnGetR0CritSect(pDevIns);
2925
2926 rc = PDMDevHlpMMIORegisterR0(pDevIns, ApicBase, 0x1000, 0,
2927 "apicMMIOWrite", "apicMMIORead", NULL);
2928 if (RT_FAILURE(rc))
2929 return rc;
2930 }
2931
2932 /*
2933 * Create the APIC timers.
2934 */
2935 for (i = 0; i < cCpus; i++) {
2936 APICState *pApic = &pThis->paLapicsR3[i];
2937 pApic->pszDesc = MMR3HeapAPrintf(pVM, MM_TAG_PDM_DEVICE_USER, "APIC Timer #%u", i);
2938 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, apicTimerCallback, pApic,
2939 TMTIMER_FLAGS_NO_CRIT_SECT, pApic->pszDesc, &pApic->pTimerR3);
2940 if (RT_FAILURE(rc))
2941 return rc;
2942 pApic->pTimerR0 = TMTimerR0Ptr(pApic->pTimerR3);
2943 pApic->pTimerRC = TMTimerRCPtr(pApic->pTimerR3);
2944 TMR3TimerSetCritSect(pApic->pTimerR3, pThis->pCritSectR3);
2945 }
2946
2947 /*
2948 * Saved state.
2949 */
2950 rc = PDMDevHlpSSMRegister3(pDevIns, APIC_SAVED_STATE_VERSION, sizeof(*pThis),
2951 apicLiveExec, apicSaveExec, apicLoadExec);
2952 if (RT_FAILURE(rc))
2953 return rc;
2954
2955 /*
2956 * Register debugger info callback.
2957 */
2958 PDMDevHlpDBGFInfoRegister(pDevIns, "lapic", "Display Local APIC state for current CPU. "
2959 "Recognizes 'basic', 'lvt', 'timer' as arguments, defaulting to 'basic'.", lapicInfo);
2960
2961#ifdef VBOX_WITH_STATISTICS
2962 /*
2963 * Statistics.
2964 */
2965 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatMMIOReadGC, STAMTYPE_COUNTER, "/Devices/APIC/MMIOReadGC", STAMUNIT_OCCURENCES, "Number of APIC MMIO reads in GC.");
2966 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatMMIOReadHC, STAMTYPE_COUNTER, "/Devices/APIC/MMIOReadHC", STAMUNIT_OCCURENCES, "Number of APIC MMIO reads in HC.");
2967 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatMMIOWriteGC, STAMTYPE_COUNTER, "/Devices/APIC/MMIOWriteGC", STAMUNIT_OCCURENCES, "Number of APIC MMIO writes in GC.");
2968 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatMMIOWriteHC, STAMTYPE_COUNTER, "/Devices/APIC/MMIOWriteHC", STAMUNIT_OCCURENCES, "Number of APIC MMIO writes in HC.");
2969 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatClearedActiveIrq,STAMTYPE_COUNTER, "/Devices/APIC/MaskedActiveIRQ", STAMUNIT_OCCURENCES, "Number of cleared irqs.");
2970 for (i = 0; i < cCpus; i++) {
2971 APICState *pApic = &pThis->paLapicsR3[i];
2972 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetInitialCount, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Calls to apicTimerSetInitialCount.", "/Devices/APIC/%u/TimerSetInitialCount", i);
2973 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetInitialCountArm, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerSetRelative calls.", "/Devices/APIC/%u/TimerSetInitialCount/Arm", i);
2974 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetInitialCountDisarm, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerStop calls.", "/Devices/APIC/%u/TimerSetInitialCount/Disasm", i);
2975 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvt, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Calls to apicTimerSetLvt.", "/Devices/APIC/%u/TimerSetLvt", i);
2976 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtClearPeriodic, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Clearing APIC_LVT_TIMER_PERIODIC.", "/Devices/APIC/%u/TimerSetLvt/ClearPeriodic", i);
2977 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtPostponed, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerStop postponed.", "/Devices/APIC/%u/TimerSetLvt/Postponed", i);
2978 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtArmed, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerSet avoided.", "/Devices/APIC/%u/TimerSetLvt/Armed", i);
2979 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtArm, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerSet necessary.", "/Devices/APIC/%u/TimerSetLvt/Arm", i);
2980 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtArmRetries, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerSet retries.", "/Devices/APIC/%u/TimerSetLvt/ArmRetries", i);
2981 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtNoRelevantChange,STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "No relevant flags changed.", "/Devices/APIC/%u/TimerSetLvt/NoRelevantChange", i);
2982 }
2983#endif
2984
2985 return VINF_SUCCESS;
2986}
2987
2988
2989/**
2990 * APIC device registration structure.
2991 */
2992const PDMDEVREG g_DeviceAPIC =
2993{
2994 /* u32Version */
2995 PDM_DEVREG_VERSION,
2996 /* szDeviceName */
2997 "apic",
2998 /* szRCMod */
2999 "VBoxDD2GC.gc",
3000 /* szR0Mod */
3001 "VBoxDD2R0.r0",
3002 /* pszDescription */
3003 "Advanced Programmable Interrupt Controller (APIC) Device",
3004 /* fFlags */
3005 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,
3006 /* fClass */
3007 PDM_DEVREG_CLASS_PIC,
3008 /* cMaxInstances */
3009 1,
3010 /* cbInstance */
3011 sizeof(APICState),
3012 /* pfnConstruct */
3013 apicConstruct,
3014 /* pfnDestruct */
3015 NULL,
3016 /* pfnRelocate */
3017 apicRelocate,
3018 /* pfnIOCtl */
3019 NULL,
3020 /* pfnPowerOn */
3021 NULL,
3022 /* pfnReset */
3023 apicReset,
3024 /* pfnSuspend */
3025 NULL,
3026 /* pfnResume */
3027 NULL,
3028 /* pfnAttach */
3029 NULL,
3030 /* pfnDetach */
3031 NULL,
3032 /* pfnQueryInterface. */
3033 NULL,
3034 /* pfnInitComplete */
3035 NULL,
3036 /* pfnPowerOff */
3037 NULL,
3038 /* pfnSoftReset */
3039 NULL,
3040 /* u32VersionEnd */
3041 PDM_DEVREG_VERSION
3042};
3043
3044#endif /* IN_RING3 */
3045
3046
3047/* IOAPIC */
3048
3049PDMBOTHCBDECL(int) ioapicMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
3050{
3051 IOAPICState *s = PDMINS_2_DATA(pDevIns, IOAPICState *);
3052 IOAPIC_LOCK(s, VINF_IOM_HC_MMIO_READ);
3053
3054 STAM_COUNTER_INC(&CTXSUFF(s->StatMMIORead));
3055 switch (cb) {
3056 case 1:
3057 *(uint8_t *)pv = ioapic_mem_readl(s, GCPhysAddr);
3058 break;
3059
3060 case 2:
3061 *(uint16_t *)pv = ioapic_mem_readl(s, GCPhysAddr);
3062 break;
3063
3064 case 4:
3065 *(uint32_t *)pv = ioapic_mem_readl(s, GCPhysAddr);
3066 break;
3067
3068 default:
3069 AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */
3070 IOAPIC_UNLOCK(s);
3071 return VERR_INTERNAL_ERROR;
3072 }
3073 IOAPIC_UNLOCK(s);
3074 return VINF_SUCCESS;
3075}
3076
3077PDMBOTHCBDECL(int) ioapicMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
3078{
3079 IOAPICState *s = PDMINS_2_DATA(pDevIns, IOAPICState *);
3080
3081 STAM_COUNTER_INC(&CTXSUFF(s->StatMMIOWrite));
3082 switch (cb) {
3083 case 1:
3084 case 2:
3085 case 4:
3086 IOAPIC_LOCK(s, VINF_IOM_HC_MMIO_WRITE);
3087 ioapic_mem_writel(s, GCPhysAddr, *(uint32_t *)pv);
3088 IOAPIC_UNLOCK(s);
3089 break;
3090
3091 default:
3092 AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */
3093 return VERR_INTERNAL_ERROR;
3094 }
3095 return VINF_SUCCESS;
3096}
3097
3098PDMBOTHCBDECL(void) ioapicSetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel)
3099{
3100 /* PDM lock is taken here; @todo add assertion */
3101 IOAPICState *pThis = PDMINS_2_DATA(pDevIns, IOAPICState *);
3102 STAM_COUNTER_INC(&pThis->CTXSUFF(StatSetIrq));
3103 LogFlow(("ioapicSetIrq: iIrq=%d iLevel=%d\n", iIrq, iLevel));
3104 ioapic_set_irq(pThis, iIrq, iLevel);
3105}
3106
3107
3108#ifdef IN_RING3
3109
3110/**
3111 * Info handler, device version. Dumps I/O APIC state.
3112 *
3113 * @param pDevIns Device instance which registered the info.
3114 * @param pHlp Callback functions for doing output.
3115 * @param pszArgs Argument string. Optional and specific to the handler.
3116 */
3117static DECLCALLBACK(void) ioapicInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
3118{
3119 IOAPICState *s = PDMINS_2_DATA(pDevIns, IOAPICState *);
3120 uint32_t val;
3121 unsigned i;
3122 unsigned max_redir;
3123
3124 pHlp->pfnPrintf(pHlp, "I/O APIC at %08X:\n", 0xfec00000);
3125 val = s->id << 24; /* Would be nice to call ioapic_mem_readl() directly, but that's not so simple. */
3126 pHlp->pfnPrintf(pHlp, " IOAPICID : %08X\n", val);
3127 pHlp->pfnPrintf(pHlp, " APIC ID = %02X\n", (val >> 24) & 0xff);
3128 val = 0x11 | ((IOAPIC_NUM_PINS - 1) << 16);
3129 max_redir = (val >> 16) & 0xff;
3130 pHlp->pfnPrintf(pHlp, " IOAPICVER : %08X\n", val);
3131 pHlp->pfnPrintf(pHlp, " version = %02X\n", val & 0xff);
3132 pHlp->pfnPrintf(pHlp, " redirs = %d\n", ((val >> 16) & 0xff) + 1);
3133 val = 0;
3134 pHlp->pfnPrintf(pHlp, " IOAPICARB : %08X\n", val);
3135 pHlp->pfnPrintf(pHlp, " arb ID = %02X\n", (val >> 24) & 0xff);
3136 Assert(sizeof(s->ioredtbl) / sizeof(s->ioredtbl[0]) > max_redir);
3137 pHlp->pfnPrintf(pHlp, "I/O redirection table\n");
3138 pHlp->pfnPrintf(pHlp, " idx dst_mode dst_addr mask trigger rirr polarity dlvr_st dlvr_mode vector\n");
3139 for (i = 0; i <= max_redir; ++i)
3140 {
3141 static const char *dmodes[] = { "Fixed ", "LowPri", "SMI ", "Resrvd",
3142 "NMI ", "INIT ", "Resrvd", "ExtINT" };
3143
3144 pHlp->pfnPrintf(pHlp, " %02d %s %02X %d %s %d %s %s %s %3d (%016llX)\n",
3145 i,
3146 s->ioredtbl[i] & (1 << 11) ? "log " : "phys", /* dest mode */
3147 (int)(s->ioredtbl[i] >> 56), /* dest addr */
3148 (int)(s->ioredtbl[i] >> 16) & 1, /* mask */
3149 s->ioredtbl[i] & (1 << 15) ? "level" : "edge ", /* trigger */
3150 (int)(s->ioredtbl[i] >> 14) & 1, /* remote IRR */
3151 s->ioredtbl[i] & (1 << 13) ? "activelo" : "activehi", /* polarity */
3152 s->ioredtbl[i] & (1 << 12) ? "pend" : "idle", /* delivery status */
3153 dmodes[(s->ioredtbl[i] >> 8) & 0x07], /* delivery mode */
3154 (int)s->ioredtbl[i] & 0xff, /* vector */
3155 s->ioredtbl[i] /* entire register */
3156 );
3157 }
3158}
3159
3160/**
3161 * @copydoc FNSSMDEVSAVEEXEC
3162 */
3163static DECLCALLBACK(int) ioapicSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
3164{
3165 IOAPICState *s = PDMINS_2_DATA(pDevIns, IOAPICState *);
3166 ioapic_save(pSSM, s);
3167 return VINF_SUCCESS;
3168}
3169
3170/**
3171 * @copydoc FNSSMDEVLOADEXEC
3172 */
3173static DECLCALLBACK(int) ioapicLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
3174{
3175 IOAPICState *s = PDMINS_2_DATA(pDevIns, IOAPICState *);
3176
3177 if (ioapic_load(pSSM, s, uVersion)) {
3178 AssertFailed();
3179 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
3180 }
3181 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
3182
3183 return VINF_SUCCESS;
3184}
3185
3186/**
3187 * @copydoc FNPDMDEVRESET
3188 */
3189static DECLCALLBACK(void) ioapicReset(PPDMDEVINS pDevIns)
3190{
3191 IOAPICState *s = PDMINS_2_DATA(pDevIns, IOAPICState *);
3192 s->pIoApicHlpR3->pfnLock(pDevIns, VERR_INTERNAL_ERROR);
3193 ioapic_reset(s);
3194 IOAPIC_UNLOCK(s);
3195}
3196
3197/**
3198 * @copydoc FNPDMDEVRELOCATE
3199 */
3200static DECLCALLBACK(void) ioapicRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
3201{
3202 IOAPICState *s = PDMINS_2_DATA(pDevIns, IOAPICState *);
3203 s->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
3204 s->pIoApicHlpRC = s->pIoApicHlpR3->pfnGetRCHelpers(pDevIns);
3205}
3206
3207/**
3208 * @copydoc FNPDMDEVCONSTRUCT
3209 */
3210static DECLCALLBACK(int) ioapicConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
3211{
3212 IOAPICState *s = PDMINS_2_DATA(pDevIns, IOAPICState *);
3213 PDMIOAPICREG IoApicReg;
3214 bool fGCEnabled;
3215 bool fR0Enabled;
3216 int rc;
3217
3218 Assert(iInstance == 0);
3219
3220 /*
3221 * Validate and read the configuration.
3222 */
3223 if (!CFGMR3AreValuesValid(pCfgHandle, "GCEnabled\0" "R0Enabled\0"))
3224 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
3225
3226 rc = CFGMR3QueryBoolDef(pCfgHandle, "GCEnabled", &fGCEnabled, true);
3227 if (RT_FAILURE(rc))
3228 return PDMDEV_SET_ERROR(pDevIns, rc,
3229 N_("Configuration error: Failed to query boolean value \"GCEnabled\""));
3230
3231 rc = CFGMR3QueryBoolDef(pCfgHandle, "R0Enabled", &fR0Enabled, true);
3232 if (RT_FAILURE(rc))
3233 return PDMDEV_SET_ERROR(pDevIns, rc,
3234 N_("Configuration error: Failed to query boolean value \"R0Enabled\""));
3235 Log(("IOAPIC: fR0Enabled=%RTbool fGCEnabled=%RTbool\n", fR0Enabled, fGCEnabled));
3236
3237 /*
3238 * Initialize the state data.
3239 */
3240 s->pDevInsR3 = pDevIns;
3241 s->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
3242 s->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
3243 ioapic_reset(s);
3244 s->id = 0;
3245
3246 /*
3247 * Register the IOAPIC and get helpers.
3248 */
3249 IoApicReg.u32Version = PDM_IOAPICREG_VERSION;
3250 IoApicReg.pfnSetIrqR3 = ioapicSetIrq;
3251 IoApicReg.pszSetIrqRC = fGCEnabled ? "ioapicSetIrq" : NULL;
3252 IoApicReg.pszSetIrqR0 = fR0Enabled ? "ioapicSetIrq" : NULL;
3253 rc = pDevIns->pDevHlpR3->pfnIOAPICRegister(pDevIns, &IoApicReg, &s->pIoApicHlpR3);
3254 if (RT_FAILURE(rc))
3255 {
3256 AssertMsgFailed(("IOAPICRegister -> %Rrc\n", rc));
3257 return rc;
3258 }
3259
3260 /*
3261 * Register MMIO callbacks and saved state.
3262 */
3263 rc = PDMDevHlpMMIORegister(pDevIns, 0xfec00000, 0x1000, s,
3264 ioapicMMIOWrite, ioapicMMIORead, NULL, "I/O APIC Memory");
3265 if (RT_FAILURE(rc))
3266 return rc;
3267
3268 if (fGCEnabled) {
3269 s->pIoApicHlpRC = s->pIoApicHlpR3->pfnGetRCHelpers(pDevIns);
3270
3271 rc = PDMDevHlpMMIORegisterGC(pDevIns, 0xfec00000, 0x1000, 0,
3272 "ioapicMMIOWrite", "ioapicMMIORead", NULL);
3273 if (RT_FAILURE(rc))
3274 return rc;
3275 }
3276
3277 if (fR0Enabled) {
3278 s->pIoApicHlpR0 = s->pIoApicHlpR3->pfnGetR0Helpers(pDevIns);
3279
3280 rc = PDMDevHlpMMIORegisterR0(pDevIns, 0xfec00000, 0x1000, 0,
3281 "ioapicMMIOWrite", "ioapicMMIORead", NULL);
3282 if (RT_FAILURE(rc))
3283 return rc;
3284 }
3285
3286 rc = PDMDevHlpSSMRegister(pDevIns, 1 /* version */, sizeof(*s), ioapicSaveExec, ioapicLoadExec);
3287 if (RT_FAILURE(rc))
3288 return rc;
3289
3290 /*
3291 * Register debugger info callback.
3292 */
3293 PDMDevHlpDBGFInfoRegister(pDevIns, "ioapic", "Display I/O APIC state.", ioapicInfo);
3294
3295#ifdef VBOX_WITH_STATISTICS
3296 /*
3297 * Statistics.
3298 */
3299 PDMDevHlpSTAMRegister(pDevIns, &s->StatMMIOReadGC, STAMTYPE_COUNTER, "/Devices/IOAPIC/MMIOReadGC", STAMUNIT_OCCURENCES, "Number of IOAPIC MMIO reads in GC.");
3300 PDMDevHlpSTAMRegister(pDevIns, &s->StatMMIOReadHC, STAMTYPE_COUNTER, "/Devices/IOAPIC/MMIOReadHC", STAMUNIT_OCCURENCES, "Number of IOAPIC MMIO reads in HC.");
3301 PDMDevHlpSTAMRegister(pDevIns, &s->StatMMIOWriteGC, STAMTYPE_COUNTER, "/Devices/IOAPIC/MMIOWriteGC", STAMUNIT_OCCURENCES, "Number of IOAPIC MMIO writes in GC.");
3302 PDMDevHlpSTAMRegister(pDevIns, &s->StatMMIOWriteHC, STAMTYPE_COUNTER, "/Devices/IOAPIC/MMIOWriteHC", STAMUNIT_OCCURENCES, "Number of IOAPIC MMIO writes in HC.");
3303 PDMDevHlpSTAMRegister(pDevIns, &s->StatSetIrqGC, STAMTYPE_COUNTER, "/Devices/IOAPIC/SetIrqGC", STAMUNIT_OCCURENCES, "Number of IOAPIC SetIrq calls in GC.");
3304 PDMDevHlpSTAMRegister(pDevIns, &s->StatSetIrqHC, STAMTYPE_COUNTER, "/Devices/IOAPIC/SetIrqHC", STAMUNIT_OCCURENCES, "Number of IOAPIC SetIrq calls in HC.");
3305#endif
3306
3307 return VINF_SUCCESS;
3308}
3309
3310/**
3311 * IO APIC device registration structure.
3312 */
3313const PDMDEVREG g_DeviceIOAPIC =
3314{
3315 /* u32Version */
3316 PDM_DEVREG_VERSION,
3317 /* szDeviceName */
3318 "ioapic",
3319 /* szRCMod */
3320 "VBoxDD2GC.gc",
3321 /* szR0Mod */
3322 "VBoxDD2R0.r0",
3323 /* pszDescription */
3324 "I/O Advanced Programmable Interrupt Controller (IO-APIC) Device",
3325 /* fFlags */
3326 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,
3327 /* fClass */
3328 PDM_DEVREG_CLASS_PIC,
3329 /* cMaxInstances */
3330 1,
3331 /* cbInstance */
3332 sizeof(IOAPICState),
3333 /* pfnConstruct */
3334 ioapicConstruct,
3335 /* pfnDestruct */
3336 NULL,
3337 /* pfnRelocate */
3338 ioapicRelocate,
3339 /* pfnIOCtl */
3340 NULL,
3341 /* pfnPowerOn */
3342 NULL,
3343 /* pfnReset */
3344 ioapicReset,
3345 /* pfnSuspend */
3346 NULL,
3347 /* pfnResume */
3348 NULL,
3349 /* pfnAttach */
3350 NULL,
3351 /* pfnDetach */
3352 NULL,
3353 /* pfnQueryInterface. */
3354 NULL,
3355 /* pfnInitComplete */
3356 NULL,
3357 /* pfnPowerOff */
3358 NULL,
3359 /* pfnSoftReset */
3360 NULL,
3361 /* u32VersionEnd */
3362 PDM_DEVREG_VERSION
3363};
3364
3365#endif /* IN_RING3 */
3366#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
Note: See TracBrowser for help on using the repository browser.

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