VirtualBox

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

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

Devices: %Vrc -> %Rrc (just preferred, not mandatory (yet))

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