VirtualBox

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

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

DevAPIC.cpp: alignment fix.

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