VirtualBox

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

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

further APIC work

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette