VirtualBox

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

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

Implemented apicHasPendingIrq.

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

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