VirtualBox

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

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

DevAPIC: Added usage note and assertion to APIC_LOCK_VOID and update the docs of the other lock macros.

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

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