VirtualBox

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

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

DevAPIC: Save and verify config. Added a couple of review comments.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 105.8 KB
Line 
1#ifdef VBOX
2/* $Id: DevAPIC.cpp 24082 2009-10-26 15:06:19Z 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#ifdef VBOX
47#define MSR_IA32_APICBASE_X2ENABLE (1<<10)
48#endif
49#define MSR_IA32_APICBASE_BASE (0xfffff<<12)
50
51#ifndef EINVAL
52# define EINVAL 1
53#endif
54
55#ifdef _MSC_VER
56# pragma warning(disable:4244)
57#endif
58
59/** The current saved state version.*/
60#define APIC_SAVED_STATE_VERSION 3
61/** The saved state version used by VirtualBox v3 and earlier.
62 * This does not include the config. */
63#define APIC_SAVED_STATE_VERSION_VBOX_30 2
64/** Some ancient version... */
65#define APIC_SAVED_STATE_VERSION_ANCIENT 1
66
67
68/** @def APIC_LOCK
69 * Acquires the PDM lock. */
70#define APIC_LOCK(pThis, rcBusy) \
71 do { \
72 int rc2 = PDMCritSectEnter((pThis)->CTX_SUFF(pCritSect), (rcBusy)); \
73 if (rc2 != VINF_SUCCESS) \
74 return rc2; \
75 } while (0)
76
77/** @def APIC_LOCK_VOID
78 * Acquires the PDM lock and does not expect failure (i.e. ring-3 only!). */
79#define APIC_LOCK_VOID(pThis, rcBusy) \
80 do { \
81 int rc2 = PDMCritSectEnter((pThis)->CTX_SUFF(pCritSect), (rcBusy)); \
82 AssertLogRelRCReturnVoid(rc2); \
83 } while (0)
84
85/** @def APIC_UNLOCK
86 * Releases the PDM lock. */
87#define APIC_UNLOCK(pThis) \
88 PDMCritSectLeave((pThis)->CTX_SUFF(pCritSect))
89
90/** @def IOAPIC_LOCK
91 * Acquires the PDM lock. */
92#define IOAPIC_LOCK(pThis, rc) \
93 do { \
94 int rc2 = (pThis)->CTX_SUFF(pIoApicHlp)->pfnLock((pThis)->CTX_SUFF(pDevIns), rc); \
95 if (rc2 != VINF_SUCCESS) \
96 return rc2; \
97 } while (0)
98
99/** @def IOAPIC_UNLOCK
100 * Releases the PDM lock. */
101#define IOAPIC_UNLOCK(pThis) (pThis)->CTX_SUFF(pIoApicHlp)->pfnUnlock((pThis)->CTX_SUFF(pDevIns))
102
103
104#define foreach_apic(dev, mask, code) \
105 do { \
106 uint32_t i; \
107 APICState *apic = (dev)->CTX_SUFF(paLapics); \
108 for (i = 0; i < (dev)->cCpus; i++) \
109 { \
110 if (mask & (1 << (apic->id))) \
111 { \
112 code; \
113 } \
114 apic++; \
115 } \
116 } while (0)
117
118# define set_bit(pvBitmap, iBit) ASMBitSet(pvBitmap, iBit)
119# define reset_bit(pvBitmap, iBit) ASMBitClear(pvBitmap, iBit)
120# define fls_bit(value) (ASMBitLastSetU32(value) - 1)
121# define ffs_bit(value) (ASMBitFirstSetU32(value) - 1)
122
123#endif /* VBOX */
124
125/*
126 * APIC support
127 *
128 * Copyright (c) 2004-2005 Fabrice Bellard
129 *
130 * This library is free software; you can redistribute it and/or
131 * modify it under the terms of the GNU Lesser General Public
132 * License as published by the Free Software Foundation; either
133 * version 2 of the License, or (at your option) any later version.
134 *
135 * This library is distributed in the hope that it will be useful,
136 * but WITHOUT ANY WARRANTY; without even the implied warranty of
137 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
138 * Lesser General Public License for more details.
139 *
140 * You should have received a copy of the GNU Lesser General Public
141 * License along with this library; if not, write to the Free Software
142 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
143 */
144#ifndef VBOX
145#include "vl.h"
146#endif
147
148#define DEBUG_APIC
149#define DEBUG_IOAPIC
150
151/* APIC Local Vector Table */
152#define APIC_LVT_TIMER 0
153#define APIC_LVT_THERMAL 1
154#define APIC_LVT_PERFORM 2
155#define APIC_LVT_LINT0 3
156#define APIC_LVT_LINT1 4
157#define APIC_LVT_ERROR 5
158#define APIC_LVT_NB 6
159
160/* APIC delivery modes */
161#define APIC_DM_FIXED 0
162#define APIC_DM_LOWPRI 1
163#define APIC_DM_SMI 2
164#define APIC_DM_NMI 4
165#define APIC_DM_INIT 5
166#define APIC_DM_SIPI 6
167#define APIC_DM_EXTINT 7
168
169/* APIC destination mode */
170#define APIC_DESTMODE_FLAT 0xf
171#define APIC_DESTMODE_CLUSTER 1
172
173#define APIC_TRIGGER_EDGE 0
174#define APIC_TRIGGER_LEVEL 1
175
176#define APIC_LVT_TIMER_PERIODIC (1<<17)
177#define APIC_LVT_MASKED (1<<16)
178#define APIC_LVT_LEVEL_TRIGGER (1<<15)
179#define APIC_LVT_REMOTE_IRR (1<<14)
180#define APIC_INPUT_POLARITY (1<<13)
181#define APIC_SEND_PENDING (1<<12)
182
183#define IOAPIC_NUM_PINS 0x18
184
185#define ESR_ILLEGAL_ADDRESS (1 << 7)
186
187#define APIC_SV_ENABLE (1 << 8)
188
189#ifdef VBOX
190#define APIC_MAX_PATCH_ATTEMPTS 100
191
192typedef uint32_t PhysApicId;
193typedef uint32_t LogApicId;
194#endif
195
196typedef struct APICState {
197#ifndef VBOX
198 CPUState *cpu_env;
199#endif /* !VBOX */
200 uint32_t apicbase;
201#ifdef VBOX
202 /* Task priority register (interrupt level) */
203 uint32_t tpr;
204 /* Logical APIC id */
205 LogApicId id;
206 /* Physical APIC id */
207 PhysApicId phys_id;
208 /** @todo: is it logical or physical? Not really used anyway now. */
209 PhysApicId arb_id;
210#else
211 uint8_t tpr;
212 uint8_t id;
213 uint8_t arb_id;
214#endif
215 uint32_t spurious_vec;
216 uint8_t log_dest;
217 uint8_t dest_mode;
218 uint32_t isr[8]; /* in service register */
219 uint32_t tmr[8]; /* trigger mode register */
220 uint32_t irr[8]; /* interrupt request register */
221 uint32_t lvt[APIC_LVT_NB];
222 uint32_t esr; /* error register */
223 uint32_t icr[2];
224 uint32_t divide_conf;
225 int count_shift;
226 uint32_t initial_count;
227#ifdef VBOX
228 uint32_t Alignment0;
229#endif
230#ifndef VBOX
231 int64_t initial_count_load_time, next_time;
232 QEMUTimer *timer;
233 struct APICState *next_apic;
234#else
235 /** The time stamp of the initial_count load, i.e. when it was started. */
236 uint64_t initial_count_load_time;
237 /** The time stamp of the next timer callback. */
238 uint64_t next_time;
239 /** The APIC timer - R3 Ptr. */
240 PTMTIMERR3 pTimerR3;
241 /** The APIC timer - R0 Ptr. */
242 PTMTIMERR0 pTimerR0;
243 /** The APIC timer - RC Ptr. */
244 PTMTIMERRC pTimerRC;
245 /** Whether the timer is armed or not */
246 bool fTimerArmed;
247 /** Alignment */
248 bool afAlignment[3];
249 /** Timer description timer. */
250 R3PTRTYPE(char *) pszDesc;
251# ifdef VBOX_WITH_STATISTICS
252# if HC_ARCH_BITS == 32
253 uint32_t u32Alignment0;
254# endif
255 STAMCOUNTER StatTimerSetInitialCount;
256 STAMCOUNTER StatTimerSetInitialCountArm;
257 STAMCOUNTER StatTimerSetInitialCountDisarm;
258 STAMCOUNTER StatTimerSetLvt;
259 STAMCOUNTER StatTimerSetLvtClearPeriodic;
260 STAMCOUNTER StatTimerSetLvtPostponed;
261 STAMCOUNTER StatTimerSetLvtArmed;
262 STAMCOUNTER StatTimerSetLvtArm;
263 STAMCOUNTER StatTimerSetLvtArmRetries;
264 STAMCOUNTER StatTimerSetLvtNoRelevantChange;
265# endif
266#endif /* VBOX */
267} APICState;
268#ifdef VBOX
269AssertCompileMemberAlignment(APICState, initial_count_load_time, 8);
270# ifdef VBOX_WITH_STATISTICS
271AssertCompileMemberAlignment(APICState, StatTimerSetInitialCount, 8);
272# endif
273#endif
274
275struct IOAPICState {
276 uint8_t id;
277 uint8_t ioregsel;
278
279 uint32_t irr;
280 uint64_t ioredtbl[IOAPIC_NUM_PINS];
281
282#ifdef VBOX
283 /** The device instance - R3 Ptr. */
284 PPDMDEVINSR3 pDevInsR3;
285 /** The IOAPIC helpers - R3 Ptr. */
286 PCPDMIOAPICHLPR3 pIoApicHlpR3;
287
288 /** The device instance - R0 Ptr. */
289 PPDMDEVINSR0 pDevInsR0;
290 /** The IOAPIC helpers - R0 Ptr. */
291 PCPDMIOAPICHLPR0 pIoApicHlpR0;
292
293 /** The device instance - RC Ptr. */
294 PPDMDEVINSRC pDevInsRC;
295 /** The IOAPIC helpers - RC Ptr. */
296 PCPDMIOAPICHLPRC pIoApicHlpRC;
297
298# ifdef VBOX_WITH_STATISTICS
299 STAMCOUNTER StatMMIOReadGC;
300 STAMCOUNTER StatMMIOReadHC;
301 STAMCOUNTER StatMMIOWriteGC;
302 STAMCOUNTER StatMMIOWriteHC;
303 STAMCOUNTER StatSetIrqGC;
304 STAMCOUNTER StatSetIrqHC;
305# endif
306#endif /* VBOX */
307};
308
309#ifdef VBOX
310typedef struct IOAPICState IOAPICState;
311
312typedef struct
313{
314 /** The device instance - R3 Ptr. */
315 PPDMDEVINSR3 pDevInsR3;
316 /** The APIC helpers - R3 Ptr. */
317 PCPDMAPICHLPR3 pApicHlpR3;
318 /** LAPICs states - R3 Ptr */
319 R3PTRTYPE(APICState *) paLapicsR3;
320 /** The critical section - R3 Ptr. */
321 R3PTRTYPE(PPDMCRITSECT) pCritSectR3;
322
323 /** The device instance - R0 Ptr. */
324 PPDMDEVINSR0 pDevInsR0;
325 /** The APIC helpers - R0 Ptr. */
326 PCPDMAPICHLPR0 pApicHlpR0;
327 /** LAPICs states - R0 Ptr */
328 R0PTRTYPE(APICState *) paLapicsR0;
329 /** The critical section - R3 Ptr. */
330 R0PTRTYPE(PPDMCRITSECT) pCritSectR0;
331
332 /** The device instance - RC Ptr. */
333 PPDMDEVINSRC pDevInsRC;
334 /** The APIC helpers - RC Ptr. */
335 PCPDMAPICHLPRC pApicHlpRC;
336 /** LAPICs states - RC Ptr */
337 RCPTRTYPE(APICState *) paLapicsRC;
338 /** The critical section - R3 Ptr. */
339 RCPTRTYPE(PPDMCRITSECT) pCritSectRC;
340
341 /** APIC specification version in this virtual hardware configuration. */
342 PDMAPICVERSION enmVersion;
343
344 /** Number of attempts made to optimize TPR accesses. */
345 uint32_t cTPRPatchAttempts;
346
347 /** Number of CPUs on the system (same as LAPIC count). */
348 uint32_t cCpus;
349 /** Whether we've got an IO APIC or not. */
350 bool fIoApic;
351 /** Alignment padding. */
352 bool afPadding[3];
353
354# ifdef VBOX_WITH_STATISTICS
355 STAMCOUNTER StatMMIOReadGC;
356 STAMCOUNTER StatMMIOReadHC;
357 STAMCOUNTER StatMMIOWriteGC;
358 STAMCOUNTER StatMMIOWriteHC;
359 STAMCOUNTER StatClearedActiveIrq;
360# endif
361} APICDeviceInfo;
362# ifdef VBOX_WITH_STATISTICS
363AssertCompileMemberAlignment(APICDeviceInfo, StatMMIOReadGC, 8);
364# endif
365#endif /* VBOX */
366
367#ifndef VBOX_DEVICE_STRUCT_TESTCASE
368
369#ifndef VBOX
370static int apic_io_memory;
371static APICState *first_local_apic = NULL;
372static int last_apic_id = 0;
373#endif /* !VBOX */
374
375
376#ifdef VBOX
377/*******************************************************************************
378* Internal Functions *
379*******************************************************************************/
380RT_C_DECLS_BEGIN
381PDMBOTHCBDECL(int) apicMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
382PDMBOTHCBDECL(int) apicMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
383PDMBOTHCBDECL(int) apicGetInterrupt(PPDMDEVINS pDevIns);
384PDMBOTHCBDECL(bool) apicHasPendingIrq(PPDMDEVINS pDevIns);
385PDMBOTHCBDECL(void) apicSetBase(PPDMDEVINS pDevIns, uint64_t val);
386PDMBOTHCBDECL(uint64_t) apicGetBase(PPDMDEVINS pDevIns);
387PDMBOTHCBDECL(void) apicSetTPR(PPDMDEVINS pDevIns, VMCPUID idCpu, uint8_t val);
388PDMBOTHCBDECL(uint8_t) apicGetTPR(PPDMDEVINS pDevIns, VMCPUID idCpu);
389PDMBOTHCBDECL(int) apicBusDeliverCallback(PPDMDEVINS pDevIns, uint8_t u8Dest, uint8_t u8DestMode,
390 uint8_t u8DeliveryMode, uint8_t iVector, uint8_t u8Polarity,
391 uint8_t u8TriggerMode);
392PDMBOTHCBDECL(int) apicWriteMSR(PPDMDEVINS pDevIns, VMCPUID iCpu, uint32_t u32Reg, uint64_t u64Value);
393PDMBOTHCBDECL(int) apicReadMSR(PPDMDEVINS pDevIns, VMCPUID iCpu, uint32_t u32Reg, uint64_t *pu64Value);
394PDMBOTHCBDECL(int) ioapicMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
395PDMBOTHCBDECL(int) ioapicMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
396PDMBOTHCBDECL(void) ioapicSetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel);
397
398static void apic_update_tpr(APICDeviceInfo *dev, APICState* s, uint32_t val);
399RT_C_DECLS_END
400
401static void apic_eoi(APICDeviceInfo *dev, APICState* s); /* */
402static uint32_t apic_get_delivery_bitmask(APICDeviceInfo* dev, uint8_t dest, uint8_t dest_mode);
403static int apic_deliver(APICDeviceInfo* dev, APICState *s,
404 uint8_t dest, uint8_t dest_mode,
405 uint8_t delivery_mode, uint8_t vector_num,
406 uint8_t polarity, uint8_t trigger_mode);
407static int apic_get_arb_pri(APICState *s);
408static int apic_get_ppr(APICState *s);
409static uint32_t apic_get_current_count(APICDeviceInfo* dev, APICState *s);
410static void apicTimerSetInitialCount(APICDeviceInfo *dev, APICState *s, uint32_t initial_count);
411static void apicTimerSetLvt(APICDeviceInfo *dev, APICState *pThis, uint32_t fNew);
412
413#endif /* VBOX */
414
415static void apic_init_ipi(APICDeviceInfo* dev, APICState *s);
416static void apic_set_irq(APICDeviceInfo* dev, APICState *s, int vector_num, int trigger_mode);
417static bool apic_update_irq(APICDeviceInfo* dev, APICState *s);
418
419
420#ifdef VBOX
421
422DECLINLINE(APICState*) getLapicById(APICDeviceInfo* dev, VMCPUID id)
423{
424 AssertFatalMsg(id < dev->cCpus, ("CPU id %d out of range\n", id));
425 return &dev->CTX_SUFF(paLapics)[id];
426}
427
428DECLINLINE(APICState*) getLapic(APICDeviceInfo* dev)
429{
430 /* LAPIC's array is indexed by CPU id */
431 VMCPUID id = dev->CTX_SUFF(pApicHlp)->pfnGetCpuId(dev->CTX_SUFF(pDevIns));
432 return getLapicById(dev, id);
433}
434
435DECLINLINE(VMCPUID) getCpuFromLapic(APICDeviceInfo* dev, APICState *s)
436{
437 /* for now we assume LAPIC physical id == CPU id */
438 return VMCPUID(s->phys_id);
439}
440
441DECLINLINE(void) cpuSetInterrupt(APICDeviceInfo* dev, APICState *s, PDMAPICIRQ enmType = PDMAPICIRQ_HARDWARE)
442{
443 LogFlow(("apic: setting interrupt flag for cpu %d\n", getCpuFromLapic(dev, s)));
444 dev->CTX_SUFF(pApicHlp)->pfnSetInterruptFF(dev->CTX_SUFF(pDevIns), enmType,
445 getCpuFromLapic(dev, s));
446}
447
448DECLINLINE(void) cpuClearInterrupt(APICDeviceInfo* dev, APICState *s)
449{
450 LogFlow(("apic: clear interrupt flag\n"));
451 dev->CTX_SUFF(pApicHlp)->pfnClearInterruptFF(dev->CTX_SUFF(pDevIns),
452 getCpuFromLapic(dev, s));
453}
454
455# ifdef IN_RING3
456
457DECLINLINE(void) cpuSendSipi(APICDeviceInfo* dev, APICState *s, int vector)
458{
459 Log2(("apic: send SIPI vector=%d\n", vector));
460
461 dev->pApicHlpR3->pfnSendSipi(dev->pDevInsR3,
462 getCpuFromLapic(dev, s),
463 vector);
464}
465
466DECLINLINE(void) cpuSendInitIpi(APICDeviceInfo* dev, APICState *s)
467{
468 Log2(("apic: send init IPI\n"));
469
470 dev->pApicHlpR3->pfnSendInitIpi(dev->pDevInsR3,
471 getCpuFromLapic(dev, s));
472}
473
474# endif /* IN_RING3 */
475
476DECLINLINE(uint32_t) getApicEnableBits(APICDeviceInfo* dev)
477{
478 switch (dev->enmVersion)
479 {
480 case PDMAPICVERSION_NONE:
481 return 0;
482 case PDMAPICVERSION_APIC:
483 return MSR_IA32_APICBASE_ENABLE;
484 case PDMAPICVERSION_X2APIC:
485 return MSR_IA32_APICBASE_ENABLE | MSR_IA32_APICBASE_X2ENABLE ;
486 default:
487 AssertMsgFailed(("Unsuported APIC version %d\n", dev->enmVersion));
488 return 0;
489 }
490}
491
492DECLINLINE(PDMAPICVERSION) getApicMode(APICState *apic)
493{
494 switch (((apic->apicbase) >> 10) & 0x3)
495 {
496 case 0:
497 return PDMAPICVERSION_NONE;
498 case 1:
499 default:
500 /* Invalid */
501 return PDMAPICVERSION_NONE;
502 case 2:
503 return PDMAPICVERSION_APIC;
504 case 3:
505 return PDMAPICVERSION_X2APIC;
506 }
507}
508
509#endif /* VBOX */
510
511#ifndef VBOX
512static void apic_bus_deliver(uint32_t deliver_bitmask, uint8_t delivery_mode,
513 uint8_t vector_num, uint8_t polarity,
514 uint8_t trigger_mode)
515{
516 APICState *apic_iter;
517#else /* VBOX */
518static int apic_bus_deliver(APICDeviceInfo* dev,
519 uint32_t deliver_bitmask, uint8_t delivery_mode,
520 uint8_t vector_num, uint8_t polarity,
521 uint8_t trigger_mode)
522{
523#endif /* VBOX */
524
525 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));
526 switch (delivery_mode) {
527 case APIC_DM_LOWPRI:
528 {
529 int d = -1;
530 if (deliver_bitmask)
531 d = ffs_bit(deliver_bitmask);
532 if (d >= 0)
533 {
534 APICState* apic = getLapicById(dev, d);
535 apic_set_irq(dev, apic, vector_num, trigger_mode);
536 }
537 return VINF_SUCCESS;
538 }
539 case APIC_DM_FIXED:
540 /* XXX: arbitration */
541 break;
542
543 case APIC_DM_SMI:
544 foreach_apic(dev, deliver_bitmask,
545 cpuSetInterrupt(dev, apic, PDMAPICIRQ_SMI));
546 return VINF_SUCCESS;
547
548 case APIC_DM_NMI:
549 foreach_apic(dev, deliver_bitmask,
550 cpuSetInterrupt(dev, apic, PDMAPICIRQ_NMI));
551 return VINF_SUCCESS;
552
553 case APIC_DM_INIT:
554 /* normal INIT IPI sent to processors */
555#ifdef VBOX
556#ifdef IN_RING3
557 foreach_apic(dev, deliver_bitmask,
558 apic_init_ipi(dev, apic));
559 return VINF_SUCCESS;
560#else
561 /* We shall send init IPI only in R3, R0 calls should be
562 rescheduled to R3 */
563 return VINF_IOM_HC_MMIO_READ_WRITE;
564#endif /* IN_RING3 */
565
566#else
567 for (apic_iter = first_local_apic; apic_iter != NULL;
568 apic_iter = apic_iter->next_apic) {
569 apic_init_ipi(apic_iter);
570 }
571#endif
572
573 case APIC_DM_EXTINT:
574 /* handled in I/O APIC code */
575 break;
576
577 default:
578 return VINF_SUCCESS;
579 }
580
581#ifdef VBOX
582 foreach_apic(dev, deliver_bitmask,
583 apic_set_irq (dev, apic, vector_num, trigger_mode));
584 return VINF_SUCCESS;
585#else /* VBOX */
586 for (apic_iter = first_local_apic; apic_iter != NULL;
587 apic_iter = apic_iter->next_apic) {
588 if (deliver_bitmask & (1 << apic_iter->id))
589 apic_set_irq(apic_iter, vector_num, trigger_mode);
590 }
591#endif /* VBOX */
592}
593
594#ifndef VBOX
595void cpu_set_apic_base(CPUState *env, uint64_t val)
596{
597 APICState *s = env->apic_state;
598#ifdef DEBUG_APIC
599 Log(("cpu_set_apic_base: %016llx\n", val));
600#endif
601
602 s->apicbase = (val & 0xfffff000) |
603 (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
604 /* if disabled, cannot be enabled again */
605 if (!(val & MSR_IA32_APICBASE_ENABLE)) {
606 s->apicbase &= ~MSR_IA32_APICBASE_ENABLE;
607 env->cpuid_features &= ~CPUID_APIC;
608 s->spurious_vec &= ~APIC_SV_ENABLE;
609 }
610}
611#else /* VBOX */
612PDMBOTHCBDECL(void) apicSetBase(PPDMDEVINS pDevIns, uint64_t val)
613{
614 APICDeviceInfo *dev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
615 Assert(PDMCritSectIsOwner(dev->CTX_SUFF(pCritSect)));
616 APICState *s = getLapic(dev); /** @todo fix interface */
617 Log(("cpu_set_apic_base: %016RX64\n", val));
618
619 /** @todo: do we need to lock here ? */
620 /* APIC_LOCK_VOID(dev, VERR_INTERNAL_ERROR); */
621 /** @todo If this change is valid immediately, then we should change the MMIO registration! */
622 /* We cannot change if this CPU is BSP or not by writing to MSR - it's hardwired */
623 PDMAPICVERSION oldMode = getApicMode(s);
624 s->apicbase =
625 (val & 0xfffff000) | /* base */
626 (val & getApicEnableBits(dev)) | /* mode */
627 (s->apicbase & MSR_IA32_APICBASE_BSP) /* keep BSP bit */;
628 PDMAPICVERSION newMode = getApicMode(s);
629
630 if (oldMode != newMode)
631 {
632 switch (newMode)
633 {
634 case PDMAPICVERSION_NONE:
635 {
636 s->spurious_vec &= ~APIC_SV_ENABLE;
637 /* Clear any pending APIC interrupt action flag. */
638 cpuClearInterrupt(dev, s);
639 /** @todo: why do we do that? */
640 dev->CTX_SUFF(pApicHlp)->pfnChangeFeature(pDevIns, PDMAPICVERSION_NONE);
641 break;
642 }
643 case PDMAPICVERSION_APIC:
644 /** @todo: map MMIO ranges, if needed */
645 break;
646 case PDMAPICVERSION_X2APIC:
647 /** @todo: unmap MMIO ranges of this APIC, according to the spec */
648 break;
649 default:
650 break;
651 }
652 }
653 /* APIC_UNLOCK(dev); */
654}
655#endif /* VBOX */
656
657#ifndef VBOX
658
659uint64_t cpu_get_apic_base(CPUState *env)
660{
661 APICState *s = env->apic_state;
662#ifdef DEBUG_APIC
663 Log(("cpu_get_apic_base: %016llx\n", (uint64_t)s->apicbase));
664#endif
665 return s->apicbase;
666}
667
668void cpu_set_apic_tpr(CPUX86State *env, uint8_t val)
669{
670 APICState *s = env->apic_state;
671 s->tpr = (val & 0x0f) << 4;
672 apic_update_irq(s);
673}
674
675uint8_t cpu_get_apic_tpr(CPUX86State *env)
676{
677 APICState *s = env->apic_state;
678 return s->tpr >> 4;
679}
680
681static int fls_bit(int value)
682{
683 unsigned int ret = 0;
684
685#ifdef HOST_I386
686 __asm__ __volatile__ ("bsr %1, %0\n" : "+r" (ret) : "rm" (value));
687 return ret;
688#else
689 if (value > 0xffff)
690 value >>= 16, ret = 16;
691 if (value > 0xff)
692 value >>= 8, ret += 8;
693 if (value > 0xf)
694 value >>= 4, ret += 4;
695 if (value > 0x3)
696 value >>= 2, ret += 2;
697 return ret + (value >> 1);
698#endif
699}
700
701static inline void set_bit(uint32_t *tab, int index)
702{
703 int i, mask;
704 i = index >> 5;
705 mask = 1 << (index & 0x1f);
706 tab[i] |= mask;
707}
708
709static inline void reset_bit(uint32_t *tab, int index)
710{
711 int i, mask;
712 i = index >> 5;
713 mask = 1 << (index & 0x1f);
714 tab[i] &= ~mask;
715}
716
717
718#else /* VBOX */
719
720PDMBOTHCBDECL(uint64_t) apicGetBase(PPDMDEVINS pDevIns)
721{
722 APICDeviceInfo *dev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
723 Assert(PDMCritSectIsOwner(dev->CTX_SUFF(pCritSect)));
724 APICState *s = getLapic(dev); /** @todo fix interface */
725 LogFlow(("apicGetBase: %016llx\n", (uint64_t)s->apicbase));
726 return s->apicbase;
727}
728
729PDMBOTHCBDECL(void) apicSetTPR(PPDMDEVINS pDevIns, VMCPUID idCpu, uint8_t val)
730{
731 APICDeviceInfo *dev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
732 Assert(PDMCritSectIsOwner(dev->CTX_SUFF(pCritSect)));
733 APICState *s = getLapicById(dev, idCpu);
734 LogFlow(("apicSetTPR: val=%#x (trp %#x -> %#x)\n", val, s->tpr, val));
735 apic_update_tpr(dev, s, val);
736}
737
738PDMBOTHCBDECL(uint8_t) apicGetTPR(PPDMDEVINS pDevIns, VMCPUID idCpu)
739{
740 /* We don't perform any locking here as that would cause a lot of contention for VT-x/AMD-V. */
741 APICDeviceInfo *dev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
742 APICState *s = getLapicById(dev, idCpu);
743 Log2(("apicGetTPR: returns %#x\n", s->tpr));
744 return s->tpr;
745}
746
747/**
748 * x2APIC MSR write interface.
749 *
750 * @returns VBox status code.
751 *
752 * @param pDevIns The device instance.
753 * @param idCpu The ID of the virtual CPU and thereby APIC index.
754 * @param u32Reg Register to write (ecx).
755 * @param u64Value The value to write (eax:edx / rax).
756 *
757 */
758PDMBOTHCBDECL(int) apicWriteMSR(PPDMDEVINS pDevIns, VMCPUID idCpu, uint32_t u32Reg, uint64_t u64Value)
759{
760 APICDeviceInfo *dev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
761 Assert(PDMCritSectIsOwner(dev->CTX_SUFF(pCritSect)));
762 int rc = VINF_SUCCESS;
763
764 if (dev->enmVersion < PDMAPICVERSION_X2APIC)
765 return VERR_EM_INTERPRETER;
766
767 APICState *pThis = getLapicById(dev, idCpu);
768
769 uint32_t index = (u32Reg - MSR_IA32_APIC_START) & 0xff;
770 switch (index)
771 {
772 case 0x02:
773 pThis->id = (u64Value >> 24);
774 break;
775 case 0x03:
776 break;
777 case 0x08:
778 apic_update_tpr(dev, pThis, u64Value);
779 break;
780 case 0x09: case 0x0a:
781 Log(("apicWriteMSR: write to read-only register %d ignored\n", index));
782 break;
783 case 0x0b: /* EOI */
784 apic_eoi(dev, pThis);
785 break;
786 case 0x0d:
787 pThis->log_dest = u64Value >> 24;
788 break;
789 case 0x0e:
790 pThis->dest_mode = u64Value >> 28;
791 break;
792 case 0x0f:
793 pThis->spurious_vec = u64Value & 0x1ff;
794 apic_update_irq(dev, pThis);
795 break;
796 case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
797 case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
798 case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
799 case 0x28:
800 Log(("apicWriteMSR: write to read-only register %d ignored\n", index));
801 break;
802
803 case 0x30:
804 /* Here one of the differences with regular APIC: ICR is single 64-bit register */
805 pThis->icr[0] = (uint32_t)u64Value;
806 pThis->icr[1] = (uint32_t)(u64Value >> 32);
807 rc = apic_deliver(dev, pThis, (pThis->icr[1] >> 24) & 0xff, (pThis->icr[0] >> 11) & 1,
808 (pThis->icr[0] >> 8) & 7, (pThis->icr[0] & 0xff),
809 (pThis->icr[0] >> 14) & 1, (pThis->icr[0] >> 15) & 1);
810 break;
811 case 0x32 + APIC_LVT_TIMER:
812 AssertCompile(APIC_LVT_TIMER == 0);
813 apicTimerSetLvt(dev, pThis, u64Value);
814 break;
815
816 case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
817 pThis->lvt[index - 0x32] = u64Value;
818 break;
819 case 0x38:
820 apicTimerSetInitialCount(dev, pThis, u64Value);
821 break;
822 case 0x39:
823 Log(("apicWriteMSR: write to read-only register %d ignored\n", index));
824 break;
825 case 0x3e:
826 {
827 int v;
828 pThis->divide_conf = u64Value & 0xb;
829 v = (pThis->divide_conf & 3) | ((pThis->divide_conf >> 1) & 4);
830 pThis->count_shift = (v + 1) & 7;
831 break;
832 }
833 case 0x3f:
834 {
835 /* Self IPI, see x2APIC book 2.4.5 */
836 int vector = u64Value & 0xff;
837 rc = apic_bus_deliver(dev,
838 1 << getLapicById(dev, idCpu)->id /* Self */,
839 0 /* Delivery mode - fixed */,
840 vector,
841 0 /* Polarity - conform to the bus */,
842 0 /* Trigger mode - edge */);
843 break;
844 }
845 default:
846 AssertMsgFailed(("apicWriteMSR: unknown index %x\n", index));
847 pThis->esr |= ESR_ILLEGAL_ADDRESS;
848 break;
849 }
850
851 return rc;
852}
853
854/**
855 * x2APIC MSR read interface.
856 *
857 * @returns VBox status code.
858 *
859 * @param pDevIns The device instance.
860 * @param idCpu The ID of the virtual CPU and thereby APIC index.
861 * @param u32Reg Register to write (ecx).
862 * @param pu64Value Where to return the value (eax:edx / rax).
863 */
864PDMBOTHCBDECL(int) apicReadMSR(PPDMDEVINS pDevIns, VMCPUID idCpu, uint32_t u32Reg, uint64_t *pu64Value)
865{
866 APICDeviceInfo *dev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
867 Assert(PDMCritSectIsOwner(dev->CTX_SUFF(pCritSect)));
868
869 if (dev->enmVersion < PDMAPICVERSION_X2APIC)
870 return VERR_EM_INTERPRETER;
871
872 uint32_t index = (u32Reg - MSR_IA32_APIC_START) & 0xff;
873 APICState* apic = getLapicById(dev, idCpu);
874 uint64_t val = 0;
875
876 switch (index)
877 {
878 case 0x02: /* id */
879 val = apic->id << 24;
880 break;
881 case 0x03: /* version */
882 val = 0x11 | ((APIC_LVT_NB - 1) << 16); /* version 0x11 */
883 break;
884 case 0x08:
885 val = apic->tpr;
886 break;
887 case 0x09:
888 val = apic_get_arb_pri(apic);
889 break;
890 case 0x0a:
891 /* ppr */
892 val = apic_get_ppr(apic);
893 break;
894 case 0x0b:
895 val = 0;
896 break;
897 case 0x0d:
898 val = apic->log_dest << 24;
899 break;
900 case 0x0e:
901 /* Bottom 28 bits are always 1 */
902 val = (apic->dest_mode << 28) | 0xfffffff;
903 break;
904 case 0x0f:
905 val = apic->spurious_vec;
906 break;
907 case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
908 val = apic->isr[index & 7];
909 break;
910 case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
911 val = apic->tmr[index & 7];
912 break;
913 case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
914 val = apic->irr[index & 7];
915 break;
916 case 0x28:
917 val = apic->esr;
918 break;
919 case 0x30:
920 /* Here one of the differences with regular APIC: ICR is single 64-bit register */
921 val = ((uint64_t)apic->icr[0x31] << 32) | apic->icr[0x30];
922 break;
923 case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
924 val = apic->lvt[index - 0x32];
925 break;
926 case 0x38:
927 val = apic->initial_count;
928 break;
929 case 0x39:
930 val = apic_get_current_count(dev, apic);
931 break;
932 case 0x3e:
933 val = apic->divide_conf;
934 break;
935 case 0x3f:
936 /* Self IPI register is write only */
937 Log(("apicReadMSR: read from write-only register %d ignored\n", index));
938 break;
939 default:
940 AssertMsgFailed(("apicReadMSR: unknown index %x\n", index));
941 apic->esr |= ESR_ILLEGAL_ADDRESS;
942 val = 0;
943 break;
944 }
945 *pu64Value = val;
946 return VINF_SUCCESS;
947}
948
949/**
950 * More or less private interface between IOAPIC, only PDM is responsible
951 * for connecting the two devices.
952 */
953PDMBOTHCBDECL(int) apicBusDeliverCallback(PPDMDEVINS pDevIns, uint8_t u8Dest, uint8_t u8DestMode,
954 uint8_t u8DeliveryMode, uint8_t iVector, uint8_t u8Polarity,
955 uint8_t u8TriggerMode)
956{
957 APICDeviceInfo *dev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
958 Assert(PDMCritSectIsOwner(dev->CTX_SUFF(pCritSect)));
959 LogFlow(("apicBusDeliverCallback: pDevIns=%p u8Dest=%#x u8DestMode=%#x u8DeliveryMode=%#x iVector=%#x u8Polarity=%#x u8TriggerMode=%#x\n",
960 pDevIns, u8Dest, u8DestMode, u8DeliveryMode, iVector, u8Polarity, u8TriggerMode));
961 return apic_bus_deliver(dev, apic_get_delivery_bitmask(dev, u8Dest, u8DestMode),
962 u8DeliveryMode, iVector, u8Polarity, u8TriggerMode);
963}
964
965#endif /* VBOX */
966
967/* return -1 if no bit is set */
968static int get_highest_priority_int(uint32_t *tab)
969{
970 int i;
971 for(i = 7; i >= 0; i--) {
972 if (tab[i] != 0) {
973 return i * 32 + fls_bit(tab[i]);
974 }
975 }
976 return -1;
977}
978
979static int apic_get_ppr(APICState *s)
980{
981 int tpr, isrv, ppr;
982
983 tpr = (s->tpr >> 4);
984 isrv = get_highest_priority_int(s->isr);
985 if (isrv < 0)
986 isrv = 0;
987 isrv >>= 4;
988 if (tpr >= isrv)
989 ppr = s->tpr;
990 else
991 ppr = isrv << 4;
992 return ppr;
993}
994
995static int apic_get_ppr_zero_tpr(APICState *s)
996{
997 int isrv;
998
999 isrv = get_highest_priority_int(s->isr);
1000 if (isrv < 0)
1001 isrv = 0;
1002 return isrv;
1003}
1004
1005static int apic_get_arb_pri(APICState *s)
1006{
1007 /* XXX: arbitration */
1008 return 0;
1009}
1010
1011/* signal the CPU if an irq is pending */
1012static bool apic_update_irq(APICDeviceInfo *dev, APICState* s)
1013{
1014 int irrv, ppr;
1015 if (!(s->spurious_vec & APIC_SV_ENABLE))
1016#ifdef VBOX
1017 {
1018 /* Clear any pending APIC interrupt action flag. */
1019 cpuClearInterrupt(dev, s);
1020 return false;
1021 }
1022#else
1023 return false;
1024#endif /* VBOX */
1025 irrv = get_highest_priority_int(s->irr);
1026 if (irrv < 0)
1027 return false;
1028 ppr = apic_get_ppr(s);
1029 if (ppr && (irrv & 0xf0) <= (ppr & 0xf0))
1030 return false;
1031#ifndef VBOX
1032 cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
1033#else
1034 cpuSetInterrupt(dev, s);
1035 return true;
1036#endif
1037}
1038
1039#ifdef VBOX
1040
1041/* Check if the APIC has a pending interrupt/if a TPR change would active one. */
1042PDMBOTHCBDECL(bool) apicHasPendingIrq(PPDMDEVINS pDevIns)
1043{
1044 int irrv, ppr;
1045 APICDeviceInfo *dev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
1046 if (!dev)
1047 return false;
1048
1049 /* We don't perform any locking here as that would cause a lot of contention for VT-x/AMD-V. */
1050
1051 APICState *s = getLapic(dev); /** @todo fix interface */
1052
1053 /*
1054 * All our callbacks now come from single IOAPIC, thus locking
1055 * seems to be excessive now (@todo: check)
1056 */
1057 irrv = get_highest_priority_int(s->irr);
1058 if (irrv < 0)
1059 return false;
1060
1061 ppr = apic_get_ppr_zero_tpr(s);
1062
1063 if (ppr && (irrv & 0xf0) <= (ppr & 0xf0))
1064 return false;
1065
1066 return true;
1067}
1068
1069static void apic_update_tpr(APICDeviceInfo *dev, APICState* s, uint32_t val)
1070{
1071 bool fIrqIsActive = false;
1072 bool fIrqWasActive = false;
1073
1074 fIrqWasActive = apic_update_irq(dev, s);
1075 s->tpr = val;
1076 fIrqIsActive = apic_update_irq(dev, s);
1077
1078 /* If an interrupt is pending and now masked, then clear the FF flag. */
1079 if (fIrqWasActive && !fIrqIsActive)
1080 {
1081 Log(("apic_update_tpr: deactivate interrupt that was masked by the TPR update (%x)\n", val));
1082 STAM_COUNTER_INC(&dev->StatClearedActiveIrq);
1083 cpuClearInterrupt(dev, s);
1084 }
1085}
1086#endif
1087
1088static void apic_set_irq(APICDeviceInfo *dev, APICState* s, int vector_num, int trigger_mode)
1089{
1090 LogFlow(("CPU%d: apic_set_irq vector=%x, trigger_mode=%x\n", s->phys_id, vector_num, trigger_mode));
1091 set_bit(s->irr, vector_num);
1092 if (trigger_mode)
1093 set_bit(s->tmr, vector_num);
1094 else
1095 reset_bit(s->tmr, vector_num);
1096 apic_update_irq(dev, s);
1097}
1098
1099static void apic_eoi(APICDeviceInfo *dev, APICState* s)
1100{
1101 int isrv;
1102 isrv = get_highest_priority_int(s->isr);
1103 if (isrv < 0)
1104 return;
1105 reset_bit(s->isr, isrv);
1106 LogFlow(("CPU%d: apic_eoi isrv=%x\n", s->phys_id, isrv));
1107 /* XXX: send the EOI packet to the APIC bus to allow the I/O APIC to
1108 set the remote IRR bit for level triggered interrupts. */
1109 apic_update_irq(dev, s);
1110}
1111
1112#ifndef VBOX
1113static uint32_t apic_get_delivery_bitmask(uint8_t dest, uint8_t dest_mode)
1114#else /* VBOX */
1115static uint32_t apic_get_delivery_bitmask(APICDeviceInfo *dev, uint8_t dest, uint8_t dest_mode)
1116#endif /* VBOX */
1117{
1118 uint32_t mask = 0;
1119
1120 if (dest_mode == 0)
1121 {
1122 if (dest == 0xff)
1123 mask = 0xff;
1124 else
1125 mask = 1 << dest;
1126 }
1127 else
1128 {
1129 APICState *apic = dev->CTX_SUFF(paLapics);
1130 uint32_t i;
1131
1132 /* XXX: cluster mode */
1133 for(i = 0; i < dev->cCpus; i++)
1134 {
1135 if (apic->dest_mode == 0xf)
1136 {
1137 if (dest & apic->log_dest)
1138 mask |= (1 << apic->id);
1139 }
1140 else if (apic->dest_mode == 0x0)
1141 {
1142 if ((dest & 0xf0) == (apic->log_dest & 0xf0)
1143 &&
1144 (dest & apic->log_dest & 0x0f))
1145 {
1146 mask |= (1 << i);
1147 }
1148 }
1149 apic++;
1150 }
1151 }
1152
1153 return mask;
1154}
1155
1156#ifdef IN_RING3
1157static void apic_init_ipi(APICDeviceInfo* dev, APICState *s)
1158{
1159 int i;
1160
1161 for(i = 0; i < APIC_LVT_NB; i++)
1162 s->lvt[i] = 1 << 16; /* mask LVT */
1163 s->tpr = 0;
1164 s->spurious_vec = 0xff;
1165 s->log_dest = 0;
1166 s->dest_mode = 0xff;
1167 memset(s->isr, 0, sizeof(s->isr));
1168 memset(s->tmr, 0, sizeof(s->tmr));
1169 memset(s->irr, 0, sizeof(s->irr));
1170 s->esr = 0;
1171 memset(s->icr, 0, sizeof(s->icr));
1172 s->divide_conf = 0;
1173 s->count_shift = 0;
1174 s->initial_count = 0;
1175 s->initial_count_load_time = 0;
1176 s->next_time = 0;
1177
1178#ifdef VBOX
1179 cpuSendInitIpi(dev, s);
1180#endif
1181}
1182
1183/* send a SIPI message to the CPU to start it */
1184static void apic_startup(APICDeviceInfo* dev, APICState *s, int vector_num)
1185{
1186#ifndef VBOX
1187 CPUState *env = s->cpu_env;
1188 if (!env->halted)
1189 return;
1190 env->eip = 0;
1191 cpu_x86_load_seg_cache(env, R_CS, vector_num << 8, vector_num << 12,
1192 0xffff, 0);
1193 env->halted = 0;
1194#else
1195 Log(("[SMP] apic_startup: %d on CPUs %d\n", vector_num, s->phys_id));
1196 cpuSendSipi(dev, s, vector_num);
1197#endif
1198}
1199#endif /* IN_RING3 */
1200
1201static int apic_deliver(APICDeviceInfo* dev, APICState *s,
1202 uint8_t dest, uint8_t dest_mode,
1203 uint8_t delivery_mode, uint8_t vector_num,
1204 uint8_t polarity, uint8_t trigger_mode)
1205{
1206 uint32_t deliver_bitmask = 0;
1207 int dest_shorthand = (s->icr[0] >> 18) & 3;
1208#ifndef VBOX
1209 APICState *apic_iter;
1210#endif /* !VBOX */
1211
1212 LogFlow(("apic_deliver dest=%x dest_mode=%x dest_shorthand=%x delivery_mode=%x vector_num=%x polarity=%x trigger_mode=%x\n", dest, dest_mode, dest_shorthand, delivery_mode, vector_num, polarity, trigger_mode));
1213
1214 switch (dest_shorthand) {
1215 case 0:
1216#ifndef VBOX
1217 deliver_bitmask = apic_get_delivery_bitmask(dest, dest_mode);
1218#else /* VBOX */
1219 deliver_bitmask = apic_get_delivery_bitmask(dev, dest, dest_mode);
1220#endif /* !VBOX */
1221 break;
1222 case 1:
1223 deliver_bitmask = (1 << s->id);
1224 break;
1225 case 2:
1226 deliver_bitmask = 0xffffffff;
1227 break;
1228 case 3:
1229 deliver_bitmask = 0xffffffff & ~(1 << s->id);
1230 break;
1231 }
1232
1233 switch (delivery_mode) {
1234 case APIC_DM_INIT:
1235 {
1236 int trig_mode = (s->icr[0] >> 15) & 1;
1237 int level = (s->icr[0] >> 14) & 1;
1238 if (level == 0 && trig_mode == 1) {
1239 foreach_apic(dev, deliver_bitmask,
1240 apic->arb_id = apic->id);
1241#ifndef VBOX
1242 return;
1243#else
1244 Log(("CPU%d: APIC_DM_INIT arbitration id(s) set\n", s->phys_id));
1245 return VINF_SUCCESS;
1246#endif
1247 }
1248 }
1249 break;
1250
1251 case APIC_DM_SIPI:
1252#ifndef VBOX
1253 for (apic_iter = first_local_apic; apic_iter != NULL;
1254 apic_iter = apic_iter->next_apic) {
1255 if (deliver_bitmask & (1 << apic_iter->id)) {
1256 /* XXX: SMP support */
1257 /* apic_startup(apic_iter); */
1258 }
1259 }
1260 return;
1261#else
1262# ifdef IN_RING3
1263 foreach_apic(dev, deliver_bitmask,
1264 apic_startup(dev, apic, vector_num));
1265 return VINF_SUCCESS;
1266# else
1267 /* We shall send SIPI only in R3, R0 calls should be
1268 rescheduled to R3 */
1269 return VINF_IOM_HC_MMIO_WRITE;
1270# endif
1271#endif /* !VBOX */
1272 }
1273
1274#ifndef VBOX
1275 apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, polarity,
1276 trigger_mode);
1277#else /* VBOX */
1278 return apic_bus_deliver(dev, deliver_bitmask, delivery_mode, vector_num,
1279 polarity, trigger_mode);
1280#endif /* VBOX */
1281}
1282
1283
1284PDMBOTHCBDECL(int) apicGetInterrupt(PPDMDEVINS pDevIns)
1285{
1286 APICDeviceInfo *dev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
1287 /* if the APIC is not installed or enabled, we let the 8259 handle the
1288 IRQs */
1289 if (!dev)
1290 {
1291 Log(("apic_get_interrupt: returns -1 (!s)\n"));
1292 return -1;
1293 }
1294
1295 Assert(PDMCritSectIsOwner(dev->CTX_SUFF(pCritSect)));
1296
1297 APICState *s = getLapic(dev); /** @todo fix interface */
1298 int intno;
1299
1300 if (!(s->spurious_vec & APIC_SV_ENABLE)) {
1301 Log(("CPU%d: apic_get_interrupt: returns -1 (APIC_SV_ENABLE)\n", s->phys_id));
1302 return -1;
1303 }
1304
1305 /* XXX: spurious IRQ handling */
1306 intno = get_highest_priority_int(s->irr);
1307 if (intno < 0) {
1308 Log(("CPU%d: apic_get_interrupt: returns -1 (irr)\n", s->phys_id));
1309 return -1;
1310 }
1311 if (s->tpr && (uint32_t)intno <= s->tpr) {
1312 Log(("apic_get_interrupt: returns %d (sp)\n", s->spurious_vec & 0xff));
1313 return s->spurious_vec & 0xff;
1314 }
1315 reset_bit(s->irr, intno);
1316 set_bit(s->isr, intno);
1317 apic_update_irq(dev, s);
1318 LogFlow(("CPU%d: apic_get_interrupt: returns %d\n", s->phys_id, intno));
1319 return intno;
1320}
1321
1322static uint32_t apic_get_current_count(APICDeviceInfo *dev, APICState *s)
1323{
1324 int64_t d;
1325 uint32_t val;
1326#ifndef VBOX
1327 d = (qemu_get_clock(vm_clock) - s->initial_count_load_time) >>
1328 s->count_shift;
1329#else /* VBOX */
1330 d = (TMTimerGet(s->CTX_SUFF(pTimer)) - s->initial_count_load_time) >>
1331 s->count_shift;
1332#endif /* VBOX */
1333 if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
1334 /* periodic */
1335 val = s->initial_count - (d % ((uint64_t)s->initial_count + 1));
1336 } else {
1337 if (d >= s->initial_count)
1338 val = 0;
1339 else
1340 val = s->initial_count - d;
1341 }
1342 return val;
1343}
1344
1345#ifndef VBOX /* we've replaced all the code working the APIC timer. */
1346
1347static void apic_timer_update(APICDeviceInfo* dev, APICState *s, int64_t current_time)
1348{
1349 int64_t next_time, d;
1350
1351 if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) {
1352 d = (current_time - s->initial_count_load_time) >>
1353 s->count_shift;
1354 if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
1355 d = ((d / ((uint64_t)s->initial_count + 1)) + 1) * ((uint64_t)s->initial_count + 1);
1356 } else {
1357 if (d >= s->initial_count)
1358 goto no_timer;
1359 d = (uint64_t)s->initial_count + 1;
1360 }
1361 next_time = s->initial_count_load_time + (d << s->count_shift);
1362# ifndef VBOX
1363 qemu_mod_timer(s->timer, next_time);
1364# else
1365 TMTimerSet(s->CTX_SUFF(pTimer), next_time);
1366 s->fTimerArmed = true;
1367# endif
1368 s->next_time = next_time;
1369 } else {
1370 no_timer:
1371# ifndef VBOX
1372 qemu_del_timer(s->timer);
1373# else
1374 TMTimerStop(s->CTX_SUFF(pTimer));
1375 s->fTimerArmed = false;
1376# endif
1377 }
1378}
1379
1380static void apic_timer(void *opaque)
1381{
1382 APICState *s = opaque;
1383
1384 if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) {
1385 LogFlow(("apic_timer: trigger irq\n"));
1386 apic_set_irq(dev, s, s->lvt[APIC_LVT_TIMER] & 0xff, APIC_TRIGGER_EDGE);
1387 }
1388 apic_timer_update(dev, s, s->next_time);
1389}
1390
1391#else /* VBOX */
1392
1393/**
1394 * Implementation of the 0380h access: Timer reset + new initial count.
1395 *
1396 * @param dev The device state.
1397 * @param pThis The APIC sub-device state.
1398 * @param u32NewInitialCount The new initial count for the timer.
1399 */
1400static void apicTimerSetInitialCount(APICDeviceInfo *dev, APICState *pThis, uint32_t u32NewInitialCount)
1401{
1402 STAM_COUNTER_INC(&pThis->StatTimerSetInitialCount);
1403 pThis->initial_count = u32NewInitialCount;
1404
1405 /*
1406 * Don't (re-)arm the timer if the it's masked or if it's
1407 * a zero length one-shot timer.
1408 */
1409 /** @todo check the correct behavior of setting a 0 initial_count for a one-shot
1410 * timer. This is just copying the behavior of the original code. */
1411 if ( !(pThis->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)
1412 && ( (pThis->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC)
1413 || u32NewInitialCount != 0))
1414 {
1415 /*
1416 * Calculate the relative next time and perform a combined timer get/set
1417 * operation. This avoids racing the clock between get and set.
1418 */
1419 uint64_t cTicksNext = u32NewInitialCount;
1420 cTicksNext += 1;
1421 cTicksNext <<= pThis->count_shift;
1422 TMTimerSetRelative(pThis->CTX_SUFF(pTimer), cTicksNext, &pThis->initial_count_load_time);
1423 pThis->next_time = pThis->initial_count_load_time + cTicksNext;
1424 pThis->fTimerArmed = true;
1425 STAM_COUNTER_INC(&pThis->StatTimerSetInitialCountArm);
1426 }
1427 else
1428 {
1429 /* Stop it if necessary and record the load time for unmasking. */
1430 if (pThis->fTimerArmed)
1431 {
1432 STAM_COUNTER_INC(&pThis->StatTimerSetInitialCountDisarm);
1433 TMTimerStop(pThis->CTX_SUFF(pTimer));
1434 pThis->fTimerArmed = false;
1435 }
1436 pThis->initial_count_load_time = TMTimerGet(pThis->CTX_SUFF(pTimer));
1437 }
1438}
1439
1440/**
1441 * Implementation of the 0320h access: change the LVT flags.
1442 *
1443 * @param dev The device state.
1444 * @param pThis The APIC sub-device state to operate on.
1445 * @param fNew The new flags.
1446 */
1447static void apicTimerSetLvt(APICDeviceInfo *dev, APICState *pThis, uint32_t fNew)
1448{
1449 STAM_COUNTER_INC(&pThis->StatTimerSetLvt);
1450
1451 /*
1452 * Make the flag change, saving the old ones so we can avoid
1453 * unnecessary work.
1454 */
1455 uint32_t const fOld = pThis->lvt[APIC_LVT_TIMER];
1456 pThis->lvt[APIC_LVT_TIMER] = fNew;
1457
1458 /* Only the masked and peridic bits are relevant (see apic_timer_update). */
1459 if ( (fOld & (APIC_LVT_MASKED | APIC_LVT_TIMER_PERIODIC))
1460 != (fNew & (APIC_LVT_MASKED | APIC_LVT_TIMER_PERIODIC)))
1461 {
1462 /*
1463 * If changed to one-shot from periodic, stop the timer if we're not
1464 * in the first period.
1465 */
1466 /** @todo check how clearing the periodic flag really should behave when not
1467 * in period 1. The current code just mirrors the behavior of the
1468 * original implementation. */
1469 if ( (fOld & APIC_LVT_TIMER_PERIODIC)
1470 && !(fNew & APIC_LVT_TIMER_PERIODIC))
1471 {
1472 STAM_COUNTER_INC(&pThis->StatTimerSetLvtClearPeriodic);
1473 uint64_t cTicks = (pThis->next_time - pThis->initial_count_load_time) >> pThis->count_shift;
1474 if (cTicks >= pThis->initial_count)
1475 {
1476 /* not first period, stop it. */
1477 TMTimerStop(pThis->CTX_SUFF(pTimer));
1478 pThis->fTimerArmed = false;
1479 }
1480 /* else: first period, let it fire normally. */
1481 }
1482
1483 /*
1484 * We postpone stopping the timer when it's masked, this way we can
1485 * avoid some timer work when the guest temporarily masks the timer.
1486 * (apicTimerCallback will stop it if still masked.)
1487 */
1488 if (fNew & APIC_LVT_MASKED)
1489 STAM_COUNTER_INC(&pThis->StatTimerSetLvtPostponed);
1490 else if (pThis->fTimerArmed)
1491 STAM_COUNTER_INC(&pThis->StatTimerSetLvtArmed);
1492 /*
1493 * If unmasked and not armed, we have to rearm the timer so it will
1494 * fire at the end of the current period.
1495 * This is code is currently RACING the virtual sync clock!
1496 */
1497 else if (fOld & APIC_LVT_MASKED)
1498 {
1499 STAM_COUNTER_INC(&pThis->StatTimerSetLvtArm);
1500 for (unsigned cTries = 0; ; cTries++)
1501 {
1502 uint64_t NextTS;
1503 uint64_t cTicks = (TMTimerGet(pThis->CTX_SUFF(pTimer)) - pThis->initial_count_load_time) >> pThis->count_shift;
1504 if (fNew & APIC_LVT_TIMER_PERIODIC)
1505 NextTS = ((cTicks / ((uint64_t)pThis->initial_count + 1)) + 1) * ((uint64_t)pThis->initial_count + 1);
1506 else
1507 {
1508 if (cTicks >= pThis->initial_count)
1509 break;
1510 NextTS = (uint64_t)pThis->initial_count + 1;
1511 }
1512 NextTS <<= pThis->count_shift;
1513 NextTS += pThis->initial_count_load_time;
1514
1515 /* Try avoid the assertion in TM.cpp... this isn't perfect! */
1516 if ( NextTS > TMTimerGet(pThis->CTX_SUFF(pTimer))
1517 || cTries > 10)
1518 {
1519 TMTimerSet(pThis->CTX_SUFF(pTimer), NextTS);
1520 pThis->next_time = NextTS;
1521 pThis->fTimerArmed = true;
1522 break;
1523 }
1524 STAM_COUNTER_INC(&pThis->StatTimerSetLvtArmRetries);
1525 }
1526 }
1527 }
1528 else
1529 STAM_COUNTER_INC(&pThis->StatTimerSetLvtNoRelevantChange);
1530}
1531
1532# ifdef IN_RING3
1533/**
1534 * Timer callback function.
1535 *
1536 * @param pDevIns The device state.
1537 * @param pTimer The timer handle.
1538 * @param pvUser User argument pointing to the APIC instance.
1539 */
1540static DECLCALLBACK(void) apicTimerCallback(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
1541{
1542 APICDeviceInfo *dev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
1543 APICState *pThis = (APICState *)pvUser;
1544 Assert(pThis->pTimerR3 == pTimer);
1545 Assert(pThis->fTimerArmed);
1546
1547 if (!(pThis->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) {
1548 LogFlow(("apic_timer: trigger irq\n"));
1549 apic_set_irq(dev, pThis, pThis->lvt[APIC_LVT_TIMER] & 0xff, APIC_TRIGGER_EDGE);
1550
1551 if (pThis->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
1552 /* new interval. */
1553 pThis->next_time += (((uint64_t)pThis->initial_count + 1) << pThis->count_shift);
1554 TMTimerSet(pThis->CTX_SUFF(pTimer), pThis->next_time);
1555 pThis->fTimerArmed = true;
1556 } else {
1557 /* single shot. */
1558 pThis->fTimerArmed = false;
1559 }
1560 } else {
1561 /* masked, do not rearm. */
1562 pThis->fTimerArmed = false;
1563 }
1564}
1565# endif /* IN_RING3 */
1566
1567#endif /* VBOX */
1568
1569#ifndef VBOX
1570static uint32_t apic_mem_readb(void *opaque, target_phys_addr_t addr)
1571{
1572 return 0;
1573}
1574static uint32_t apic_mem_readw(void *opaque, target_phys_addr_t addr)
1575{
1576 return 0;
1577}
1578
1579static void apic_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
1580{
1581}
1582
1583static void apic_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
1584{
1585}
1586#endif /* !VBOX */
1587
1588
1589#ifndef VBOX
1590static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr)
1591{
1592 CPUState *env;
1593 APICState *s;
1594#else /* VBOX */
1595static uint32_t apic_mem_readl(APICDeviceInfo* dev, APICState *s, target_phys_addr_t addr)
1596{
1597#endif /* VBOX */
1598 uint32_t val;
1599 int index;
1600
1601#ifndef VBOX
1602 env = cpu_single_env;
1603 if (!env)
1604 return 0;
1605 s = env->apic_state;
1606#endif /* !VBOX */
1607
1608 index = (addr >> 4) & 0xff;
1609 switch(index) {
1610 case 0x02: /* id */
1611 val = s->id << 24;
1612 break;
1613 case 0x03: /* version */
1614 val = 0x11 | ((APIC_LVT_NB - 1) << 16); /* version 0x11 */
1615 break;
1616 case 0x08:
1617 val = s->tpr;
1618 break;
1619 case 0x09:
1620 val = apic_get_arb_pri(s);
1621 break;
1622 case 0x0a:
1623 /* ppr */
1624 val = apic_get_ppr(s);
1625 break;
1626 case 0x0b:
1627 Log(("apic_mem_readl %x %x -> write only returning 0\n", addr, index));
1628 val = 0;
1629 break;
1630 case 0x0d:
1631 val = s->log_dest << 24;
1632 break;
1633 case 0x0e:
1634#ifdef VBOX
1635 /* Bottom 28 bits are always 1 */
1636 val = (s->dest_mode << 28) | 0xfffffff;
1637#else
1638 val = s->dest_mode << 28;
1639#endif
1640 break;
1641 case 0x0f:
1642 val = s->spurious_vec;
1643 break;
1644#ifndef VBOX
1645 case 0x10 ... 0x17:
1646#else /* VBOX */
1647 case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
1648#endif /* VBOX */
1649 val = s->isr[index & 7];
1650 break;
1651#ifndef VBOX
1652 case 0x18 ... 0x1f:
1653#else /* VBOX */
1654 case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
1655#endif /* VBOX */
1656 val = s->tmr[index & 7];
1657 break;
1658#ifndef VBOX
1659 case 0x20 ... 0x27:
1660#else /* VBOX */
1661 case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
1662#endif /* VBOX */
1663 val = s->irr[index & 7];
1664 break;
1665 case 0x28:
1666 val = s->esr;
1667 break;
1668 case 0x30:
1669 case 0x31:
1670 val = s->icr[index & 1];
1671 break;
1672#ifndef VBOX
1673 case 0x32 ... 0x37:
1674#else /* VBOX */
1675 case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
1676#endif /* VBOX */
1677 val = s->lvt[index - 0x32];
1678 break;
1679 case 0x38:
1680 val = s->initial_count;
1681 break;
1682 case 0x39:
1683 val = apic_get_current_count(dev, s);
1684 break;
1685 case 0x3e:
1686 val = s->divide_conf;
1687 break;
1688 default:
1689 AssertMsgFailed(("apic_mem_readl: unknown index %x\n", index));
1690 s->esr |= ESR_ILLEGAL_ADDRESS;
1691 val = 0;
1692 break;
1693 }
1694#ifdef DEBUG_APIC
1695 Log(("CPU%d: APIC read: %08x = %08x\n", s->phys_id, (uint32_t)addr, val));
1696#endif
1697 return val;
1698}
1699
1700#ifndef VBOX
1701static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
1702{
1703 CPUState *env;
1704 APICState *s;
1705#else /* VBOX */
1706static int apic_mem_writel(APICDeviceInfo* dev, APICState *s, target_phys_addr_t addr, uint32_t val)
1707{
1708 int rc = VINF_SUCCESS;
1709#endif /* VBOX */
1710 int index;
1711
1712#ifndef VBOX
1713 env = cpu_single_env;
1714 if (!env)
1715 return;
1716 s = env->apic_state;
1717#endif /* !VBOX */
1718
1719#ifdef DEBUG_APIC
1720 Log(("CPU%d: APIC write: %08x = %08x\n", s->phys_id, (uint32_t)addr, val));
1721#endif
1722
1723 index = (addr >> 4) & 0xff;
1724 switch(index) {
1725 case 0x02:
1726 s->id = (val >> 24);
1727 break;
1728 case 0x03:
1729 Log(("apic_mem_writel: write to version register; ignored\n"));
1730 break;
1731 case 0x08:
1732#ifdef VBOX
1733 apic_update_tpr(dev, s, val);
1734#else
1735 s->tpr = val;
1736 apic_update_irq(s);
1737#endif
1738 break;
1739 case 0x09:
1740 case 0x0a:
1741 Log(("apic_mem_writel: write to read-only register %d ignored\n", index));
1742 break;
1743 case 0x0b: /* EOI */
1744 apic_eoi(dev, s);
1745 break;
1746 case 0x0d:
1747 s->log_dest = val >> 24;
1748 break;
1749 case 0x0e:
1750 s->dest_mode = val >> 28;
1751 break;
1752 case 0x0f:
1753 s->spurious_vec = val & 0x1ff;
1754 apic_update_irq(dev, s);
1755 break;
1756#ifndef VBOX
1757 case 0x10 ... 0x17:
1758 case 0x18 ... 0x1f:
1759 case 0x20 ... 0x27:
1760 case 0x28:
1761#else
1762 case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
1763 case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
1764 case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
1765 case 0x28:
1766 Log(("apic_mem_writel: write to read-only register %d ignored\n", index));
1767#endif
1768 break;
1769
1770 case 0x30:
1771 s->icr[0] = val;
1772 rc = apic_deliver(dev, s, (s->icr[1] >> 24) & 0xff,
1773 (s->icr[0] >> 11) & 1,
1774 (s->icr[0] >> 8) & 7, (s->icr[0] & 0xff),
1775 (s->icr[0] >> 14) & 1, (s->icr[0] >> 15) & 1);
1776 break;
1777 case 0x31:
1778 s->icr[1] = val;
1779 break;
1780#ifndef VBOX
1781 case 0x32 ... 0x37:
1782#else /* VBOX */
1783 case 0x32 + APIC_LVT_TIMER:
1784 AssertCompile(APIC_LVT_TIMER == 0);
1785 apicTimerSetLvt(dev, s, val);
1786 break;
1787 case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
1788#endif /* VBOX */
1789 {
1790 int n = index - 0x32;
1791 s->lvt[n] = val;
1792#ifndef VBOX
1793 if (n == APIC_LVT_TIMER)
1794 apic_timer_update(s, qemu_get_clock(vm_clock));
1795#endif /* !VBOX*/
1796 }
1797 break;
1798 case 0x38:
1799#ifndef VBOX
1800 s->initial_count = val;
1801 s->initial_count_load_time = qemu_get_clock(vm_clock);
1802 apic_timer_update(dev, s, s->initial_count_load_time);
1803#else /* VBOX */
1804 apicTimerSetInitialCount(dev, s, val);
1805#endif /* VBOX*/
1806 break;
1807 case 0x39:
1808 Log(("apic_mem_writel: write to read-only register %d ignored\n", index));
1809 break;
1810 case 0x3e:
1811 {
1812 int v;
1813 s->divide_conf = val & 0xb;
1814 v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4);
1815 s->count_shift = (v + 1) & 7;
1816 }
1817 break;
1818 default:
1819 AssertMsgFailed(("apic_mem_writel: unknown index %x\n", index));
1820 s->esr |= ESR_ILLEGAL_ADDRESS;
1821 break;
1822 }
1823#ifdef VBOX
1824 return rc;
1825#endif
1826}
1827
1828#ifdef IN_RING3
1829
1830static void apic_save(QEMUFile *f, void *opaque)
1831{
1832 APICState *s = (APICState*)opaque;
1833 int i;
1834
1835 qemu_put_be32s(f, &s->apicbase);
1836#ifdef VBOX
1837 qemu_put_be32s(f, &s->id);
1838 qemu_put_be32s(f, &s->phys_id);
1839 qemu_put_be32s(f, &s->arb_id);
1840 qemu_put_be32s(f, &s->tpr);
1841#else
1842 qemu_put_8s(f, &s->id);
1843 qemu_put_8s(f, &s->arb_id);
1844 qemu_put_8s(f, &s->tpr);
1845#endif
1846 qemu_put_be32s(f, &s->spurious_vec);
1847 qemu_put_8s(f, &s->log_dest);
1848 qemu_put_8s(f, &s->dest_mode);
1849 for (i = 0; i < 8; i++) {
1850 qemu_put_be32s(f, &s->isr[i]);
1851 qemu_put_be32s(f, &s->tmr[i]);
1852 qemu_put_be32s(f, &s->irr[i]);
1853 }
1854 for (i = 0; i < APIC_LVT_NB; i++) {
1855 qemu_put_be32s(f, &s->lvt[i]);
1856 }
1857 qemu_put_be32s(f, &s->esr);
1858 qemu_put_be32s(f, &s->icr[0]);
1859 qemu_put_be32s(f, &s->icr[1]);
1860 qemu_put_be32s(f, &s->divide_conf);
1861 qemu_put_be32s(f, &s->count_shift);
1862 qemu_put_be32s(f, &s->initial_count);
1863 qemu_put_be64s(f, &s->initial_count_load_time);
1864 qemu_put_be64s(f, &s->next_time);
1865
1866#ifdef VBOX
1867 TMR3TimerSave(s->CTX_SUFF(pTimer), f);
1868#endif
1869}
1870
1871static int apic_load(QEMUFile *f, void *opaque, int version_id)
1872{
1873 APICState *s = (APICState*)opaque;
1874 int i;
1875
1876#ifdef VBOX
1877 /* XXX: what if the base changes? (registered memory regions) */
1878 qemu_get_be32s(f, &s->apicbase);
1879
1880 switch (version_id)
1881 {
1882 case APIC_SAVED_STATE_VERSION_ANCIENT:
1883 {
1884 uint8_t val = 0;
1885 qemu_get_8s(f, &val);
1886 s->id = val;
1887 /* UP only in old saved states */
1888 s->phys_id = 0;
1889 qemu_get_8s(f, &val);
1890 s->arb_id = val;
1891 break;
1892 }
1893 case APIC_SAVED_STATE_VERSION:
1894 case APIC_SAVED_STATE_VERSION_VBOX_30:
1895 qemu_get_be32s(f, &s->id);
1896 qemu_get_be32s(f, &s->phys_id);
1897 qemu_get_be32s(f, &s->arb_id);
1898 break;
1899 default:
1900 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1901 }
1902 qemu_get_be32s(f, &s->tpr);
1903#else
1904 if (version_id != 1)
1905 return -EINVAL;
1906
1907 /* XXX: what if the base changes? (registered memory regions) */
1908 qemu_get_be32s(f, &s->apicbase);
1909 qemu_get_8s(f, &s->id);
1910 qemu_get_8s(f, &s->arb_id);
1911 qemu_get_8s(f, &s->tpr);
1912#endif
1913 qemu_get_be32s(f, &s->spurious_vec);
1914 qemu_get_8s(f, &s->log_dest);
1915 qemu_get_8s(f, &s->dest_mode);
1916 for (i = 0; i < 8; i++) {
1917 qemu_get_be32s(f, &s->isr[i]);
1918 qemu_get_be32s(f, &s->tmr[i]);
1919 qemu_get_be32s(f, &s->irr[i]);
1920 }
1921 for (i = 0; i < APIC_LVT_NB; i++) {
1922 qemu_get_be32s(f, &s->lvt[i]);
1923 }
1924 qemu_get_be32s(f, &s->esr);
1925 qemu_get_be32s(f, &s->icr[0]);
1926 qemu_get_be32s(f, &s->icr[1]);
1927 qemu_get_be32s(f, &s->divide_conf);
1928 qemu_get_be32s(f, (uint32_t *)&s->count_shift);
1929 qemu_get_be32s(f, (uint32_t *)&s->initial_count);
1930 qemu_get_be64s(f, (uint64_t *)&s->initial_count_load_time);
1931 qemu_get_be64s(f, (uint64_t *)&s->next_time);
1932
1933#ifdef VBOX
1934 int rc = TMR3TimerLoad(s->CTX_SUFF(pTimer), f);
1935 s->fTimerArmed = TMTimerIsActive(s->CTX_SUFF(pTimer));
1936#endif
1937
1938 return VINF_SUCCESS; /** @todo darn mess! */
1939}
1940#ifndef VBOX
1941static void apic_reset(void *opaque)
1942{
1943 APICState *s = (APICState*)opaque;
1944 apic_init_ipi(s);
1945}
1946#endif
1947
1948#endif /* IN_RING3 */
1949
1950#ifndef VBOX
1951static CPUReadMemoryFunc *apic_mem_read[3] = {
1952 apic_mem_readb,
1953 apic_mem_readw,
1954 apic_mem_readl,
1955};
1956
1957static CPUWriteMemoryFunc *apic_mem_write[3] = {
1958 apic_mem_writeb,
1959 apic_mem_writew,
1960 apic_mem_writel,
1961};
1962
1963int apic_init(CPUState *env)
1964{
1965 APICState *s;
1966
1967 s = qemu_mallocz(sizeof(APICState));
1968 if (!s)
1969 return -1;
1970 env->apic_state = s;
1971 apic_init_ipi(s);
1972 s->id = last_apic_id++;
1973 s->cpu_env = env;
1974 s->apicbase = 0xfee00000 |
1975 (s->id ? 0 : MSR_IA32_APICBASE_BSP) | MSR_IA32_APICBASE_ENABLE;
1976
1977 /* XXX: mapping more APICs at the same memory location */
1978 if (apic_io_memory == 0) {
1979 /* NOTE: the APIC is directly connected to the CPU - it is not
1980 on the global memory bus. */
1981 apic_io_memory = cpu_register_io_memory(0, apic_mem_read,
1982 apic_mem_write, NULL);
1983 cpu_register_physical_memory(s->apicbase & ~0xfff, 0x1000,
1984 apic_io_memory);
1985 }
1986 s->timer = qemu_new_timer(vm_clock, apic_timer, s);
1987
1988 register_savevm("apic", 0, 1, apic_save, apic_load, s);
1989 qemu_register_reset(apic_reset, s);
1990
1991 s->next_apic = first_local_apic;
1992 first_local_apic = s;
1993
1994 return 0;
1995}
1996#endif /* !VBOX */
1997
1998static void ioapic_service(IOAPICState *s)
1999{
2000 uint8_t i;
2001 uint8_t trig_mode;
2002 uint8_t vector;
2003 uint8_t delivery_mode;
2004 uint32_t mask;
2005 uint64_t entry;
2006 uint8_t dest;
2007 uint8_t dest_mode;
2008 uint8_t polarity;
2009
2010 for (i = 0; i < IOAPIC_NUM_PINS; i++) {
2011 mask = 1 << i;
2012 if (s->irr & mask) {
2013 entry = s->ioredtbl[i];
2014 if (!(entry & APIC_LVT_MASKED)) {
2015 trig_mode = ((entry >> 15) & 1);
2016 dest = entry >> 56;
2017 dest_mode = (entry >> 11) & 1;
2018 delivery_mode = (entry >> 8) & 7;
2019 polarity = (entry >> 13) & 1;
2020 if (trig_mode == APIC_TRIGGER_EDGE)
2021 s->irr &= ~mask;
2022 if (delivery_mode == APIC_DM_EXTINT)
2023#ifndef VBOX /* malc: i'm still not so sure about ExtINT delivery */
2024 vector = pic_read_irq(isa_pic);
2025#else /* VBOX */
2026 {
2027 AssertMsgFailed(("Delivery mode ExtINT"));
2028 vector = 0xff; /* incorrect but shuts up gcc. */
2029 }
2030#endif /* VBOX */
2031 else
2032 vector = entry & 0xff;
2033
2034#ifndef VBOX
2035 apic_bus_deliver(apic_get_delivery_bitmask(dest, dest_mode),
2036 delivery_mode, vector, polarity, trig_mode);
2037#else /* VBOX */
2038 int rc = s->CTX_SUFF(pIoApicHlp)->pfnApicBusDeliver(s->CTX_SUFF(pDevIns),
2039 dest,
2040 dest_mode,
2041 delivery_mode,
2042 vector,
2043 polarity,
2044 trig_mode);
2045 /* We must be sure that attempts to reschedule in R3
2046 never get here */
2047 Assert(rc == VINF_SUCCESS);
2048#endif /* VBOX */
2049 }
2050 }
2051 }
2052}
2053
2054#ifdef VBOX
2055static
2056#endif
2057void ioapic_set_irq(void *opaque, int vector, int level)
2058{
2059 IOAPICState *s = (IOAPICState*)opaque;
2060
2061 if (vector >= 0 && vector < IOAPIC_NUM_PINS) {
2062 uint32_t mask = 1 << vector;
2063 uint64_t entry = s->ioredtbl[vector];
2064
2065 if ((entry >> 15) & 1) {
2066 /* level triggered */
2067 if (level) {
2068 s->irr |= mask;
2069 ioapic_service(s);
2070#ifdef VBOX
2071 if ((level & PDM_IRQ_LEVEL_FLIP_FLOP) == PDM_IRQ_LEVEL_FLIP_FLOP) {
2072 s->irr &= ~mask;
2073 }
2074#endif
2075 } else {
2076 s->irr &= ~mask;
2077 }
2078 } else {
2079 /* edge triggered */
2080 if (level) {
2081 s->irr |= mask;
2082 ioapic_service(s);
2083 }
2084 }
2085 }
2086}
2087
2088static uint32_t ioapic_mem_readl(void *opaque, target_phys_addr_t addr)
2089{
2090 IOAPICState *s = (IOAPICState*)opaque;
2091 int index;
2092 uint32_t val = 0;
2093
2094 addr &= 0xff;
2095 if (addr == 0x00) {
2096 val = s->ioregsel;
2097 } else if (addr == 0x10) {
2098 switch (s->ioregsel) {
2099 case 0x00:
2100 val = s->id << 24;
2101 break;
2102 case 0x01:
2103 val = 0x11 | ((IOAPIC_NUM_PINS - 1) << 16); /* version 0x11 */
2104 break;
2105 case 0x02:
2106 val = 0;
2107 break;
2108 default:
2109 index = (s->ioregsel - 0x10) >> 1;
2110 if (index >= 0 && index < IOAPIC_NUM_PINS) {
2111 if (s->ioregsel & 1)
2112 val = s->ioredtbl[index] >> 32;
2113 else
2114 val = s->ioredtbl[index] & 0xffffffff;
2115 }
2116 }
2117#ifdef DEBUG_IOAPIC
2118 Log(("I/O APIC read: %08x = %08x\n", s->ioregsel, val));
2119#endif
2120 }
2121 return val;
2122}
2123
2124static void ioapic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
2125{
2126 IOAPICState *s = (IOAPICState*)opaque;
2127 int index;
2128
2129 addr &= 0xff;
2130 if (addr == 0x00) {
2131 s->ioregsel = val;
2132 return;
2133 } else if (addr == 0x10) {
2134#ifdef DEBUG_IOAPIC
2135 Log(("I/O APIC write: %08x = %08x\n", s->ioregsel, val));
2136#endif
2137 switch (s->ioregsel) {
2138 case 0x00:
2139 s->id = (val >> 24) & 0xff;
2140 return;
2141 case 0x01:
2142 case 0x02:
2143 return;
2144 default:
2145 index = (s->ioregsel - 0x10) >> 1;
2146 if (index >= 0 && index < IOAPIC_NUM_PINS) {
2147 if (s->ioregsel & 1) {
2148 s->ioredtbl[index] &= 0xffffffff;
2149 s->ioredtbl[index] |= (uint64_t)val << 32;
2150 } else {
2151#ifdef VBOX
2152 /* According to IOAPIC spec, vectors should be from 0x10 to 0xfe */
2153 uint8_t vec = val & 0xff;
2154 if ((val & APIC_LVT_MASKED) ||
2155 ((vec >= 0x10) && (vec < 0xff)))
2156 {
2157 s->ioredtbl[index] &= ~0xffffffffULL;
2158 s->ioredtbl[index] |= val;
2159 }
2160 else
2161 {
2162 /*
2163 * Linux 2.6 kernels has pretty strange function
2164 * unlock_ExtINT_logic() which writes
2165 * absolutely bogus (all 0) value into the vector
2166 * with pretty vague explanation why.
2167 * So we just ignore such writes.
2168 */
2169 LogRel(("IOAPIC GUEST BUG: bad vector writing %x(sel=%x) to %d\n", val, s->ioregsel, index));
2170 }
2171 }
2172#else
2173 s->ioredtbl[index] &= ~0xffffffffULL;
2174 s->ioredtbl[index] |= val;
2175#endif
2176 ioapic_service(s);
2177 }
2178 }
2179 }
2180}
2181
2182#ifdef IN_RING3
2183
2184static void ioapic_save(QEMUFile *f, void *opaque)
2185{
2186 IOAPICState *s = (IOAPICState*)opaque;
2187 int i;
2188
2189 qemu_put_8s(f, &s->id);
2190 qemu_put_8s(f, &s->ioregsel);
2191 for (i = 0; i < IOAPIC_NUM_PINS; i++) {
2192 qemu_put_be64s(f, &s->ioredtbl[i]);
2193 }
2194}
2195
2196static int ioapic_load(QEMUFile *f, void *opaque, int version_id)
2197{
2198 IOAPICState *s = (IOAPICState*)opaque;
2199 int i;
2200
2201 if (version_id != 1)
2202 return -EINVAL;
2203
2204 qemu_get_8s(f, &s->id);
2205 qemu_get_8s(f, &s->ioregsel);
2206 for (i = 0; i < IOAPIC_NUM_PINS; i++) {
2207 qemu_get_be64s(f, &s->ioredtbl[i]);
2208 }
2209 return 0;
2210}
2211
2212static void ioapic_reset(void *opaque)
2213{
2214 IOAPICState *s = (IOAPICState*)opaque;
2215#ifdef VBOX
2216 PPDMDEVINSR3 pDevIns = s->pDevInsR3;
2217 PCPDMIOAPICHLPR3 pIoApicHlp = s->pIoApicHlpR3;
2218#endif
2219 int i;
2220
2221 memset(s, 0, sizeof(*s));
2222 for(i = 0; i < IOAPIC_NUM_PINS; i++)
2223 s->ioredtbl[i] = 1 << 16; /* mask LVT */
2224
2225#ifdef VBOX
2226 if (pDevIns)
2227 {
2228 s->pDevInsR3 = pDevIns;
2229 s->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2230 s->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
2231 }
2232 if (pIoApicHlp)
2233 {
2234 s->pIoApicHlpR3 = pIoApicHlp;
2235 s->pIoApicHlpRC = s->pIoApicHlpR3->pfnGetRCHelpers(pDevIns);
2236 s->pIoApicHlpR0 = s->pIoApicHlpR3->pfnGetR0Helpers(pDevIns);
2237 }
2238#endif
2239}
2240
2241#endif /* IN_RING3 */
2242
2243#ifndef VBOX
2244static CPUReadMemoryFunc *ioapic_mem_read[3] = {
2245 ioapic_mem_readl,
2246 ioapic_mem_readl,
2247 ioapic_mem_readl,
2248};
2249
2250static CPUWriteMemoryFunc *ioapic_mem_write[3] = {
2251 ioapic_mem_writel,
2252 ioapic_mem_writel,
2253 ioapic_mem_writel,
2254};
2255
2256IOAPICState *ioapic_init(void)
2257{
2258 IOAPICState *s;
2259 int io_memory;
2260
2261 s = qemu_mallocz(sizeof(IOAPICState));
2262 if (!s)
2263 return NULL;
2264 ioapic_reset(s);
2265 s->id = last_apic_id++;
2266
2267 io_memory = cpu_register_io_memory(0, ioapic_mem_read,
2268 ioapic_mem_write, s);
2269 cpu_register_physical_memory(0xfec00000, 0x1000, io_memory);
2270
2271 register_savevm("ioapic", 0, 1, ioapic_save, ioapic_load, s);
2272 qemu_register_reset(ioapic_reset, s);
2273
2274 return s;
2275}
2276#endif /* !VBOX */
2277
2278/* LAPIC */
2279PDMBOTHCBDECL(int) apicMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
2280{
2281 APICDeviceInfo *dev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2282 APICState *s = getLapic(dev);
2283
2284 Log(("CPU%d: apicMMIORead at %llx\n", s->phys_id, (uint64_t)GCPhysAddr));
2285
2286 /** @todo: add LAPIC range validity checks (different LAPICs can theoretically have
2287 different physical addresses, see #3092) */
2288
2289 STAM_COUNTER_INC(&CTXSUFF(dev->StatMMIORead));
2290 switch (cb)
2291 {
2292 case 1:
2293 *(uint8_t *)pv = 0;
2294 break;
2295
2296 case 2:
2297 *(uint16_t *)pv = 0;
2298 break;
2299
2300 case 4:
2301 {
2302#if 0 /** @note experimental */
2303#ifndef IN_RING3
2304 uint32_t index = (GCPhysAddr >> 4) & 0xff;
2305
2306 if ( index == 0x08 /* TPR */
2307 && ++s->cTPRPatchAttempts < APIC_MAX_PATCH_ATTEMPTS)
2308 {
2309#ifdef IN_RC
2310 pDevIns->pDevHlpGC->pfnPATMSetMMIOPatchInfo(pDevIns, GCPhysAddr, &s->tpr);
2311#else
2312 RTGCPTR pDevInsGC = PDMINS2DATA_GCPTR(pDevIns);
2313 pDevIns->pDevHlpR0->pfnPATMSetMMIOPatchInfo(pDevIns, GCPhysAddr, pDevIns + RT_OFFSETOF(APICState, tpr));
2314#endif
2315 return VINF_PATM_HC_MMIO_PATCH_READ;
2316 }
2317#endif
2318#endif /* experimental */
2319 APIC_LOCK(dev, VINF_IOM_HC_MMIO_READ);
2320 *(uint32_t *)pv = apic_mem_readl(dev, s, GCPhysAddr);
2321 APIC_UNLOCK(dev);
2322 break;
2323 }
2324 default:
2325 AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */
2326 return VERR_INTERNAL_ERROR;
2327 }
2328 return VINF_SUCCESS;
2329}
2330
2331PDMBOTHCBDECL(int) apicMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
2332{
2333 APICDeviceInfo *dev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2334 APICState *s = getLapic(dev);
2335
2336 Log(("CPU%d: apicMMIOWrite at %llx\n", s->phys_id, (uint64_t)GCPhysAddr));
2337
2338 /** @todo: add LAPIC range validity checks (multiple LAPICs can theoretically have
2339 different physical addresses, see #3092) */
2340
2341 STAM_COUNTER_INC(&CTXSUFF(dev->StatMMIOWrite));
2342 switch (cb)
2343 {
2344 case 1:
2345 case 2:
2346 /* ignore */
2347 break;
2348
2349 case 4:
2350 {
2351 int rc;
2352 APIC_LOCK(dev, VINF_IOM_HC_MMIO_WRITE);
2353 rc = apic_mem_writel(dev, s, GCPhysAddr, *(uint32_t *)pv);
2354 APIC_UNLOCK(dev);
2355 return rc;
2356 }
2357
2358 default:
2359 AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */
2360 return VERR_INTERNAL_ERROR;
2361 }
2362 return VINF_SUCCESS;
2363}
2364
2365#ifdef IN_RING3
2366
2367/* Print a 8-dword LAPIC bit map (256 bits). */
2368static void lapicDumpVec(APICDeviceInfo *dev, APICState *lapic, PCDBGFINFOHLP pHlp, unsigned start)
2369{
2370 unsigned i;
2371 uint32_t val;
2372
2373 for (i = 0; i < 8; ++i)
2374 {
2375 val = apic_mem_readl(dev, lapic, start + (i << 4));
2376 pHlp->pfnPrintf(pHlp, "%08X", val);
2377 }
2378 pHlp->pfnPrintf(pHlp, "\n");
2379}
2380
2381/* Print basic LAPIC state. */
2382static DECLCALLBACK(void) lapicInfoBasic(APICDeviceInfo *dev, APICState *lapic, PCDBGFINFOHLP pHlp)
2383{
2384 uint32_t val;
2385 unsigned max_lvt;
2386
2387 pHlp->pfnPrintf(pHlp, "Local APIC at %08X:\n", lapic->apicbase);
2388 val = apic_mem_readl(dev, lapic, 0x20);
2389 pHlp->pfnPrintf(pHlp, " LAPIC ID : %08X\n", val);
2390 pHlp->pfnPrintf(pHlp, " APIC ID = %02X\n", (val >> 24) & 0xff);
2391 val = apic_mem_readl(dev, lapic, 0x30);
2392 max_lvt = (val >> 16) & 0xff;
2393 pHlp->pfnPrintf(pHlp, " APIC VER : %08X\n", val);
2394 pHlp->pfnPrintf(pHlp, " version = %02X\n", val & 0xff);
2395 pHlp->pfnPrintf(pHlp, " lvts = %d\n", ((val >> 16) & 0xff) + 1);
2396 val = apic_mem_readl(dev, lapic, 0x80);
2397 pHlp->pfnPrintf(pHlp, " TPR : %08X\n", val);
2398 pHlp->pfnPrintf(pHlp, " task pri = %d/%d\n", (val >> 4) & 0xf, val & 0xf);
2399 val = apic_mem_readl(dev, lapic, 0xA0);
2400 pHlp->pfnPrintf(pHlp, " PPR : %08X\n", val);
2401 pHlp->pfnPrintf(pHlp, " cpu pri = %d/%d\n", (val >> 4) & 0xf, val & 0xf);
2402 val = apic_mem_readl(dev, lapic, 0xD0);
2403 pHlp->pfnPrintf(pHlp, " LDR : %08X\n", val);
2404 pHlp->pfnPrintf(pHlp, " log id = %02X\n", (val >> 24) & 0xff);
2405 val = apic_mem_readl(dev, lapic, 0xE0);
2406 pHlp->pfnPrintf(pHlp, " DFR : %08X\n", val);
2407 val = apic_mem_readl(dev, lapic, 0xF0);
2408 pHlp->pfnPrintf(pHlp, " SVR : %08X\n", val);
2409 pHlp->pfnPrintf(pHlp, " focus = %s\n", val & (1 << 9) ? "check off" : "check on");
2410 pHlp->pfnPrintf(pHlp, " lapic = %s\n", val & (1 << 8) ? "ENABLED" : "DISABLED");
2411 pHlp->pfnPrintf(pHlp, " vector = %02X\n", val & 0xff);
2412 pHlp->pfnPrintf(pHlp, " ISR : ");
2413 lapicDumpVec(dev, lapic, pHlp, 0x100);
2414 val = get_highest_priority_int(lapic->isr);
2415 pHlp->pfnPrintf(pHlp, " highest = %02X\n", val == ~0U ? 0 : val);
2416 pHlp->pfnPrintf(pHlp, " IRR : ");
2417 lapicDumpVec(dev, lapic, pHlp, 0x200);
2418 val = get_highest_priority_int(lapic->irr);
2419 pHlp->pfnPrintf(pHlp, " highest = %02X\n", val == ~0U ? 0 : val);
2420 val = apic_mem_readl(dev, lapic, 0x320);
2421}
2422
2423/* Print the more interesting LAPIC LVT entries. */
2424static DECLCALLBACK(void) lapicInfoLVT(APICDeviceInfo *dev, APICState *lapic, PCDBGFINFOHLP pHlp)
2425{
2426 uint32_t val;
2427 static const char *dmodes[] = { "Fixed ", "Reserved", "SMI", "Reserved",
2428 "NMI", "INIT", "Reserved", "ExtINT" };
2429
2430 val = apic_mem_readl(dev, lapic, 0x320);
2431 pHlp->pfnPrintf(pHlp, " LVT Timer : %08X\n", val);
2432 pHlp->pfnPrintf(pHlp, " mode = %s\n", val & (1 << 17) ? "periodic" : "one-shot");
2433 pHlp->pfnPrintf(pHlp, " mask = %d\n", (val >> 16) & 1);
2434 pHlp->pfnPrintf(pHlp, " status = %s\n", val & (1 << 12) ? "pending" : "idle");
2435 pHlp->pfnPrintf(pHlp, " vector = %02X\n", val & 0xff);
2436 val = apic_mem_readl(dev, lapic, 0x350);
2437 pHlp->pfnPrintf(pHlp, " LVT LINT0 : %08X\n", val);
2438 pHlp->pfnPrintf(pHlp, " mask = %d\n", (val >> 16) & 1);
2439 pHlp->pfnPrintf(pHlp, " trigger = %s\n", val & (1 << 15) ? "level" : "edge");
2440 pHlp->pfnPrintf(pHlp, " rem irr = %d\n", (val >> 14) & 1);
2441 pHlp->pfnPrintf(pHlp, " polarty = %d\n", (val >> 13) & 1);
2442 pHlp->pfnPrintf(pHlp, " status = %s\n", val & (1 << 12) ? "pending" : "idle");
2443 pHlp->pfnPrintf(pHlp, " delivry = %s\n", dmodes[(val >> 8) & 7]);
2444 pHlp->pfnPrintf(pHlp, " vector = %02X\n", val & 0xff);
2445 val = apic_mem_readl(dev, lapic, 0x360);
2446 pHlp->pfnPrintf(pHlp, " LVT LINT1 : %08X\n", val);
2447 pHlp->pfnPrintf(pHlp, " mask = %d\n", (val >> 16) & 1);
2448 pHlp->pfnPrintf(pHlp, " trigger = %s\n", val & (1 << 15) ? "level" : "edge");
2449 pHlp->pfnPrintf(pHlp, " rem irr = %d\n", (val >> 14) & 1);
2450 pHlp->pfnPrintf(pHlp, " polarty = %d\n", (val >> 13) & 1);
2451 pHlp->pfnPrintf(pHlp, " status = %s\n", val & (1 << 12) ? "pending" : "idle");
2452 pHlp->pfnPrintf(pHlp, " delivry = %s\n", dmodes[(val >> 8) & 7]);
2453 pHlp->pfnPrintf(pHlp, " vector = %02X\n", val & 0xff);
2454}
2455
2456/* Print LAPIC timer state. */
2457static DECLCALLBACK(void) lapicInfoTimer(APICDeviceInfo *dev, APICState *lapic, PCDBGFINFOHLP pHlp)
2458{
2459 uint32_t val;
2460 unsigned divider;
2461
2462 pHlp->pfnPrintf(pHlp, "Local APIC timer:\n");
2463 val = apic_mem_readl(dev, lapic, 0x380);
2464 pHlp->pfnPrintf(pHlp, " Initial count : %08X\n", val);
2465 val = apic_mem_readl(dev, lapic, 0x390);
2466 pHlp->pfnPrintf(pHlp, " Current count : %08X\n", val);
2467 val = apic_mem_readl(dev, lapic, 0x3E0);
2468 pHlp->pfnPrintf(pHlp, " Divide config : %08X\n", val);
2469 divider = ((val >> 1) & 0x04) | (val & 0x03);
2470 pHlp->pfnPrintf(pHlp, " divider = %d\n", divider == 7 ? 1 : 2 << divider);
2471}
2472
2473/**
2474 * Info handler, device version. Dumps Local APIC(s) state according to given argument.
2475 *
2476 * @param pDevIns Device instance which registered the info.
2477 * @param pHlp Callback functions for doing output.
2478 * @param pszArgs Argument string. Optional.
2479 */
2480static DECLCALLBACK(void) lapicInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
2481{
2482 APICDeviceInfo *dev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2483 APICState *lapic;
2484
2485 lapic = getLapic(dev);
2486
2487 if (pszArgs == NULL || !strcmp(pszArgs, "basic"))
2488 {
2489 lapicInfoBasic(dev, lapic, pHlp);
2490 }
2491 else if (!strcmp(pszArgs, "lvt"))
2492 {
2493 lapicInfoLVT(dev, lapic, pHlp);
2494 }
2495 else if (!strcmp(pszArgs, "timer"))
2496 {
2497 lapicInfoTimer(dev, lapic, pHlp);
2498 }
2499 else
2500 {
2501 pHlp->pfnPrintf(pHlp, "Invalid argument. Recognized arguments are 'basic', 'lvt', 'timer'.\n");
2502 }
2503}
2504
2505/**
2506 * @copydoc FNSSMDEVLIVEEXEC
2507 */
2508static DECLCALLBACK(int) apicLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
2509{
2510 APICDeviceInfo *pThis = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2511
2512 SSMR3PutU32( pSSM, pThis->cCpus);
2513 SSMR3PutBool(pSSM, pThis->fIoApic);
2514 SSMR3PutU32( pSSM, pThis->enmVersion);
2515 AssertCompile(PDMAPICVERSION_APIC == 2);
2516
2517 return VINF_SSM_DONT_CALL_AGAIN;
2518}
2519
2520/**
2521 * @copydoc FNSSMDEVSAVEEXEC
2522 */
2523static DECLCALLBACK(int) apicSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
2524{
2525 APICDeviceInfo *dev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2526
2527 /* config */
2528 apicLiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
2529
2530 /* save all APICs data, @todo: is it correct? */
2531 foreach_apic(dev, 0xffffffff, apic_save(pSSM, apic));
2532
2533 return VINF_SUCCESS;
2534}
2535
2536/**
2537 * @copydoc FNSSMDEVLOADEXEC
2538 */
2539static DECLCALLBACK(int) apicLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
2540{
2541 APICDeviceInfo *pThis = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2542
2543 if ( uVersion != APIC_SAVED_STATE_VERSION
2544 && uVersion != APIC_SAVED_STATE_VERSION_VBOX_30
2545 && uVersion != APIC_SAVED_STATE_VERSION_ANCIENT)
2546 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
2547
2548 /* config */
2549 if (uVersion > APIC_SAVED_STATE_VERSION_VBOX_30) {
2550 uint32_t cCpus;
2551 int rc = SSMR3GetU32(pSSM, &cCpus); AssertRCReturn(rc, rc);
2552 if (cCpus != pThis->cCpus)
2553 {
2554 LogRel(("APIC: Config mismatch - cCpus: saved=%#x config=%#x\n", cCpus, pThis->cCpus));
2555 return VERR_SSM_LOAD_CONFIG_MISMATCH;
2556 }
2557 bool fIoApic;
2558 rc = SSMR3GetBool(pSSM, &fIoApic); AssertRCReturn(rc, rc);
2559 if (fIoApic != pThis->fIoApic)
2560 {
2561 LogRel(("APIC: Config mismatch - fIoApic: saved=%RTbool config=%RTbool\n", fIoApic, pThis->fIoApic));
2562 return VERR_SSM_LOAD_CONFIG_MISMATCH;
2563 }
2564 uint32_t uApicVersion;
2565 rc = SSMR3GetU32(pSSM, &uApicVersion); AssertRCReturn(rc, rc);
2566 if (uApicVersion != (uint32_t)pThis->enmVersion)
2567 {
2568 LogRel(("APIC: Config mismatch - uApicVersion: saved=%#x config=%#x\n", uApicVersion, pThis->enmVersion));
2569 return VERR_SSM_LOAD_CONFIG_MISMATCH;
2570 }
2571 }
2572
2573 if (uPass != SSM_PASS_FINAL)
2574 return VINF_SUCCESS;
2575
2576 /* load all APICs data */ /** @todo: is it correct? */
2577 foreach_apic(pThis, 0xffffffff,
2578 if (apic_load(pSSM, apic, uVersion)) {
2579 AssertFailed();
2580 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
2581 }
2582 );
2583 return VINF_SUCCESS;
2584}
2585
2586/**
2587 * @copydoc FNPDMDEVRESET
2588 */
2589static DECLCALLBACK(void) apicReset(PPDMDEVINS pDevIns)
2590{
2591 APICDeviceInfo *dev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2592 unsigned i;
2593
2594 APIC_LOCK_VOID(dev, VERR_INTERNAL_ERROR);
2595
2596 /* Reset all APICs. */
2597 for (i = 0; i < dev->cCpus; i++) {
2598 APICState *pApic = &dev->CTX_SUFF(paLapics)[i];
2599 TMTimerStop(pApic->CTX_SUFF(pTimer));
2600
2601 /* Do not send an init ipi to the VCPU; we take
2602 * care of the proper init ourselves.
2603 apic_init_ipi(dev, pApic);
2604 */
2605
2606 /* malc, I've removed the initing duplicated in apic_init_ipi(). This
2607 * arb_id was left over.. */
2608 pApic->arb_id = 0;
2609 /* Reset should re-enable the APIC. */
2610 pApic->apicbase = 0xfee00000 | MSR_IA32_APICBASE_ENABLE;
2611 if (pApic->phys_id == 0)
2612 pApic->apicbase |= MSR_IA32_APICBASE_BSP;
2613
2614 /* Clear any pending APIC interrupt action flag. */
2615 cpuClearInterrupt(dev, pApic);
2616 }
2617 /** @todo r=bird: Why is this done everytime, while the constructor first
2618 * checks the CPUID? Who is right? */
2619 dev->pApicHlpR3->pfnChangeFeature(dev->pDevInsR3, dev->enmVersion);
2620
2621 APIC_UNLOCK(dev);
2622}
2623
2624/**
2625 * @copydoc FNPDMDEVRELOCATE
2626 */
2627static DECLCALLBACK(void) apicRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
2628{
2629 APICDeviceInfo *pThis = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2630 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2631 pThis->pApicHlpRC = pThis->pApicHlpR3->pfnGetRCHelpers(pDevIns);
2632 pThis->paLapicsRC = MMHyperR3ToRC(PDMDevHlpGetVM(pDevIns), pThis->paLapicsR3);
2633 pThis->pCritSectRC = pThis->pApicHlpR3->pfnGetRCCritSect(pDevIns);
2634 for (uint32_t i = 0; i < pThis->cCpus; i++)
2635 pThis->paLapicsR3[i].pTimerRC = TMTimerRCPtr(pThis->paLapicsR3[i].pTimerR3);
2636}
2637
2638DECLINLINE(void) initApicData(APICState* apic, uint8_t id)
2639{
2640 int i;
2641 memset(apic, 0, sizeof(*apic));
2642 apic->apicbase = UINT32_C(0xfee00000) | MSR_IA32_APICBASE_ENABLE;
2643 /* Mark first CPU as BSP */
2644 if (id == 0)
2645 apic->apicbase |= MSR_IA32_APICBASE_BSP;
2646 for (i = 0; i < APIC_LVT_NB; i++)
2647 apic->lvt[i] = 1 << 16; /* mask LVT */
2648 apic->spurious_vec = 0xff;
2649 apic->phys_id = apic->id = id;
2650}
2651
2652/**
2653 * @copydoc FNPDMDEVCONSTRUCT
2654 */
2655static DECLCALLBACK(int) apicConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
2656{
2657 PDMAPICREG ApicReg;
2658 int rc;
2659 uint32_t i;
2660 bool fIoApic;
2661 bool fGCEnabled;
2662 bool fR0Enabled;
2663 APICDeviceInfo *pThis = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2664 uint32_t cCpus;
2665
2666 /*
2667 * Only single device instance.
2668 */
2669 Assert(iInstance == 0);
2670
2671 /*
2672 * Validate configuration.
2673 */
2674 if (!CFGMR3AreValuesValid(pCfgHandle,
2675 "IOAPIC\0"
2676 "GCEnabled\0"
2677 "R0Enabled\0"
2678 "NumCPUs\0"))
2679 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
2680
2681 rc = CFGMR3QueryBoolDef(pCfgHandle, "IOAPIC", &fIoApic, true);
2682 if (RT_FAILURE(rc))
2683 return PDMDEV_SET_ERROR(pDevIns, rc,
2684 N_("Configuration error: Failed to read \"IOAPIC\""));
2685
2686 rc = CFGMR3QueryBoolDef(pCfgHandle, "GCEnabled", &fGCEnabled, true);
2687 if (RT_FAILURE(rc))
2688 return PDMDEV_SET_ERROR(pDevIns, rc,
2689 N_("Configuration error: Failed to query boolean value \"GCEnabled\""));
2690
2691 rc = CFGMR3QueryBoolDef(pCfgHandle, "R0Enabled", &fR0Enabled, true);
2692 if (RT_FAILURE(rc))
2693 return PDMDEV_SET_ERROR(pDevIns, rc,
2694 N_("Configuration error: Failed to query boolean value \"R0Enabled\""));
2695
2696 rc = CFGMR3QueryU32Def(pCfgHandle, "NumCPUs", &cCpus, 1);
2697 if (RT_FAILURE(rc))
2698 return PDMDEV_SET_ERROR(pDevIns, rc,
2699 N_("Configuration error: Failed to query integer value \"NumCPUs\""));
2700
2701 Log(("APIC: cCpus=%d fR0Enabled=%RTbool fGCEnabled=%RTbool fIoApic=%RTbool\n", cCpus, fR0Enabled, fGCEnabled, fIoApic));
2702
2703 /** @todo Current implementation is limited to 32 CPUs due to the use of 32
2704 * bits bitmasks. */
2705 if (cCpus > 32)
2706 return PDMDEV_SET_ERROR(pDevIns, rc,
2707 N_("Configuration error: Invalid value for \"NumCPUs\""));
2708
2709 /*
2710 * Init the data.
2711 */
2712 pThis->pDevInsR3 = pDevIns;
2713 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
2714 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2715 pThis->cCpus = cCpus;
2716 pThis->fIoApic = fIoApic;
2717 /* Use PDMAPICVERSION_X2APIC to activate x2APIC mode */
2718 pThis->enmVersion = PDMAPICVERSION_APIC;
2719
2720 PVM pVM = PDMDevHlpGetVM(pDevIns);
2721 /*
2722 * We are not freeing this memory, as it's automatically released when guest exits.
2723 */
2724 rc = MMHyperAlloc(pVM, cCpus * sizeof(APICState), 1, MM_TAG_PDM_DEVICE_USER, (void **)&pThis->paLapicsR3);
2725 if (RT_FAILURE(rc))
2726 return VERR_NO_MEMORY;
2727 pThis->paLapicsR0 = MMHyperR3ToR0(pVM, pThis->paLapicsR3);
2728 pThis->paLapicsRC = MMHyperR3ToRC(pVM, pThis->paLapicsR3);
2729
2730 for (i = 0; i < cCpus; i++)
2731 initApicData(&pThis->paLapicsR3[i], i);
2732
2733 /*
2734 * Register the APIC.
2735 */
2736 ApicReg.u32Version = PDM_APICREG_VERSION;
2737 ApicReg.pfnGetInterruptR3 = apicGetInterrupt;
2738 ApicReg.pfnHasPendingIrqR3 = apicHasPendingIrq;
2739 ApicReg.pfnSetBaseR3 = apicSetBase;
2740 ApicReg.pfnGetBaseR3 = apicGetBase;
2741 ApicReg.pfnSetTPRR3 = apicSetTPR;
2742 ApicReg.pfnGetTPRR3 = apicGetTPR;
2743 ApicReg.pfnWriteMSRR3 = apicWriteMSR;
2744 ApicReg.pfnReadMSRR3 = apicReadMSR;
2745 ApicReg.pfnBusDeliverR3 = apicBusDeliverCallback;
2746 if (fGCEnabled) {
2747 ApicReg.pszGetInterruptRC = "apicGetInterrupt";
2748 ApicReg.pszHasPendingIrqRC = "apicHasPendingIrq";
2749 ApicReg.pszSetBaseRC = "apicSetBase";
2750 ApicReg.pszGetBaseRC = "apicGetBase";
2751 ApicReg.pszSetTPRRC = "apicSetTPR";
2752 ApicReg.pszGetTPRRC = "apicGetTPR";
2753 ApicReg.pszWriteMSRRC = "apicWriteMSR";
2754 ApicReg.pszReadMSRRC = "apicReadMSR";
2755 ApicReg.pszBusDeliverRC = "apicBusDeliverCallback";
2756 } else {
2757 ApicReg.pszGetInterruptRC = NULL;
2758 ApicReg.pszHasPendingIrqRC = NULL;
2759 ApicReg.pszSetBaseRC = NULL;
2760 ApicReg.pszGetBaseRC = NULL;
2761 ApicReg.pszSetTPRRC = NULL;
2762 ApicReg.pszGetTPRRC = NULL;
2763 ApicReg.pszWriteMSRRC = NULL;
2764 ApicReg.pszReadMSRRC = NULL;
2765 ApicReg.pszBusDeliverRC = NULL;
2766 }
2767 if (fR0Enabled) {
2768 ApicReg.pszGetInterruptR0 = "apicGetInterrupt";
2769 ApicReg.pszHasPendingIrqR0 = "apicHasPendingIrq";
2770 ApicReg.pszSetBaseR0 = "apicSetBase";
2771 ApicReg.pszGetBaseR0 = "apicGetBase";
2772 ApicReg.pszSetTPRR0 = "apicSetTPR";
2773 ApicReg.pszGetTPRR0 = "apicGetTPR";
2774 ApicReg.pszWriteMSRR0 = "apicWriteMSR";
2775 ApicReg.pszReadMSRR0 = "apicReadMSR";
2776 ApicReg.pszBusDeliverR0 = "apicBusDeliverCallback";
2777 } else {
2778 ApicReg.pszGetInterruptR0 = NULL;
2779 ApicReg.pszHasPendingIrqR0 = NULL;
2780 ApicReg.pszSetBaseR0 = NULL;
2781 ApicReg.pszGetBaseR0 = NULL;
2782 ApicReg.pszSetTPRR0 = NULL;
2783 ApicReg.pszGetTPRR0 = NULL;
2784 ApicReg.pszWriteMSRR0 = NULL;
2785 ApicReg.pszReadMSRR0 = NULL;
2786 ApicReg.pszBusDeliverR0 = NULL;
2787 }
2788
2789 Assert(pDevIns->pDevHlpR3->pfnAPICRegister);
2790 rc = pDevIns->pDevHlpR3->pfnAPICRegister(pDevIns, &ApicReg, &pThis->pApicHlpR3);
2791 AssertLogRelRCReturn(rc, rc);
2792 pThis->pCritSectR3 = pThis->pApicHlpR3->pfnGetR3CritSect(pDevIns);
2793
2794 /*
2795 * The the CPUID feature bit.
2796 */
2797 /** @todo r=bird: See remark in the apicReset. */
2798 uint32_t u32Eax, u32Ebx, u32Ecx, u32Edx;
2799 PDMDevHlpGetCpuId(pDevIns, 0, &u32Eax, &u32Ebx, &u32Ecx, &u32Edx);
2800 if (u32Eax >= 1) {
2801 if ( fIoApic /* If IOAPIC is enabled, enable Local APIC in any case */
2802 || ( u32Ebx == X86_CPUID_VENDOR_INTEL_EBX
2803 && u32Ecx == X86_CPUID_VENDOR_INTEL_ECX
2804 && u32Edx == X86_CPUID_VENDOR_INTEL_EDX /* GenuineIntel */)
2805 || ( u32Ebx == X86_CPUID_VENDOR_AMD_EBX
2806 && u32Ecx == X86_CPUID_VENDOR_AMD_ECX
2807 && u32Edx == X86_CPUID_VENDOR_AMD_EDX /* AuthenticAMD */)) {
2808 LogRel(("Activating Local APIC\n"));
2809 pThis->pApicHlpR3->pfnChangeFeature(pDevIns, pThis->enmVersion);
2810 }
2811 }
2812
2813 /*
2814 * Register the MMIO range.
2815 */
2816 uint32_t ApicBase = pThis->paLapicsR3[0].apicbase & ~0xfff;
2817 rc = PDMDevHlpMMIORegister(pDevIns, ApicBase, 0x1000, pThis,
2818 apicMMIOWrite, apicMMIORead, NULL, "APIC Memory");
2819 if (RT_FAILURE(rc))
2820 return rc;
2821
2822 if (fGCEnabled) {
2823 pThis->pApicHlpRC = pThis->pApicHlpR3->pfnGetRCHelpers(pDevIns);
2824 pThis->pCritSectRC = pThis->pApicHlpR3->pfnGetRCCritSect(pDevIns);
2825
2826 rc = PDMDevHlpMMIORegisterGC(pDevIns, ApicBase, 0x1000, 0,
2827 "apicMMIOWrite", "apicMMIORead", NULL);
2828 if (RT_FAILURE(rc))
2829 return rc;
2830 }
2831
2832 if (fR0Enabled) {
2833 pThis->pApicHlpR0 = pThis->pApicHlpR3->pfnGetR0Helpers(pDevIns);
2834 pThis->pCritSectR0 = pThis->pApicHlpR3->pfnGetR0CritSect(pDevIns);
2835
2836 rc = PDMDevHlpMMIORegisterR0(pDevIns, ApicBase, 0x1000, 0,
2837 "apicMMIOWrite", "apicMMIORead", NULL);
2838 if (RT_FAILURE(rc))
2839 return rc;
2840 }
2841
2842 /*
2843 * Create the APIC timers.
2844 */
2845 for (i = 0; i < cCpus; i++) {
2846 APICState *pApic = &pThis->paLapicsR3[i];
2847 pApic->pszDesc = MMR3HeapAPrintf(pVM, MM_TAG_PDM_DEVICE_USER, "APIC Timer #%u", i);
2848 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, apicTimerCallback, pApic,
2849 TMTIMER_FLAGS_NO_CRIT_SECT, pApic->pszDesc, &pApic->pTimerR3);
2850 if (RT_FAILURE(rc))
2851 return rc;
2852 pApic->pTimerR0 = TMTimerR0Ptr(pApic->pTimerR3);
2853 pApic->pTimerRC = TMTimerRCPtr(pApic->pTimerR3);
2854 TMR3TimerSetCritSect(pApic->pTimerR3, pThis->pCritSectR3);
2855 }
2856
2857 /*
2858 * Saved state.
2859 */
2860 rc = PDMDevHlpSSMRegister3(pDevIns, APIC_SAVED_STATE_VERSION, sizeof(*pThis),
2861 apicLiveExec, apicSaveExec, apicLoadExec);
2862 if (RT_FAILURE(rc))
2863 return rc;
2864
2865 /*
2866 * Register debugger info callback.
2867 */
2868 PDMDevHlpDBGFInfoRegister(pDevIns, "lapic", "Display Local APIC state for current CPU. "
2869 "Recognizes 'basic', 'lvt', 'timer' as arguments, defaulting to 'basic'.", lapicInfo);
2870
2871#ifdef VBOX_WITH_STATISTICS
2872 /*
2873 * Statistics.
2874 */
2875 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatMMIOReadGC, STAMTYPE_COUNTER, "/Devices/APIC/MMIOReadGC", STAMUNIT_OCCURENCES, "Number of APIC MMIO reads in GC.");
2876 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatMMIOReadHC, STAMTYPE_COUNTER, "/Devices/APIC/MMIOReadHC", STAMUNIT_OCCURENCES, "Number of APIC MMIO reads in HC.");
2877 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatMMIOWriteGC, STAMTYPE_COUNTER, "/Devices/APIC/MMIOWriteGC", STAMUNIT_OCCURENCES, "Number of APIC MMIO writes in GC.");
2878 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatMMIOWriteHC, STAMTYPE_COUNTER, "/Devices/APIC/MMIOWriteHC", STAMUNIT_OCCURENCES, "Number of APIC MMIO writes in HC.");
2879 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatClearedActiveIrq,STAMTYPE_COUNTER, "/Devices/APIC/MaskedActiveIRQ", STAMUNIT_OCCURENCES, "Number of cleared irqs.");
2880 for (i = 0; i < cCpus; i++) {
2881 APICState *pApic = &pThis->paLapicsR3[i];
2882 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetInitialCount, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Calls to apicTimerSetInitialCount.", "/Devices/APIC/%u/TimerSetInitialCount", i);
2883 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetInitialCountArm, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerSetRelative calls.", "/Devices/APIC/%u/TimerSetInitialCount/Arm", i);
2884 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetInitialCountDisarm, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerStop calls.", "/Devices/APIC/%u/TimerSetInitialCount/Disasm", i);
2885 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvt, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Calls to apicTimerSetLvt.", "/Devices/APIC/%u/TimerSetLvt", i);
2886 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtClearPeriodic, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Clearing APIC_LVT_TIMER_PERIODIC.", "/Devices/APIC/%u/TimerSetLvt/ClearPeriodic", i);
2887 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtPostponed, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerStop postponed.", "/Devices/APIC/%u/TimerSetLvt/Postponed", i);
2888 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtArmed, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerSet avoided.", "/Devices/APIC/%u/TimerSetLvt/Armed", i);
2889 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtArm, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerSet necessary.", "/Devices/APIC/%u/TimerSetLvt/Arm", i);
2890 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtArmRetries, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "TMTimerSet retries.", "/Devices/APIC/%u/TimerSetLvt/ArmRetries", i);
2891 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetLvtNoRelevantChange,STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "No relevant flags changed.", "/Devices/APIC/%u/TimerSetLvt/NoRelevantChange", i);
2892 }
2893#endif
2894
2895 return VINF_SUCCESS;
2896}
2897
2898
2899/**
2900 * APIC device registration structure.
2901 */
2902const PDMDEVREG g_DeviceAPIC =
2903{
2904 /* u32Version */
2905 PDM_DEVREG_VERSION,
2906 /* szDeviceName */
2907 "apic",
2908 /* szRCMod */
2909 "VBoxDD2GC.gc",
2910 /* szR0Mod */
2911 "VBoxDD2R0.r0",
2912 /* pszDescription */
2913 "Advanced Programmable Interrupt Controller (APIC) Device",
2914 /* fFlags */
2915 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64 | PDM_DEVREG_FLAGS_PAE36 | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
2916 /* fClass */
2917 PDM_DEVREG_CLASS_PIC,
2918 /* cMaxInstances */
2919 1,
2920 /* cbInstance */
2921 sizeof(APICState),
2922 /* pfnConstruct */
2923 apicConstruct,
2924 /* pfnDestruct */
2925 NULL,
2926 /* pfnRelocate */
2927 apicRelocate,
2928 /* pfnIOCtl */
2929 NULL,
2930 /* pfnPowerOn */
2931 NULL,
2932 /* pfnReset */
2933 apicReset,
2934 /* pfnSuspend */
2935 NULL,
2936 /* pfnResume */
2937 NULL,
2938 /* pfnAttach */
2939 NULL,
2940 /* pfnDetach */
2941 NULL,
2942 /* pfnQueryInterface. */
2943 NULL,
2944 /* pfnInitComplete */
2945 NULL,
2946 /* pfnPowerOff */
2947 NULL,
2948 /* pfnSoftReset */
2949 NULL,
2950 /* u32VersionEnd */
2951 PDM_DEVREG_VERSION
2952};
2953
2954#endif /* IN_RING3 */
2955
2956
2957/* IOAPIC */
2958
2959PDMBOTHCBDECL(int) ioapicMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
2960{
2961 IOAPICState *s = PDMINS_2_DATA(pDevIns, IOAPICState *);
2962 IOAPIC_LOCK(s, VINF_IOM_HC_MMIO_READ);
2963
2964 STAM_COUNTER_INC(&CTXSUFF(s->StatMMIORead));
2965 switch (cb) {
2966 case 1:
2967 *(uint8_t *)pv = ioapic_mem_readl(s, GCPhysAddr);
2968 break;
2969
2970 case 2:
2971 *(uint16_t *)pv = ioapic_mem_readl(s, GCPhysAddr);
2972 break;
2973
2974 case 4:
2975 *(uint32_t *)pv = ioapic_mem_readl(s, GCPhysAddr);
2976 break;
2977
2978 default:
2979 AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */
2980 IOAPIC_UNLOCK(s);
2981 return VERR_INTERNAL_ERROR;
2982 }
2983 IOAPIC_UNLOCK(s);
2984 return VINF_SUCCESS;
2985}
2986
2987PDMBOTHCBDECL(int) ioapicMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
2988{
2989 IOAPICState *s = PDMINS_2_DATA(pDevIns, IOAPICState *);
2990
2991 STAM_COUNTER_INC(&CTXSUFF(s->StatMMIOWrite));
2992 switch (cb) {
2993 case 1:
2994 case 2:
2995 case 4:
2996 IOAPIC_LOCK(s, VINF_IOM_HC_MMIO_WRITE);
2997 ioapic_mem_writel(s, GCPhysAddr, *(uint32_t *)pv);
2998 IOAPIC_UNLOCK(s);
2999 break;
3000
3001 default:
3002 AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */
3003 return VERR_INTERNAL_ERROR;
3004 }
3005 return VINF_SUCCESS;
3006}
3007
3008PDMBOTHCBDECL(void) ioapicSetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel)
3009{
3010 /* PDM lock is taken here; @todo add assertion */
3011 IOAPICState *pThis = PDMINS_2_DATA(pDevIns, IOAPICState *);
3012 STAM_COUNTER_INC(&pThis->CTXSUFF(StatSetIrq));
3013 LogFlow(("ioapicSetIrq: iIrq=%d iLevel=%d\n", iIrq, iLevel));
3014 ioapic_set_irq(pThis, iIrq, iLevel);
3015}
3016
3017
3018#ifdef IN_RING3
3019
3020/**
3021 * Info handler, device version. Dumps I/O APIC state.
3022 *
3023 * @param pDevIns Device instance which registered the info.
3024 * @param pHlp Callback functions for doing output.
3025 * @param pszArgs Argument string. Optional and specific to the handler.
3026 */
3027static DECLCALLBACK(void) ioapicInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
3028{
3029 IOAPICState *s = PDMINS_2_DATA(pDevIns, IOAPICState *);
3030 uint32_t val;
3031 unsigned i;
3032 unsigned max_redir;
3033
3034 pHlp->pfnPrintf(pHlp, "I/O APIC at %08X:\n", 0xfec00000);
3035 val = s->id << 24; /* Would be nice to call ioapic_mem_readl() directly, but that's not so simple. */
3036 pHlp->pfnPrintf(pHlp, " IOAPICID : %08X\n", val);
3037 pHlp->pfnPrintf(pHlp, " APIC ID = %02X\n", (val >> 24) & 0xff);
3038 val = 0x11 | ((IOAPIC_NUM_PINS - 1) << 16);
3039 max_redir = (val >> 16) & 0xff;
3040 pHlp->pfnPrintf(pHlp, " IOAPICVER : %08X\n", val);
3041 pHlp->pfnPrintf(pHlp, " version = %02X\n", val & 0xff);
3042 pHlp->pfnPrintf(pHlp, " redirs = %d\n", ((val >> 16) & 0xff) + 1);
3043 val = 0;
3044 pHlp->pfnPrintf(pHlp, " IOAPICARB : %08X\n", val);
3045 pHlp->pfnPrintf(pHlp, " arb ID = %02X\n", (val >> 24) & 0xff);
3046 Assert(sizeof(s->ioredtbl) / sizeof(s->ioredtbl[0]) > max_redir);
3047 pHlp->pfnPrintf(pHlp, "I/O redirection table\n");
3048 pHlp->pfnPrintf(pHlp, " idx dst_mode dst_addr mask trigger rirr polarity dlvr_st dlvr_mode vector\n");
3049 for (i = 0; i <= max_redir; ++i)
3050 {
3051 static const char *dmodes[] = { "Fixed ", "LowPri", "SMI ", "Resrvd",
3052 "NMI ", "INIT ", "Resrvd", "ExtINT" };
3053
3054 pHlp->pfnPrintf(pHlp, " %02d %s %02X %d %s %d %s %s %s %3d (%016llX)\n",
3055 i,
3056 s->ioredtbl[i] & (1 << 11) ? "log " : "phys", /* dest mode */
3057 (int)(s->ioredtbl[i] >> 56), /* dest addr */
3058 (int)(s->ioredtbl[i] >> 16) & 1, /* mask */
3059 s->ioredtbl[i] & (1 << 15) ? "level" : "edge ", /* trigger */
3060 (int)(s->ioredtbl[i] >> 14) & 1, /* remote IRR */
3061 s->ioredtbl[i] & (1 << 13) ? "activelo" : "activehi", /* polarity */
3062 s->ioredtbl[i] & (1 << 12) ? "pend" : "idle", /* delivery status */
3063 dmodes[(s->ioredtbl[i] >> 8) & 0x07], /* delivery mode */
3064 (int)s->ioredtbl[i] & 0xff, /* vector */
3065 s->ioredtbl[i] /* entire register */
3066 );
3067 }
3068}
3069
3070/**
3071 * @copydoc FNSSMDEVSAVEEXEC
3072 */
3073static DECLCALLBACK(int) ioapicSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
3074{
3075 IOAPICState *s = PDMINS_2_DATA(pDevIns, IOAPICState *);
3076 ioapic_save(pSSM, s);
3077 return VINF_SUCCESS;
3078}
3079
3080/**
3081 * @copydoc FNSSMDEVLOADEXEC
3082 */
3083static DECLCALLBACK(int) ioapicLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
3084{
3085 IOAPICState *s = PDMINS_2_DATA(pDevIns, IOAPICState *);
3086
3087 if (ioapic_load(pSSM, s, uVersion)) {
3088 AssertFailed();
3089 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
3090 }
3091 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
3092
3093 return VINF_SUCCESS;
3094}
3095
3096/**
3097 * @copydoc FNPDMDEVRESET
3098 */
3099static DECLCALLBACK(void) ioapicReset(PPDMDEVINS pDevIns)
3100{
3101 IOAPICState *s = PDMINS_2_DATA(pDevIns, IOAPICState *);
3102 s->pIoApicHlpR3->pfnLock(pDevIns, VERR_INTERNAL_ERROR);
3103 ioapic_reset(s);
3104 IOAPIC_UNLOCK(s);
3105}
3106
3107/**
3108 * @copydoc FNPDMDEVRELOCATE
3109 */
3110static DECLCALLBACK(void) ioapicRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
3111{
3112 IOAPICState *s = PDMINS_2_DATA(pDevIns, IOAPICState *);
3113 s->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
3114 s->pIoApicHlpRC = s->pIoApicHlpR3->pfnGetRCHelpers(pDevIns);
3115}
3116
3117/**
3118 * @copydoc FNPDMDEVCONSTRUCT
3119 */
3120static DECLCALLBACK(int) ioapicConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
3121{
3122 IOAPICState *s = PDMINS_2_DATA(pDevIns, IOAPICState *);
3123 PDMIOAPICREG IoApicReg;
3124 bool fGCEnabled;
3125 bool fR0Enabled;
3126 int rc;
3127
3128 Assert(iInstance == 0);
3129
3130 /*
3131 * Validate and read the configuration.
3132 */
3133 if (!CFGMR3AreValuesValid(pCfgHandle, "GCEnabled\0" "R0Enabled\0"))
3134 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
3135
3136 rc = CFGMR3QueryBoolDef(pCfgHandle, "GCEnabled", &fGCEnabled, true);
3137 if (RT_FAILURE(rc))
3138 return PDMDEV_SET_ERROR(pDevIns, rc,
3139 N_("Configuration error: Failed to query boolean value \"GCEnabled\""));
3140
3141 rc = CFGMR3QueryBoolDef(pCfgHandle, "R0Enabled", &fR0Enabled, true);
3142 if (RT_FAILURE(rc))
3143 return PDMDEV_SET_ERROR(pDevIns, rc,
3144 N_("Configuration error: Failed to query boolean value \"R0Enabled\""));
3145 Log(("IOAPIC: fR0Enabled=%RTbool fGCEnabled=%RTbool\n", fR0Enabled, fGCEnabled));
3146
3147 /*
3148 * Initialize the state data.
3149 */
3150 s->pDevInsR3 = pDevIns;
3151 s->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
3152 s->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
3153 ioapic_reset(s);
3154 s->id = 0;
3155
3156 /*
3157 * Register the IOAPIC and get helpers.
3158 */
3159 IoApicReg.u32Version = PDM_IOAPICREG_VERSION;
3160 IoApicReg.pfnSetIrqR3 = ioapicSetIrq;
3161 IoApicReg.pszSetIrqRC = fGCEnabled ? "ioapicSetIrq" : NULL;
3162 IoApicReg.pszSetIrqR0 = fR0Enabled ? "ioapicSetIrq" : NULL;
3163 rc = pDevIns->pDevHlpR3->pfnIOAPICRegister(pDevIns, &IoApicReg, &s->pIoApicHlpR3);
3164 if (RT_FAILURE(rc))
3165 {
3166 AssertMsgFailed(("IOAPICRegister -> %Rrc\n", rc));
3167 return rc;
3168 }
3169
3170 /*
3171 * Register MMIO callbacks and saved state.
3172 */
3173 rc = PDMDevHlpMMIORegister(pDevIns, 0xfec00000, 0x1000, s,
3174 ioapicMMIOWrite, ioapicMMIORead, NULL, "I/O APIC Memory");
3175 if (RT_FAILURE(rc))
3176 return rc;
3177
3178 if (fGCEnabled) {
3179 s->pIoApicHlpRC = s->pIoApicHlpR3->pfnGetRCHelpers(pDevIns);
3180
3181 rc = PDMDevHlpMMIORegisterGC(pDevIns, 0xfec00000, 0x1000, 0,
3182 "ioapicMMIOWrite", "ioapicMMIORead", NULL);
3183 if (RT_FAILURE(rc))
3184 return rc;
3185 }
3186
3187 if (fR0Enabled) {
3188 s->pIoApicHlpR0 = s->pIoApicHlpR3->pfnGetR0Helpers(pDevIns);
3189
3190 rc = PDMDevHlpMMIORegisterR0(pDevIns, 0xfec00000, 0x1000, 0,
3191 "ioapicMMIOWrite", "ioapicMMIORead", NULL);
3192 if (RT_FAILURE(rc))
3193 return rc;
3194 }
3195
3196 rc = PDMDevHlpSSMRegister(pDevIns, 1 /* version */, sizeof(*s), ioapicSaveExec, ioapicLoadExec);
3197 if (RT_FAILURE(rc))
3198 return rc;
3199
3200 /*
3201 * Register debugger info callback.
3202 */
3203 PDMDevHlpDBGFInfoRegister(pDevIns, "ioapic", "Display I/O APIC state.", ioapicInfo);
3204
3205#ifdef VBOX_WITH_STATISTICS
3206 /*
3207 * Statistics.
3208 */
3209 PDMDevHlpSTAMRegister(pDevIns, &s->StatMMIOReadGC, STAMTYPE_COUNTER, "/Devices/IOAPIC/MMIOReadGC", STAMUNIT_OCCURENCES, "Number of IOAPIC MMIO reads in GC.");
3210 PDMDevHlpSTAMRegister(pDevIns, &s->StatMMIOReadHC, STAMTYPE_COUNTER, "/Devices/IOAPIC/MMIOReadHC", STAMUNIT_OCCURENCES, "Number of IOAPIC MMIO reads in HC.");
3211 PDMDevHlpSTAMRegister(pDevIns, &s->StatMMIOWriteGC, STAMTYPE_COUNTER, "/Devices/IOAPIC/MMIOWriteGC", STAMUNIT_OCCURENCES, "Number of IOAPIC MMIO writes in GC.");
3212 PDMDevHlpSTAMRegister(pDevIns, &s->StatMMIOWriteHC, STAMTYPE_COUNTER, "/Devices/IOAPIC/MMIOWriteHC", STAMUNIT_OCCURENCES, "Number of IOAPIC MMIO writes in HC.");
3213 PDMDevHlpSTAMRegister(pDevIns, &s->StatSetIrqGC, STAMTYPE_COUNTER, "/Devices/IOAPIC/SetIrqGC", STAMUNIT_OCCURENCES, "Number of IOAPIC SetIrq calls in GC.");
3214 PDMDevHlpSTAMRegister(pDevIns, &s->StatSetIrqHC, STAMTYPE_COUNTER, "/Devices/IOAPIC/SetIrqHC", STAMUNIT_OCCURENCES, "Number of IOAPIC SetIrq calls in HC.");
3215#endif
3216
3217 return VINF_SUCCESS;
3218}
3219
3220/**
3221 * IO APIC device registration structure.
3222 */
3223const PDMDEVREG g_DeviceIOAPIC =
3224{
3225 /* u32Version */
3226 PDM_DEVREG_VERSION,
3227 /* szDeviceName */
3228 "ioapic",
3229 /* szRCMod */
3230 "VBoxDD2GC.gc",
3231 /* szR0Mod */
3232 "VBoxDD2R0.r0",
3233 /* pszDescription */
3234 "I/O Advanced Programmable Interrupt Controller (IO-APIC) Device",
3235 /* fFlags */
3236 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64 | PDM_DEVREG_FLAGS_PAE36 | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
3237 /* fClass */
3238 PDM_DEVREG_CLASS_PIC,
3239 /* cMaxInstances */
3240 1,
3241 /* cbInstance */
3242 sizeof(IOAPICState),
3243 /* pfnConstruct */
3244 ioapicConstruct,
3245 /* pfnDestruct */
3246 NULL,
3247 /* pfnRelocate */
3248 ioapicRelocate,
3249 /* pfnIOCtl */
3250 NULL,
3251 /* pfnPowerOn */
3252 NULL,
3253 /* pfnReset */
3254 ioapicReset,
3255 /* pfnSuspend */
3256 NULL,
3257 /* pfnResume */
3258 NULL,
3259 /* pfnAttach */
3260 NULL,
3261 /* pfnDetach */
3262 NULL,
3263 /* pfnQueryInterface. */
3264 NULL,
3265 /* pfnInitComplete */
3266 NULL,
3267 /* pfnPowerOff */
3268 NULL,
3269 /* pfnSoftReset */
3270 NULL,
3271 /* u32VersionEnd */
3272 PDM_DEVREG_VERSION
3273};
3274
3275#endif /* IN_RING3 */
3276#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
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