VirtualBox

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

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

More logging

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