VirtualBox

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

Last change on this file since 6300 was 6300, checked in by vboxsync, 17 years ago

no "\n", ".", nor "!" at end of an error message

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 60.2 KB
Line 
1#ifdef VBOX
2/* $Id: DevAPIC.cpp 6300 2008-01-09 16:41:22Z 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 innotek GmbH
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_BASE (0xfffff<<12)
43
44#ifndef EINVAL
45# define EINVAL 1
46#endif
47
48#ifdef _MSC_VER
49# pragma warning(disable:4244)
50#endif
51
52/** @def APIC_LOCK
53 * Acquires the PDM lock. This is a NOP if locking is disabled. */
54/** @def APIC_UNLOCK
55 * Releases the PDM lock. This is a NOP if locking is disabled. */
56/** @def IOAPIC_LOCK
57 * Acquires the PDM lock. This is a NOP if locking is disabled. */
58/** @def IOAPIC_UNLOCK
59 * Releases the PDM lock. This is a NOP if locking is disabled. */
60#ifdef VBOX_WITH_PDM_LOCK
61# define APIC_LOCK(pThis, rc) \
62 do { \
63 int rc2 = (pThis)->CTXALLSUFF(pApicHlp)->pfnLock((pThis)->CTXSUFF(pDevIns), rc); \
64 if (rc2 != VINF_SUCCESS) \
65 return rc2; \
66 } while (0)
67# define APIC_UNLOCK(pThis) \
68 (pThis)->CTXALLSUFF(pApicHlp)->pfnUnlock((pThis)->CTXSUFF(pDevIns))
69# define IOAPIC_LOCK(pThis, rc) \
70 do { \
71 int rc2 = (pThis)->CTXALLSUFF(pIoApicHlp)->pfnLock((pThis)->CTXSUFF(pDevIns), rc); \
72 if (rc2 != VINF_SUCCESS) \
73 return rc2; \
74 } while (0)
75# define IOAPIC_UNLOCK(pThis) (pThis)->CTXALLSUFF(pIoApicHlp)->pfnUnlock((pThis)->CTXSUFF(pDevIns))
76#else /* !VBOX_WITH_PDM_LOCK */
77# define APIC_LOCK(pThis, rc) do { } while (0)
78# define APIC_UNLOCK(pThis) do { } while (0)
79# define IOAPIC_LOCK(pThis, rc) do { } while (0)
80# define IOAPIC_UNLOCK(pThis) do { } while (0)
81#endif /* !VBOX_WITH_PDM_LOCK */
82
83
84#endif /* VBOX */
85
86/*
87 * APIC support
88 *
89 * Copyright (c) 2004-2005 Fabrice Bellard
90 *
91 * This library is free software; you can redistribute it and/or
92 * modify it under the terms of the GNU Lesser General Public
93 * License as published by the Free Software Foundation; either
94 * version 2 of the License, or (at your option) any later version.
95 *
96 * This library is distributed in the hope that it will be useful,
97 * but WITHOUT ANY WARRANTY; without even the implied warranty of
98 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
99 * Lesser General Public License for more details.
100 *
101 * You should have received a copy of the GNU Lesser General Public
102 * License along with this library; if not, write to the Free Software
103 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
104 */
105#ifndef VBOX
106#include "vl.h"
107#endif
108
109#define DEBUG_APIC
110#define DEBUG_IOAPIC
111
112/* APIC Local Vector Table */
113#define APIC_LVT_TIMER 0
114#define APIC_LVT_THERMAL 1
115#define APIC_LVT_PERFORM 2
116#define APIC_LVT_LINT0 3
117#define APIC_LVT_LINT1 4
118#define APIC_LVT_ERROR 5
119#define APIC_LVT_NB 6
120
121/* APIC delivery modes */
122#define APIC_DM_FIXED 0
123#define APIC_DM_LOWPRI 1
124#define APIC_DM_SMI 2
125#define APIC_DM_NMI 4
126#define APIC_DM_INIT 5
127#define APIC_DM_SIPI 6
128#define APIC_DM_EXTINT 7
129
130/* APIC destination mode */
131#define APIC_DESTMODE_FLAT 0xf
132#define APIC_DESTMODE_CLUSTER 1
133
134#define APIC_TRIGGER_EDGE 0
135#define APIC_TRIGGER_LEVEL 1
136
137#define APIC_LVT_TIMER_PERIODIC (1<<17)
138#define APIC_LVT_MASKED (1<<16)
139#define APIC_LVT_LEVEL_TRIGGER (1<<15)
140#define APIC_LVT_REMOTE_IRR (1<<14)
141#define APIC_INPUT_POLARITY (1<<13)
142#define APIC_SEND_PENDING (1<<12)
143
144#define IOAPIC_NUM_PINS 0x18
145
146#define ESR_ILLEGAL_ADDRESS (1 << 7)
147
148#define APIC_SV_ENABLE (1 << 8)
149
150#ifdef VBOX
151#define APIC_MAX_PATCH_ATTEMPTS 100
152#endif
153
154typedef struct APICState {
155#ifndef VBOX
156 CPUState *cpu_env;
157#endif /* !VBOX */
158 uint32_t apicbase;
159 uint8_t id;
160 uint8_t arb_id;
161#ifdef VBOX
162 uint32_t tpr;
163#else
164 uint8_t tpr;
165#endif
166 uint32_t spurious_vec;
167 uint8_t log_dest;
168 uint8_t dest_mode;
169 uint32_t isr[8]; /* in service register */
170 uint32_t tmr[8]; /* trigger mode register */
171 uint32_t irr[8]; /* interrupt request register */
172 uint32_t lvt[APIC_LVT_NB];
173 uint32_t esr; /* error register */
174 uint32_t icr[2];
175
176 uint32_t divide_conf;
177 int count_shift;
178 uint32_t initial_count;
179#ifdef VBOX
180 uint32_t Alignment0;
181#endif
182 int64_t initial_count_load_time, next_time;
183#ifndef VBOX
184 QEMUTimer *timer;
185
186 struct APICState *next_apic;
187#else /* VBOX */
188 /** HC pointer to the device instance. */
189 R3R0PTRTYPE(PPDMDEVINS) pDevInsHC;
190 /** Pointer to the APIC HC helpers. */
191 PCPDMAPICHLPR3 pApicHlpR3;
192 /** The APIC timer - HC Ptr. */
193 R3R0PTRTYPE(PTMTIMER) pTimerHC;
194 /** Pointer to the APIC R0 helpers. */
195 PCPDMAPICHLPR0 pApicHlpR0;
196
197 /** GC pointer to the device instance. */
198 PPDMDEVINSGC pDevInsGC;
199 /** Pointer to the APIC GC helpers. */
200 PCPDMAPICHLPGC pApicHlpGC;
201 /** The APIC timer - GC Ptr. */
202 PTMTIMERGC pTimerGC;
203
204 /** Number of attempts made to optimize TPR accesses. */
205 uint32_t ulTPRPatchAttempts;
206
207# ifdef VBOX_WITH_STATISTICS
208 STAMCOUNTER StatMMIOReadGC;
209 STAMCOUNTER StatMMIOReadHC;
210 STAMCOUNTER StatMMIOWriteGC;
211 STAMCOUNTER StatMMIOWriteHC;
212 STAMCOUNTER StatClearedActiveIrq;
213# endif
214#endif /* VBOX */
215} APICState;
216
217struct IOAPICState {
218 uint8_t id;
219 uint8_t ioregsel;
220
221 uint32_t irr;
222 uint64_t ioredtbl[IOAPIC_NUM_PINS];
223
224#ifdef VBOX
225 /** HC pointer to the device instance. */
226 R3R0PTRTYPE(PPDMDEVINS) pDevInsHC;
227 /** Pointer to the IOAPIC R3 helpers. */
228 PCPDMIOAPICHLPR3 pIoApicHlpR3;
229
230 /** GC pointer to the device instance. */
231 PPDMDEVINSGC pDevInsGC;
232 /** Pointer to the IOAPIC GC helpers. */
233 PCPDMIOAPICHLPGC pIoApicHlpGC;
234
235 /** Pointer to the IOAPIC R0 helpers. */
236 PCPDMIOAPICHLPR0 pIoApicHlpR0;
237# if HC_ARCH_BITS == 32
238 uint32_t Alignment0;
239# endif
240# ifdef VBOX_WITH_STATISTICS
241 STAMCOUNTER StatMMIOReadGC;
242 STAMCOUNTER StatMMIOReadHC;
243 STAMCOUNTER StatMMIOWriteGC;
244 STAMCOUNTER StatMMIOWriteHC;
245 STAMCOUNTER StatSetIrqGC;
246 STAMCOUNTER StatSetIrqHC;
247# endif
248#endif /* VBOX */
249};
250
251#ifdef VBOX
252typedef struct IOAPICState IOAPICState;
253#endif /* VBOX */
254
255#ifndef VBOX_DEVICE_STRUCT_TESTCASE
256#ifndef VBOX
257static int apic_io_memory;
258static APICState *first_local_apic = NULL;
259static int last_apic_id = 0;
260#endif /* !VBOX */
261
262static void apic_init_ipi(APICState *s);
263static void apic_set_irq(APICState *s, int vector_num, int trigger_mode);
264static bool apic_update_irq(APICState *s);
265
266#ifdef VBOX
267static uint32_t apic_get_delivery_bitmask(APICState *s, uint8_t dest, uint8_t dest_mode);
268__BEGIN_DECLS
269PDMBOTHCBDECL(int) apicMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
270PDMBOTHCBDECL(int) apicMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
271PDMBOTHCBDECL(int) apicGetInterrupt(PPDMDEVINS pDevIns);
272PDMBOTHCBDECL(void) apicSetBase(PPDMDEVINS pDevIns, uint64_t val);
273PDMBOTHCBDECL(uint64_t) apicGetBase(PPDMDEVINS pDevIns);
274PDMBOTHCBDECL(void) apicSetTPR(PPDMDEVINS pDevIns, uint8_t val);
275PDMBOTHCBDECL(uint8_t) apicGetTPR(PPDMDEVINS pDevIns);
276PDMBOTHCBDECL(void) apicBusDeliverCallback(PPDMDEVINS pDevIns, uint8_t u8Dest, uint8_t u8DestMode,
277 uint8_t u8DeliveryMode, uint8_t iVector, uint8_t u8Polarity,
278 uint8_t u8TriggerMode);
279PDMBOTHCBDECL(int) ioapicMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
280PDMBOTHCBDECL(int) ioapicMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
281PDMBOTHCBDECL(void) ioapicSetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel);
282
283static void apic_update_tpr(APICState *s, uint32_t val);
284__END_DECLS
285#endif /* VBOX */
286
287#ifndef VBOX
288static void apic_bus_deliver(uint32_t deliver_bitmask, uint8_t delivery_mode,
289 uint8_t vector_num, uint8_t polarity,
290 uint8_t trigger_mode)
291{
292 APICState *apic_iter;
293#else /* VBOX */
294static void apic_bus_deliver(APICState *s, uint32_t deliver_bitmask, uint8_t delivery_mode,
295 uint8_t vector_num, uint8_t polarity,
296 uint8_t trigger_mode)
297{
298#endif /* VBOX */
299
300 switch (delivery_mode) {
301 case APIC_DM_LOWPRI:
302 case APIC_DM_FIXED:
303 /* XXX: arbitration */
304 break;
305
306 case APIC_DM_SMI:
307 case APIC_DM_NMI:
308 break;
309
310 case APIC_DM_INIT:
311 /* normal INIT IPI sent to processors */
312#ifdef VBOX
313 apic_init_ipi (s);
314#else
315 for (apic_iter = first_local_apic; apic_iter != NULL;
316 apic_iter = apic_iter->next_apic) {
317 apic_init_ipi(apic_iter);
318 }
319#endif
320 return;
321
322 case APIC_DM_EXTINT:
323 /* handled in I/O APIC code */
324 break;
325
326 default:
327 return;
328 }
329
330#ifdef VBOX
331 if (deliver_bitmask & (1 << s->id))
332 apic_set_irq (s, vector_num, trigger_mode);
333#else /* VBOX */
334 for (apic_iter = first_local_apic; apic_iter != NULL;
335 apic_iter = apic_iter->next_apic) {
336 if (deliver_bitmask & (1 << apic_iter->id))
337 apic_set_irq(apic_iter, vector_num, trigger_mode);
338 }
339#endif /* VBOX */
340}
341
342#ifndef VBOX
343void cpu_set_apic_base(CPUState *env, uint64_t val)
344{
345 APICState *s = env->apic_state;
346#ifdef DEBUG_APIC
347 Log(("cpu_set_apic_base: %016llx\n", val));
348#endif
349
350 s->apicbase = (val & 0xfffff000) |
351 (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
352 /* if disabled, cannot be enabled again */
353 if (!(val & MSR_IA32_APICBASE_ENABLE)) {
354 s->apicbase &= ~MSR_IA32_APICBASE_ENABLE;
355 env->cpuid_features &= ~CPUID_APIC;
356 s->spurious_vec &= ~APIC_SV_ENABLE;
357 }
358}
359#else /* VBOX */
360PDMBOTHCBDECL(void) apicSetBase(PPDMDEVINS pDevIns, uint64_t val)
361{
362 APICState *s = PDMINS2DATA(pDevIns, APICState *);
363 Log(("cpu_set_apic_base: %016RX64\n", val));
364
365 /** @todo If this change is valid immediately, then we should change the MMIO registration! */
366 s->apicbase = (val & 0xfffff000) |
367 (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
368 /* if disabled, cannot be enabled again (until reset) */
369 if (!(val & MSR_IA32_APICBASE_ENABLE)) {
370 s->apicbase &= ~MSR_IA32_APICBASE_ENABLE;
371 s->spurious_vec &= ~APIC_SV_ENABLE;
372
373 /* Clear any pending APIC interrupt action flag. */
374 s->CTXALLSUFF(pApicHlp)->pfnClearInterruptFF(s->CTXSUFF(pDevIns));
375 s->CTXALLSUFF(pApicHlp)->pfnChangeFeature(pDevIns, false);
376 }
377}
378#endif /* VBOX */
379#ifndef VBOX
380
381uint64_t cpu_get_apic_base(CPUState *env)
382{
383 APICState *s = env->apic_state;
384#ifdef DEBUG_APIC
385 Log(("cpu_get_apic_base: %016llx\n", (uint64_t)s->apicbase));
386#endif
387 return s->apicbase;
388}
389
390void cpu_set_apic_tpr(CPUX86State *env, uint8_t val)
391{
392 APICState *s = env->apic_state;
393 s->tpr = (val & 0x0f) << 4;
394 apic_update_irq(s);
395}
396
397uint8_t cpu_get_apic_tpr(CPUX86State *env)
398{
399 APICState *s = env->apic_state;
400 return s->tpr >> 4;
401}
402
403static int fls_bit(int value)
404{
405 unsigned int ret = 0;
406
407#ifdef HOST_I386
408 __asm__ __volatile__ ("bsr %1, %0\n" : "+r" (ret) : "rm" (value));
409 return ret;
410#else
411 if (value > 0xffff)
412 value >>= 16, ret = 16;
413 if (value > 0xff)
414 value >>= 8, ret += 8;
415 if (value > 0xf)
416 value >>= 4, ret += 4;
417 if (value > 0x3)
418 value >>= 2, ret += 2;
419 return ret + (value >> 1);
420#endif
421}
422
423static inline void set_bit(uint32_t *tab, int index)
424{
425 int i, mask;
426 i = index >> 5;
427 mask = 1 << (index & 0x1f);
428 tab[i] |= mask;
429}
430
431static inline void reset_bit(uint32_t *tab, int index)
432{
433 int i, mask;
434 i = index >> 5;
435 mask = 1 << (index & 0x1f);
436 tab[i] &= ~mask;
437}
438
439
440#else /* VBOX */
441
442PDMBOTHCBDECL(uint64_t) apicGetBase(PPDMDEVINS pDevIns)
443{
444 APICState *s = PDMINS2DATA(pDevIns, APICState *);
445 Log(("apicGetBase: %016llx\n", (uint64_t)s->apicbase));
446 return s->apicbase;
447}
448
449PDMBOTHCBDECL(void) apicSetTPR(PPDMDEVINS pDevIns, uint8_t val)
450{
451 APICState *s = PDMINS2DATA(pDevIns, APICState *);
452 LogFlow(("apicSetTPR: val=%#x (trp %#x -> %#x)\n", val, s->tpr, (val & 0x0f) << 4));
453 apic_update_tpr(s, (val & 0x0f) << 4);
454}
455
456PDMBOTHCBDECL(uint8_t) apicGetTPR(PPDMDEVINS pDevIns)
457{
458 APICState *s = PDMINS2DATA(pDevIns, APICState *);
459 LogFlow(("apicGetTPR: returns %#x\n", s->tpr >> 4));
460 return s->tpr >> 4;
461}
462
463/**
464 * More or less private interface between IOAPIC, only PDM is responsible
465 * for connecting the two devices.
466 */
467PDMBOTHCBDECL(void) apicBusDeliverCallback(PPDMDEVINS pDevIns, uint8_t u8Dest, uint8_t u8DestMode,
468 uint8_t u8DeliveryMode, uint8_t iVector, uint8_t u8Polarity,
469 uint8_t u8TriggerMode)
470{
471 APICState *s = PDMINS2DATA(pDevIns, APICState *);
472 LogFlow(("apicBusDeliverCallback: s=%p pDevIns=%p u8Dest=%#x u8DestMode=%#x u8DeliveryMode=%#x iVector=%#x u8Polarity=%#x u8TriggerMode=%#x\n",
473 s, pDevIns, u8Dest, u8DestMode, u8DeliveryMode, iVector, u8Polarity, u8TriggerMode));
474 apic_bus_deliver(s, apic_get_delivery_bitmask(s, u8Dest, u8DestMode),
475 u8DeliveryMode, iVector, u8Polarity, u8TriggerMode);
476}
477
478# define set_bit(pvBitmap, iBit) ASMBitSet(pvBitmap, iBit)
479# define reset_bit(pvBitmap, iBit) ASMBitClear(pvBitmap, iBit)
480# define fls_bit(value) (ASMBitLastSetU32(value) - 1)
481
482#endif /* VBOX */
483
484/* return -1 if no bit is set */
485static int get_highest_priority_int(uint32_t *tab)
486{
487 int i;
488 for(i = 7; i >= 0; i--) {
489 if (tab[i] != 0) {
490 return i * 32 + fls_bit(tab[i]);
491 }
492 }
493 return -1;
494}
495
496static int apic_get_ppr(APICState *s)
497{
498 int tpr, isrv, ppr;
499
500 tpr = (s->tpr >> 4);
501 isrv = get_highest_priority_int(s->isr);
502 if (isrv < 0)
503 isrv = 0;
504 isrv >>= 4;
505 if (tpr >= isrv)
506 ppr = s->tpr;
507 else
508 ppr = isrv << 4;
509 return ppr;
510}
511
512static int apic_get_arb_pri(APICState *s)
513{
514 /* XXX: arbitration */
515 return 0;
516}
517
518/* signal the CPU if an irq is pending */
519static bool apic_update_irq(APICState *s)
520{
521 int irrv, ppr;
522 if (!(s->spurious_vec & APIC_SV_ENABLE))
523#ifdef VBOX
524 {
525 /* Clear any pending APIC interrupt action flag. */
526 s->CTXALLSUFF(pApicHlp)->pfnClearInterruptFF(s->CTXSUFF(pDevIns));
527 return false;
528 }
529#else
530 return false;
531#endif /* VBOX */
532 irrv = get_highest_priority_int(s->irr);
533 if (irrv < 0)
534 return false;
535 ppr = apic_get_ppr(s);
536 if (ppr && (irrv & 0xf0) <= (ppr & 0xf0))
537 return false;
538#ifndef VBOX
539 cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
540#else
541 s->CTXALLSUFF(pApicHlp)->pfnSetInterruptFF(s->CTXSUFF(pDevIns));
542 return true;
543#endif
544}
545
546#ifdef VBOX
547static void apic_update_tpr(APICState *s, uint32_t val)
548{
549 bool fIrqIsActive = false;
550 bool fIrqWasActive = false;
551
552 fIrqWasActive = apic_update_irq(s);
553 s->tpr = val;
554 fIrqIsActive = apic_update_irq(s);
555
556 /* If an interrupt is pending and now masked, then clear the FF flag. */
557 if (fIrqWasActive && !fIrqIsActive)
558 {
559 Log(("apic_update_tpr: deactivate interrupt that was masked by the TPR update (%x)\n", val));
560 STAM_COUNTER_INC(&s->StatClearedActiveIrq);
561 s->CTXALLSUFF(pApicHlp)->pfnClearInterruptFF(s->CTXSUFF(pDevIns));
562 }
563}
564#endif
565
566static void apic_set_irq(APICState *s, int vector_num, int trigger_mode)
567{
568 set_bit(s->irr, vector_num);
569 if (trigger_mode)
570 set_bit(s->tmr, vector_num);
571 else
572 reset_bit(s->tmr, vector_num);
573 apic_update_irq(s);
574}
575
576static void apic_eoi(APICState *s)
577{
578 int isrv;
579 isrv = get_highest_priority_int(s->isr);
580 if (isrv < 0)
581 return;
582 reset_bit(s->isr, isrv);
583 /* XXX: send the EOI packet to the APIC bus to allow the I/O APIC to
584 set the remote IRR bit for level triggered interrupts. */
585 apic_update_irq(s);
586}
587
588#ifndef VBOX
589static uint32_t apic_get_delivery_bitmask(uint8_t dest, uint8_t dest_mode)
590#else /* VBOX */
591static uint32_t apic_get_delivery_bitmask(APICState *s, uint8_t dest, uint8_t dest_mode)
592#endif /* VBOX */
593{
594 uint32_t mask = 0;
595#ifndef VBOX
596 APICState *apic_iter;
597#endif /* !VBOX */
598
599 if (dest_mode == 0) {
600 if (dest == 0xff)
601 mask = 0xff;
602 else
603 mask = 1 << dest;
604 } else {
605 /* XXX: cluster mode */
606#ifdef VBOX
607 if (dest & s->log_dest)
608 mask |= 1 << s->id;
609#else /* !VBOX */
610 for (apic_iter = first_local_apic; apic_iter != NULL;
611 apic_iter = apic_iter->next_apic) {
612 if (dest & apic_iter->log_dest)
613 mask |= (1 << apic_iter->id);
614 }
615#endif /* !VBOX */
616 }
617
618 return mask;
619}
620
621
622static void apic_init_ipi(APICState *s)
623{
624 int i;
625
626 for(i = 0; i < APIC_LVT_NB; i++)
627 s->lvt[i] = 1 << 16; /* mask LVT */
628 s->tpr = 0;
629 s->spurious_vec = 0xff;
630 s->log_dest = 0;
631 s->dest_mode = 0xff;
632 memset(s->isr, 0, sizeof(s->isr));
633 memset(s->tmr, 0, sizeof(s->tmr));
634 memset(s->irr, 0, sizeof(s->irr));
635 for(i = 0; i < APIC_LVT_NB; i++)
636 s->lvt[i] = 1 << 16; /* mask LVT */
637 s->esr = 0;
638 memset(s->icr, 0, sizeof(s->icr));
639 s->divide_conf = 0;
640 s->count_shift = 0;
641 s->initial_count = 0;
642 s->initial_count_load_time = 0;
643 s->next_time = 0;
644}
645
646static void apic_deliver(APICState *s, uint8_t dest, uint8_t dest_mode,
647 uint8_t delivery_mode, uint8_t vector_num,
648 uint8_t polarity, uint8_t trigger_mode)
649{
650 uint32_t deliver_bitmask = 0;
651 int dest_shorthand = (s->icr[0] >> 18) & 3;
652#ifndef VBOX
653 APICState *apic_iter;
654#endif /* !VBOX */
655
656 switch (delivery_mode) {
657 case APIC_DM_LOWPRI:
658 /* XXX: serch for focus processor, arbitration */
659 dest = s->id;
660
661 case APIC_DM_INIT:
662 {
663 int trig_mode = (s->icr[0] >> 15) & 1;
664 int level = (s->icr[0] >> 14) & 1;
665 if (level == 0 && trig_mode == 1) {
666#ifdef VBOX
667 if (deliver_bitmask & (1 << s->id)) {
668 s->arb_id = s->id;
669 }
670#else /* !VBOX */
671 for (apic_iter = first_local_apic; apic_iter != NULL;
672 apic_iter = apic_iter->next_apic) {
673 if (deliver_bitmask & (1 << apic_iter->id)) {
674 apic_iter->arb_id = apic_iter->id;
675 }
676 }
677#endif /* !VBOX */
678 return;
679 }
680 }
681 break;
682
683 case APIC_DM_SIPI:
684#ifndef VBOX
685 for (apic_iter = first_local_apic; apic_iter != NULL;
686 apic_iter = apic_iter->next_apic) {
687 if (deliver_bitmask & (1 << apic_iter->id)) {
688 /* XXX: SMP support */
689 /* apic_startup(apic_iter); */
690 }
691 }
692#endif /* !VBOX */
693 return;
694 }
695
696 switch (dest_shorthand) {
697 case 0:
698#ifndef VBOX
699 deliver_bitmask = apic_get_delivery_bitmask(dest, dest_mode);
700#else /* VBOX */
701 deliver_bitmask = apic_get_delivery_bitmask(s, dest, dest_mode);
702#endif /* !VBOX */
703 break;
704 case 1:
705 deliver_bitmask = (1 << s->id);
706 break;
707 case 2:
708 deliver_bitmask = 0xffffffff;
709 break;
710 case 3:
711 deliver_bitmask = 0xffffffff & ~(1 << s->id);
712 break;
713 }
714
715#ifndef VBOX
716 apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, polarity,
717 trigger_mode);
718#else /* VBOX */
719 apic_bus_deliver(s, deliver_bitmask, delivery_mode, vector_num, polarity,
720 trigger_mode);
721#endif /* VBOX */
722}
723
724#ifndef VBOX
725int apic_get_interrupt(CPUState *env)
726{
727 APICState *s = env->apic_state;
728#else /* VBOX */
729PDMBOTHCBDECL(int) apicGetInterrupt(PPDMDEVINS pDevIns)
730{
731 APICState *s = PDMINS2DATA(pDevIns, APICState *);
732#endif /* VBOX */
733 int intno;
734
735 /* if the APIC is installed or enabled, we let the 8259 handle the
736 IRQs */
737 if (!s) {
738 Log(("apic_get_interrupt: returns -1 (!s)\n"));
739 return -1;
740 }
741 if (!(s->spurious_vec & APIC_SV_ENABLE)) {
742 Log(("apic_get_interrupt: returns -1 (APIC_SV_ENABLE)\n"));
743 return -1;
744 }
745
746 /* XXX: spurious IRQ handling */
747 intno = get_highest_priority_int(s->irr);
748 if (intno < 0) {
749 Log(("apic_get_interrupt: returns -1 (irr)\n"));
750 return -1;
751 }
752 if (s->tpr && (uint32_t)intno <= s->tpr) {
753 Log(("apic_get_interrupt: returns %d (sp)\n", s->spurious_vec & 0xff));
754 return s->spurious_vec & 0xff;
755 }
756 reset_bit(s->irr, intno);
757 set_bit(s->isr, intno);
758 apic_update_irq(s);
759 LogFlow(("apic_get_interrupt: returns %d\n", intno));
760 return intno;
761}
762
763static uint32_t apic_get_current_count(APICState *s)
764{
765 int64_t d;
766 uint32_t val;
767#ifndef VBOX
768 d = (qemu_get_clock(vm_clock) - s->initial_count_load_time) >>
769 s->count_shift;
770#else /* VBOX */
771 d = (TMTimerGet(s->CTXSUFF(pTimer)) - s->initial_count_load_time) >>
772 s->count_shift;
773#endif /* VBOX */
774 if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
775 /* periodic */
776 val = s->initial_count - (d % ((uint64_t)s->initial_count + 1));
777 } else {
778 if (d >= s->initial_count)
779 val = 0;
780 else
781 val = s->initial_count - d;
782 }
783 return val;
784}
785
786static void apic_timer_update(APICState *s, int64_t current_time)
787{
788 int64_t next_time, d;
789
790 if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) {
791 d = (current_time - s->initial_count_load_time) >>
792 s->count_shift;
793 if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
794 d = ((d / ((uint64_t)s->initial_count + 1)) + 1) * ((uint64_t)s->initial_count + 1);
795 } else {
796 if (d >= s->initial_count)
797 goto no_timer;
798 d = (uint64_t)s->initial_count + 1;
799 }
800 next_time = s->initial_count_load_time + (d << s->count_shift);
801#ifndef VBOX
802 qemu_mod_timer(s->timer, next_time);
803#else
804 TMTimerSet(s->CTXSUFF(pTimer), next_time);
805#endif
806 s->next_time = next_time;
807 } else {
808 no_timer:
809#ifndef VBOX
810 qemu_del_timer(s->timer);
811#else
812 TMTimerStop(s->CTXSUFF(pTimer));
813#endif
814 }
815}
816
817#ifdef IN_RING3
818#ifndef VBOX
819static void apic_timer(void *opaque)
820{
821 APICState *s = opaque;
822#else /* VBOX */
823static DECLCALLBACK(void) apicTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer)
824{
825 APICState *s = PDMINS2DATA(pDevIns, APICState *);
826# ifdef VBOX_WITH_PDM_LOCK
827 s->pApicHlpR3->pfnLock(pDevIns, VERR_INTERNAL_ERROR);
828# endif
829#endif /* VBOX */
830
831 if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) {
832 apic_set_irq(s, s->lvt[APIC_LVT_TIMER] & 0xff, APIC_TRIGGER_EDGE);
833 }
834 apic_timer_update(s, s->next_time);
835
836#ifdef VBOX
837 APIC_UNLOCK(s);
838#endif
839}
840#endif /* IN_RING3 */
841
842#ifndef VBOX
843static uint32_t apic_mem_readb(void *opaque, target_phys_addr_t addr)
844{
845 return 0;
846}
847
848static uint32_t apic_mem_readw(void *opaque, target_phys_addr_t addr)
849{
850 return 0;
851}
852
853static void apic_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
854{
855}
856
857static void apic_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
858{
859}
860#endif /* !VBOX */
861
862
863#ifndef VBOX
864static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr)
865{
866 CPUState *env;
867 APICState *s;
868#else /* VBOX */
869static uint32_t apic_mem_readl(APICState *s, target_phys_addr_t addr)
870{
871#endif /* VBOX */
872 uint32_t val;
873 int index;
874
875#ifndef VBOX
876 env = cpu_single_env;
877 if (!env)
878 return 0;
879 s = env->apic_state;
880#endif /* !VBOX */
881
882 index = (addr >> 4) & 0xff;
883 switch(index) {
884 case 0x02: /* id */
885 val = s->id << 24;
886 break;
887 case 0x03: /* version */
888 val = 0x11 | ((APIC_LVT_NB - 1) << 16); /* version 0x11 */
889 break;
890 case 0x08:
891 val = s->tpr;
892 break;
893 case 0x09:
894 val = apic_get_arb_pri(s);
895 break;
896 case 0x0a:
897 /* ppr */
898 val = apic_get_ppr(s);
899 break;
900#ifdef VBOX
901 case 0x0b:
902 Log(("apic_mem_readl %x %x -> write only returning 0\n", addr, index));
903 val = 0;
904 break;
905#endif
906
907 case 0x0d:
908 val = s->log_dest << 24;
909 break;
910 case 0x0e:
911#ifdef VBOX
912 /* Bottom 28 bits are always 1 */
913 val = (s->dest_mode << 28) | 0xfffffff;
914#else
915 val = s->dest_mode << 28;
916#endif
917 break;
918 case 0x0f:
919 val = s->spurious_vec;
920 break;
921#ifndef VBOX
922 case 0x10 ... 0x17:
923#else /* VBOX */
924 case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
925#endif /* VBOX */
926 val = s->isr[index & 7];
927 break;
928#ifndef VBOX
929 case 0x18 ... 0x1f:
930#else /* VBOX */
931 case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
932#endif /* VBOX */
933 val = s->tmr[index & 7];
934 break;
935#ifndef VBOX
936 case 0x20 ... 0x27:
937#else /* VBOX */
938 case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
939#endif /* VBOX */
940 val = s->irr[index & 7];
941 break;
942 case 0x28:
943 val = s->esr;
944 break;
945 case 0x30:
946 case 0x31:
947 val = s->icr[index & 1];
948 break;
949#ifndef VBOX
950 case 0x32 ... 0x37:
951#else /* VBOX */
952 case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
953#endif /* VBOX */
954 val = s->lvt[index - 0x32];
955 break;
956 case 0x38:
957 val = s->initial_count;
958 break;
959 case 0x39:
960 val = apic_get_current_count(s);
961 break;
962 case 0x3e:
963 val = s->divide_conf;
964 break;
965 default:
966 AssertMsgFailed(("apic_mem_readl: unknown index %x\n", index));
967 s->esr |= ESR_ILLEGAL_ADDRESS;
968 val = 0;
969 break;
970 }
971#ifdef DEBUG_APIC
972 Log(("APIC read: %08x = %08x\n", (uint32_t)addr, val));
973#endif
974 return val;
975}
976
977#ifndef VBOX
978static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
979{
980 CPUState *env;
981 APICState *s;
982#else /* VBOX */
983static int apic_mem_writel(APICState *s, target_phys_addr_t addr, uint32_t val)
984{
985#endif /* VBOX */
986 int index;
987
988#ifndef VBOX
989 env = cpu_single_env;
990 if (!env)
991 return;
992 s = env->apic_state;
993#endif /* !VBOX */
994
995#ifdef DEBUG_APIC
996 Log(("APIC write: %08x = %08x\n", (uint32_t)addr, val));
997#endif
998
999 index = (addr >> 4) & 0xff;
1000 switch(index) {
1001 case 0x02:
1002 s->id = (val >> 24);
1003 break;
1004 case 0x03:
1005 Log(("apic_mem_writel: write to version register; ignored\n"));
1006 break;
1007 case 0x08:
1008#ifdef VBOX
1009 apic_update_tpr(s, val);
1010#else
1011 s->tpr = val;
1012 apic_update_irq(s);
1013#endif
1014 break;
1015 case 0x09:
1016 case 0x0a:
1017 Log(("apic_mem_writel: write to read-only register %d ignored\n", index));
1018 break;
1019 case 0x0b: /* EOI */
1020 apic_eoi(s);
1021 break;
1022 case 0x0d:
1023 s->log_dest = val >> 24;
1024 break;
1025 case 0x0e:
1026 s->dest_mode = val >> 28;
1027 break;
1028 case 0x0f:
1029 s->spurious_vec = val & 0x1ff;
1030 apic_update_irq(s);
1031 break;
1032#ifndef VBOX
1033 case 0x10 ... 0x17:
1034 case 0x18 ... 0x1f:
1035 case 0x20 ... 0x27:
1036 case 0x28:
1037#else
1038 case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
1039 case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
1040 case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
1041 case 0x28:
1042 Log(("apic_mem_writel: write to read-only register %d ignored\n", index));
1043#endif
1044 break;
1045
1046 case 0x30:
1047 s->icr[0] = val;
1048 apic_deliver(s, (s->icr[1] >> 24) & 0xff, (s->icr[0] >> 11) & 1,
1049 (s->icr[0] >> 8) & 7, (s->icr[0] & 0xff),
1050 (s->icr[0] >> 14) & 1, (s->icr[0] >> 15) & 1);
1051 break;
1052 case 0x31:
1053 s->icr[1] = val;
1054 break;
1055#ifndef VBOX
1056 case 0x32 ... 0x37:
1057#else /* VBOX */
1058 case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
1059#endif /* VBOX */
1060 {
1061 int n = index - 0x32;
1062 s->lvt[n] = val;
1063 if (n == APIC_LVT_TIMER)
1064#ifndef VBOX
1065 apic_timer_update(s, qemu_get_clock(vm_clock));
1066#else /* VBOX */
1067 apic_timer_update(s, TMTimerGet(s->CTXSUFF(pTimer)));
1068#endif /* VBOX*/
1069 }
1070 break;
1071 case 0x38:
1072 s->initial_count = val;
1073#ifndef VBOX
1074 s->initial_count_load_time = qemu_get_clock(vm_clock);
1075#else /* VBOX */
1076 s->initial_count_load_time = TMTimerGet(s->CTXSUFF(pTimer));
1077#endif /* VBOX*/
1078 apic_timer_update(s, s->initial_count_load_time);
1079 break;
1080 case 0x39:
1081 Log(("apic_mem_writel: write to read-only register %d ignored\n", index));
1082 break;
1083 case 0x3e:
1084 {
1085 int v;
1086 s->divide_conf = val & 0xb;
1087 v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4);
1088 s->count_shift = (v + 1) & 7;
1089 }
1090 break;
1091 default:
1092 AssertMsgFailed(("apic_mem_writel: unknown index %x\n", index));
1093 s->esr |= ESR_ILLEGAL_ADDRESS;
1094 break;
1095 }
1096#ifdef VBOX
1097 return VINF_SUCCESS;
1098#endif
1099}
1100
1101#ifdef IN_RING3
1102
1103static void apic_save(QEMUFile *f, void *opaque)
1104{
1105 APICState *s = (APICState*)opaque;
1106 int i;
1107
1108 qemu_put_be32s(f, &s->apicbase);
1109 qemu_put_8s(f, &s->id);
1110 qemu_put_8s(f, &s->arb_id);
1111#ifdef VBOX
1112 qemu_put_be32s(f, &s->tpr);
1113#else
1114 qemu_put_8s(f, &s->tpr);
1115#endif
1116 qemu_put_be32s(f, &s->spurious_vec);
1117 qemu_put_8s(f, &s->log_dest);
1118 qemu_put_8s(f, &s->dest_mode);
1119 for (i = 0; i < 8; i++) {
1120 qemu_put_be32s(f, &s->isr[i]);
1121 qemu_put_be32s(f, &s->tmr[i]);
1122 qemu_put_be32s(f, &s->irr[i]);
1123 }
1124 for (i = 0; i < APIC_LVT_NB; i++) {
1125 qemu_put_be32s(f, &s->lvt[i]);
1126 }
1127 qemu_put_be32s(f, &s->esr);
1128 qemu_put_be32s(f, &s->icr[0]);
1129 qemu_put_be32s(f, &s->icr[1]);
1130 qemu_put_be32s(f, &s->divide_conf);
1131 qemu_put_be32s(f, &s->count_shift);
1132 qemu_put_be32s(f, &s->initial_count);
1133 qemu_put_be64s(f, &s->initial_count_load_time);
1134 qemu_put_be64s(f, &s->next_time);
1135}
1136
1137static int apic_load(QEMUFile *f, void *opaque, int version_id)
1138{
1139 APICState *s = (APICState*)opaque;
1140 int i;
1141
1142 if (version_id != 1)
1143 return -EINVAL;
1144
1145 /* XXX: what if the base changes? (registered memory regions) */
1146 qemu_get_be32s(f, &s->apicbase);
1147 qemu_get_8s(f, &s->id);
1148 qemu_get_8s(f, &s->arb_id);
1149#ifdef VBOX
1150 qemu_get_be32s(f, &s->tpr);
1151#else
1152 qemu_get_8s(f, &s->tpr);
1153#endif
1154 qemu_get_be32s(f, &s->spurious_vec);
1155 qemu_get_8s(f, &s->log_dest);
1156 qemu_get_8s(f, &s->dest_mode);
1157 for (i = 0; i < 8; i++) {
1158 qemu_get_be32s(f, &s->isr[i]);
1159 qemu_get_be32s(f, &s->tmr[i]);
1160 qemu_get_be32s(f, &s->irr[i]);
1161 }
1162 for (i = 0; i < APIC_LVT_NB; i++) {
1163 qemu_get_be32s(f, &s->lvt[i]);
1164 }
1165 qemu_get_be32s(f, &s->esr);
1166 qemu_get_be32s(f, &s->icr[0]);
1167 qemu_get_be32s(f, &s->icr[1]);
1168 qemu_get_be32s(f, &s->divide_conf);
1169 qemu_get_be32s(f, (uint32_t *)&s->count_shift);
1170 qemu_get_be32s(f, (uint32_t *)&s->initial_count);
1171 qemu_get_be64s(f, (uint64_t *)&s->initial_count_load_time);
1172 qemu_get_be64s(f, (uint64_t *)&s->next_time);
1173 return 0;
1174}
1175
1176static void apic_reset(void *opaque)
1177{
1178 APICState *s = (APICState*)opaque;
1179#ifdef VBOX
1180 TMTimerStop(s->CTXSUFF(pTimer));
1181
1182 /* malc, I've removed the initing duplicated in apic_init_ipi(). This
1183 * arb_id was left over.. */
1184 s->arb_id = 0;
1185
1186 /* Reset should re-enable the APIC. */
1187 s->apicbase = 0xfee00000 | MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE;
1188 s->pApicHlpR3->pfnChangeFeature(s->pDevInsHC, true);
1189
1190#endif /* VBOX */
1191 apic_init_ipi(s);
1192}
1193
1194#endif /* IN_RING3 */
1195
1196#ifndef VBOX
1197static CPUReadMemoryFunc *apic_mem_read[3] = {
1198 apic_mem_readb,
1199 apic_mem_readw,
1200 apic_mem_readl,
1201};
1202
1203static CPUWriteMemoryFunc *apic_mem_write[3] = {
1204 apic_mem_writeb,
1205 apic_mem_writew,
1206 apic_mem_writel,
1207};
1208
1209int apic_init(CPUState *env)
1210{
1211 APICState *s;
1212
1213 s = qemu_mallocz(sizeof(APICState));
1214 if (!s)
1215 return -1;
1216 env->apic_state = s;
1217 apic_init_ipi(s);
1218 s->id = last_apic_id++;
1219 s->cpu_env = env;
1220 s->apicbase = 0xfee00000 |
1221 (s->id ? 0 : MSR_IA32_APICBASE_BSP) | MSR_IA32_APICBASE_ENABLE;
1222
1223 /* XXX: mapping more APICs at the same memory location */
1224 if (apic_io_memory == 0) {
1225 /* NOTE: the APIC is directly connected to the CPU - it is not
1226 on the global memory bus. */
1227 apic_io_memory = cpu_register_io_memory(0, apic_mem_read,
1228 apic_mem_write, NULL);
1229 cpu_register_physical_memory(s->apicbase & ~0xfff, 0x1000,
1230 apic_io_memory);
1231 }
1232 s->timer = qemu_new_timer(vm_clock, apic_timer, s);
1233
1234 register_savevm("apic", 0, 1, apic_save, apic_load, s);
1235 qemu_register_reset(apic_reset, s);
1236
1237 s->next_apic = first_local_apic;
1238 first_local_apic = s;
1239
1240 return 0;
1241}
1242#endif /* !VBOX */
1243
1244static void ioapic_service(IOAPICState *s)
1245{
1246 uint8_t i;
1247 uint8_t trig_mode;
1248 uint8_t vector;
1249 uint8_t delivery_mode;
1250 uint32_t mask;
1251 uint64_t entry;
1252 uint8_t dest;
1253 uint8_t dest_mode;
1254 uint8_t polarity;
1255
1256 for (i = 0; i < IOAPIC_NUM_PINS; i++) {
1257 mask = 1 << i;
1258 if (s->irr & mask) {
1259 entry = s->ioredtbl[i];
1260 if (!(entry & APIC_LVT_MASKED)) {
1261 trig_mode = ((entry >> 15) & 1);
1262 dest = entry >> 56;
1263 dest_mode = (entry >> 11) & 1;
1264 delivery_mode = (entry >> 8) & 7;
1265 polarity = (entry >> 13) & 1;
1266 if (trig_mode == APIC_TRIGGER_EDGE)
1267 s->irr &= ~mask;
1268 if (delivery_mode == APIC_DM_EXTINT)
1269#ifndef VBOX /* malc: i'm still not so sure about ExtINT delivery */
1270 vector = pic_read_irq(isa_pic);
1271#else /* VBOX */
1272 {
1273 AssertMsgFailed(("Delivery mode ExtINT"));
1274 vector = 0xff; /* incorrect but shuts up gcc. */
1275 }
1276#endif /* VBOX */
1277 else
1278 vector = entry & 0xff;
1279
1280#ifndef VBOX
1281 apic_bus_deliver(apic_get_delivery_bitmask(dest, dest_mode),
1282 delivery_mode, vector, polarity, trig_mode);
1283#else /* VBOX */
1284 s->CTXALLSUFF(pIoApicHlp)->pfnApicBusDeliver(s->CTXSUFF(pDevIns),
1285 dest,
1286 dest_mode,
1287 delivery_mode,
1288 vector,
1289 polarity,
1290 trig_mode);
1291#endif /* VBOX */
1292 }
1293 }
1294 }
1295}
1296
1297#ifdef VBOX
1298static
1299#endif
1300void ioapic_set_irq(void *opaque, int vector, int level)
1301{
1302 IOAPICState *s = (IOAPICState*)opaque;
1303
1304 if (vector >= 0 && vector < IOAPIC_NUM_PINS) {
1305 uint32_t mask = 1 << vector;
1306 uint64_t entry = s->ioredtbl[vector];
1307
1308 if ((entry >> 15) & 1) {
1309 /* level triggered */
1310 if (level) {
1311 s->irr |= mask;
1312 ioapic_service(s);
1313#ifdef VBOX
1314 if ((level & PDM_IRQ_LEVEL_FLIP_FLOP) == PDM_IRQ_LEVEL_FLIP_FLOP) {
1315 s->irr &= ~mask;
1316 }
1317#endif
1318 } else {
1319 s->irr &= ~mask;
1320 }
1321 } else {
1322 /* edge triggered */
1323 if (level) {
1324 s->irr |= mask;
1325 ioapic_service(s);
1326 }
1327 }
1328 }
1329}
1330
1331static uint32_t ioapic_mem_readl(void *opaque, target_phys_addr_t addr)
1332{
1333 IOAPICState *s = (IOAPICState*)opaque;
1334 int index;
1335 uint32_t val = 0;
1336
1337 addr &= 0xff;
1338 if (addr == 0x00) {
1339 val = s->ioregsel;
1340 } else if (addr == 0x10) {
1341 switch (s->ioregsel) {
1342 case 0x00:
1343 val = s->id << 24;
1344 break;
1345 case 0x01:
1346 val = 0x11 | ((IOAPIC_NUM_PINS - 1) << 16); /* version 0x11 */
1347 break;
1348 case 0x02:
1349 val = 0;
1350 break;
1351 default:
1352 index = (s->ioregsel - 0x10) >> 1;
1353 if (index >= 0 && index < IOAPIC_NUM_PINS) {
1354 if (s->ioregsel & 1)
1355 val = s->ioredtbl[index] >> 32;
1356 else
1357 val = s->ioredtbl[index] & 0xffffffff;
1358 }
1359 }
1360#ifdef DEBUG_IOAPIC
1361 Log(("I/O APIC read: %08x = %08x\n", s->ioregsel, val));
1362#endif
1363 }
1364 return val;
1365}
1366
1367static void ioapic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
1368{
1369 IOAPICState *s = (IOAPICState*)opaque;
1370 int index;
1371
1372 addr &= 0xff;
1373 if (addr == 0x00) {
1374 s->ioregsel = val;
1375 return;
1376 } else if (addr == 0x10) {
1377#ifdef DEBUG_IOAPIC
1378 Log(("I/O APIC write: %08x = %08x\n", s->ioregsel, val));
1379#endif
1380 switch (s->ioregsel) {
1381 case 0x00:
1382 s->id = (val >> 24) & 0xff;
1383 return;
1384 case 0x01:
1385 case 0x02:
1386 return;
1387 default:
1388 index = (s->ioregsel - 0x10) >> 1;
1389 if (index >= 0 && index < IOAPIC_NUM_PINS) {
1390 if (s->ioregsel & 1) {
1391 s->ioredtbl[index] &= 0xffffffff;
1392 s->ioredtbl[index] |= (uint64_t)val << 32;
1393 } else {
1394 s->ioredtbl[index] &= ~0xffffffffULL;
1395 s->ioredtbl[index] |= val;
1396 }
1397 ioapic_service(s);
1398 }
1399 }
1400 }
1401}
1402
1403#ifdef IN_RING3
1404
1405static void ioapic_save(QEMUFile *f, void *opaque)
1406{
1407 IOAPICState *s = (IOAPICState*)opaque;
1408 int i;
1409
1410 qemu_put_8s(f, &s->id);
1411 qemu_put_8s(f, &s->ioregsel);
1412 for (i = 0; i < IOAPIC_NUM_PINS; i++) {
1413 qemu_put_be64s(f, &s->ioredtbl[i]);
1414 }
1415}
1416
1417static int ioapic_load(QEMUFile *f, void *opaque, int version_id)
1418{
1419 IOAPICState *s = (IOAPICState*)opaque;
1420 int i;
1421
1422 if (version_id != 1)
1423 return -EINVAL;
1424
1425 qemu_get_8s(f, &s->id);
1426 qemu_get_8s(f, &s->ioregsel);
1427 for (i = 0; i < IOAPIC_NUM_PINS; i++) {
1428 qemu_get_be64s(f, &s->ioredtbl[i]);
1429 }
1430 return 0;
1431}
1432
1433static void ioapic_reset(void *opaque)
1434{
1435 IOAPICState *s = (IOAPICState*)opaque;
1436#ifdef VBOX
1437 PPDMDEVINSR3 pDevIns = s->pDevInsHC;
1438 PCPDMIOAPICHLPR3 pIoApicHlp = s->pIoApicHlpR3;
1439#endif
1440 int i;
1441
1442 memset(s, 0, sizeof(*s));
1443 for(i = 0; i < IOAPIC_NUM_PINS; i++)
1444 s->ioredtbl[i] = 1 << 16; /* mask LVT */
1445
1446#ifdef VBOX
1447 if (pDevIns)
1448 {
1449 s->pDevInsHC = pDevIns;
1450 s->pDevInsGC = PDMDEVINS_2_GCPTR(pDevIns);
1451 }
1452 if (pIoApicHlp)
1453 {
1454 s->pIoApicHlpR3 = pIoApicHlp;
1455 s->pIoApicHlpGC = s->pIoApicHlpR3->pfnGetGCHelpers(pDevIns);
1456 s->pIoApicHlpR0 = s->pIoApicHlpR3->pfnGetR0Helpers(pDevIns);
1457 }
1458#endif
1459}
1460
1461#endif /* IN_RING3 */
1462
1463#ifndef VBOX
1464static CPUReadMemoryFunc *ioapic_mem_read[3] = {
1465 ioapic_mem_readl,
1466 ioapic_mem_readl,
1467 ioapic_mem_readl,
1468};
1469
1470static CPUWriteMemoryFunc *ioapic_mem_write[3] = {
1471 ioapic_mem_writel,
1472 ioapic_mem_writel,
1473 ioapic_mem_writel,
1474};
1475
1476IOAPICState *ioapic_init(void)
1477{
1478 IOAPICState *s;
1479 int io_memory;
1480
1481 s = qemu_mallocz(sizeof(IOAPICState));
1482 if (!s)
1483 return NULL;
1484 ioapic_reset(s);
1485 s->id = last_apic_id++;
1486
1487 io_memory = cpu_register_io_memory(0, ioapic_mem_read,
1488 ioapic_mem_write, s);
1489 cpu_register_physical_memory(0xfec00000, 0x1000, io_memory);
1490
1491 register_savevm("ioapic", 0, 1, ioapic_save, ioapic_load, s);
1492 qemu_register_reset(ioapic_reset, s);
1493
1494 return s;
1495}
1496#endif /* !VBOX */
1497
1498/* LAPIC */
1499
1500/* LAPICs MMIO is wrong, in SMP there is no relation between memory range and
1501 lapic, it's only the CPU that executes this memory access is what matters */
1502
1503PDMBOTHCBDECL(int) apicMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
1504{
1505 APICState *s = PDMINS2DATA(pDevIns, APICState *);
1506
1507 STAM_COUNTER_INC(&CTXSUFF(s->StatMMIORead));
1508 switch (cb)
1509 {
1510 case 1:
1511 *(uint8_t *)pv = 0;
1512 break;
1513
1514 case 2:
1515 *(uint16_t *)pv = 0;
1516 break;
1517
1518 case 4:
1519 {
1520#if 0 /** @note experimental */
1521#ifndef IN_RING3
1522 uint32_t index = (GCPhysAddr >> 4) & 0xff;
1523
1524 if ( index == 0x08 /* TPR */
1525 && ++s->ulTPRPatchAttempts < APIC_MAX_PATCH_ATTEMPTS)
1526 {
1527#ifdef IN_GC
1528 pDevIns->pDevHlpGC->pfnPATMSetMMIOPatchInfo(pDevIns, GCPhysAddr, &s->tpr);
1529#else
1530 RTGCPTR pDevInsGC = PDMINS2DATA_GCPTR(pDevIns);
1531 pDevIns->pDevHlpR0->pfnPATMSetMMIOPatchInfo(pDevIns, GCPhysAddr, pDevIns + RT_OFFSETOF(APICState, tpr));
1532#endif
1533 return VINF_PATM_HC_MMIO_PATCH_READ;
1534 }
1535#endif
1536#endif /* experimental */
1537 APIC_LOCK(s, VINF_IOM_HC_MMIO_READ);
1538 *(uint32_t *)pv = apic_mem_readl(s, GCPhysAddr);
1539 APIC_UNLOCK(s);
1540 break;
1541 }
1542 default:
1543 AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */
1544 return VERR_INTERNAL_ERROR;
1545 }
1546 return VINF_SUCCESS;
1547}
1548
1549PDMBOTHCBDECL(int) apicMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
1550{
1551 APICState *s = PDMINS2DATA(pDevIns, APICState *);
1552
1553 STAM_COUNTER_INC(&CTXSUFF(s->StatMMIOWrite));
1554 switch (cb)
1555 {
1556 case 1:
1557 case 2:
1558 /* ignore */
1559 break;
1560
1561 case 4:
1562 {
1563 int rc;
1564 APIC_LOCK(s, VINF_IOM_HC_MMIO_WRITE);
1565 rc = apic_mem_writel(s, GCPhysAddr, *(uint32_t *)pv);
1566 APIC_UNLOCK(s);
1567 return rc;
1568 }
1569
1570 default:
1571 AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */
1572 return VERR_INTERNAL_ERROR;
1573 }
1574 return VINF_SUCCESS;
1575}
1576
1577#ifdef IN_RING3
1578
1579/**
1580 * @copydoc FNSSMDEVSAVEEXEC
1581 */
1582static DECLCALLBACK(int) apicSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
1583{
1584 APICState *s = PDMINS2DATA(pDevIns, APICState *);
1585 apic_save(pSSMHandle, s);
1586 return TMR3TimerSave(s->CTXSUFF(pTimer), pSSMHandle);
1587}
1588
1589/**
1590 * @copydoc FNSSMDEVLOADEXEC
1591 */
1592static DECLCALLBACK(int) apicLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle, uint32_t u32Version)
1593{
1594 APICState *s = PDMINS2DATA(pDevIns, APICState *);
1595 if (apic_load(pSSMHandle, s, u32Version)) {
1596 AssertFailed();
1597 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1598 }
1599 return TMR3TimerLoad(s->CTXSUFF(pTimer), pSSMHandle);
1600}
1601
1602/**
1603 * @copydoc FNPDMDEVRESET
1604 */
1605static DECLCALLBACK(void) apicReset(PPDMDEVINS pDevIns)
1606{
1607 APICState *s = PDMINS2DATA(pDevIns, APICState *);
1608#ifdef VBOX_WITH_PDM_LOCK
1609 s->pApicHlpR3->pfnLock(pDevIns, VERR_INTERNAL_ERROR);
1610#endif
1611 apic_reset(s);
1612 /* Clear any pending APIC interrupt action flag. */
1613 s->pApicHlpR3->pfnClearInterruptFF(pDevIns);
1614 APIC_UNLOCK(s);
1615}
1616
1617/**
1618 * @copydoc FNPDMDEVRELOCATE
1619 */
1620static DECLCALLBACK(void) apicRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
1621{
1622 APICState *pData = PDMINS2DATA(pDevIns, APICState *);
1623 pData->pDevInsGC = PDMDEVINS_2_GCPTR(pDevIns);
1624 pData->pApicHlpGC = pData->pApicHlpR3->pfnGetGCHelpers(pDevIns);
1625 pData->pTimerGC = TMTimerGCPtr(pData->CTXSUFF(pTimer));
1626}
1627
1628/**
1629 * @copydoc FNPDMDEVCONSTRUCT
1630 */
1631static DECLCALLBACK(int) apicConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
1632{
1633 APICState *pData = PDMINS2DATA(pDevIns, APICState *);
1634 PDMAPICREG ApicReg;
1635 int rc;
1636 int i;
1637 bool fIOAPIC;
1638 bool fGCEnabled;
1639 bool fR0Enabled;
1640 Assert(iInstance == 0);
1641
1642 /*
1643 * Validate configuration.
1644 */
1645 if (!CFGMR3AreValuesValid(pCfgHandle, "IOAPIC\0GCEnabled\0R0Enabled\0"))
1646 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
1647
1648 rc = CFGMR3QueryBool (pCfgHandle, "IOAPIC", &fIOAPIC);
1649 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1650 fIOAPIC = true;
1651 else if (VBOX_FAILURE (rc))
1652 return PDMDEV_SET_ERROR(pDevIns, rc,
1653 N_("Configuration error: Failed to read \"IOAPIC\""));
1654
1655 rc = CFGMR3QueryBool(pCfgHandle, "GCEnabled", &fGCEnabled);
1656 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1657 fGCEnabled = true;
1658 else
1659 return PDMDEV_SET_ERROR(pDevIns, rc,
1660 N_("Configuration error: Failed to query boolean value \"GCEnabled\""));
1661 Log(("APIC: fGCEnabled=%d\n", fGCEnabled));
1662
1663 rc = CFGMR3QueryBool(pCfgHandle, "R0Enabled", &fR0Enabled);
1664 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1665 fR0Enabled = true;
1666 else
1667 return PDMDEV_SET_ERROR(pDevIns, rc,
1668 N_("Configuration error: Failed to query boolean value \"R0Enabled\""));
1669 Log(("APIC: fR0Enabled=%d\n", fR0Enabled));
1670
1671 /*
1672 * Init the data.
1673 */
1674 pData->pDevInsHC = pDevIns;
1675 pData->pDevInsGC = PDMDEVINS_2_GCPTR(pDevIns);
1676 pData->apicbase = 0xfee00000 | MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE;
1677 for (i = 0; i < APIC_LVT_NB; i++)
1678 pData->lvt[i] = 1 << 16; /* mask LVT */
1679 pData->spurious_vec = 0xff;
1680
1681 /*
1682 * Register the APIC.
1683 */
1684 ApicReg.u32Version = PDM_APICREG_VERSION;
1685 ApicReg.pfnGetInterruptHC = apicGetInterrupt;
1686 ApicReg.pfnSetBaseHC = apicSetBase;
1687 ApicReg.pfnGetBaseHC = apicGetBase;
1688 ApicReg.pfnSetTPRHC = apicSetTPR;
1689 ApicReg.pfnGetTPRHC = apicGetTPR;
1690 ApicReg.pfnBusDeliverHC = apicBusDeliverCallback;
1691 if (fGCEnabled) {
1692 ApicReg.pszGetInterruptGC = "apicGetInterrupt";
1693 ApicReg.pszSetBaseGC = "apicSetBase";
1694 ApicReg.pszGetBaseGC = "apicGetBase";
1695 ApicReg.pszSetTPRGC = "apicSetTPR";
1696 ApicReg.pszGetTPRGC = "apicGetTPR";
1697 ApicReg.pszBusDeliverGC = "apicBusDeliverCallback";
1698 } else {
1699 ApicReg.pszGetInterruptGC = NULL;
1700 ApicReg.pszSetBaseGC = NULL;
1701 ApicReg.pszGetBaseGC = NULL;
1702 ApicReg.pszSetTPRGC = NULL;
1703 ApicReg.pszGetTPRGC = NULL;
1704 ApicReg.pszBusDeliverGC = NULL;
1705 }
1706 if (fR0Enabled) {
1707 ApicReg.pszGetInterruptR0 = "apicGetInterrupt";
1708 ApicReg.pszSetBaseR0 = "apicSetBase";
1709 ApicReg.pszGetBaseR0 = "apicGetBase";
1710 ApicReg.pszSetTPRR0 = "apicSetTPR";
1711 ApicReg.pszGetTPRR0 = "apicGetTPR";
1712 ApicReg.pszBusDeliverR0 = "apicBusDeliverCallback";
1713 } else {
1714 ApicReg.pszGetInterruptR0 = NULL;
1715 ApicReg.pszSetBaseR0 = NULL;
1716 ApicReg.pszGetBaseR0 = NULL;
1717 ApicReg.pszSetTPRR0 = NULL;
1718 ApicReg.pszGetTPRR0 = NULL;
1719 ApicReg.pszBusDeliverR0 = NULL;
1720 }
1721
1722 Assert(pDevIns->pDevHlp->pfnAPICRegister);
1723 rc = pDevIns->pDevHlp->pfnAPICRegister(pDevIns, &ApicReg, &pData->pApicHlpR3);
1724 if (VBOX_FAILURE(rc))
1725 {
1726 AssertMsgFailed(("APICRegister -> %Vrc\n", rc));
1727 return rc;
1728 }
1729 pData->pApicHlpGC = pData->pApicHlpR3->pfnGetGCHelpers(pDevIns);
1730
1731 /*
1732 * The the CPUID feature bit.
1733 */
1734 uint32_t u32Eax, u32Ebx, u32Ecx, u32Edx;
1735 PDMDevHlpGetCpuId(pDevIns, 0, &u32Eax, &u32Ebx, &u32Ecx, &u32Edx);
1736 if (u32Eax >= 1)
1737 {
1738 if ( fIOAPIC /* If IOAPIC is enabled, enable Local APIC in any case */
1739 || ( u32Ebx == X86_CPUID_VENDOR_INTEL_EBX
1740 && u32Ecx == X86_CPUID_VENDOR_INTEL_ECX
1741 && u32Edx == X86_CPUID_VENDOR_INTEL_EDX /* GenuineIntel */)
1742 || ( u32Ebx == X86_CPUID_VENDOR_AMD_EBX
1743 && u32Ecx == X86_CPUID_VENDOR_AMD_ECX
1744 && u32Edx == X86_CPUID_VENDOR_AMD_EDX /* AuthenticAMD */))
1745 {
1746 LogRel(("Activating Local APIC\n"));
1747 pData->pApicHlpR3->pfnChangeFeature(pDevIns, true);
1748 }
1749 }
1750
1751 /*
1752 * Register the MMIO range.
1753 */
1754 rc = PDMDevHlpMMIORegister(pDevIns, pData->apicbase & ~0xfff, 0x1000, pData,
1755 apicMMIOWrite, apicMMIORead, NULL, "APIC Memory");
1756 if (VBOX_FAILURE(rc))
1757 return rc;
1758
1759 if (fGCEnabled) {
1760 rc = PDMDevHlpMMIORegisterGC(pDevIns, pData->apicbase & ~0xfff, 0x1000, 0,
1761 "apicMMIOWrite", "apicMMIORead", NULL, "APIC Memory");
1762 if (VBOX_FAILURE(rc))
1763 return rc;
1764 }
1765
1766 if (fR0Enabled) {
1767 pData->pApicHlpR0 = pData->pApicHlpR3->pfnGetR0Helpers(pDevIns);
1768
1769 rc = PDMDevHlpMMIORegisterR0(pDevIns, pData->apicbase & ~0xfff, 0x1000, 0,
1770 "apicMMIOWrite", "apicMMIORead", NULL, "APIC Memory");
1771 if (VBOX_FAILURE(rc))
1772 return rc;
1773 }
1774
1775 /*
1776 * Create the APIC timer.
1777 */
1778 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, apicTimer,
1779 "APIC Timer", &pData->CTXSUFF(pTimer));
1780 if (VBOX_FAILURE(rc))
1781 return rc;
1782 pData->pTimerGC = TMTimerGCPtr(pData->CTXSUFF(pTimer));
1783
1784 /*
1785 * Saved state.
1786 */
1787 rc = PDMDevHlpSSMRegister(pDevIns, pDevIns->pDevReg->szDeviceName, iInstance, 1 /* version */,
1788 sizeof(*pData), NULL, apicSaveExec, NULL, NULL, apicLoadExec, NULL);
1789 if (VBOX_FAILURE(rc))
1790 return rc;
1791
1792#ifdef VBOX_WITH_STATISTICS
1793 /*
1794 * Statistics.
1795 */
1796 PDMDevHlpSTAMRegister(pDevIns, &pData->StatMMIOReadGC, STAMTYPE_COUNTER, "/PDM/APIC/MMIOReadGC", STAMUNIT_OCCURENCES, "Number of APIC MMIO reads in GC.");
1797 PDMDevHlpSTAMRegister(pDevIns, &pData->StatMMIOReadHC, STAMTYPE_COUNTER, "/PDM/APIC/MMIOReadHC", STAMUNIT_OCCURENCES, "Number of APIC MMIO reads in HC.");
1798 PDMDevHlpSTAMRegister(pDevIns, &pData->StatMMIOWriteGC, STAMTYPE_COUNTER, "/PDM/APIC/MMIOWriteGC", STAMUNIT_OCCURENCES, "Number of APIC MMIO writes in GC.");
1799 PDMDevHlpSTAMRegister(pDevIns, &pData->StatMMIOWriteHC, STAMTYPE_COUNTER, "/PDM/APIC/MMIOWriteHC", STAMUNIT_OCCURENCES, "Number of APIC MMIO writes in HC.");
1800 PDMDevHlpSTAMRegister(pDevIns, &pData->StatClearedActiveIrq, STAMTYPE_COUNTER, "/PDM/APIC/Masked/ActiveIRQ", STAMUNIT_OCCURENCES, "Number of cleared irqs.");
1801#endif
1802
1803 return VINF_SUCCESS;
1804}
1805
1806
1807/**
1808 * APIC device registration structure.
1809 */
1810const PDMDEVREG g_DeviceAPIC =
1811{
1812 /* u32Version */
1813 PDM_DEVREG_VERSION,
1814 /* szDeviceName */
1815 "apic",
1816 /* szGCMod */
1817 "VBoxDD2GC.gc",
1818 /* szR0Mod */
1819 "VBoxDD2R0.r0",
1820 /* pszDescription */
1821 "Advanced Programmable Interrupt Controller (APIC) Device",
1822 /* fFlags */
1823 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64 | PDM_DEVREG_FLAGS_PAE36 | PDM_DEVREG_FLAGS_GC | PDM_DEVREG_FLAGS_R0,
1824 /* fClass */
1825 PDM_DEVREG_CLASS_PIC,
1826 /* cMaxInstances */
1827 1,
1828 /* cbInstance */
1829 sizeof(APICState),
1830 /* pfnConstruct */
1831 apicConstruct,
1832 /* pfnDestruct */
1833 NULL,
1834 /* pfnRelocate */
1835 apicRelocate,
1836 /* pfnIOCtl */
1837 NULL,
1838 /* pfnPowerOn */
1839 NULL,
1840 /* pfnReset */
1841 apicReset,
1842 /* pfnSuspend */
1843 NULL,
1844 /* pfnResume */
1845 NULL,
1846 /* pfnAttach */
1847 NULL,
1848 /* pfnDetach */
1849 NULL,
1850 /* pfnQueryInterface. */
1851 NULL
1852};
1853
1854#endif /* IN_RING3 */
1855
1856
1857
1858
1859/* IOAPIC */
1860
1861PDMBOTHCBDECL(int) ioapicMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
1862{
1863 IOAPICState *s = PDMINS2DATA(pDevIns, IOAPICState *);
1864 IOAPIC_LOCK(s, VINF_IOM_HC_MMIO_READ);
1865
1866 STAM_COUNTER_INC(&CTXSUFF(s->StatMMIORead));
1867 switch (cb)
1868 {
1869 case 1:
1870 *(uint8_t *)pv = ioapic_mem_readl(s, GCPhysAddr);
1871 break;
1872
1873 case 2:
1874 *(uint16_t *)pv = ioapic_mem_readl(s, GCPhysAddr);
1875 break;
1876
1877 case 4:
1878 *(uint32_t *)pv = ioapic_mem_readl(s, GCPhysAddr);
1879 break;
1880
1881 default:
1882 AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */
1883 IOAPIC_UNLOCK(s);
1884 return VERR_INTERNAL_ERROR;
1885 }
1886 IOAPIC_UNLOCK(s);
1887 return VINF_SUCCESS;
1888}
1889
1890PDMBOTHCBDECL(int) ioapicMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
1891{
1892 IOAPICState *s = PDMINS2DATA(pDevIns, IOAPICState *);
1893
1894 STAM_COUNTER_INC(&CTXSUFF(s->StatMMIOWrite));
1895 switch (cb)
1896 {
1897 case 1:
1898 case 2:
1899 case 4:
1900 IOAPIC_LOCK(s, VINF_IOM_HC_MMIO_WRITE);
1901 ioapic_mem_writel(s, GCPhysAddr, *(uint32_t *)pv);
1902 IOAPIC_UNLOCK(s);
1903 break;
1904
1905 default:
1906 AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */
1907 return VERR_INTERNAL_ERROR;
1908 }
1909 return VINF_SUCCESS;
1910}
1911
1912PDMBOTHCBDECL(void) ioapicSetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel)
1913{
1914 IOAPICState *pThis = PDMINS2DATA(pDevIns, IOAPICState *);
1915 STAM_COUNTER_INC(&pThis->CTXSUFF(StatSetIrq));
1916 LogFlow(("ioapicSetIrq: iIrq=%d iLevel=%d\n", iIrq, iLevel));
1917 ioapic_set_irq(pThis, iIrq, iLevel);
1918}
1919
1920
1921#ifdef IN_RING3
1922
1923/**
1924 * @copydoc FNSSMDEVSAVEEXEC
1925 */
1926static DECLCALLBACK(int) ioapicSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
1927{
1928 IOAPICState *s = PDMINS2DATA(pDevIns, IOAPICState *);
1929 ioapic_save(pSSMHandle, s);
1930 return VINF_SUCCESS;
1931}
1932
1933/**
1934 * @copydoc FNSSMDEVLOADEXEC
1935 */
1936static DECLCALLBACK(int) ioapicLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle, uint32_t u32Version)
1937{
1938 IOAPICState *s = PDMINS2DATA(pDevIns, IOAPICState *);
1939
1940 if (ioapic_load(pSSMHandle, s, u32Version)) {
1941 AssertFailed();
1942 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1943 }
1944
1945 return VINF_SUCCESS;
1946}
1947
1948/**
1949 * @copydoc FNPDMDEVRESET
1950 */
1951static DECLCALLBACK(void) ioapicReset(PPDMDEVINS pDevIns)
1952{
1953 IOAPICState *s = PDMINS2DATA(pDevIns, IOAPICState *);
1954#ifdef VBOX_WITH_PDM_LOCK
1955 s->pIoApicHlpR3->pfnLock(pDevIns, VERR_INTERNAL_ERROR);
1956#endif
1957 ioapic_reset(s);
1958 IOAPIC_UNLOCK(s);
1959}
1960
1961/**
1962 * @copydoc FNPDMDEVRELOCATE
1963 */
1964static DECLCALLBACK(void) ioapicRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
1965{
1966 IOAPICState *s = PDMINS2DATA(pDevIns, IOAPICState *);
1967 s->pDevInsGC = PDMDEVINS_2_GCPTR(pDevIns);
1968 s->pIoApicHlpGC = s->pIoApicHlpR3->pfnGetGCHelpers(pDevIns);
1969}
1970
1971/**
1972 * @copydoc FNPDMDEVCONSTRUCT
1973 */
1974static DECLCALLBACK(int) ioapicConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
1975{
1976 IOAPICState *s = PDMINS2DATA(pDevIns, IOAPICState *);
1977 PDMIOAPICREG IoApicReg;
1978 bool fGCEnabled;
1979 bool fR0Enabled;
1980 int rc;
1981
1982 Assert(iInstance == 0);
1983
1984 /*
1985 * Validate and read the configuration.
1986 */
1987 if (!CFGMR3AreValuesValid(pCfgHandle, "GCEnabled\0R0Enabled\0"))
1988 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
1989
1990 rc = CFGMR3QueryBool(pCfgHandle, "GCEnabled", &fGCEnabled);
1991 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1992 fGCEnabled = true;
1993 else if (VBOX_FAILURE(rc))
1994 return PDMDEV_SET_ERROR(pDevIns, rc,
1995 N_("Configuration error: Failed to query boolean value \"GCEnabled\""));
1996 Log(("IOAPIC: fGCEnabled=%d\n", fGCEnabled));
1997
1998 rc = CFGMR3QueryBool(pCfgHandle, "R0Enabled", &fR0Enabled);
1999 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
2000 fR0Enabled = true;
2001 else if (VBOX_FAILURE(rc))
2002 return PDMDEV_SET_ERROR(pDevIns, rc,
2003 N_("Configuration error: Failed to query boolean value \"R0Enabled\""));
2004 Log(("IOAPIC: fR0Enabled=%d\n", fR0Enabled));
2005
2006 /*
2007 * Initialize the state data.
2008 */
2009 s->pDevInsHC = pDevIns;
2010 s->pDevInsGC = PDMDEVINS_2_GCPTR(pDevIns);
2011 ioapic_reset(s);
2012 s->id = 0;
2013
2014 /*
2015 * Register the IOAPIC and get helpers.
2016 */
2017 IoApicReg.u32Version = PDM_IOAPICREG_VERSION;
2018 IoApicReg.pfnSetIrqHC = ioapicSetIrq;
2019 IoApicReg.pszSetIrqGC = fGCEnabled ? "ioapicSetIrq" : NULL;
2020 IoApicReg.pszSetIrqR0 = fR0Enabled ? "ioapicSetIrq" : NULL;
2021 rc = pDevIns->pDevHlp->pfnIOAPICRegister(pDevIns, &IoApicReg, &s->pIoApicHlpR3);
2022 if (VBOX_FAILURE(rc))
2023 {
2024 AssertMsgFailed(("IOAPICRegister -> %Vrc\n", rc));
2025 return rc;
2026 }
2027 s->pIoApicHlpGC = s->pIoApicHlpR3->pfnGetGCHelpers(pDevIns);
2028
2029 /*
2030 * Register MMIO callbacks and saved state.
2031 */
2032 rc = PDMDevHlpMMIORegister(pDevIns, 0xfec00000, 0x1000, s,
2033 ioapicMMIOWrite, ioapicMMIORead, NULL, "I/O APIC Memory");
2034 if (VBOX_FAILURE(rc))
2035 return rc;
2036
2037 if (fGCEnabled) {
2038 rc = PDMDevHlpMMIORegisterGC(pDevIns, 0xfec00000, 0x1000, 0,
2039 "ioapicMMIOWrite", "ioapicMMIORead", NULL, "I/O APIC Memory");
2040 if (VBOX_FAILURE(rc))
2041 return rc;
2042 }
2043
2044 if (fR0Enabled) {
2045 s->pIoApicHlpR0 = s->pIoApicHlpR3->pfnGetR0Helpers(pDevIns);
2046
2047 rc = PDMDevHlpMMIORegisterR0(pDevIns, 0xfec00000, 0x1000, 0,
2048 "ioapicMMIOWrite", "ioapicMMIORead", NULL, "I/O APIC Memory");
2049 if (VBOX_FAILURE(rc))
2050 return rc;
2051 }
2052
2053 rc = PDMDevHlpSSMRegister(pDevIns, pDevIns->pDevReg->szDeviceName, iInstance, 1 /* version */,
2054 sizeof(*s), NULL, ioapicSaveExec, NULL, NULL, ioapicLoadExec, NULL);
2055 if (VBOX_FAILURE(rc))
2056 return rc;
2057
2058#ifdef VBOX_WITH_STATISTICS
2059 /*
2060 * Statistics.
2061 */
2062 PDMDevHlpSTAMRegister(pDevIns, &s->StatMMIOReadGC, STAMTYPE_COUNTER, "/PDM/IOAPIC/MMIOReadGC", STAMUNIT_OCCURENCES, "Number of IOAPIC MMIO reads in GC.");
2063 PDMDevHlpSTAMRegister(pDevIns, &s->StatMMIOReadHC, STAMTYPE_COUNTER, "/PDM/IOAPIC/MMIOReadHC", STAMUNIT_OCCURENCES, "Number of IOAPIC MMIO reads in HC.");
2064 PDMDevHlpSTAMRegister(pDevIns, &s->StatMMIOWriteGC, STAMTYPE_COUNTER, "/PDM/IOAPIC/MMIOWriteGC", STAMUNIT_OCCURENCES, "Number of IOAPIC MMIO writes in GC.");
2065 PDMDevHlpSTAMRegister(pDevIns, &s->StatMMIOWriteHC, STAMTYPE_COUNTER, "/PDM/IOAPIC/MMIOWriteHC", STAMUNIT_OCCURENCES, "Number of IOAPIC MMIO writes in HC.");
2066 PDMDevHlpSTAMRegister(pDevIns, &s->StatSetIrqGC, STAMTYPE_COUNTER, "/PDM/IOAPIC/SetIrqGC", STAMUNIT_OCCURENCES, "Number of IOAPIC SetIrq calls in GC.");
2067 PDMDevHlpSTAMRegister(pDevIns, &s->StatSetIrqHC, STAMTYPE_COUNTER, "/PDM/IOAPIC/SetIrqHC", STAMUNIT_OCCURENCES, "Number of IOAPIC SetIrq calls in HC.");
2068#endif
2069
2070 return VINF_SUCCESS;
2071}
2072
2073/**
2074 * IO APIC device registration structure.
2075 */
2076const PDMDEVREG g_DeviceIOAPIC =
2077{
2078 /* u32Version */
2079 PDM_DEVREG_VERSION,
2080 /* szDeviceName */
2081 "ioapic",
2082 /* szGCMod */
2083 "VBoxDD2GC.gc",
2084 /* szR0Mod */
2085 "VBoxDD2R0.r0",
2086 /* pszDescription */
2087 "I/O Advanced Programmable Interrupt Controller (IO-APIC) Device",
2088 /* fFlags */
2089 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64 | PDM_DEVREG_FLAGS_PAE36 | PDM_DEVREG_FLAGS_GC | PDM_DEVREG_FLAGS_R0,
2090 /* fClass */
2091 PDM_DEVREG_CLASS_PIC,
2092 /* cMaxInstances */
2093 1,
2094 /* cbInstance */
2095 sizeof(IOAPICState),
2096 /* pfnConstruct */
2097 ioapicConstruct,
2098 /* pfnDestruct */
2099 NULL,
2100 /* pfnRelocate */
2101 ioapicRelocate,
2102 /* pfnIOCtl */
2103 NULL,
2104 /* pfnPowerOn */
2105 NULL,
2106 /* pfnReset */
2107 ioapicReset,
2108 /* pfnSuspend */
2109 NULL,
2110 /* pfnResume */
2111 NULL,
2112 /* pfnAttach */
2113 NULL,
2114 /* pfnDetach */
2115 NULL,
2116 /* pfnQueryInterface. */
2117 NULL,
2118 /* pfnInitComplete */
2119 NULL,
2120 /* pfnPowerOff */
2121 NULL
2122};
2123
2124#endif /* IN_RING3 */
2125#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
2126
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