VirtualBox

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

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

some interrupt routing code

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