VirtualBox

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

Last change on this file since 10390 was 10214, checked in by vboxsync, 16 years ago

Too noisy log statement

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