VirtualBox

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

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

Working on tracking IRQs for tracing and logging purposes.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use