VirtualBox

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

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

Logging change

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