VirtualBox

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

Last change on this file since 10719 was 10665, checked in by vboxsync, 16 years ago

Fixed apicHasPendingInterrupt.

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