VirtualBox

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

Last change on this file since 40754 was 40280, checked in by vboxsync, 12 years ago

Corrected a bunch of HC and GC uses in status codes.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use