VirtualBox

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

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

APIC versioning in features interface

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