VirtualBox

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

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

Check and assume PDM locking is performed when calling the APIC interface.

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