VirtualBox

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

Last change on this file since 32504 was 32504, checked in by vboxsync, 14 years ago

SUPDrv,IPRT,VMM,DevAPIC: Added RTTimerCanDoHighResolution and exposed the RTTimer* API to the ring-0 modules. Fixed two regression from r65858 (TM + APIC).

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

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