VirtualBox

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

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

NMI/SMI changes

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

© 2023 Oracle
ContactPrivacy policyTerms of Use