VirtualBox

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

Last change on this file since 66714 was 63618, checked in by vboxsync, 8 years ago

DevIoApic: Comment regarding remote IRR bit and corresponding bugref.

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