VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/DevIOAPIC_New.cpp@ 62162

Last change on this file since 62162 was 62162, checked in by vboxsync, 9 years ago

VMM, IOAPIC: Temporarily enable using the PDM lock instead of the dedicated I/O APIC lock.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 54.0 KB
Line 
1/* $Id: DevIOAPIC_New.cpp 62162 2016-07-11 15:03:44Z vboxsync $ */
2/** @file
3 * IO APIC - Input/Output Advanced Programmable Interrupt Controller.
4 */
5
6/*
7 * Copyright (C) 2016 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
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_DEV_IOAPIC
23#include <VBox/log.h>
24#include <VBox/vmm/hm.h>
25#include <VBox/msi.h>
26#include <VBox/vmm/pdmdev.h>
27
28#include "VBoxDD.h"
29#include <iprt/x86.h>
30
31
32/*********************************************************************************************************************************
33* Defined Constants And Macros *
34*********************************************************************************************************************************/
35/** The current IO APIC saved state version. */
36#define IOAPIC_SAVED_STATE_VERSION 2
37/** The saved state version used by VirtualBox 5.0 and
38 * earlier. */
39#define IOAPIC_SAVED_STATE_VERSION_VBOX_50 1
40
41/** Implementation specified by the "Intel I/O Controller Hub 9
42 * (ICH9) Family" */
43#define IOAPIC_HARDWARE_VERSION_ICH9 1
44/** Implementation specified by the "82093AA I/O Advanced Programmable Interrupt
45Controller" */
46#define IOAPIC_HARDWARE_VERSION_82093AA 2
47/** The IO APIC implementation to use. */
48#define IOAPIC_HARDWARE_VERSION IOAPIC_HARDWARE_VERSION_ICH9
49
50#if IOAPIC_HARDWARE_VERSION == IOAPIC_HARDWARE_VERSION_82093AA
51/** The version. */
52# define IOAPIC_VERSION 0x11
53/** The ID mask. */
54# define IOAPIC_ID_MASK 0x0f
55#elif IOAPIC_HARDWARE_VERSION == IOAPIC_HARDWARE_VERSION_ICH9
56/** The version. */
57# define IOAPIC_VERSION 0x20
58/** The ID mask. */
59# define IOAPIC_ID_MASK 0xff
60#else
61# error "Implement me"
62#endif
63
64/** The default MMIO base physical address. */
65#define IOAPIC_MMIO_BASE_PHYSADDR UINT64_C(0xfec00000)
66/** The size of the MMIO range. */
67#define IOAPIC_MMIO_SIZE X86_PAGE_4K_SIZE
68/** The mask for getting direct registers from physical address. */
69#define IOAPIC_MMIO_REG_MASK 0xff
70
71/** The number of interrupt input pins. */
72#define IOAPIC_NUM_INTR_PINS 24
73/** Maximum redirection entires. */
74#define IOAPIC_MAX_REDIR_ENTRIES (IOAPIC_NUM_INTR_PINS - 1)
75
76/** Version register - Gets the version. */
77#define IOAPIC_VER_GET_VER(a_Reg) ((a_Reg) & 0xff)
78/** Version register - Gets the maximum redirection entry. */
79#define IOAPIC_VER_GET_MRE(a_Reg) (((a_Reg) >> 16) & 0xff)
80/** Version register - Gets whether Pin Assertion Register (PRQ) is
81 * supported. */
82#define IOAPIC_VER_HAS_PRQ(a_Reg) RT_BOOL((a_Reg) & RT_BIT_32(15))
83
84/** Index register - Valid write mask. */
85#define IOAPIC_INDEX_VALID_WRITE_MASK UINT32_C(0xff)
86
87/** Arbitration register - Gets the ID. */
88#define IOAPIC_ARB_GET_ID(a_Reg) ((a_Reg) >> 24 & 0xf)
89
90/** ID register - Gets the ID. */
91#define IOAPIC_ID_GET_ID(a_Reg) ((a_Reg) >> 24 & IOAPIC_ID_MASK)
92
93/** Redirection table entry - Vector. */
94#define IOAPIC_RTE_VECTOR UINT64_C(0xff)
95/** Redirection table entry - Delivery mode. */
96#define IOAPIC_RTE_DELIVERY_MODE (RT_BIT_64(8) | RT_BIT_64(9) | RT_BIT_64(10))
97/** Redirection table entry - Destination mode. */
98#define IOAPIC_RTE_DEST_MODE RT_BIT_64(11)
99/** Redirection table entry - Delivery status. */
100#define IOAPIC_RTE_DELIVERY_STATUS RT_BIT_64(12)
101/** Redirection table entry - Interrupt input pin polarity. */
102#define IOAPIC_RTE_POLARITY RT_BIT_64(13)
103/** Redirection table entry - Remote IRR. */
104#define IOAPIC_RTE_REMOTE_IRR RT_BIT_64(14)
105/** Redirection table entry - Trigger Mode. */
106#define IOAPIC_RTE_TRIGGER_MODE RT_BIT_64(15)
107/** Redirection table entry - the mask bit number. */
108#define IOAPIC_RTE_MASK_BIT 16
109/** Redirection table entry - the mask. */
110#define IOAPIC_RTE_MASK RT_BIT_64(IOAPIC_RTE_MASK_BIT)
111/** Redirection table entry - Extended Destination ID. */
112#define IOAPIC_RTE_EXT_DEST_ID UINT64_C(0x00ff000000000000)
113/** Redirection table entry - Destination. */
114#define IOAPIC_RTE_DEST UINT64_C(0xff00000000000000)
115
116/** Redirection table entry - Gets the destination. */
117#define IOAPIC_RTE_GET_DEST(a_Reg) ((a_Reg) >> 56 & 0xff)
118/** Redirection table entry - Gets the mask flag. */
119#define IOAPIC_RTE_GET_MASK(a_Reg) (((a_Reg) >> IOAPIC_RTE_MASK_BIT) & 0x1)
120/** Redirection table entry - Checks whether it's masked. */
121#define IOAPIC_RTE_IS_MASKED(a_Reg) ((a_Reg) & IOAPIC_RTE_MASK)
122/** Redirection table entry - Gets the trigger mode. */
123#define IOAPIC_RTE_GET_TRIGGER_MODE(a_Reg) (((a_Reg) >> 15) & 0x1)
124/** Redirection table entry - Gets the remote IRR flag. */
125#define IOAPIC_RTE_GET_REMOTE_IRR(a_Reg) (((a_Reg) >> 14) & 0x1)
126/** Redirection table entry - Gets the interrupt pin polarity. */
127#define IOAPIC_RTE_GET_POLARITY(a_Reg) (((a_Reg) >> 13) & 0x1)
128/** Redirection table entry - Gets the delivery status. */
129#define IOAPIC_RTE_GET_DELIVERY_STATUS(a_Reg) (((a_Reg) >> 12) & 0x1)
130/** Redirection table entry - Gets the destination mode. */
131#define IOAPIC_RTE_GET_DEST_MODE(a_Reg) (((a_Reg) >> 11) & 0x1)
132/** Redirection table entry - Gets the delivery mode. */
133#define IOAPIC_RTE_GET_DELIVERY_MODE(a_Reg) (((a_Reg) >> 8) & 0x7)
134/** Redirection table entry - Gets the vector. */
135#define IOAPIC_RTE_GET_VECTOR(a_Reg) ((a_Reg) & IOAPIC_RTE_VECTOR)
136/** Redirection table entry - Valid write mask. */
137#define IOAPIC_RTE_VALID_WRITE_MASK ( IOAPIC_RTE_DEST | IOAPIC_RTE_MASK | IOAPIC_RTE_TRIGGER_MODE \
138 | IOAPIC_RTE_POLARITY | IOAPIC_RTE_DEST_MODE | IOAPIC_RTE_DELIVERY_MODE \
139 | IOAPIC_RTE_VECTOR)
140
141#if IOAPIC_HARDWARE_VERSION == IOAPIC_HARDWARE_VERSION_82093AA
142/** Redirection table entry - Valid read mask. */
143# define IOAPIC_RTE_VALID_READ_MASK ( IOAPIC_RTE_DEST | IOAPIC_RTE_MASK | IOAPIC_RTE_TRIGGER_MODE \
144 | IOAPIC_RTE_REMOTE_IRR | IOAPIC_RTE_POLARITY | IOAPIC_RTE_DELIVERY_STATUS \
145 | IOAPIC_RTE_DEST_MODE | IOAPIC_RTE_DELIVERY_MODE | IOAPIC_RTE_VECTOR)
146#elif IOAPIC_HARDWARE_VERSION == IOAPIC_HARDWARE_VERSION_ICH9
147/** Redirection table entry - Valid read mask. */
148# define IOAPIC_RTE_VALID_READ_MASK ( IOAPIC_RTE_DEST | IOAPIC_RTE_EXT_DEST_ID | IOAPIC_RTE_MASK \
149 | IOAPIC_RTE_TRIGGER_MODE | IOAPIC_RTE_REMOTE_IRR | IOAPIC_RTE_POLARITY \
150 | IOAPIC_RTE_DELIVERY_STATUS | IOAPIC_RTE_DEST_MODE | IOAPIC_RTE_DELIVERY_MODE \
151 | IOAPIC_RTE_VECTOR)
152#endif
153/** Redirection table entry - Trigger mode edge. */
154#define IOAPIC_RTE_TRIGGER_MODE_EDGE 0
155/** Redirection table entry - Trigger mode level. */
156#define IOAPIC_RTE_TRIGGER_MODE_LEVEL 1
157/** Redirection table entry - Destination mode physical. */
158#define IOAPIC_RTE_DEST_MODE_PHYSICAL 0
159/** Redirection table entry - Destination mode logical. */
160#define IOAPIC_RTE_DEST_MODE_LOGICAL 1
161
162
163/** Index of indirect registers in the I/O APIC register table. */
164#define IOAPIC_INDIRECT_INDEX_ID 0x0
165#define IOAPIC_INDIRECT_INDEX_VERSION 0x1
166#if IOAPIC_HARDWARE_VERSION == IOAPIC_HARDWARE_VERSION_82093AA
167# define IOAPIC_INDIRECT_INDEX_ARB 0x2
168#endif
169#define IOAPIC_INDIRECT_INDEX_REDIR_TBL_START 0x10
170#define IOAPIC_INDIRECT_INDEX_REDIR_TBL_END 0x3F
171
172/** Offset of direct registers in the I/O APIC MMIO space. */
173#define IOAPIC_DIRECT_OFF_INDEX 0x00
174#define IOAPIC_DIRECT_OFF_DATA 0x10
175#if IOAPIC_HARDWARE_VERSION == IOAPIC_HARDWARE_VERSION_ICH9
176# define IOAPIC_DIRECT_OFF_EOI 0x40
177#endif
178
179#define IOAPIC_WITH_PDM_CRITSECT
180#ifdef IOAPIC_WITH_PDM_CRITSECT
181# define IOAPIC_LOCK(pThis, rcBusy) (pThis)->CTX_SUFF(pIoApicHlp)->pfnLock((pThis)->CTX_SUFF(pDevIns), (rcBusy))
182# define IOAPIC_UNLOCK(pThis) (pThis)->CTX_SUFF(pIoApicHlp)->pfnUnlock((pThis)->CTX_SUFF(pDevIns))
183#else
184# define IOAPIC_LOCK(pThis, rcBusy) PDMCritSectEnter(&(pThis)->CritSect, (rcBusy))
185# define IOAPIC_UNLOCK(pThis) PDMCritSectLeave(&(pThis)->CritSect)
186#endif
187
188
189/*********************************************************************************************************************************
190* Structures and Typedefs *
191*********************************************************************************************************************************/
192/**
193 * The per-VM I/O APIC device state.
194 */
195typedef struct IOAPIC
196{
197 /** The device instance - R3 Ptr. */
198 PPDMDEVINSR3 pDevInsR3;
199 /** The IOAPIC helpers - R3 Ptr. */
200 PCPDMIOAPICHLPR3 pIoApicHlpR3;
201
202 /** The device instance - R0 Ptr. */
203 PPDMDEVINSR0 pDevInsR0;
204 /** The IOAPIC helpers - R0 Ptr. */
205 PCPDMIOAPICHLPR0 pIoApicHlpR0;
206
207 /** The device instance - RC Ptr. */
208 PPDMDEVINSRC pDevInsRC;
209 /** The IOAPIC helpers - RC Ptr. */
210 PCPDMIOAPICHLPRC pIoApicHlpRC;
211
212 /** The ID register. */
213 uint8_t volatile u8Id;
214 /** The index register. */
215 uint8_t volatile u8Index;
216 /** Number of CPUs. */
217 uint8_t cCpus;
218 /* Alignment padding. */
219 uint8_t u8Padding0[5];
220
221 /** The redirection table registers. */
222 uint64_t au64RedirTable[IOAPIC_NUM_INTR_PINS];
223 /** The IRQ tags and source IDs for each pin (tracing purposes). */
224 uint32_t au32TagSrc[IOAPIC_NUM_INTR_PINS];
225
226 /** Alignment padding. */
227 uint32_t u32Padding2;
228 /** The internal IRR reflecting state of the interrupt lines. */
229 uint32_t uIrr;
230
231#ifndef IOAPIC_WITH_PDM_CRITSECT
232 /** The critsect for updating to the RTEs. */
233 PDMCRITSECT CritSect;
234#endif
235
236#ifdef VBOX_WITH_STATISTICS
237 /** Number of MMIO reads in RZ. */
238 STAMCOUNTER StatMmioReadRZ;
239 /** Number of MMIO reads in R3. */
240 STAMCOUNTER StatMmioReadR3;
241
242 /** Number of MMIO writes in RZ. */
243 STAMCOUNTER StatMmioWriteRZ;
244 /** Number of MMIO writes in R3. */
245 STAMCOUNTER StatMmioWriteR3;
246
247 /** Number of SetIrq calls in RZ. */
248 STAMCOUNTER StatSetIrqRZ;
249 /** Number of SetIrq calls in R3. */
250 STAMCOUNTER StatSetIrqR3;
251
252 /** Number of SetEoi calls in RZ. */
253 STAMCOUNTER StatSetEoiRZ;
254 /** Number of SetEoi calls in R3. */
255 STAMCOUNTER StatSetEoiR3;
256
257 /** Number of redundant edge-triggered interrupts. */
258 STAMCOUNTER StatRedundantEdgeIntr;
259 /** Number of redundant level-triggered interrupts. */
260 STAMCOUNTER StatRedundantLevelIntr;
261 /** Number of suppressed level-triggered interrupts (by remote IRR). */
262 STAMCOUNTER StatSuppressedLevelIntr;
263 /** Number of returns to ring-3 due to EOI broadcast lock contention. */
264 STAMCOUNTER StatEoiContention;
265 /** Number of returns to ring-3 due to Set RTE lock contention. */
266 STAMCOUNTER StatSetRteContention;
267 /** Number of level-triggered interrupts dispatched to the local APIC(s). */
268 STAMCOUNTER StatLevelIrqSent;
269 /** Number of EOIs received for level-triggered interrupts from the local
270 * APIC(s). */
271 STAMCOUNTER StatEoiReceived;
272#endif
273} IOAPIC;
274/** Pointer to IOAPIC data. */
275typedef IOAPIC *PIOAPIC;
276/** Pointer to a const IOAPIC data. */
277typedef IOAPIC const *PCIOAPIC;
278AssertCompileMemberAlignment(IOAPIC, au64RedirTable, 8);
279
280#ifndef VBOX_DEVICE_STRUCT_TESTCASE
281
282#if IOAPIC_HARDWARE_VERSION == IOAPIC_HARDWARE_VERSION_82093AA
283/**
284 * Gets the arbitration register.
285 *
286 * @returns The arbitration.
287 */
288DECLINLINE(uint32_t) ioapicGetArb(void)
289{
290 Log2(("IOAPIC: ioapicGetArb: returns 0\n"));
291 return 0;
292}
293#endif
294
295
296/**
297 * Gets the version register.
298 *
299 * @returns The version.
300 */
301DECLINLINE(uint32_t) ioapicGetVersion(void)
302{
303 uint32_t uValue = RT_MAKE_U32(IOAPIC_VERSION, IOAPIC_MAX_REDIR_ENTRIES);
304 Log2(("IOAPIC: ioapicGetVersion: returns %#RX32\n", uValue));
305 return uValue;
306}
307
308
309/**
310 * Sets the ID register.
311 *
312 * @param pThis Pointer to the IOAPIC instance.
313 * @param uValue The value to set.
314 */
315DECLINLINE(void) ioapicSetId(PIOAPIC pThis, uint32_t uValue)
316{
317 Log2(("IOAPIC: ioapicSetId: uValue=%#RX32\n", uValue));
318 ASMAtomicWriteU8(&pThis->u8Id, (uValue >> 24) & IOAPIC_ID_MASK);
319}
320
321
322/**
323 * Gets the ID register.
324 *
325 * @returns The ID.
326 * @param pThis Pointer to the IOAPIC instance.
327 */
328DECLINLINE(uint32_t) ioapicGetId(PCIOAPIC pThis)
329{
330 uint32_t uValue = (uint32_t)(pThis->u8Id & IOAPIC_ID_MASK) << 24;
331 Log2(("IOAPIC: ioapicGetId: returns %#RX32\n", uValue));
332 return uValue;
333}
334
335
336/**
337 * Sets the index register.
338 *
339 * @param pThis Pointer to the IOAPIC instance.
340 * @param uValue The value to set.
341 */
342DECLINLINE(void) ioapicSetIndex(PIOAPIC pThis, uint32_t uValue)
343{
344 LogFlow(("IOAPIC: ioapicSetIndex: uValue=%#RX32\n", uValue));
345 ASMAtomicWriteU8(&pThis->u8Index, uValue & IOAPIC_INDEX_VALID_WRITE_MASK);
346}
347
348
349/**
350 * Gets the index register.
351 *
352 * @returns The index value.
353 */
354DECLINLINE(uint32_t) ioapicGetIndex(PCIOAPIC pThis)
355{
356 uint32_t const uValue = pThis->u8Index;
357 LogFlow(("IOAPIC: ioapicGetIndex: returns %#x\n", uValue));
358 return uValue;
359}
360
361
362/**
363 * Signals the next pending interrupt for the specified Redirection Table Entry
364 * (RTE).
365 *
366 * @param pThis The IOAPIC instance.
367 * @param idxRte The index of the RTE.
368 *
369 * @remarks It is the responsibility of the caller to verify that an interrupt is
370 * pending for the pin corresponding to the RTE before calling this
371 * function.
372 */
373static void ioapicSignalIntrForRte(PIOAPIC pThis, uint8_t idxRte)
374{
375#ifndef IOAPIC_WITH_PDM_CRITSECT
376 Assert(PDMCritSectIsOwner(&pThis->CritSect));
377#endif
378
379 /* Ensure the RTE isn't masked. */
380 uint64_t const u64Rte = pThis->au64RedirTable[idxRte];
381 if (!IOAPIC_RTE_IS_MASKED(u64Rte))
382 {
383 /* We cannot accept another level-triggered interrupt until remote IRR has been cleared. */
384 uint8_t const u8TriggerMode = IOAPIC_RTE_GET_TRIGGER_MODE(u64Rte);
385 if (u8TriggerMode == IOAPIC_RTE_TRIGGER_MODE_LEVEL)
386 {
387 uint8_t const u8RemoteIrr = IOAPIC_RTE_GET_REMOTE_IRR(u64Rte);
388 if (u8RemoteIrr)
389 {
390 STAM_COUNTER_INC(&pThis->StatSuppressedLevelIntr);
391 return;
392 }
393 }
394
395 uint8_t const u8Vector = IOAPIC_RTE_GET_VECTOR(u64Rte);
396 uint8_t const u8DeliveryMode = IOAPIC_RTE_GET_DELIVERY_MODE(u64Rte);
397 uint8_t const u8DestMode = IOAPIC_RTE_GET_DEST_MODE(u64Rte);
398 uint8_t const u8Polarity = IOAPIC_RTE_GET_POLARITY(u64Rte);
399 uint8_t const u8Dest = IOAPIC_RTE_GET_DEST(u64Rte);
400 uint32_t const u32TagSrc = pThis->au32TagSrc[idxRte];
401
402 Log2(("IOAPIC: Signaling %s-triggered interrupt. Dest=%#x DestMode=%s Vector=%#x (%u)",
403 u8TriggerMode == IOAPIC_RTE_TRIGGER_MODE_EDGE ? "edge" : "level", u8Dest,
404 u8DestMode == IOAPIC_RTE_DEST_MODE_PHYSICAL ? "physical" : "logical", u8Vector, u8Vector));
405
406 /*
407 * Deliver to the local APIC via the system/3-wire-APIC bus.
408 */
409 int rc = pThis->CTX_SUFF(pIoApicHlp)->pfnApicBusDeliver(pThis->CTX_SUFF(pDevIns),
410 u8Dest,
411 u8DestMode,
412 u8DeliveryMode,
413 u8Vector,
414 u8Polarity,
415 u8TriggerMode,
416 u32TagSrc);
417 /* Can't reschedule to R3. */
418 Assert(rc == VINF_SUCCESS || rc == VERR_APIC_INTR_DISCARDED);
419#ifdef DEBUG_ramshankar
420 if (rc == VERR_APIC_INTR_DISCARDED)
421 AssertMsgFailed(("APIC: Interrupt discarded u8Vector=%#x (%u) u64Rte=%#RX64\n", u8Vector, u8Vector, u64Rte));
422#endif
423
424 /*
425 * For level-triggered interrupts, we set the remote IRR bit to indicate
426 * the local APIC has accepted the interrupt.
427 *
428 * For edge-triggered interrupts, we should not clear the IRR bit as it
429 * should remain intact to reflect the state of the interrupt line.
430 * The device will explicitly transition to inactive state via the
431 * ioapicSetIrq() callback.
432 */
433 if ( u8TriggerMode == IOAPIC_RTE_TRIGGER_MODE_LEVEL
434 && rc == VINF_SUCCESS)
435 {
436 Assert(u8TriggerMode == IOAPIC_RTE_TRIGGER_MODE_LEVEL);
437 pThis->au64RedirTable[idxRte] |= IOAPIC_RTE_REMOTE_IRR;
438 STAM_COUNTER_INC(&pThis->StatLevelIrqSent);
439 }
440 }
441}
442
443
444/**
445 * Gets the redirection table entry.
446 *
447 * @returns The redirection table entry.
448 * @param pThis Pointer to the IOAPIC instance.
449 * @param uIndex The index value.
450 */
451DECLINLINE(uint32_t) ioapicGetRedirTableEntry(PCIOAPIC pThis, uint32_t uIndex)
452{
453 uint8_t const idxRte = (uIndex - IOAPIC_INDIRECT_INDEX_REDIR_TBL_START) >> 1;
454 uint32_t uValue;
455 if (!(uIndex & 1))
456 uValue = RT_LO_U32(pThis->au64RedirTable[idxRte]) & RT_LO_U32(IOAPIC_RTE_VALID_READ_MASK);
457 else
458 uValue = RT_HI_U32(pThis->au64RedirTable[idxRte]) & RT_HI_U32(IOAPIC_RTE_VALID_READ_MASK);
459
460 LogFlow(("IOAPIC: ioapicGetRedirTableEntry: uIndex=%#RX32 idxRte=%u returns %#RX32\n", uIndex, idxRte, uValue));
461 return uValue;
462}
463
464
465/**
466 * Sets the redirection table entry.
467 *
468 * @param pThis Pointer to the IOAPIC instance.
469 * @param uIndex The index value.
470 * @param uValue The value to set.
471 */
472static int ioapicSetRedirTableEntry(PIOAPIC pThis, uint32_t uIndex, uint32_t uValue)
473{
474 uint8_t const idxRte = (uIndex - IOAPIC_INDIRECT_INDEX_REDIR_TBL_START) >> 1;
475 AssertMsg(idxRte < RT_ELEMENTS(pThis->au64RedirTable), ("Invalid index %u, expected <= %u\n", idxRte,
476 RT_ELEMENTS(pThis->au64RedirTable)));
477
478 int rc = IOAPIC_LOCK(pThis, VINF_IOM_R3_MMIO_WRITE);
479 if (rc == VINF_SUCCESS)
480 {
481 /*
482 * Write the low or high 32-bit value into the specified 64-bit RTE register,
483 * update only the valid, writable bits.
484 *
485 * We need to preserve the read-only bits as it can have dire consequences
486 * otherwise, see @bugref{8386#c24}.
487 */
488 uint64_t const u64Rte = pThis->au64RedirTable[idxRte];
489 if (!(uIndex & 1))
490 {
491 uint32_t const u32RtePreserveLo = RT_LO_U32(u64Rte) & ~RT_LO_U32(IOAPIC_RTE_VALID_WRITE_MASK);
492 uint32_t const u32RteNewLo = (uValue & RT_LO_U32(IOAPIC_RTE_VALID_WRITE_MASK)) | u32RtePreserveLo;
493 uint64_t const u64RteHi = u64Rte & UINT64_C(0xffffffff00000000);
494 pThis->au64RedirTable[idxRte] = u64RteHi | u32RteNewLo;
495 }
496 else
497 {
498 uint32_t const u32RtePreserveHi = RT_HI_U32(u64Rte) & ~RT_HI_U32(IOAPIC_RTE_VALID_WRITE_MASK);
499 uint32_t const u32RteLo = RT_LO_U32(u64Rte);
500 uint64_t const u64RteNewHi = ((uint64_t)((uValue & RT_HI_U32(IOAPIC_RTE_VALID_WRITE_MASK)) | u32RtePreserveHi) << 32);
501 pThis->au64RedirTable[idxRte] = u64RteNewHi | u32RteLo;
502 }
503
504 /*
505 * Signal the next pending interrupt for this RTE.
506 */
507 uint32_t const uPinMask = UINT32_C(1) << idxRte;
508 if (pThis->uIrr & uPinMask)
509 ioapicSignalIntrForRte(pThis, idxRte);
510
511 IOAPIC_UNLOCK(pThis);
512 LogFlow(("IOAPIC: ioapicSetRedirTableEntry: uIndex=%#RX32 idxRte=%u uValue=%#RX32\n", uIndex, idxRte, uValue));
513 }
514 else
515 STAM_COUNTER_INC(&pThis->StatSetRteContention);
516
517 return rc;
518}
519
520
521/**
522 * Gets the data register.
523 *
524 * @returns The data value.
525 * @param pThis Pointer to the IOAPIC instance.
526 */
527static uint32_t ioapicGetData(PCIOAPIC pThis)
528{
529 uint8_t const uIndex = pThis->u8Index;
530 if ( uIndex >= IOAPIC_INDIRECT_INDEX_REDIR_TBL_START
531 && uIndex <= IOAPIC_INDIRECT_INDEX_REDIR_TBL_END)
532 return ioapicGetRedirTableEntry(pThis, uIndex);
533
534 uint32_t uValue;
535 switch (uIndex)
536 {
537 case IOAPIC_INDIRECT_INDEX_ID:
538 uValue = ioapicGetId(pThis);
539 break;
540
541 case IOAPIC_INDIRECT_INDEX_VERSION:
542 uValue = ioapicGetVersion();
543 break;
544
545#if IOAPIC_HARDWARE_VERSION == IOAPIC_HARDWARE_VERSION_82093AA
546 case IOAPIC_INDIRECT_INDEX_ARB:
547 uValue = ioapicGetArb();
548 break;
549#endif
550
551 default:
552 uValue = UINT32_C(0xffffffff);
553 Log2(("IOAPIC: Attempt to read register at invalid index %#x\n", uIndex));
554 break;
555 }
556 return uValue;
557}
558
559
560/**
561 * Sets the data register.
562 *
563 * @param pThis Pointer to the IOAPIC instance.
564 * @param uValue The value to set.
565 */
566static int ioapicSetData(PIOAPIC pThis, uint32_t uValue)
567{
568 uint8_t const uIndex = pThis->u8Index;
569 LogFlow(("IOAPIC: ioapicSetData: uIndex=%#x uValue=%#RX32\n", uIndex, uValue));
570
571 if ( uIndex >= IOAPIC_INDIRECT_INDEX_REDIR_TBL_START
572 && uIndex <= IOAPIC_INDIRECT_INDEX_REDIR_TBL_END)
573 return ioapicSetRedirTableEntry(pThis, uIndex, uValue);
574
575 if (uIndex == IOAPIC_INDIRECT_INDEX_ID)
576 ioapicSetId(pThis, uValue);
577 else
578 Log2(("IOAPIC: ioapicSetData: Invalid index %#RX32, ignoring write request with uValue=%#RX32\n", uIndex, uValue));
579
580 return VINF_SUCCESS;
581}
582
583
584/**
585 * @interface_method_impl{PDMIOAPICREG,pfnSetEoiR3}
586 */
587PDMBOTHCBDECL(int) ioapicSetEoi(PPDMDEVINS pDevIns, uint8_t u8Vector)
588{
589 PIOAPIC pThis = PDMINS_2_DATA(pDevIns, PIOAPIC);
590 STAM_COUNTER_INC(&pThis->CTX_SUFF_Z(StatSetEoi));
591 LogFlow(("IOAPIC: ioapicSetEoi: u8Vector=%#x (%u)\n", u8Vector, u8Vector));
592
593 bool fRemoteIrrCleared = false;
594 int rc = IOAPIC_LOCK(pThis, VINF_IOM_R3_MMIO_WRITE);
595 if (rc == VINF_SUCCESS)
596 {
597 for (uint8_t idxRte = 0; idxRte < RT_ELEMENTS(pThis->au64RedirTable); idxRte++)
598 {
599 uint64_t const u64Rte = pThis->au64RedirTable[idxRte];
600 if (IOAPIC_RTE_GET_VECTOR(u64Rte) == u8Vector)
601 {
602#ifdef DEBUG_ramshankar
603 /* This assertion may trigger when restoring saved-states created using the old, incorrect I/O APIC code. */
604 Assert(IOAPIC_RTE_GET_REMOTE_IRR(u64Rte));
605#endif
606 pThis->au64RedirTable[idxRte] &= ~IOAPIC_RTE_REMOTE_IRR;
607 fRemoteIrrCleared = true;
608 STAM_COUNTER_INC(&pThis->StatEoiReceived);
609 Log2(("IOAPIC: ioapicSetEoi: Cleared remote IRR, idxRte=%u vector=%#x (%u)\n", idxRte, u8Vector, u8Vector));
610
611 /*
612 * Signal the next pending interrupt for this RTE.
613 */
614 uint32_t const uPinMask = UINT32_C(1) << idxRte;
615 if (pThis->uIrr & uPinMask)
616 ioapicSignalIntrForRte(pThis, idxRte);
617 }
618 }
619
620 IOAPIC_UNLOCK(pThis);
621 AssertMsg(fRemoteIrrCleared, ("Failed to clear remote IRR for vector %#x (%u)\n", u8Vector, u8Vector));
622 }
623 else
624 STAM_COUNTER_INC(&pThis->StatEoiContention);
625
626 return rc;
627}
628
629
630/**
631 * @interface_method_impl{PDMIOAPICREG,pfnSetIrqR3}
632 */
633PDMBOTHCBDECL(void) ioapicSetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel, uint32_t uTagSrc)
634{
635#define IOAPIC_ASSERT_IRQ(a_idxRte, a_PinMask) do { \
636 pThis->au32TagSrc[(a_idxRte)] = !pThis->au32TagSrc[(a_idxRte)] ? uTagSrc : RT_BIT_32(31); \
637 pThis->uIrr |= a_PinMask; \
638 ioapicSignalIntrForRte(pThis, (a_idxRte)); \
639 } while (0)
640
641 PIOAPIC pThis = PDMINS_2_DATA(pDevIns, PIOAPIC);
642 LogFlow(("IOAPIC: ioapicSetIrq: iIrq=%d iLevel=%d uTagSrc=%#x\n", iIrq, iLevel, uTagSrc));
643
644 STAM_COUNTER_INC(&pThis->CTX_SUFF_Z(StatSetIrq));
645
646 if (RT_LIKELY(iIrq >= 0 && iIrq < (int)RT_ELEMENTS(pThis->au64RedirTable)))
647 {
648 int rc = IOAPIC_LOCK(pThis, VINF_SUCCESS);
649 AssertRC(rc);
650
651 uint8_t const idxRte = iIrq;
652 uint32_t const uPinMask = UINT32_C(1) << idxRte;
653 uint32_t const u32RteLo = RT_LO_U32(pThis->au64RedirTable[idxRte]);
654 uint8_t const u8TriggerMode = IOAPIC_RTE_GET_TRIGGER_MODE(u32RteLo);
655
656 bool fActive = RT_BOOL(iLevel & 1);
657 /** @todo Polarity is busted elsewhere, we need to fix that
658 * first. See @bugref{8386#c7}. */
659#if 0
660 uint8_t const u8Polarity = IOAPIC_RTE_GET_POLARITY(u32RteLo);
661 fActive ^= u8Polarity; */
662#endif
663 if (!fActive)
664 {
665 pThis->uIrr &= ~uPinMask;
666 IOAPIC_UNLOCK(pThis);
667 return;
668 }
669
670 bool const fFlipFlop = ((iLevel & PDM_IRQ_LEVEL_FLIP_FLOP) == PDM_IRQ_LEVEL_FLIP_FLOP);
671 uint32_t const uPrevIrr = pThis->uIrr & uPinMask;
672 if (!fFlipFlop)
673 {
674 if (u8TriggerMode == IOAPIC_RTE_TRIGGER_MODE_EDGE)
675 {
676 /*
677 * For edge-triggered interrupts, we need to act only on a low to high edge transition.
678 * See ICH9 spec. 13.5.7 "REDIR_TBL: Redirection Table (LPC I/F-D31:F0)".
679 */
680 if (!uPrevIrr)
681 IOAPIC_ASSERT_IRQ(idxRte, uPinMask);
682 else
683 {
684 STAM_COUNTER_INC(&pThis->StatRedundantEdgeIntr);
685 Log2(("IOAPIC: Redundant edge-triggered interrupt %#x (%u)\n", idxRte, idxRte));
686 }
687 }
688 else
689 {
690 Assert(u8TriggerMode == IOAPIC_RTE_TRIGGER_MODE_LEVEL);
691
692 /*
693 * For level-triggered interrupts, redundant interrupts are not a problem
694 * and will eventually be delivered anyway after an EOI, but our PDM devices
695 * should not typically call us with no change to the level.
696 */
697 if (!uPrevIrr)
698 { /* likely */ }
699 else
700 {
701 STAM_COUNTER_INC(&pThis->StatRedundantLevelIntr);
702 Log2(("IOAPIC: Redundant level-triggered interrupt %#x (%u)\n", idxRte, idxRte));
703 }
704
705 IOAPIC_ASSERT_IRQ(idxRte, uPinMask);
706 }
707 }
708 else
709 {
710 /*
711 * The device is flip-flopping the interrupt line, which implies we should de-assert
712 * and assert the interrupt line. The interrupt line is left in the asserted state
713 * after a flip-flop request. The de-assert is a NOP wrts to signaling an interrupt
714 * hence just the assert is done.
715 */
716 IOAPIC_ASSERT_IRQ(idxRte, uPinMask);
717 }
718
719 IOAPIC_UNLOCK(pThis);
720 }
721#undef IOAPIC_ASSERT_IRQ
722}
723
724
725/**
726 * @interface_method_impl{PDMIOAPICREG,pfnSendMsiR3}
727 */
728PDMBOTHCBDECL(void) ioapicSendMsi(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, uint32_t uValue, uint32_t uTagSrc)
729{
730 PCIOAPIC pThis = PDMINS_2_DATA(pDevIns, PCIOAPIC);
731 LogFlow(("IOAPIC: ioapicSendMsi: GCPhys=%#RGp uValue=%#RX32\n", GCPhys, uValue));
732
733 /*
734 * Parse the message from the physical address.
735 * See Intel spec. 10.11.1 "Message Address Register Format".
736 */
737 uint8_t const u8DestAddr = (GCPhys & VBOX_MSI_ADDR_DEST_ID_MASK) >> VBOX_MSI_ADDR_DEST_ID_SHIFT;
738 uint8_t const u8DestMode = (GCPhys >> VBOX_MSI_ADDR_DEST_MODE_SHIFT) & 0x1;
739 /** @todo Check if we need to implement Redirection Hint Indicator. */
740 /* uint8_t const uRedirectHint = (GCPhys >> VBOX_MSI_ADDR_REDIRECTION_SHIFT) & 0x1; */
741
742 /*
743 * Parse the message data.
744 * See Intel spec. 10.11.2 "Message Data Register Format".
745 */
746 uint8_t const u8Vector = (uValue & VBOX_MSI_DATA_VECTOR_MASK) >> VBOX_MSI_DATA_VECTOR_SHIFT;
747 uint8_t const u8TriggerMode = (uValue >> VBOX_MSI_DATA_TRIGGER_SHIFT) & 0x1;
748 uint8_t const u8DeliveryMode = (uValue >> VBOX_MSI_DATA_DELIVERY_MODE_SHIFT) & 0x7;
749
750 /*
751 * Deliver to the local APIC via the system/3-wire-APIC bus.
752 */
753 int rc = pThis->CTX_SUFF(pIoApicHlp)->pfnApicBusDeliver(pDevIns,
754 u8DestAddr,
755 u8DestMode,
756 u8DeliveryMode,
757 u8Vector,
758 0 /* u8Polarity - N/A */,
759 u8TriggerMode,
760 uTagSrc);
761 /* Can't reschedule to R3. */
762 Assert(rc == VINF_SUCCESS || rc == VERR_APIC_INTR_DISCARDED);
763}
764
765
766/**
767 * @callback_method_impl{FNIOMMMIOREAD}
768 */
769PDMBOTHCBDECL(int) ioapicMmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
770{
771 PIOAPIC pThis = PDMINS_2_DATA(pDevIns, PIOAPIC);
772 STAM_COUNTER_INC(&pThis->CTX_SUFF_Z(StatMmioRead));
773
774 int rc = VINF_SUCCESS;
775 uint32_t *puValue = (uint32_t *)pv;
776 uint32_t offReg = GCPhysAddr & IOAPIC_MMIO_REG_MASK;
777 switch (offReg)
778 {
779 case IOAPIC_DIRECT_OFF_INDEX:
780 *puValue = ioapicGetIndex(pThis);
781 break;
782
783 case IOAPIC_DIRECT_OFF_DATA:
784 *puValue = ioapicGetData(pThis);
785 break;
786
787 default:
788 Log2(("IOAPIC: ioapicMmioRead: Invalid offset. GCPhysAddr=%#RGp offReg=%#x\n", GCPhysAddr, offReg));
789 rc = VINF_IOM_MMIO_UNUSED_FF;
790 break;
791 }
792
793 LogFlow(("IOAPIC: ioapicMmioRead: offReg=%#x, returns %#RX32\n", offReg, *puValue));
794 return rc;
795}
796
797
798/**
799 * @callback_method_impl{FNIOMMMIOWRITE}
800 */
801PDMBOTHCBDECL(int) ioapicMmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb)
802{
803 PIOAPIC pThis = PDMINS_2_DATA(pDevIns, PIOAPIC);
804
805 STAM_COUNTER_INC(&pThis->CTX_SUFF_Z(StatMmioWrite));
806
807 Assert(!(GCPhysAddr & 3));
808 Assert(cb == 4);
809
810 uint32_t const uValue = *(uint32_t const *)pv;
811 uint32_t const offReg = GCPhysAddr & IOAPIC_MMIO_REG_MASK;
812
813 LogFlow(("IOAPIC: ioapicMmioWrite: pThis=%p GCPhysAddr=%#RGp cb=%u uValue=%#RX32\n", pThis, GCPhysAddr, cb, uValue));
814 int rc = VINF_SUCCESS;
815 switch (offReg)
816 {
817 case IOAPIC_DIRECT_OFF_INDEX:
818 ioapicSetIndex(pThis, uValue);
819 break;
820
821 case IOAPIC_DIRECT_OFF_DATA:
822 rc = ioapicSetData(pThis, uValue);
823 break;
824
825#if IOAPIC_HARDWARE_VERSION == IOAPIC_HARDWARE_VERSION_ICH9
826 case IOAPIC_DIRECT_OFF_EOI:
827 rc = ioapicSetEoi(pDevIns, uValue);
828 break;
829#endif
830
831 default:
832 Log2(("IOAPIC: ioapicMmioWrite: Invalid offset. GCPhysAddr=%#RGp offReg=%#x\n", GCPhysAddr, offReg));
833 break;
834 }
835
836 return rc;
837}
838
839
840#ifdef IN_RING3
841/** @interface_method_impl{DBGFREGDESC,pfnGet} */
842static DECLCALLBACK(int) ioapicDbgReg_GetIndex(void *pvUser, PCDBGFREGDESC pDesc, PDBGFREGVAL pValue)
843{
844 pValue->u32 = ioapicGetIndex(PDMINS_2_DATA((PPDMDEVINS)pvUser, PCIOAPIC));
845 return VINF_SUCCESS;
846}
847
848/** @interface_method_impl{DBGFREGDESC,pfnSet} */
849static DECLCALLBACK(int) ioapicDbgReg_SetIndex(void *pvUser, PCDBGFREGDESC pDesc, PCDBGFREGVAL pValue, PCDBGFREGVAL pfMask)
850{
851 ioapicSetIndex(PDMINS_2_DATA((PPDMDEVINS)pvUser, PIOAPIC), pValue->u8);
852 return VINF_SUCCESS;
853}
854
855/** @interface_method_impl{DBGFREGDESC,pfnGet} */
856static DECLCALLBACK(int) ioapicDbgReg_GetData(void *pvUser, PCDBGFREGDESC pDesc, PDBGFREGVAL pValue)
857{
858 pValue->u32 = ioapicGetData((PDMINS_2_DATA((PPDMDEVINS)pvUser, PCIOAPIC)));
859 return VINF_SUCCESS;
860}
861
862/** @interface_method_impl{DBGFREGDESC,pfnSet} */
863static DECLCALLBACK(int) ioapicDbgReg_SetData(void *pvUser, PCDBGFREGDESC pDesc, PCDBGFREGVAL pValue, PCDBGFREGVAL pfMask)
864{
865 return ioapicSetData(PDMINS_2_DATA((PPDMDEVINS)pvUser, PIOAPIC), pValue->u32);
866}
867
868/** @interface_method_impl{DBGFREGDESC,pfnGet} */
869static DECLCALLBACK(int) ioapicDbgReg_GetVersion(void *pvUser, PCDBGFREGDESC pDesc, PDBGFREGVAL pValue)
870{
871 pValue->u32 = ioapicGetVersion();
872 return VINF_SUCCESS;
873}
874
875/** @interface_method_impl{DBGFREGDESC,pfnGet} */
876static DECLCALLBACK(int) ioapicDbgReg_GetArb(void *pvUser, PCDBGFREGDESC pDesc, PDBGFREGVAL pValue)
877{
878#if IOAPIC_HARDWARE_VERSION == IOAPIC_HARDWARE_VERSION_82093AA
879 pValue->u32 = ioapicGetArb(PDMINS_2_DATA((PPDMDEVINS)pvUser, PCIOAPIC));
880#else
881 pValue->u32 = UINT32_C(0xffffffff);
882#endif
883 return VINF_SUCCESS;
884}
885
886/** @interface_method_impl{DBGFREGDESC,pfnGet} */
887static DECLCALLBACK(int) ioapicDbgReg_GetRte(void *pvUser, PCDBGFREGDESC pDesc, PDBGFREGVAL pValue)
888{
889 PCIOAPIC pThis = PDMINS_2_DATA((PPDMDEVINS)pvUser, PCIOAPIC);
890 Assert(pDesc->offRegister < RT_ELEMENTS(pThis->au64RedirTable));
891 pValue->u64 = pThis->au64RedirTable[pDesc->offRegister];
892 return VINF_SUCCESS;
893}
894
895/** @interface_method_impl{DBGFREGDESC,pfnSet} */
896static DECLCALLBACK(int) ioapicDbgReg_SetRte(void *pvUser, PCDBGFREGDESC pDesc, PCDBGFREGVAL pValue, PCDBGFREGVAL pfMask)
897{
898 PIOAPIC pThis = PDMINS_2_DATA((PPDMDEVINS)pvUser, PIOAPIC);
899 /* No locks, no checks, just do it. */
900 Assert(pDesc->offRegister < RT_ELEMENTS(pThis->au64RedirTable));
901 pThis->au64RedirTable[pDesc->offRegister] = pValue->u64;
902 return VINF_SUCCESS;
903}
904
905/** IOREDTBLn sub fields. */
906static DBGFREGSUBFIELD const g_aRteSubs[] =
907{
908 { "vector", 0, 8, 0, 0, NULL, NULL },
909 { "dlvr_mode", 8, 3, 0, 0, NULL, NULL },
910 { "dest_mode", 11, 1, 0, 0, NULL, NULL },
911 { "dlvr_status", 12, 1, 0, DBGFREGSUBFIELD_FLAGS_READ_ONLY, NULL, NULL },
912 { "polarity", 13, 1, 0, 0, NULL, NULL },
913 { "remote_irr", 14, 1, 0, DBGFREGSUBFIELD_FLAGS_READ_ONLY, NULL, NULL },
914 { "trigger_mode", 15, 1, 0, 0, NULL, NULL },
915 { "mask", 16, 1, 0, 0, NULL, NULL },
916#if IOAPIC_HARDWARE_VERSION == IOAPIC_HARDWARE_VERSION_ICH9
917 { "ext_dest_id", 48, 8, 0, DBGFREGSUBFIELD_FLAGS_READ_ONLY, NULL, NULL },
918#endif
919 { "dest", 56, 8, 0, 0, NULL, NULL },
920 DBGFREGSUBFIELD_TERMINATOR()
921};
922
923/** Register descriptors for DBGF. */
924static DBGFREGDESC const g_aRegDesc[] =
925{
926 { "index", DBGFREG_END, DBGFREGVALTYPE_U8, 0, 0, ioapicDbgReg_GetIndex, ioapicDbgReg_SetIndex, NULL, NULL },
927 { "data", DBGFREG_END, DBGFREGVALTYPE_U32, 0, 0, ioapicDbgReg_GetData, ioapicDbgReg_SetData, NULL, NULL },
928 { "version", DBGFREG_END, DBGFREGVALTYPE_U32, DBGFREG_FLAGS_READ_ONLY, 0, ioapicDbgReg_GetVersion, NULL, NULL, NULL },
929#if IOAPIC_HARDWARE_VERSION == IOAPIC_HARDWARE_VERSION_82093AA
930 { "arb", DBGFREG_END, DBGFREGVALTYPE_U32, DBGFREG_FLAGS_READ_ONLY, 0, ioapicDbgReg_GetArb, NULL, NULL, NULL },
931#endif
932 { "rte0", DBGFREG_END, DBGFREGVALTYPE_U64, 0, 0, ioapicDbgReg_GetRte, ioapicDbgReg_SetRte, NULL, &g_aRteSubs[0] },
933 { "rte1", DBGFREG_END, DBGFREGVALTYPE_U64, 0, 1, ioapicDbgReg_GetRte, ioapicDbgReg_SetRte, NULL, &g_aRteSubs[0] },
934 { "rte2", DBGFREG_END, DBGFREGVALTYPE_U64, 0, 2, ioapicDbgReg_GetRte, ioapicDbgReg_SetRte, NULL, &g_aRteSubs[0] },
935 { "rte3", DBGFREG_END, DBGFREGVALTYPE_U64, 0, 3, ioapicDbgReg_GetRte, ioapicDbgReg_SetRte, NULL, &g_aRteSubs[0] },
936 { "rte4", DBGFREG_END, DBGFREGVALTYPE_U64, 0, 4, ioapicDbgReg_GetRte, ioapicDbgReg_SetRte, NULL, &g_aRteSubs[0] },
937 { "rte5", DBGFREG_END, DBGFREGVALTYPE_U64, 0, 5, ioapicDbgReg_GetRte, ioapicDbgReg_SetRte, NULL, &g_aRteSubs[0] },
938 { "rte6", DBGFREG_END, DBGFREGVALTYPE_U64, 0, 6, ioapicDbgReg_GetRte, ioapicDbgReg_SetRte, NULL, &g_aRteSubs[0] },
939 { "rte7", DBGFREG_END, DBGFREGVALTYPE_U64, 0, 7, ioapicDbgReg_GetRte, ioapicDbgReg_SetRte, NULL, &g_aRteSubs[0] },
940 { "rte8", DBGFREG_END, DBGFREGVALTYPE_U64, 0, 8, ioapicDbgReg_GetRte, ioapicDbgReg_SetRte, NULL, &g_aRteSubs[0] },
941 { "rte9", DBGFREG_END, DBGFREGVALTYPE_U64, 0, 9, ioapicDbgReg_GetRte, ioapicDbgReg_SetRte, NULL, &g_aRteSubs[0] },
942 { "rte10", DBGFREG_END, DBGFREGVALTYPE_U64, 0, 10, ioapicDbgReg_GetRte, ioapicDbgReg_SetRte, NULL, &g_aRteSubs[0] },
943 { "rte11", DBGFREG_END, DBGFREGVALTYPE_U64, 0, 11, ioapicDbgReg_GetRte, ioapicDbgReg_SetRte, NULL, &g_aRteSubs[0] },
944 { "rte12", DBGFREG_END, DBGFREGVALTYPE_U64, 0, 12, ioapicDbgReg_GetRte, ioapicDbgReg_SetRte, NULL, &g_aRteSubs[0] },
945 { "rte13", DBGFREG_END, DBGFREGVALTYPE_U64, 0, 13, ioapicDbgReg_GetRte, ioapicDbgReg_SetRte, NULL, &g_aRteSubs[0] },
946 { "rte14", DBGFREG_END, DBGFREGVALTYPE_U64, 0, 14, ioapicDbgReg_GetRte, ioapicDbgReg_SetRte, NULL, &g_aRteSubs[0] },
947 { "rte15", DBGFREG_END, DBGFREGVALTYPE_U64, 0, 15, ioapicDbgReg_GetRte, ioapicDbgReg_SetRte, NULL, &g_aRteSubs[0] },
948 { "rte16", DBGFREG_END, DBGFREGVALTYPE_U64, 0, 16, ioapicDbgReg_GetRte, ioapicDbgReg_SetRte, NULL, &g_aRteSubs[0] },
949 { "rte17", DBGFREG_END, DBGFREGVALTYPE_U64, 0, 17, ioapicDbgReg_GetRte, ioapicDbgReg_SetRte, NULL, &g_aRteSubs[0] },
950 { "rte18", DBGFREG_END, DBGFREGVALTYPE_U64, 0, 18, ioapicDbgReg_GetRte, ioapicDbgReg_SetRte, NULL, &g_aRteSubs[0] },
951 { "rte19", DBGFREG_END, DBGFREGVALTYPE_U64, 0, 19, ioapicDbgReg_GetRte, ioapicDbgReg_SetRte, NULL, &g_aRteSubs[0] },
952 { "rte20", DBGFREG_END, DBGFREGVALTYPE_U64, 0, 20, ioapicDbgReg_GetRte, ioapicDbgReg_SetRte, NULL, &g_aRteSubs[0] },
953 { "rte21", DBGFREG_END, DBGFREGVALTYPE_U64, 0, 21, ioapicDbgReg_GetRte, ioapicDbgReg_SetRte, NULL, &g_aRteSubs[0] },
954 { "rte22", DBGFREG_END, DBGFREGVALTYPE_U64, 0, 22, ioapicDbgReg_GetRte, ioapicDbgReg_SetRte, NULL, &g_aRteSubs[0] },
955 { "rte23", DBGFREG_END, DBGFREGVALTYPE_U64, 0, 23, ioapicDbgReg_GetRte, ioapicDbgReg_SetRte, NULL, &g_aRteSubs[0] },
956 DBGFREGDESC_TERMINATOR()
957};
958
959
960/**
961 * @callback_method_impl{FNDBGFHANDLERDEV}
962 */
963static DECLCALLBACK(void) ioapicR3DbgInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
964{
965 PCIOAPIC pThis = PDMINS_2_DATA(pDevIns, PIOAPIC);
966 LogFlow(("IOAPIC: ioapicR3DbgInfo: pThis=%p pszArgs=%s\n", pThis, pszArgs));
967
968 pHlp->pfnPrintf(pHlp, "I/O APIC at %#010x:\n", IOAPIC_MMIO_BASE_PHYSADDR);
969
970 uint32_t const uId = ioapicGetId(pThis);
971 pHlp->pfnPrintf(pHlp, " ID = %#RX32\n", uId);
972 pHlp->pfnPrintf(pHlp, " ID = %#x\n", IOAPIC_ID_GET_ID(uId));
973
974 uint32_t const uVer = ioapicGetVersion();
975 pHlp->pfnPrintf(pHlp, " Version = %#RX32\n", uVer);
976 pHlp->pfnPrintf(pHlp, " Version = %#x\n", IOAPIC_VER_GET_VER(uVer));
977 pHlp->pfnPrintf(pHlp, " Pin Assert Reg. Support = %RTbool\n", IOAPIC_VER_HAS_PRQ(uVer));
978 pHlp->pfnPrintf(pHlp, " Max. Redirection Entry = %u\n", IOAPIC_VER_GET_MRE(uVer));
979
980#if IOAPIC_HARDWARE_VERSION == IOAPIC_HARDWARE_VERSION_82093AA
981 uint32_t const uArb = ioapicGetArb();
982 pHlp->pfnPrintf(pHlp, " Arbitration = %#RX32\n", uArb);
983 pHlp->pfnPrintf(pHlp, " Arbitration ID = %#x\n", IOAPIC_ARB_GET_ID(uArb));
984#endif
985
986 pHlp->pfnPrintf(pHlp, " Current index = %#x\n", ioapicGetIndex(pThis));
987
988 pHlp->pfnPrintf(pHlp, " I/O Redirection Table and IRR:\n");
989 pHlp->pfnPrintf(pHlp, " idx dst_mode dst_addr mask irr trigger rirr polar dlvr_st dlvr_mode vector\n");
990
991 for (uint8_t idxRte = 0; idxRte < RT_ELEMENTS(pThis->au64RedirTable); idxRte++)
992 {
993 static const char * const s_apszDeliveryModes[] =
994 {
995 "Fixed ",
996 "LowPri",
997 "SMI ",
998 "Rsvd ",
999 "NMI ",
1000 "INIT ",
1001 "Rsvd ",
1002 "ExtINT"
1003 };
1004
1005 const uint64_t u64Rte = pThis->au64RedirTable[idxRte];
1006 const char *pszDestMode = IOAPIC_RTE_GET_DEST_MODE(u64Rte) == 0 ? "phys" : "log ";
1007 const uint8_t uDest = IOAPIC_RTE_GET_DEST(u64Rte);
1008 const uint8_t uMask = IOAPIC_RTE_GET_MASK(u64Rte);
1009 const char *pszTriggerMode = IOAPIC_RTE_GET_TRIGGER_MODE(u64Rte) == 0 ? "edge " : "level";
1010 const uint8_t uRemoteIrr = IOAPIC_RTE_GET_REMOTE_IRR(u64Rte);
1011 const char *pszPolarity = IOAPIC_RTE_GET_POLARITY(u64Rte) == 0 ? "acthi" : "actlo";
1012 const char *pszDeliveryStatus = IOAPIC_RTE_GET_DELIVERY_STATUS(u64Rte) == 0 ? "idle" : "pend";
1013 const uint8_t uDeliveryMode = IOAPIC_RTE_GET_DELIVERY_MODE(u64Rte);
1014 Assert(uDeliveryMode < RT_ELEMENTS(s_apszDeliveryModes));
1015 const char *pszDeliveryMode = s_apszDeliveryModes[uDeliveryMode];
1016 const uint8_t uVector = IOAPIC_RTE_GET_VECTOR(u64Rte);
1017
1018 pHlp->pfnPrintf(pHlp, " %02d %s %02x %u %u %s %u %s %s %s %3u (%016llx)\n",
1019 idxRte,
1020 pszDestMode,
1021 uDest,
1022 uMask,
1023 (pThis->uIrr >> idxRte) & 1,
1024 pszTriggerMode,
1025 uRemoteIrr,
1026 pszPolarity,
1027 pszDeliveryStatus,
1028 pszDeliveryMode,
1029 uVector,
1030 u64Rte);
1031 }
1032}
1033
1034
1035/**
1036 * @copydoc FNSSMDEVSAVEEXEC
1037 */
1038static DECLCALLBACK(int) ioapicR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1039{
1040 PCIOAPIC pThis = PDMINS_2_DATA(pDevIns, PCIOAPIC);
1041 LogFlow(("IOAPIC: ioapicR3SaveExec\n"));
1042
1043 SSMR3PutU32(pSSM, pThis->uIrr);
1044 SSMR3PutU8(pSSM, pThis->u8Id);
1045 SSMR3PutU8(pSSM, pThis->u8Index);
1046 for (uint8_t idxRte = 0; idxRte < RT_ELEMENTS(pThis->au64RedirTable); idxRte++)
1047 SSMR3PutU64(pSSM, pThis->au64RedirTable[idxRte]);
1048
1049 return VINF_SUCCESS;
1050}
1051
1052
1053/**
1054 * @copydoc FNSSMDEVLOADEXEC
1055 */
1056static DECLCALLBACK(int) ioapicR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1057{
1058 PIOAPIC pThis = PDMINS_2_DATA(pDevIns, PIOAPIC);
1059 LogFlow(("APIC: apicR3LoadExec: uVersion=%u uPass=%#x\n", uVersion, uPass));
1060
1061 Assert(uPass == SSM_PASS_FINAL);
1062 NOREF(uPass);
1063
1064 /* Weed out invalid versions. */
1065 if ( uVersion != IOAPIC_SAVED_STATE_VERSION
1066 && uVersion != IOAPIC_SAVED_STATE_VERSION_VBOX_50)
1067 {
1068 LogRel(("IOAPIC: ioapicR3LoadExec: Invalid/unrecognized saved-state version %u (%#x)\n", uVersion, uVersion));
1069 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1070 }
1071
1072 if (uVersion == IOAPIC_SAVED_STATE_VERSION)
1073 SSMR3GetU32(pSSM, (uint32_t *)&pThis->uIrr);
1074
1075 SSMR3GetU8(pSSM, (uint8_t *)&pThis->u8Id);
1076 SSMR3GetU8(pSSM, (uint8_t *)&pThis->u8Index);
1077 for (uint8_t idxRte = 0; idxRte < RT_ELEMENTS(pThis->au64RedirTable); idxRte++)
1078 SSMR3GetU64(pSSM, &pThis->au64RedirTable[idxRte]);
1079
1080 return VINF_SUCCESS;
1081}
1082
1083
1084/**
1085 * @interface_method_impl{PDMDEVREG,pfnReset}
1086 */
1087static DECLCALLBACK(void) ioapicR3Reset(PPDMDEVINS pDevIns)
1088{
1089 PIOAPIC pThis = PDMINS_2_DATA(pDevIns, PIOAPIC);
1090 LogFlow(("IOAPIC: ioapicR3Reset: pThis=%p\n", pThis));
1091
1092 /* There might be devices threads calling ioapicSetIrq() in parallel, hence the lock. */
1093 IOAPIC_LOCK(pThis, VERR_IGNORED);
1094
1095 pThis->uIrr = 0;
1096 pThis->u8Index = 0;
1097 pThis->u8Id = 0;
1098
1099 for (uint8_t idxRte = 0; idxRte < RT_ELEMENTS(pThis->au64RedirTable); idxRte++)
1100 {
1101 pThis->au64RedirTable[idxRte] = IOAPIC_RTE_MASK;
1102 pThis->au32TagSrc[idxRte] = 0;
1103 }
1104
1105 IOAPIC_UNLOCK(pThis);
1106}
1107
1108
1109/**
1110 * @interface_method_impl{PDMDEVREG,pfnRelocate}
1111 */
1112static DECLCALLBACK(void) ioapicR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
1113{
1114 PIOAPIC pThis = PDMINS_2_DATA(pDevIns, PIOAPIC);
1115 LogFlow(("IOAPIC: ioapicR3Relocate: pThis=%p offDelta=%RGi\n", pThis, offDelta));
1116
1117 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1118 pThis->pIoApicHlpRC = pThis->pIoApicHlpR3->pfnGetRCHelpers(pDevIns);
1119}
1120
1121
1122/**
1123 * @interface_method_impl{PDMDEVREG,pfnDestruct}
1124 */
1125static DECLCALLBACK(int) ioapicR3Destruct(PPDMDEVINS pDevIns)
1126{
1127 PIOAPIC pThis = PDMINS_2_DATA(pDevIns, PIOAPIC);
1128 LogFlow(("IOAPIC: ioapicR3Destruct: pThis=%p\n", pThis));
1129 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
1130
1131#ifndef IOAPIC_WITH_PDM_CRITSECT
1132 /*
1133 * Destroy the RTE critical section.
1134 */
1135 if (PDMCritSectIsInitialized(&pThis->CritSect))
1136 PDMR3CritSectDelete(&pThis->CritSect);
1137#endif
1138
1139 return VINF_SUCCESS;
1140}
1141
1142
1143/**
1144 * @interface_method_impl{PDMDEVREG,pfnConstruct}
1145 */
1146static DECLCALLBACK(int) ioapicR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
1147{
1148 PIOAPIC pThis = PDMINS_2_DATA(pDevIns, PIOAPIC);
1149 LogFlow(("IOAPIC: ioapicR3Construct: pThis=%p iInstance=%d\n", pThis, iInstance));
1150 Assert(iInstance == 0);
1151
1152 /*
1153 * Initialize the state data.
1154 */
1155 pThis->pDevInsR3 = pDevIns;
1156 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
1157 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1158
1159 /*
1160 * Validate and read the configuration.
1161 */
1162 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "NumCPUs|RZEnabled", "");
1163
1164 /* The number of CPUs is currently unused, but left in CFGM and saved-state in case an ID of 0 is
1165 upsets some guest which we haven't yet tested. */
1166 uint32_t cCpus;
1167 int rc = CFGMR3QueryU32Def(pCfg, "NumCPUs", &cCpus, 1);
1168 if (RT_FAILURE(rc))
1169 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to query integer value \"NumCPUs\""));
1170 pThis->cCpus = (uint8_t)cCpus;
1171
1172 bool fRZEnabled;
1173 rc = CFGMR3QueryBoolDef(pCfg, "RZEnabled", &fRZEnabled, true);
1174 if (RT_FAILURE(rc))
1175 return PDMDEV_SET_ERROR(pDevIns, rc,
1176 N_("Configuration error: Failed to query boolean value \"RZEnabled\""));
1177
1178 Log2(("IOAPIC: cCpus=%u fRZEnabled=%RTbool\n", cCpus, fRZEnabled));
1179
1180 /*
1181 * We will use our own critical section for the IOAPIC device.
1182 */
1183 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
1184 AssertRCReturn(rc, rc);
1185
1186#ifndef IOAPIC_WITH_PDM_CRITSECT
1187 /*
1188 * Setup the critical section to protect concurrent writes to the RTEs.
1189 */
1190 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "IOAPIC");
1191 if (RT_FAILURE(rc))
1192 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, N_("IOAPIC: Failed to create critical section. rc=%Rrc"), rc);
1193#endif
1194
1195 /*
1196 * Register the IOAPIC.
1197 */
1198 PDMIOAPICREG IoApicReg;
1199 RT_ZERO(IoApicReg);
1200 IoApicReg.u32Version = PDM_IOAPICREG_VERSION;
1201 IoApicReg.pfnSetIrqR3 = ioapicSetIrq;
1202 IoApicReg.pfnSendMsiR3 = ioapicSendMsi;
1203 IoApicReg.pfnSetEoiR3 = ioapicSetEoi;
1204 if (fRZEnabled)
1205 {
1206 IoApicReg.pszSetIrqRC = "ioapicSetIrq";
1207 IoApicReg.pszSetIrqR0 = "ioapicSetIrq";
1208
1209 IoApicReg.pszSendMsiRC = "ioapicSendMsi";
1210 IoApicReg.pszSendMsiR0 = "ioapicSendMsi";
1211
1212 IoApicReg.pszSetEoiRC = "ioapicSetEoi";
1213 IoApicReg.pszSetEoiR0 = "ioapicSetEoi";
1214 }
1215 rc = PDMDevHlpIOAPICRegister(pDevIns, &IoApicReg, &pThis->pIoApicHlpR3);
1216 if (RT_FAILURE(rc))
1217 {
1218 AssertMsgFailed(("IOAPIC: PDMDevHlpIOAPICRegister failed! rc=%Rrc\n", rc));
1219 return rc;
1220 }
1221
1222 /*
1223 * Register MMIO callbacks.
1224 */
1225 rc = PDMDevHlpMMIORegister(pDevIns, IOAPIC_MMIO_BASE_PHYSADDR, IOAPIC_MMIO_SIZE, pThis,
1226 IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_DWORD_ZEROED, ioapicMmioWrite, ioapicMmioRead,
1227 "I/O APIC");
1228 if (RT_SUCCESS(rc))
1229 {
1230 if (fRZEnabled)
1231 {
1232 pThis->pIoApicHlpRC = pThis->pIoApicHlpR3->pfnGetRCHelpers(pDevIns);
1233 rc = PDMDevHlpMMIORegisterRC(pDevIns, IOAPIC_MMIO_BASE_PHYSADDR, IOAPIC_MMIO_SIZE, NIL_RTRCPTR /* pvUser */,
1234 "ioapicMmioWrite", "ioapicMmioRead");
1235 AssertRCReturn(rc, rc);
1236
1237 pThis->pIoApicHlpR0 = pThis->pIoApicHlpR3->pfnGetR0Helpers(pDevIns);
1238 rc = PDMDevHlpMMIORegisterR0(pDevIns, IOAPIC_MMIO_BASE_PHYSADDR, IOAPIC_MMIO_SIZE, NIL_RTR0PTR /* pvUser */,
1239 "ioapicMmioWrite", "ioapicMmioRead");
1240 AssertRCReturn(rc, rc);
1241 }
1242 }
1243 else
1244 {
1245 LogRel(("IOAPIC: PDMDevHlpMMIORegister failed! rc=%Rrc\n", rc));
1246 return rc;
1247 }
1248
1249 /*
1250 * Register saved-state callbacks.
1251 */
1252 rc = PDMDevHlpSSMRegister(pDevIns, IOAPIC_SAVED_STATE_VERSION, sizeof(*pThis), ioapicR3SaveExec, ioapicR3LoadExec);
1253 if (RT_FAILURE(rc))
1254 {
1255 LogRel(("IOAPIC: PDMDevHlpSSMRegister failed! rc=%Rrc\n", rc));
1256 return rc;
1257 }
1258
1259 /*
1260 * Register debugger info callback.
1261 */
1262 rc = PDMDevHlpDBGFInfoRegister(pDevIns, "ioapic", "Display IO APIC state.", ioapicR3DbgInfo);
1263 AssertRCReturn(rc, rc);
1264
1265 /*
1266 * Register debugger register access.
1267 */
1268 rc = PDMDevHlpDBGFRegRegister(pDevIns, g_aRegDesc); AssertRC(rc);
1269 AssertRCReturn(rc, rc);
1270
1271#ifdef VBOX_WITH_STATISTICS
1272 /*
1273 * Statistics.
1274 */
1275 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatMmioReadRZ, STAMTYPE_COUNTER, "/Devices/IOAPIC/RZ/MmioReadRZ", STAMUNIT_OCCURENCES, "Number of IOAPIC MMIO reads in RZ.");
1276 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatMmioWriteRZ, STAMTYPE_COUNTER, "/Devices/IOAPIC/RZ/MmioWriteRZ", STAMUNIT_OCCURENCES, "Number of IOAPIC MMIO writes in RZ.");
1277 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatSetIrqRZ, STAMTYPE_COUNTER, "/Devices/IOAPIC/RZ/SetIrqRZ", STAMUNIT_OCCURENCES, "Number of IOAPIC SetIrq calls in RZ.");
1278 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatSetEoiRZ, STAMTYPE_COUNTER, "/Devices/IOAPIC/RZ/SetEoiRZ", STAMUNIT_OCCURENCES, "Number of IOAPIC SetEoi calls in RZ.");
1279
1280 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatMmioReadR3, STAMTYPE_COUNTER, "/Devices/IOAPIC/R3/MmioReadR3", STAMUNIT_OCCURENCES, "Number of IOAPIC MMIO reads in R3");
1281 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatMmioWriteR3, STAMTYPE_COUNTER, "/Devices/IOAPIC/R3/MmioWriteR3", STAMUNIT_OCCURENCES, "Number of IOAPIC MMIO writes in R3.");
1282 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatSetIrqR3, STAMTYPE_COUNTER, "/Devices/IOAPIC/R3/SetIrqR3", STAMUNIT_OCCURENCES, "Number of IOAPIC SetIrq calls in R3.");
1283 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatSetEoiR3, STAMTYPE_COUNTER, "/Devices/IOAPIC/R3/SetEoiR3", STAMUNIT_OCCURENCES, "Number of IOAPIC SetEoi calls in R3.");
1284
1285 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRedundantEdgeIntr, STAMTYPE_COUNTER, "/Devices/IOAPIC/RedundantEdgeIntr", STAMUNIT_OCCURENCES, "Number of redundant edge-triggered interrupts (no IRR change).");
1286 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRedundantLevelIntr, STAMTYPE_COUNTER, "/Devices/IOAPIC/RedundantLevelIntr", STAMUNIT_OCCURENCES, "Number of redundant level-triggered interrupts (no IRR change).");
1287 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatSuppressedLevelIntr, STAMTYPE_COUNTER, "/Devices/IOAPIC/SuppressedLevelIntr", STAMUNIT_OCCURENCES, "Number of suppressed level-triggered interrupts by remote IRR.");
1288
1289 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatEoiContention, STAMTYPE_COUNTER, "/Devices/IOAPIC/CritSect/ContentionSetEoi", STAMUNIT_OCCURENCES, "Number of times the critsect is busy during EOI writes causing trips to R3.");
1290 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatSetRteContention, STAMTYPE_COUNTER, "/Devices/IOAPIC/CritSect/ContentionSetRte", STAMUNIT_OCCURENCES, "Number of times the critsect is busy during RTE writes causing trips to R3.");
1291
1292 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatLevelIrqSent, STAMTYPE_COUNTER, "/Devices/IOAPIC/LevelIntr/Sent", STAMUNIT_OCCURENCES, "Number of level-triggered interrupts sent to the local APIC(s).");
1293 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatEoiReceived, STAMTYPE_COUNTER, "/Devices/IOAPIC/LevelIntr/Recv", STAMUNIT_OCCURENCES, "Number of EOIs received for level-triggered interrupts from the local APIC(s).");
1294#endif
1295
1296 /*
1297 * Init. the device state.
1298 */
1299 LogRel(("IOAPIC: Using implementation 2.0!\n"));
1300 ioapicR3Reset(pDevIns);
1301
1302 return VINF_SUCCESS;
1303}
1304
1305
1306/**
1307 * IO APIC device registration structure.
1308 */
1309const PDMDEVREG g_DeviceIOAPIC =
1310{
1311 /* u32Version */
1312 PDM_DEVREG_VERSION,
1313 /* szName */
1314 "ioapic",
1315 /* szRCMod */
1316 "VBoxDDRC.rc",
1317 /* szR0Mod */
1318 "VBoxDDR0.r0",
1319 /* pszDescription */
1320 "I/O Advanced Programmable Interrupt Controller (IO-APIC) Device",
1321 /* fFlags */
1322 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64 | PDM_DEVREG_FLAGS_PAE36
1323 | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
1324 /* fClass */
1325 PDM_DEVREG_CLASS_PIC,
1326 /* cMaxInstances */
1327 1,
1328 /* cbInstance */
1329 sizeof(IOAPIC),
1330 /* pfnConstruct */
1331 ioapicR3Construct,
1332 /* pfnDestruct */
1333 ioapicR3Destruct,
1334 /* pfnRelocate */
1335 ioapicR3Relocate,
1336 /* pfnMemSetup */
1337 NULL,
1338 /* pfnPowerOn */
1339 NULL,
1340 /* pfnReset */
1341 ioapicR3Reset,
1342 /* pfnSuspend */
1343 NULL,
1344 /* pfnResume */
1345 NULL,
1346 /* pfnAttach */
1347 NULL,
1348 /* pfnDetach */
1349 NULL,
1350 /* pfnQueryInterface. */
1351 NULL,
1352 /* pfnInitComplete */
1353 NULL,
1354 /* pfnPowerOff */
1355 NULL,
1356 /* pfnSoftReset */
1357 NULL,
1358 /* u32VersionEnd */
1359 PDM_DEVREG_VERSION
1360};
1361
1362#endif /* IN_RING3 */
1363
1364#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
1365
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