VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/DevIoApic.cpp@ 38082

Last change on this file since 38082 was 37637, checked in by vboxsync, 13 years ago

ioapicMMIOWrite: Don't access more than cb bytes from pv!

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 24.8 KB
Line 
1/* $Id: DevIoApic.cpp 37637 2011-06-24 15:06:23Z vboxsync $ */
2/** @file
3 * I/O Advanced Programmable Interrupt Controller (IO-APIC) Device.
4 */
5
6/*
7 * Copyright (C) 2006-2010 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 * --------------------------------------------------------------------
17 *
18 * This code is based on:
19 *
20 * apic.c revision 1.5 @@OSETODO
21 *
22 * APIC support
23 *
24 * Copyright (c) 2004-2005 Fabrice Bellard
25 *
26 * This library is free software; you can redistribute it and/or
27 * modify it under the terms of the GNU Lesser General Public
28 * License as published by the Free Software Foundation; either
29 * version 2 of the License, or (at your option) any later version.
30 *
31 * This library is distributed in the hope that it will be useful,
32 * but WITHOUT ANY WARRANTY; without even the implied warranty of
33 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
34 * Lesser General Public License for more details.
35 *
36 * You should have received a copy of the GNU Lesser General Public
37 * License along with this library; if not, write to the Free Software
38 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
39 */
40
41/*******************************************************************************
42* Header Files *
43*******************************************************************************/
44#define LOG_GROUP LOG_GROUP_DEV_APIC
45#include <VBox/vmm/pdmdev.h>
46
47#include <VBox/log.h>
48#include <VBox/vmm/stam.h>
49#include <iprt/assert.h>
50#include <iprt/asm.h>
51
52#include <VBox/msi.h>
53
54#include "VBoxDD2.h"
55#include "DevApic.h"
56
57
58/*******************************************************************************
59* Defined Constants And Macros *
60*******************************************************************************/
61/** @def IOAPIC_LOCK
62 * Acquires the PDM lock. */
63#define IOAPIC_LOCK(pThis, rc) \
64 do { \
65 int rc2 = (pThis)->CTX_SUFF(pIoApicHlp)->pfnLock((pThis)->CTX_SUFF(pDevIns), rc); \
66 if (rc2 != VINF_SUCCESS) \
67 return rc2; \
68 } while (0)
69
70/** @def IOAPIC_UNLOCK
71 * Releases the PDM lock. */
72#define IOAPIC_UNLOCK(pThis) (pThis)->CTX_SUFF(pIoApicHlp)->pfnUnlock((pThis)->CTX_SUFF(pDevIns))
73
74
75#define foreach_apic(pDev, mask, code) \
76 do { \
77 APICState *apic = (pDev)->CTX_SUFF(paLapics); \
78 for (uint32_t i = 0; i < (pDev)->cCpus; i++) \
79 { \
80 if (mask & (1 << (apic->id))) \
81 { \
82 code; \
83 } \
84 apic++; \
85 } \
86 } while (0)
87
88# define set_bit(pvBitmap, iBit) ASMBitSet(pvBitmap, iBit)
89# define reset_bit(pvBitmap, iBit) ASMBitClear(pvBitmap, iBit)
90# define fls_bit(value) (ASMBitLastSetU32(value) - 1)
91# define ffs_bit(value) (ASMBitFirstSetU32(value) - 1)
92
93#define DEBUG_IOAPIC
94#define IOAPIC_NUM_PINS 0x18
95
96
97/*******************************************************************************
98* Structures and Typedefs *
99*******************************************************************************/
100struct IOAPICState {
101 uint8_t id;
102 uint8_t ioregsel;
103
104 uint32_t irr;
105 uint64_t ioredtbl[IOAPIC_NUM_PINS];
106
107 /** The device instance - R3 Ptr. */
108 PPDMDEVINSR3 pDevInsR3;
109 /** The IOAPIC helpers - R3 Ptr. */
110 PCPDMIOAPICHLPR3 pIoApicHlpR3;
111
112 /** The device instance - R0 Ptr. */
113 PPDMDEVINSR0 pDevInsR0;
114 /** The IOAPIC helpers - R0 Ptr. */
115 PCPDMIOAPICHLPR0 pIoApicHlpR0;
116
117 /** The device instance - RC Ptr. */
118 PPDMDEVINSRC pDevInsRC;
119 /** The IOAPIC helpers - RC Ptr. */
120 PCPDMIOAPICHLPRC pIoApicHlpRC;
121
122# ifdef VBOX_WITH_STATISTICS
123 STAMCOUNTER StatMMIOReadGC;
124 STAMCOUNTER StatMMIOReadHC;
125 STAMCOUNTER StatMMIOWriteGC;
126 STAMCOUNTER StatMMIOWriteHC;
127 STAMCOUNTER StatSetIrqGC;
128 STAMCOUNTER StatSetIrqHC;
129# endif
130};
131
132typedef struct IOAPICState IOAPICState;
133
134#ifndef VBOX_DEVICE_STRUCT_TESTCASE
135
136/*******************************************************************************
137* Internal Functions *
138*******************************************************************************/
139
140
141static void ioapic_service(IOAPICState *s)
142{
143 uint8_t i;
144 uint8_t trig_mode;
145 uint8_t vector;
146 uint8_t delivery_mode;
147 uint32_t mask;
148 uint64_t entry;
149 uint8_t dest;
150 uint8_t dest_mode;
151 uint8_t polarity;
152
153 for (i = 0; i < IOAPIC_NUM_PINS; i++) {
154 mask = 1 << i;
155 if (s->irr & mask) {
156 entry = s->ioredtbl[i];
157 if (!(entry & APIC_LVT_MASKED)) {
158 trig_mode = ((entry >> 15) & 1);
159 dest = entry >> 56;
160 dest_mode = (entry >> 11) & 1;
161 delivery_mode = (entry >> 8) & 7;
162 polarity = (entry >> 13) & 1;
163 if (trig_mode == APIC_TRIGGER_EDGE)
164 s->irr &= ~mask;
165 if (delivery_mode == APIC_DM_EXTINT)
166 /* malc: i'm still not so sure about ExtINT delivery */
167 {
168 AssertMsgFailed(("Delivery mode ExtINT"));
169 vector = 0xff; /* incorrect but shuts up gcc. */
170 }
171 else
172 vector = entry & 0xff;
173
174 int rc = s->CTX_SUFF(pIoApicHlp)->pfnApicBusDeliver(s->CTX_SUFF(pDevIns),
175 dest,
176 dest_mode,
177 delivery_mode,
178 vector,
179 polarity,
180 trig_mode);
181 /* We must be sure that attempts to reschedule in R3
182 never get here */
183 Assert(rc == VINF_SUCCESS);
184 }
185 }
186 }
187}
188
189
190static void ioapic_set_irq(void *opaque, int vector, int level)
191{
192 IOAPICState *s = (IOAPICState*)opaque;
193
194 if (vector >= 0 && vector < IOAPIC_NUM_PINS) {
195 uint32_t mask = 1 << vector;
196 uint64_t entry = s->ioredtbl[vector];
197
198 if ((entry >> 15) & 1) {
199 /* level triggered */
200 if (level) {
201 s->irr |= mask;
202 ioapic_service(s);
203 if ((level & PDM_IRQ_LEVEL_FLIP_FLOP) == PDM_IRQ_LEVEL_FLIP_FLOP) {
204 s->irr &= ~mask;
205 }
206 } else {
207 s->irr &= ~mask;
208 }
209 } else {
210 /* edge triggered */
211 if (level) {
212 s->irr |= mask;
213 ioapic_service(s);
214 }
215 }
216 }
217}
218
219static uint32_t ioapic_mem_readl(void *opaque, RTGCPHYS addr)
220{
221 IOAPICState *s = (IOAPICState*)opaque;
222 int index;
223 uint32_t val = 0;
224
225 addr &= 0xff;
226 if (addr == 0x00) {
227 val = s->ioregsel;
228 } else if (addr == 0x10) {
229 switch (s->ioregsel) {
230 case 0x00:
231 val = s->id << 24;
232 break;
233 case 0x01:
234 val = 0x11 | ((IOAPIC_NUM_PINS - 1) << 16); /* version 0x11 */
235 break;
236 case 0x02:
237 val = 0;
238 break;
239 default:
240 index = (s->ioregsel - 0x10) >> 1;
241 if (index >= 0 && index < IOAPIC_NUM_PINS) {
242 if (s->ioregsel & 1)
243 val = s->ioredtbl[index] >> 32;
244 else
245 val = s->ioredtbl[index] & 0xffffffff;
246 }
247 }
248#ifdef DEBUG_IOAPIC
249 Log(("I/O APIC read: %08x = %08x\n", s->ioregsel, val));
250#endif
251 }
252 return val;
253}
254
255static void ioapic_mem_writel(void *opaque, RTGCPHYS addr, uint32_t val)
256{
257 IOAPICState *s = (IOAPICState*)opaque;
258 int index;
259
260 addr &= 0xff;
261 if (addr == 0x00) {
262 s->ioregsel = val;
263 return;
264 } else if (addr == 0x10) {
265#ifdef DEBUG_IOAPIC
266 Log(("I/O APIC write: %08x = %08x\n", s->ioregsel, val));
267#endif
268 switch (s->ioregsel) {
269 case 0x00:
270 s->id = (val >> 24) & 0xff;
271 return;
272 case 0x01:
273 case 0x02:
274 return;
275 default:
276 index = (s->ioregsel - 0x10) >> 1;
277 if (index >= 0 && index < IOAPIC_NUM_PINS) {
278 if (s->ioregsel & 1) {
279 s->ioredtbl[index] &= 0xffffffff;
280 s->ioredtbl[index] |= (uint64_t)val << 32;
281 } else {
282 /* According to IOAPIC spec, vectors should be from 0x10 to 0xfe */
283 uint8_t vec = val & 0xff;
284 if ((val & APIC_LVT_MASKED) ||
285 ((vec >= 0x10) && (vec < 0xff)))
286 {
287 s->ioredtbl[index] &= ~0xffffffffULL;
288 s->ioredtbl[index] |= val;
289 }
290 else
291 {
292 /*
293 * Linux 2.6 kernels has pretty strange function
294 * unlock_ExtINT_logic() which writes
295 * absolutely bogus (all 0) value into the vector
296 * with pretty vague explanation why.
297 * So we just ignore such writes.
298 */
299 LogRel(("IOAPIC GUEST BUG: bad vector writing %x(sel=%x) to %d\n", val, s->ioregsel, index));
300 }
301 }
302 ioapic_service(s);
303 }
304 }
305 }
306}
307
308#ifdef IN_RING3
309
310static void ioapic_save(SSMHANDLE *f, void *opaque)
311{
312 IOAPICState *s = (IOAPICState*)opaque;
313 int i;
314
315 SSMR3PutU8(f, s->id);
316 SSMR3PutU8(f, s->ioregsel);
317 for (i = 0; i < IOAPIC_NUM_PINS; i++) {
318 SSMR3PutU64(f, s->ioredtbl[i]);
319 }
320}
321
322static int ioapic_load(SSMHANDLE *f, void *opaque, int version_id)
323{
324 IOAPICState *s = (IOAPICState*)opaque;
325 int i;
326
327 if (version_id != 1)
328 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
329
330 SSMR3GetU8(f, &s->id);
331 SSMR3GetU8(f, &s->ioregsel);
332 for (i = 0; i < IOAPIC_NUM_PINS; i++) {
333 SSMR3GetU64(f, &s->ioredtbl[i]);
334 }
335 return 0;
336}
337
338static void ioapic_reset(void *opaque)
339{
340 IOAPICState *s = (IOAPICState*)opaque;
341 PPDMDEVINSR3 pDevIns = s->pDevInsR3;
342 PCPDMIOAPICHLPR3 pIoApicHlp = s->pIoApicHlpR3;
343 int i;
344
345 memset(s, 0, sizeof(*s));
346 for(i = 0; i < IOAPIC_NUM_PINS; i++)
347 s->ioredtbl[i] = 1 << 16; /* mask LVT */
348
349 if (pDevIns)
350 {
351 s->pDevInsR3 = pDevIns;
352 s->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
353 s->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
354 }
355 if (pIoApicHlp)
356 {
357 s->pIoApicHlpR3 = pIoApicHlp;
358 s->pIoApicHlpRC = s->pIoApicHlpR3->pfnGetRCHelpers(pDevIns);
359 s->pIoApicHlpR0 = s->pIoApicHlpR3->pfnGetR0Helpers(pDevIns);
360 }
361}
362
363#endif /* IN_RING3 */
364
365
366/* IOAPIC */
367
368PDMBOTHCBDECL(int) ioapicMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
369{
370 IOAPICState *s = PDMINS_2_DATA(pDevIns, IOAPICState *);
371 IOAPIC_LOCK(s, VINF_IOM_HC_MMIO_READ);
372
373 STAM_COUNTER_INC(&CTXSUFF(s->StatMMIORead));
374 switch (cb) {
375 case 1:
376 *(uint8_t *)pv = ioapic_mem_readl(s, GCPhysAddr);
377 break;
378
379 case 2:
380 *(uint16_t *)pv = ioapic_mem_readl(s, GCPhysAddr);
381 break;
382
383 case 4:
384 *(uint32_t *)pv = ioapic_mem_readl(s, GCPhysAddr);
385 break;
386
387 default:
388 AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */
389 IOAPIC_UNLOCK(s);
390 return VERR_INTERNAL_ERROR;
391 }
392 IOAPIC_UNLOCK(s);
393 return VINF_SUCCESS;
394}
395
396PDMBOTHCBDECL(int) ioapicMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb)
397{
398 IOAPICState *s = PDMINS_2_DATA(pDevIns, IOAPICState *);
399
400 STAM_COUNTER_INC(&CTXSUFF(s->StatMMIOWrite));
401 IOAPIC_LOCK(s, VINF_IOM_HC_MMIO_WRITE);
402 switch (cb)
403 {
404 case 1: ioapic_mem_writel(s, GCPhysAddr, *(uint8_t const *)pv); break;
405 case 2: ioapic_mem_writel(s, GCPhysAddr, *(uint16_t const *)pv); break;
406 case 4: ioapic_mem_writel(s, GCPhysAddr, *(uint32_t const *)pv); break;
407
408 default:
409 IOAPIC_UNLOCK(s);
410 AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */
411 return VERR_INTERNAL_ERROR;
412 }
413 IOAPIC_UNLOCK(s);
414 return VINF_SUCCESS;
415}
416
417PDMBOTHCBDECL(void) ioapicSetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel)
418{
419 /* PDM lock is taken here; @todo add assertion */
420 IOAPICState *pThis = PDMINS_2_DATA(pDevIns, IOAPICState *);
421 STAM_COUNTER_INC(&pThis->CTXSUFF(StatSetIrq));
422 LogFlow(("ioapicSetIrq: iIrq=%d iLevel=%d\n", iIrq, iLevel));
423 ioapic_set_irq(pThis, iIrq, iLevel);
424}
425
426PDMBOTHCBDECL(void) ioapicSendMsi(PPDMDEVINS pDevIns, RTGCPHYS GCAddr, uint32_t uValue)
427{
428 IOAPICState *pThis = PDMINS_2_DATA(pDevIns, IOAPICState *);
429
430 LogFlow(("ioapicSendMsi: Address=%p uValue=%\n", GCAddr, uValue));
431
432 uint8_t dest = (GCAddr & VBOX_MSI_ADDR_DEST_ID_MASK) >> VBOX_MSI_ADDR_DEST_ID_SHIFT;
433 uint8_t vector_num = (uValue & VBOX_MSI_DATA_VECTOR_MASK) >> VBOX_MSI_DATA_VECTOR_SHIFT;
434 uint8_t dest_mode = (GCAddr >> VBOX_MSI_ADDR_DEST_MODE_SHIFT) & 0x1;
435 uint8_t trigger_mode = (uValue >> VBOX_MSI_DATA_TRIGGER_SHIFT) & 0x1;
436 uint8_t delivery_mode = (uValue >> VBOX_MSI_DATA_DELIVERY_MODE_SHIFT) & 0x7;
437 /**
438 * This bit indicates whether the message should be directed to the
439 * processor with the lowest interrupt priority among
440 * processors that can receive the interrupt, ignored ATM.
441 */
442 uint8_t redir_hint = (GCAddr >> VBOX_MSI_ADDR_REDIRECTION_SHIFT) & 0x1;
443
444 int rc = pThis->CTX_SUFF(pIoApicHlp)->pfnApicBusDeliver(pDevIns,
445 dest,
446 dest_mode,
447 delivery_mode,
448 vector_num,
449 0 /* polarity, n/a */,
450 trigger_mode);
451 /* We must be sure that attempts to reschedule in R3
452 never get here */
453 Assert(rc == VINF_SUCCESS);
454}
455
456#ifdef IN_RING3
457
458/**
459 * Info handler, device version. Dumps I/O APIC state.
460 *
461 * @param pDevIns Device instance which registered the info.
462 * @param pHlp Callback functions for doing output.
463 * @param pszArgs Argument string. Optional and specific to the handler.
464 */
465static DECLCALLBACK(void) ioapicInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
466{
467 IOAPICState *s = PDMINS_2_DATA(pDevIns, IOAPICState *);
468 uint32_t val;
469 unsigned i;
470 unsigned max_redir;
471
472 pHlp->pfnPrintf(pHlp, "I/O APIC at %08X:\n", 0xfec00000);
473 val = s->id << 24; /* Would be nice to call ioapic_mem_readl() directly, but that's not so simple. */
474 pHlp->pfnPrintf(pHlp, " IOAPICID : %08X\n", val);
475 pHlp->pfnPrintf(pHlp, " APIC ID = %02X\n", (val >> 24) & 0xff);
476 val = 0x11 | ((IOAPIC_NUM_PINS - 1) << 16);
477 max_redir = (val >> 16) & 0xff;
478 pHlp->pfnPrintf(pHlp, " IOAPICVER : %08X\n", val);
479 pHlp->pfnPrintf(pHlp, " version = %02X\n", val & 0xff);
480 pHlp->pfnPrintf(pHlp, " redirs = %d\n", ((val >> 16) & 0xff) + 1);
481 val = 0;
482 pHlp->pfnPrintf(pHlp, " IOAPICARB : %08X\n", val);
483 pHlp->pfnPrintf(pHlp, " arb ID = %02X\n", (val >> 24) & 0xff);
484 Assert(sizeof(s->ioredtbl) / sizeof(s->ioredtbl[0]) > max_redir);
485 pHlp->pfnPrintf(pHlp, "I/O redirection table\n");
486 pHlp->pfnPrintf(pHlp, " idx dst_mode dst_addr mask trigger rirr polarity dlvr_st dlvr_mode vector\n");
487 for (i = 0; i <= max_redir; ++i)
488 {
489 static const char *dmodes[] = { "Fixed ", "LowPri", "SMI ", "Resrvd",
490 "NMI ", "INIT ", "Resrvd", "ExtINT" };
491
492 pHlp->pfnPrintf(pHlp, " %02d %s %02X %d %s %d %s %s %s %3d (%016llX)\n",
493 i,
494 s->ioredtbl[i] & (1 << 11) ? "log " : "phys", /* dest mode */
495 (int)(s->ioredtbl[i] >> 56), /* dest addr */
496 (int)(s->ioredtbl[i] >> 16) & 1, /* mask */
497 s->ioredtbl[i] & (1 << 15) ? "level" : "edge ", /* trigger */
498 (int)(s->ioredtbl[i] >> 14) & 1, /* remote IRR */
499 s->ioredtbl[i] & (1 << 13) ? "activelo" : "activehi", /* polarity */
500 s->ioredtbl[i] & (1 << 12) ? "pend" : "idle", /* delivery status */
501 dmodes[(s->ioredtbl[i] >> 8) & 0x07], /* delivery mode */
502 (int)s->ioredtbl[i] & 0xff, /* vector */
503 s->ioredtbl[i] /* entire register */
504 );
505 }
506}
507
508/**
509 * @copydoc FNSSMDEVSAVEEXEC
510 */
511static DECLCALLBACK(int) ioapicSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
512{
513 IOAPICState *s = PDMINS_2_DATA(pDevIns, IOAPICState *);
514 ioapic_save(pSSM, s);
515 return VINF_SUCCESS;
516}
517
518/**
519 * @copydoc FNSSMDEVLOADEXEC
520 */
521static DECLCALLBACK(int) ioapicLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
522{
523 IOAPICState *s = PDMINS_2_DATA(pDevIns, IOAPICState *);
524
525 if (ioapic_load(pSSM, s, uVersion)) {
526 AssertFailed();
527 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
528 }
529 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
530
531 return VINF_SUCCESS;
532}
533
534/**
535 * @copydoc FNPDMDEVRESET
536 */
537static DECLCALLBACK(void) ioapicReset(PPDMDEVINS pDevIns)
538{
539 IOAPICState *s = PDMINS_2_DATA(pDevIns, IOAPICState *);
540 s->pIoApicHlpR3->pfnLock(pDevIns, VERR_INTERNAL_ERROR);
541 ioapic_reset(s);
542 IOAPIC_UNLOCK(s);
543}
544
545/**
546 * @copydoc FNPDMDEVRELOCATE
547 */
548static DECLCALLBACK(void) ioapicRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
549{
550 IOAPICState *s = PDMINS_2_DATA(pDevIns, IOAPICState *);
551 s->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
552 s->pIoApicHlpRC = s->pIoApicHlpR3->pfnGetRCHelpers(pDevIns);
553}
554
555/**
556 * @copydoc FNPDMDEVCONSTRUCT
557 */
558static DECLCALLBACK(int) ioapicConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
559{
560 IOAPICState *s = PDMINS_2_DATA(pDevIns, IOAPICState *);
561 PDMIOAPICREG IoApicReg;
562 bool fGCEnabled;
563 bool fR0Enabled;
564 int rc;
565 uint32_t cCpus;
566
567 Assert(iInstance == 0);
568
569 /*
570 * Validate and read the configuration.
571 */
572 if (!CFGMR3AreValuesValid(pCfg,
573 "GCEnabled\0"
574 "R0Enabled\0"
575 "NumCPUs\0"))
576 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
577
578 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fGCEnabled, true);
579 if (RT_FAILURE(rc))
580 return PDMDEV_SET_ERROR(pDevIns, rc,
581 N_("Configuration error: Failed to query boolean value \"GCEnabled\""));
582
583 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
584 if (RT_FAILURE(rc))
585 return PDMDEV_SET_ERROR(pDevIns, rc,
586 N_("Configuration error: Failed to query boolean value \"R0Enabled\""));
587
588 rc = CFGMR3QueryU32Def(pCfg, "NumCPUs", &cCpus, 1);
589 if (RT_FAILURE(rc))
590 return PDMDEV_SET_ERROR(pDevIns, rc,
591 N_("Configuration error: Failed to query integer value \"NumCPUs\""));
592
593 Log(("IOAPIC: fR0Enabled=%RTbool fGCEnabled=%RTbool\n", fR0Enabled, fGCEnabled));
594
595 /*
596 * Initialize the state data.
597 */
598
599 s->pDevInsR3 = pDevIns;
600 s->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
601 s->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
602 ioapic_reset(s);
603 s->id = cCpus;
604
605 /*
606 * Register the IOAPIC and get helpers.
607 */
608 IoApicReg.u32Version = PDM_IOAPICREG_VERSION;
609 IoApicReg.pfnSetIrqR3 = ioapicSetIrq;
610 IoApicReg.pszSetIrqRC = fGCEnabled ? "ioapicSetIrq" : NULL;
611 IoApicReg.pszSetIrqR0 = fR0Enabled ? "ioapicSetIrq" : NULL;
612 IoApicReg.pfnSendMsiR3 = ioapicSendMsi;
613 IoApicReg.pszSendMsiRC = fGCEnabled ? "ioapicSendMsi" : NULL;
614 IoApicReg.pszSendMsiR0 = fR0Enabled ? "ioapicSendMsi" : NULL;
615
616 rc = PDMDevHlpIOAPICRegister(pDevIns, &IoApicReg, &s->pIoApicHlpR3);
617 if (RT_FAILURE(rc))
618 {
619 AssertMsgFailed(("IOAPICRegister -> %Rrc\n", rc));
620 return rc;
621 }
622
623 /*
624 * Register MMIO callbacks and saved state.
625 */
626 rc = PDMDevHlpMMIORegister(pDevIns, 0xfec00000, 0x1000, s,
627 ioapicMMIOWrite, ioapicMMIORead, NULL, "I/O APIC Memory");
628 if (RT_FAILURE(rc))
629 return rc;
630
631 if (fGCEnabled) {
632 s->pIoApicHlpRC = s->pIoApicHlpR3->pfnGetRCHelpers(pDevIns);
633
634 rc = PDMDevHlpMMIORegisterRC(pDevIns, 0xfec00000, 0x1000, 0,
635 "ioapicMMIOWrite", "ioapicMMIORead", NULL);
636 if (RT_FAILURE(rc))
637 return rc;
638 }
639
640 if (fR0Enabled) {
641 s->pIoApicHlpR0 = s->pIoApicHlpR3->pfnGetR0Helpers(pDevIns);
642
643 rc = PDMDevHlpMMIORegisterR0(pDevIns, 0xfec00000, 0x1000, 0,
644 "ioapicMMIOWrite", "ioapicMMIORead", NULL);
645 if (RT_FAILURE(rc))
646 return rc;
647 }
648
649 rc = PDMDevHlpSSMRegister(pDevIns, 1 /* version */, sizeof(*s), ioapicSaveExec, ioapicLoadExec);
650 if (RT_FAILURE(rc))
651 return rc;
652
653 /*
654 * Register debugger info callback.
655 */
656 PDMDevHlpDBGFInfoRegister(pDevIns, "ioapic", "Display I/O APIC state.", ioapicInfo);
657
658#ifdef VBOX_WITH_STATISTICS
659 /*
660 * Statistics.
661 */
662 PDMDevHlpSTAMRegister(pDevIns, &s->StatMMIOReadGC, STAMTYPE_COUNTER, "/Devices/IOAPIC/MMIOReadGC", STAMUNIT_OCCURENCES, "Number of IOAPIC MMIO reads in GC.");
663 PDMDevHlpSTAMRegister(pDevIns, &s->StatMMIOReadHC, STAMTYPE_COUNTER, "/Devices/IOAPIC/MMIOReadHC", STAMUNIT_OCCURENCES, "Number of IOAPIC MMIO reads in HC.");
664 PDMDevHlpSTAMRegister(pDevIns, &s->StatMMIOWriteGC, STAMTYPE_COUNTER, "/Devices/IOAPIC/MMIOWriteGC", STAMUNIT_OCCURENCES, "Number of IOAPIC MMIO writes in GC.");
665 PDMDevHlpSTAMRegister(pDevIns, &s->StatMMIOWriteHC, STAMTYPE_COUNTER, "/Devices/IOAPIC/MMIOWriteHC", STAMUNIT_OCCURENCES, "Number of IOAPIC MMIO writes in HC.");
666 PDMDevHlpSTAMRegister(pDevIns, &s->StatSetIrqGC, STAMTYPE_COUNTER, "/Devices/IOAPIC/SetIrqGC", STAMUNIT_OCCURENCES, "Number of IOAPIC SetIrq calls in GC.");
667 PDMDevHlpSTAMRegister(pDevIns, &s->StatSetIrqHC, STAMTYPE_COUNTER, "/Devices/IOAPIC/SetIrqHC", STAMUNIT_OCCURENCES, "Number of IOAPIC SetIrq calls in HC.");
668#endif
669
670 return VINF_SUCCESS;
671}
672
673/**
674 * IO APIC device registration structure.
675 */
676const PDMDEVREG g_DeviceIOAPIC =
677{
678 /* u32Version */
679 PDM_DEVREG_VERSION,
680 /* szName */
681 "ioapic",
682 /* szRCMod */
683 "VBoxDD2GC.gc",
684 /* szR0Mod */
685 "VBoxDD2R0.r0",
686 /* pszDescription */
687 "I/O Advanced Programmable Interrupt Controller (IO-APIC) Device",
688 /* fFlags */
689 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,
690 /* fClass */
691 PDM_DEVREG_CLASS_PIC,
692 /* cMaxInstances */
693 1,
694 /* cbInstance */
695 sizeof(IOAPICState),
696 /* pfnConstruct */
697 ioapicConstruct,
698 /* pfnDestruct */
699 NULL,
700 /* pfnRelocate */
701 ioapicRelocate,
702 /* pfnIOCtl */
703 NULL,
704 /* pfnPowerOn */
705 NULL,
706 /* pfnReset */
707 ioapicReset,
708 /* pfnSuspend */
709 NULL,
710 /* pfnResume */
711 NULL,
712 /* pfnAttach */
713 NULL,
714 /* pfnDetach */
715 NULL,
716 /* pfnQueryInterface. */
717 NULL,
718 /* pfnInitComplete */
719 NULL,
720 /* pfnPowerOff */
721 NULL,
722 /* pfnSoftReset */
723 NULL,
724 /* u32VersionEnd */
725 PDM_DEVREG_VERSION
726};
727
728#endif /* IN_RING3 */
729#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
Note: See TracBrowser for help on using the repository browser.

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