VirtualBox

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

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

per-LAPIC timers, cleanup, all LAPICs state save-restore, relocation

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