VirtualBox

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

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

The Big Sun Rebranding Header Change

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