VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/apic.c@ 239

Last change on this file since 239 was 1, checked in by vboxsync, 55 years ago

import

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