VirtualBox

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

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

Devices/IOAPIC: Fixed typo disallowing writing of the IOAPIC ID register. Fixes Fedora 5 x86 install test.

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