VirtualBox

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

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

header (C) fixes

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