VirtualBox

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

最後變更 在這個檔案從24144是 24133,由 vboxsync 提交於 15 年 前

DevAPIC: fixed default case. grr.

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

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