[2781] | 1 | /* $Id: DevPIC.cpp 40280 2012-02-28 19:47:00Z vboxsync $ */
|
---|
[1] | 2 | /** @file
|
---|
[11261] | 3 | * DevPIC - Intel 8259 Programmable Interrupt Controller (PIC) Device.
|
---|
[1] | 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[28800] | 7 | * Copyright (C) 2006-2007 Oracle Corporation
|
---|
[1] | 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
|
---|
[5999] | 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.
|
---|
[1] | 16 | */
|
---|
| 17 |
|
---|
| 18 | /*******************************************************************************
|
---|
| 19 | * Header Files *
|
---|
| 20 | *******************************************************************************/
|
---|
| 21 | #define LOG_GROUP LOG_GROUP_DEV_PIC
|
---|
[35346] | 22 | #include <VBox/vmm/pdmdev.h>
|
---|
[1] | 23 | #include <VBox/log.h>
|
---|
| 24 | #include <iprt/assert.h>
|
---|
[11265] | 25 | #include <iprt/string.h>
|
---|
[1] | 26 |
|
---|
[35353] | 27 | #include "VBoxDD.h"
|
---|
[1] | 28 |
|
---|
| 29 |
|
---|
| 30 | /*******************************************************************************
|
---|
| 31 | * Defined Constants And Macros *
|
---|
| 32 | *******************************************************************************/
|
---|
| 33 | /** @def PIC_LOCK
|
---|
| 34 | * Acquires the PDM lock. This is a NOP if locking is disabled. */
|
---|
| 35 | /** @def PIC_UNLOCK
|
---|
| 36 | * Releases the PDM lock. This is a NOP if locking is disabled. */
|
---|
[10202] | 37 | #define PIC_LOCK(pThis, rc) \
|
---|
[1] | 38 | do { \
|
---|
[11261] | 39 | int rc2 = (pThis)->CTX_SUFF(pPicHlp)->pfnLock((pThis)->CTX_SUFF(pDevIns), rc); \
|
---|
[1] | 40 | if (rc2 != VINF_SUCCESS) \
|
---|
| 41 | return rc2; \
|
---|
| 42 | } while (0)
|
---|
[10202] | 43 | #define PIC_UNLOCK(pThis) \
|
---|
[11261] | 44 | (pThis)->CTX_SUFF(pPicHlp)->pfnUnlock((pThis)->CTX_SUFF(pDevIns))
|
---|
[1] | 45 |
|
---|
| 46 |
|
---|
[490] | 47 | #ifndef VBOX_DEVICE_STRUCT_TESTCASE
|
---|
[1] | 48 | /*******************************************************************************
|
---|
| 49 | * Internal Functions *
|
---|
| 50 | *******************************************************************************/
|
---|
[20374] | 51 | RT_C_DECLS_BEGIN
|
---|
[1] | 52 |
|
---|
| 53 | PDMBOTHCBDECL(void) picSetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel);
|
---|
| 54 | PDMBOTHCBDECL(int) picGetInterrupt(PPDMDEVINS pDevIns);
|
---|
| 55 | PDMBOTHCBDECL(int) picIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
|
---|
| 56 | PDMBOTHCBDECL(int) picIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
|
---|
| 57 | PDMBOTHCBDECL(int) picIOPortElcrRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
|
---|
| 58 | PDMBOTHCBDECL(int) picIOPortElcrWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
|
---|
| 59 |
|
---|
[20374] | 60 | RT_C_DECLS_END
|
---|
[490] | 61 | #endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
|
---|
[1] | 62 |
|
---|
| 63 |
|
---|
| 64 | /*
|
---|
| 65 | * QEMU 8259 interrupt controller emulation
|
---|
| 66 | *
|
---|
| 67 | * Copyright (c) 2003-2004 Fabrice Bellard
|
---|
| 68 | *
|
---|
| 69 | * Permission is hereby granted, free of charge, to any person obtaining a copy
|
---|
| 70 | * of this software and associated documentation files (the "Software"), to deal
|
---|
| 71 | * in the Software without restriction, including without limitation the rights
|
---|
| 72 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
---|
| 73 | * copies of the Software, and to permit persons to whom the Software is
|
---|
| 74 | * furnished to do so, subject to the following conditions:
|
---|
| 75 | *
|
---|
| 76 | * The above copyright notice and this permission notice shall be included in
|
---|
| 77 | * all copies or substantial portions of the Software.
|
---|
| 78 | *
|
---|
| 79 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
---|
| 80 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
---|
| 81 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
---|
| 82 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
---|
| 83 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
---|
| 84 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
---|
| 85 | * THE SOFTWARE.
|
---|
| 86 | */
|
---|
| 87 |
|
---|
| 88 | /* debug PIC */
|
---|
| 89 | #define DEBUG_PIC
|
---|
| 90 |
|
---|
| 91 | /*#define DEBUG_IRQ_COUNT*/
|
---|
| 92 |
|
---|
| 93 | typedef struct PicState {
|
---|
| 94 | uint8_t last_irr; /* edge detection */
|
---|
| 95 | uint8_t irr; /* interrupt request register */
|
---|
| 96 | uint8_t imr; /* interrupt mask register */
|
---|
| 97 | uint8_t isr; /* interrupt service register */
|
---|
| 98 | uint8_t priority_add; /* highest irq priority */
|
---|
| 99 | uint8_t irq_base;
|
---|
| 100 | uint8_t read_reg_select;
|
---|
| 101 | uint8_t poll;
|
---|
| 102 | uint8_t special_mask;
|
---|
| 103 | uint8_t init_state;
|
---|
| 104 | uint8_t auto_eoi;
|
---|
| 105 | uint8_t rotate_on_auto_eoi;
|
---|
| 106 | uint8_t special_fully_nested_mode;
|
---|
| 107 | uint8_t init4; /* true if 4 byte init */
|
---|
| 108 | uint8_t elcr; /* PIIX edge/trigger selection*/
|
---|
| 109 | uint8_t elcr_mask;
|
---|
[11261] | 110 | /** Pointer to the device instance, R3 Ptr. */
|
---|
| 111 | PPDMDEVINSR3 pDevInsR3;
|
---|
| 112 | /** Pointer to the device instance, R0 Ptr. */
|
---|
| 113 | PPDMDEVINSR0 pDevInsR0;
|
---|
| 114 | /** Pointer to the device instance, RC Ptr. */
|
---|
| 115 | PPDMDEVINSRC pDevInsRC;
|
---|
| 116 | RTRCPTR Alignment0; /**< Structure size alignment. */
|
---|
[1] | 117 | } PicState;
|
---|
| 118 |
|
---|
| 119 | /**
|
---|
| 120 | * A PIC device instance data.
|
---|
| 121 | */
|
---|
| 122 | typedef struct DEVPIC
|
---|
| 123 | {
|
---|
| 124 | /** The two interrupt controllers. */
|
---|
| 125 | PicState aPics[2];
|
---|
[11261] | 126 | /** Pointer to the device instance - R3 Ptr. */
|
---|
| 127 | PPDMDEVINSR3 pDevInsR3;
|
---|
[1] | 128 | /** Pointer to the PIC R3 helpers. */
|
---|
| 129 | PCPDMPICHLPR3 pPicHlpR3;
|
---|
[11261] | 130 | /** Pointer to the device instance - R0 Ptr. */
|
---|
| 131 | PPDMDEVINSR0 pDevInsR0;
|
---|
[490] | 132 | /** Pointer to the PIC R0 helpers. */
|
---|
| 133 | PCPDMPICHLPR0 pPicHlpR0;
|
---|
[11261] | 134 | /** Pointer to the device instance - RC Ptr. */
|
---|
| 135 | PPDMDEVINSRC pDevInsRC;
|
---|
| 136 | /** Pointer to the PIC RC helpers. */
|
---|
| 137 | PCPDMPICHLPRC pPicHlpRC;
|
---|
[35073] | 138 | /** Number of release log entries. Used to prevent flooding. */
|
---|
| 139 | uint32_t cRelLogEntries;
|
---|
| 140 | uint32_t u32AlignmentPadding;
|
---|
[1] | 141 | #ifdef VBOX_WITH_STATISTICS
|
---|
| 142 | STAMCOUNTER StatSetIrqGC;
|
---|
| 143 | STAMCOUNTER StatSetIrqHC;
|
---|
| 144 | STAMCOUNTER StatClearedActiveIRQ2;
|
---|
| 145 | STAMCOUNTER StatClearedActiveMasterIRQ;
|
---|
| 146 | STAMCOUNTER StatClearedActiveSlaveIRQ;
|
---|
| 147 | #endif
|
---|
| 148 | } DEVPIC, *PDEVPIC;
|
---|
| 149 |
|
---|
[490] | 150 |
|
---|
| 151 | #ifndef VBOX_DEVICE_STRUCT_TESTCASE
|
---|
[1] | 152 | #ifdef LOG_ENABLED
|
---|
[3308] | 153 | static inline void DumpPICState(PicState *s, const char *szFn)
|
---|
[1] | 154 | {
|
---|
[11264] | 155 | PDEVPIC pThis = PDMINS_2_DATA(s->CTX_SUFF(pDevIns), PDEVPIC);
|
---|
[1] | 156 |
|
---|
| 157 | Log2(("%s: pic%d: elcr=%x last_irr=%x irr=%x imr=%x isr=%x irq_base=%x\n",
|
---|
[11264] | 158 | szFn, (&pThis->aPics[0] == s) ? 0 : 1,
|
---|
[1] | 159 | s->elcr, s->last_irr, s->irr, s->imr, s->isr, s->irq_base));
|
---|
| 160 | }
|
---|
| 161 | #else
|
---|
[11264] | 162 | # define DumpPICState(pThis, szFn) do { } while (0)
|
---|
[1] | 163 | #endif
|
---|
| 164 |
|
---|
| 165 | /* set irq level. If an edge is detected, then the IRR is set to 1 */
|
---|
| 166 | static inline void pic_set_irq1(PicState *s, int irq, int level)
|
---|
| 167 | {
|
---|
| 168 | int mask;
|
---|
| 169 | Log(("pic_set_irq1: irq=%d level=%d\n", irq, level));
|
---|
| 170 | mask = 1 << irq;
|
---|
| 171 | if (s->elcr & mask) {
|
---|
| 172 | /* level triggered */
|
---|
| 173 | if (level) {
|
---|
[5208] | 174 | Log2(("pic_set_irq1(ls) irr=%d irrnew=%d\n", s->irr, s->irr | mask));
|
---|
[1] | 175 | s->irr |= mask;
|
---|
| 176 | s->last_irr |= mask;
|
---|
| 177 | } else {
|
---|
[5208] | 178 | Log2(("pic_set_irq1(lc) irr=%d irrnew=%d\n", s->irr, s->irr & ~mask));
|
---|
[1] | 179 | s->irr &= ~mask;
|
---|
| 180 | s->last_irr &= ~mask;
|
---|
| 181 | }
|
---|
| 182 | } else {
|
---|
| 183 | /* edge triggered */
|
---|
| 184 | if (level) {
|
---|
| 185 | if ((s->last_irr & mask) == 0)
|
---|
| 186 | {
|
---|
| 187 | Log2(("pic_set_irq1 irr=%x last_irr=%x\n", s->irr | mask, s->last_irr));
|
---|
| 188 | s->irr |= mask;
|
---|
| 189 | }
|
---|
| 190 | s->last_irr |= mask;
|
---|
| 191 | } else {
|
---|
[34697] | 192 | s->irr &= ~mask;
|
---|
[1] | 193 | s->last_irr &= ~mask;
|
---|
| 194 | }
|
---|
| 195 | }
|
---|
| 196 | DumpPICState(s, "pic_set_irq1");
|
---|
| 197 | }
|
---|
| 198 |
|
---|
| 199 | /* return the highest priority found in mask (highest = smallest
|
---|
| 200 | number). Return 8 if no irq */
|
---|
| 201 | static inline int get_priority(PicState *s, int mask)
|
---|
| 202 | {
|
---|
| 203 | int priority;
|
---|
| 204 | if (mask == 0)
|
---|
| 205 | return 8;
|
---|
| 206 | priority = 0;
|
---|
| 207 | while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0)
|
---|
| 208 | priority++;
|
---|
| 209 | return priority;
|
---|
| 210 | }
|
---|
| 211 |
|
---|
| 212 | /* return the pic wanted interrupt. return -1 if none */
|
---|
| 213 | static int pic_get_irq(PicState *s)
|
---|
| 214 | {
|
---|
[11262] | 215 | PicState *pics = &(PDMINS_2_DATA(s->CTX_SUFF(pDevIns), PDEVPIC))->aPics[0];
|
---|
[1] | 216 | int mask, cur_priority, priority;
|
---|
| 217 | Log(("pic_get_irq%d: mask=%x\n", (s == pics) ? 0 : 1, s->irr & ~s->imr));
|
---|
| 218 | DumpPICState(s, "pic_get_irq");
|
---|
| 219 |
|
---|
| 220 | mask = s->irr & ~s->imr;
|
---|
| 221 | priority = get_priority(s, mask);
|
---|
| 222 | Log(("pic_get_irq: priority=%x\n", priority));
|
---|
| 223 | if (priority == 8)
|
---|
| 224 | return -1;
|
---|
| 225 | /* compute current priority. If special fully nested mode on the
|
---|
| 226 | master, the IRQ coming from the slave is not taken into account
|
---|
| 227 | for the priority computation. */
|
---|
| 228 | mask = s->isr;
|
---|
| 229 | if (s->special_fully_nested_mode && s == &pics[0])
|
---|
| 230 | mask &= ~(1 << 2);
|
---|
| 231 | cur_priority = get_priority(s, mask);
|
---|
| 232 | Log(("pic_get_irq%d: cur_priority=%x pending=%d\n", (s == pics) ? 0 : 1, cur_priority, (priority == 8) ? -1 : (priority + s->priority_add) & 7));
|
---|
| 233 | if (priority < cur_priority) {
|
---|
| 234 | /* higher priority found: an irq should be generated */
|
---|
| 235 | return (priority + s->priority_add) & 7;
|
---|
| 236 | } else {
|
---|
| 237 | return -1;
|
---|
| 238 | }
|
---|
| 239 | }
|
---|
| 240 |
|
---|
| 241 | /* raise irq to CPU if necessary. must be called every time the active
|
---|
| 242 | irq may change */
|
---|
[11264] | 243 | static int pic_update_irq(PDEVPIC pThis)
|
---|
[1] | 244 | {
|
---|
[11264] | 245 | PicState *pics = &pThis->aPics[0];
|
---|
[1] | 246 | int irq2, irq;
|
---|
| 247 |
|
---|
| 248 | /* first look at slave pic */
|
---|
| 249 | irq2 = pic_get_irq(&pics[1]);
|
---|
| 250 | Log(("pic_update_irq irq2=%d\n", irq2));
|
---|
| 251 | if (irq2 >= 0) {
|
---|
| 252 | /* if irq request by slave pic, signal master PIC */
|
---|
| 253 | pic_set_irq1(&pics[0], 2, 1);
|
---|
[34697] | 254 | } else {
|
---|
| 255 | /* If not, clear the IR on the master PIC. */
|
---|
[1] | 256 | pic_set_irq1(&pics[0], 2, 0);
|
---|
| 257 | }
|
---|
| 258 | /* look at requested irq */
|
---|
| 259 | irq = pic_get_irq(&pics[0]);
|
---|
| 260 | if (irq >= 0)
|
---|
| 261 | {
|
---|
| 262 | /* If irq 2 is pending on the master pic, then there must be one pending on the slave pic too! Otherwise we'll get
|
---|
| 263 | * spurious slave interrupts in picGetInterrupt.
|
---|
| 264 | */
|
---|
| 265 | if (irq != 2 || irq2 != -1)
|
---|
| 266 | {
|
---|
| 267 | #if defined(DEBUG_PIC)
|
---|
| 268 | int i;
|
---|
| 269 | for(i = 0; i < 2; i++) {
|
---|
| 270 | Log(("pic%d: imr=%x irr=%x padd=%d\n",
|
---|
| 271 | i, pics[i].imr, pics[i].irr,
|
---|
| 272 | pics[i].priority_add));
|
---|
| 273 | }
|
---|
| 274 | Log(("pic: cpu_interrupt\n"));
|
---|
| 275 | #endif
|
---|
[11264] | 276 | pThis->CTX_SUFF(pPicHlp)->pfnSetInterruptFF(pThis->CTX_SUFF(pDevIns));
|
---|
[1] | 277 | }
|
---|
| 278 | else
|
---|
| 279 | {
|
---|
[11264] | 280 | STAM_COUNTER_INC(&pThis->StatClearedActiveIRQ2);
|
---|
[1] | 281 | Log(("pic_update_irq: irq 2 is active, but no interrupt is pending on the slave pic!!\n"));
|
---|
| 282 | /* Clear it here, so lower priority interrupts can still be dispatched. */
|
---|
[3489] | 283 |
|
---|
| 284 | /* if this was the only pending irq, then we must clear the interrupt ff flag */
|
---|
[11264] | 285 | pThis->CTX_SUFF(pPicHlp)->pfnClearInterruptFF(pThis->CTX_SUFF(pDevIns));
|
---|
[3489] | 286 |
|
---|
[1] | 287 | /** @note Is this correct? */
|
---|
| 288 | pics[0].irr &= ~(1 << 2);
|
---|
[3489] | 289 |
|
---|
| 290 | /* Call ourselves again just in case other interrupts are pending */
|
---|
[11264] | 291 | return pic_update_irq(pThis);
|
---|
[1] | 292 | }
|
---|
| 293 | }
|
---|
[8923] | 294 | else
|
---|
| 295 | {
|
---|
| 296 | Log(("pic_update_irq: no interrupt is pending!!\n"));
|
---|
| 297 |
|
---|
| 298 | /* we must clear the interrupt ff flag */
|
---|
[11264] | 299 | pThis->CTX_SUFF(pPicHlp)->pfnClearInterruptFF(pThis->CTX_SUFF(pDevIns));
|
---|
[8923] | 300 | }
|
---|
[1] | 301 | return VINF_SUCCESS;
|
---|
| 302 | }
|
---|
| 303 |
|
---|
| 304 | /** @note if an interrupt line state changes from unmasked to masked, then it must be deactivated when currently pending! */
|
---|
[11264] | 305 | static void pic_update_imr(PDEVPIC pThis, PicState *s, uint8_t val)
|
---|
[1] | 306 | {
|
---|
| 307 | int irq, intno;
|
---|
| 308 | PicState *pActivePIC;
|
---|
| 309 |
|
---|
| 310 | /* Query the current pending irq, if any. */
|
---|
[11264] | 311 | pActivePIC = &pThis->aPics[0];
|
---|
[1] | 312 | intno = irq = pic_get_irq(pActivePIC);
|
---|
| 313 | if (irq == 2)
|
---|
| 314 | {
|
---|
[11264] | 315 | pActivePIC = &pThis->aPics[1];
|
---|
[1] | 316 | irq = pic_get_irq(pActivePIC);
|
---|
| 317 | intno = irq + 8;
|
---|
| 318 | }
|
---|
| 319 |
|
---|
| 320 | /* Update IMR */
|
---|
| 321 | s->imr = val;
|
---|
| 322 |
|
---|
| 323 | /* If an interrupt is pending and now masked, then clear the FF flag. */
|
---|
| 324 | if ( irq >= 0
|
---|
| 325 | && ((1 << irq) & ~pActivePIC->imr) == 0)
|
---|
| 326 | {
|
---|
| 327 | Log(("pic_update_imr: pic0: elcr=%x last_irr=%x irr=%x imr=%x isr=%x irq_base=%x\n",
|
---|
[11264] | 328 | pThis->aPics[0].elcr, pThis->aPics[0].last_irr, pThis->aPics[0].irr, pThis->aPics[0].imr, pThis->aPics[0].isr, pThis->aPics[0].irq_base));
|
---|
[1] | 329 | Log(("pic_update_imr: pic1: elcr=%x last_irr=%x irr=%x imr=%x isr=%x irq_base=%x\n",
|
---|
[11264] | 330 | pThis->aPics[1].elcr, pThis->aPics[1].last_irr, pThis->aPics[1].irr, pThis->aPics[1].imr, pThis->aPics[1].isr, pThis->aPics[1].irq_base));
|
---|
[1] | 331 |
|
---|
| 332 | /* Clear pending IRQ 2 on master controller in case of slave interrupt. */
|
---|
| 333 | /** @todo Is this correct? */
|
---|
| 334 | if (intno > 7)
|
---|
| 335 | {
|
---|
[11264] | 336 | pThis->aPics[0].irr &= ~(1 << 2);
|
---|
| 337 | STAM_COUNTER_INC(&pThis->StatClearedActiveSlaveIRQ);
|
---|
[1] | 338 | }
|
---|
| 339 | else
|
---|
[11264] | 340 | STAM_COUNTER_INC(&pThis->StatClearedActiveMasterIRQ);
|
---|
[1] | 341 |
|
---|
| 342 | Log(("pic_update_imr: clear pending interrupt %d\n", intno));
|
---|
[11264] | 343 | pThis->CTX_SUFF(pPicHlp)->pfnClearInterruptFF(pThis->CTX_SUFF(pDevIns));
|
---|
[1] | 344 | }
|
---|
| 345 | }
|
---|
| 346 |
|
---|
| 347 |
|
---|
| 348 | /**
|
---|
| 349 | * Set the an IRQ.
|
---|
| 350 | *
|
---|
| 351 | * @param pDevIns Device instance of the PICs.
|
---|
| 352 | * @param iIrq IRQ number to set.
|
---|
| 353 | * @param iLevel IRQ level.
|
---|
| 354 | */
|
---|
| 355 | PDMBOTHCBDECL(void) picSetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel)
|
---|
| 356 | {
|
---|
[11264] | 357 | PDEVPIC pThis = PDMINS_2_DATA(pDevIns, PDEVPIC);
|
---|
| 358 | Assert(pThis->CTX_SUFF(pDevIns) == pDevIns);
|
---|
| 359 | Assert(pThis->aPics[0].CTX_SUFF(pDevIns) == pDevIns);
|
---|
| 360 | Assert(pThis->aPics[1].CTX_SUFF(pDevIns) == pDevIns);
|
---|
[1] | 361 | AssertMsg(iIrq < 16, ("iIrq=%d\n", iIrq));
|
---|
| 362 |
|
---|
| 363 | Log(("picSetIrq %d %d\n", iIrq, iLevel));
|
---|
[11264] | 364 | DumpPICState(&pThis->aPics[0], "picSetIrq");
|
---|
| 365 | DumpPICState(&pThis->aPics[1], "picSetIrq");
|
---|
| 366 | STAM_COUNTER_INC(&pThis->CTXSUFF(StatSetIrq));
|
---|
[2538] | 367 | if ((iLevel & PDM_IRQ_LEVEL_FLIP_FLOP) == PDM_IRQ_LEVEL_FLIP_FLOP)
|
---|
| 368 | {
|
---|
[34695] | 369 | /* A flip-flop lowers the IRQ line and immediately raises it, so
|
---|
| 370 | * that a rising edge is guaranteed to occur. Note that the IRQ
|
---|
| 371 | * line must be held high for a while to avoid spurious interrupts.
|
---|
| 372 | */
|
---|
[11264] | 373 | pic_set_irq1(&pThis->aPics[iIrq >> 3], iIrq & 7, 0);
|
---|
| 374 | pic_update_irq(pThis);
|
---|
[2538] | 375 | }
|
---|
[34695] | 376 | pic_set_irq1(&pThis->aPics[iIrq >> 3], iIrq & 7, iLevel & PDM_IRQ_LEVEL_HIGH);
|
---|
| 377 | pic_update_irq(pThis);
|
---|
[1] | 378 | }
|
---|
| 379 |
|
---|
| 380 |
|
---|
| 381 | /* acknowledge interrupt 'irq' */
|
---|
| 382 | static inline void pic_intack(PicState *s, int irq)
|
---|
| 383 | {
|
---|
| 384 | if (s->auto_eoi) {
|
---|
| 385 | if (s->rotate_on_auto_eoi)
|
---|
| 386 | s->priority_add = (irq + 1) & 7;
|
---|
| 387 | } else {
|
---|
| 388 | s->isr |= (1 << irq);
|
---|
| 389 | }
|
---|
| 390 | /* We don't clear a level sensitive interrupt here */
|
---|
| 391 | if (!(s->elcr & (1 << irq)))
|
---|
[5208] | 392 | {
|
---|
| 393 | Log2(("pic_intack: irr=%x irrnew=%x\n", s->irr, s->irr & ~(1 << irq)));
|
---|
[1] | 394 | s->irr &= ~(1 << irq);
|
---|
[5208] | 395 | }
|
---|
[1] | 396 | }
|
---|
| 397 |
|
---|
| 398 |
|
---|
| 399 | /**
|
---|
| 400 | * Get a pending interrupt.
|
---|
| 401 | *
|
---|
| 402 | * @returns Pending interrupt number.
|
---|
| 403 | * @param pDevIns Device instance of the PICs.
|
---|
| 404 | */
|
---|
| 405 | PDMBOTHCBDECL(int) picGetInterrupt(PPDMDEVINS pDevIns)
|
---|
| 406 | {
|
---|
[11264] | 407 | PDEVPIC pThis = PDMINS_2_DATA(pDevIns, PDEVPIC);
|
---|
[1] | 408 | int irq;
|
---|
| 409 | int irq2;
|
---|
| 410 | int intno;
|
---|
| 411 |
|
---|
| 412 | /* read the irq from the PIC */
|
---|
[11264] | 413 | DumpPICState(&pThis->aPics[0], "picGetInterrupt");
|
---|
| 414 | DumpPICState(&pThis->aPics[1], "picGetInterrupt");
|
---|
[1] | 415 |
|
---|
[11264] | 416 | irq = pic_get_irq(&pThis->aPics[0]);
|
---|
[1] | 417 | if (irq >= 0)
|
---|
| 418 | {
|
---|
[11264] | 419 | pic_intack(&pThis->aPics[0], irq);
|
---|
[1] | 420 | if (irq == 2)
|
---|
| 421 | {
|
---|
[11264] | 422 | irq2 = pic_get_irq(&pThis->aPics[1]);
|
---|
[1] | 423 | if (irq2 >= 0) {
|
---|
[11264] | 424 | pic_intack(&pThis->aPics[1], irq2);
|
---|
[1] | 425 | }
|
---|
| 426 | else
|
---|
| 427 | {
|
---|
[38921] | 428 | /* Interrupt went away or is now masked. */
|
---|
| 429 | Log(("picGetInterrupt: spurious IRQ on slave controller, converted to IRQ15\n"));
|
---|
[1] | 430 | irq2 = 7;
|
---|
| 431 | }
|
---|
[11264] | 432 | intno = pThis->aPics[1].irq_base + irq2;
|
---|
| 433 | Log2(("picGetInterrupt1: %x base=%x irq=%x\n", intno, pThis->aPics[1].irq_base, irq2));
|
---|
[1] | 434 | irq = irq2 + 8;
|
---|
| 435 | }
|
---|
| 436 | else {
|
---|
[11264] | 437 | intno = pThis->aPics[0].irq_base + irq;
|
---|
| 438 | Log2(("picGetInterrupt0: %x base=%x irq=%x\n", intno, pThis->aPics[0].irq_base, irq));
|
---|
[1] | 439 | }
|
---|
| 440 | }
|
---|
| 441 | else
|
---|
| 442 | {
|
---|
[38921] | 443 | /* Interrupt went away or is now masked. */
|
---|
| 444 | Log(("picGetInterrupt: spurious IRQ on master controller, converted to IRQ7\n"));
|
---|
[1] | 445 | irq = 7;
|
---|
[11264] | 446 | intno = pThis->aPics[0].irq_base + irq;
|
---|
[1] | 447 | }
|
---|
[11264] | 448 | pic_update_irq(pThis);
|
---|
[1] | 449 |
|
---|
[11264] | 450 | Log(("picGetInterrupt: 0x%02x pending 0:%d 1:%d\n", intno, pic_get_irq(&pThis->aPics[0]), pic_get_irq(&pThis->aPics[1])));
|
---|
[1] | 451 |
|
---|
| 452 | return intno;
|
---|
| 453 | }
|
---|
| 454 |
|
---|
| 455 | static void pic_reset(PicState *s)
|
---|
| 456 | {
|
---|
[11261] | 457 | PPDMDEVINSR3 pDevInsR3 = s->pDevInsR3;
|
---|
| 458 | PPDMDEVINSR0 pDevInsR0 = s->pDevInsR0;
|
---|
| 459 | PPDMDEVINSRC pDevInsRC = s->pDevInsRC;
|
---|
| 460 | int elcr_mask = s->elcr_mask;
|
---|
| 461 | int elcr = s->elcr;
|
---|
[1] | 462 |
|
---|
| 463 | memset(s, 0, sizeof(PicState));
|
---|
[11261] | 464 |
|
---|
| 465 | s->elcr = elcr;
|
---|
| 466 | s->elcr_mask = elcr_mask;
|
---|
| 467 | s->pDevInsRC = pDevInsRC;
|
---|
| 468 | s->pDevInsR0 = pDevInsR0;
|
---|
| 469 | s->pDevInsR3 = pDevInsR3;
|
---|
[1] | 470 | }
|
---|
| 471 |
|
---|
| 472 |
|
---|
| 473 | static int pic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
|
---|
| 474 | {
|
---|
| 475 | PicState *s = (PicState*)opaque;
|
---|
[11264] | 476 | PDEVPIC pThis = PDMINS_2_DATA(s->CTX_SUFF(pDevIns), PDEVPIC);
|
---|
[1] | 477 | int rc = VINF_SUCCESS;
|
---|
| 478 | int priority, cmd, irq;
|
---|
| 479 |
|
---|
| 480 | Log(("pic_write: addr=0x%02x val=0x%02x\n", addr, val));
|
---|
| 481 | addr &= 1;
|
---|
| 482 | if (addr == 0) {
|
---|
| 483 | if (val & 0x10) {
|
---|
| 484 | /* init */
|
---|
| 485 | pic_reset(s);
|
---|
| 486 | /* deassert a pending interrupt */
|
---|
[11264] | 487 | pThis->CTX_SUFF(pPicHlp)->pfnClearInterruptFF(pThis->CTX_SUFF(pDevIns));
|
---|
[1] | 488 |
|
---|
| 489 | s->init_state = 1;
|
---|
| 490 | s->init4 = val & 1;
|
---|
| 491 | if (val & 0x02)
|
---|
| 492 | AssertReleaseMsgFailed(("single mode not supported"));
|
---|
| 493 | if (val & 0x08)
|
---|
[35073] | 494 | if (pThis->cRelLogEntries++ < 64)
|
---|
| 495 | LogRel(("pic_write: Level sensitive IRQ setting ignored.\n"));
|
---|
[1] | 496 | } else if (val & 0x08) {
|
---|
| 497 | if (val & 0x04)
|
---|
| 498 | s->poll = 1;
|
---|
| 499 | if (val & 0x02)
|
---|
| 500 | s->read_reg_select = val & 1;
|
---|
| 501 | if (val & 0x40)
|
---|
| 502 | s->special_mask = (val >> 5) & 1;
|
---|
| 503 | } else {
|
---|
| 504 | cmd = val >> 5;
|
---|
| 505 | switch(cmd) {
|
---|
| 506 | case 0:
|
---|
| 507 | case 4:
|
---|
| 508 | s->rotate_on_auto_eoi = cmd >> 2;
|
---|
| 509 | break;
|
---|
| 510 | case 1: /* end of interrupt */
|
---|
| 511 | case 5:
|
---|
| 512 | {
|
---|
| 513 | priority = get_priority(s, s->isr);
|
---|
| 514 | if (priority != 8) {
|
---|
| 515 | irq = (priority + s->priority_add) & 7;
|
---|
| 516 | Log(("pic_write: EOI prio=%d irq=%d\n", priority, irq));
|
---|
| 517 | s->isr &= ~(1 << irq);
|
---|
| 518 | if (cmd == 5)
|
---|
| 519 | s->priority_add = (irq + 1) & 7;
|
---|
[11264] | 520 | rc = pic_update_irq(pThis);
|
---|
[1] | 521 | Assert(rc == VINF_SUCCESS);
|
---|
[5208] | 522 | DumpPICState(s, "eoi");
|
---|
[1] | 523 | }
|
---|
| 524 | break;
|
---|
| 525 | }
|
---|
| 526 | case 3:
|
---|
| 527 | {
|
---|
| 528 | irq = val & 7;
|
---|
| 529 | Log(("pic_write: EOI2 for irq %d\n", irq));
|
---|
| 530 | s->isr &= ~(1 << irq);
|
---|
[11264] | 531 | rc = pic_update_irq(pThis);
|
---|
[1] | 532 | Assert(rc == VINF_SUCCESS);
|
---|
[5208] | 533 | DumpPICState(s, "eoi2");
|
---|
[1] | 534 | break;
|
---|
| 535 | }
|
---|
| 536 | case 6:
|
---|
| 537 | {
|
---|
| 538 | s->priority_add = (val + 1) & 7;
|
---|
[6321] | 539 | Log(("pic_write: lowest priority %d (highest %d)\n", val & 7, s->priority_add));
|
---|
[11264] | 540 | rc = pic_update_irq(pThis);
|
---|
[1] | 541 | Assert(rc == VINF_SUCCESS);
|
---|
| 542 | break;
|
---|
| 543 | }
|
---|
| 544 | case 7:
|
---|
| 545 | {
|
---|
| 546 | irq = val & 7;
|
---|
| 547 | Log(("pic_write: EOI3 for irq %d\n", irq));
|
---|
| 548 | s->isr &= ~(1 << irq);
|
---|
| 549 | s->priority_add = (irq + 1) & 7;
|
---|
[11264] | 550 | rc = pic_update_irq(pThis);
|
---|
[1] | 551 | Assert(rc == VINF_SUCCESS);
|
---|
[5208] | 552 | DumpPICState(s, "eoi3");
|
---|
[1] | 553 | break;
|
---|
| 554 | }
|
---|
| 555 | default:
|
---|
| 556 | /* no operation */
|
---|
| 557 | break;
|
---|
| 558 | }
|
---|
| 559 | }
|
---|
| 560 | } else {
|
---|
| 561 | switch(s->init_state) {
|
---|
| 562 | case 0:
|
---|
| 563 | {
|
---|
| 564 | /* normal mode */
|
---|
[11264] | 565 | pic_update_imr(pThis, s, val);
|
---|
[1] | 566 |
|
---|
[11264] | 567 | rc = pic_update_irq(pThis);
|
---|
[1] | 568 | Assert(rc == VINF_SUCCESS);
|
---|
| 569 | break;
|
---|
| 570 | }
|
---|
| 571 | case 1:
|
---|
| 572 | s->irq_base = val & 0xf8;
|
---|
| 573 | s->init_state = 2;
|
---|
| 574 | Log(("pic_write: set irq base to %x\n", s->irq_base));
|
---|
| 575 | break;
|
---|
| 576 | case 2:
|
---|
| 577 | if (s->init4) {
|
---|
| 578 | s->init_state = 3;
|
---|
| 579 | } else {
|
---|
| 580 | s->init_state = 0;
|
---|
| 581 | }
|
---|
| 582 | break;
|
---|
| 583 | case 3:
|
---|
| 584 | s->special_fully_nested_mode = (val >> 4) & 1;
|
---|
| 585 | s->auto_eoi = (val >> 1) & 1;
|
---|
| 586 | s->init_state = 0;
|
---|
| 587 | Log(("pic_write: special_fully_nested_mode=%d auto_eoi=%d\n", s->special_fully_nested_mode, s->auto_eoi));
|
---|
| 588 | break;
|
---|
| 589 | }
|
---|
| 590 | }
|
---|
| 591 | return rc;
|
---|
| 592 | }
|
---|
| 593 |
|
---|
| 594 |
|
---|
| 595 | static uint32_t pic_poll_read (PicState *s, uint32_t addr1)
|
---|
| 596 | {
|
---|
[11264] | 597 | PDEVPIC pThis = PDMINS_2_DATA(s->CTX_SUFF(pDevIns), PDEVPIC);
|
---|
| 598 | PicState *pics = &pThis->aPics[0];
|
---|
[1] | 599 | int ret;
|
---|
| 600 |
|
---|
| 601 | ret = pic_get_irq(s);
|
---|
| 602 | if (ret >= 0) {
|
---|
| 603 | if (addr1 >> 7) {
|
---|
| 604 | Log2(("pic_poll_read: clear slave irq (isr)\n"));
|
---|
| 605 | pics[0].isr &= ~(1 << 2);
|
---|
| 606 | pics[0].irr &= ~(1 << 2);
|
---|
| 607 | }
|
---|
| 608 | Log2(("pic_poll_read: clear irq %d (isr)\n", ret));
|
---|
| 609 | s->irr &= ~(1 << ret);
|
---|
| 610 | s->isr &= ~(1 << ret);
|
---|
| 611 | if (addr1 >> 7 || ret != 2)
|
---|
[11264] | 612 | pic_update_irq(pThis);
|
---|
[1] | 613 | } else {
|
---|
[37159] | 614 | ret = 0;
|
---|
[11264] | 615 | pic_update_irq(pThis);
|
---|
[1] | 616 | }
|
---|
| 617 |
|
---|
| 618 | return ret;
|
---|
| 619 | }
|
---|
| 620 |
|
---|
| 621 |
|
---|
| 622 | static uint32_t pic_ioport_read(void *opaque, uint32_t addr1, int *pRC)
|
---|
| 623 | {
|
---|
| 624 | PicState *s = (PicState*)opaque;
|
---|
| 625 | unsigned int addr;
|
---|
| 626 | int ret;
|
---|
| 627 |
|
---|
| 628 | *pRC = VINF_SUCCESS;
|
---|
| 629 |
|
---|
| 630 | addr = addr1;
|
---|
| 631 | addr &= 1;
|
---|
| 632 | if (s->poll) {
|
---|
| 633 | ret = pic_poll_read(s, addr1);
|
---|
| 634 | s->poll = 0;
|
---|
| 635 | } else {
|
---|
| 636 | if (addr == 0) {
|
---|
| 637 | if (s->read_reg_select)
|
---|
| 638 | ret = s->isr;
|
---|
| 639 | else
|
---|
| 640 | ret = s->irr;
|
---|
| 641 | } else {
|
---|
| 642 | ret = s->imr;
|
---|
| 643 | }
|
---|
| 644 | }
|
---|
| 645 | Log(("pic_read: addr=0x%02x val=0x%02x\n", addr1, ret));
|
---|
| 646 | return ret;
|
---|
| 647 | }
|
---|
| 648 |
|
---|
| 649 |
|
---|
| 650 |
|
---|
[11265] | 651 | /* -=-=-=-=-=- wrappers / stuff -=-=-=-=-=- */
|
---|
[1] | 652 |
|
---|
| 653 | /**
|
---|
| 654 | * Port I/O Handler for IN operations.
|
---|
| 655 | *
|
---|
| 656 | * @returns VBox status code.
|
---|
| 657 | *
|
---|
| 658 | * @param pDevIns The device instance.
|
---|
| 659 | * @param pvUser User argument - pointer to the PIC in question.
|
---|
| 660 | * @param uPort Port number used for the IN operation.
|
---|
| 661 | * @param pu32 Where to store the result.
|
---|
| 662 | * @param cb Number of bytes read.
|
---|
| 663 | */
|
---|
| 664 | PDMBOTHCBDECL(int) picIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
|
---|
| 665 | {
|
---|
[11264] | 666 | PDEVPIC pThis = PDMINS_2_DATA(pDevIns, PDEVPIC);
|
---|
[113] | 667 | uint32_t iPic = (uint32_t)(uintptr_t)pvUser;
|
---|
[1] | 668 |
|
---|
| 669 | Assert(iPic == 0 || iPic == 1);
|
---|
| 670 | if (cb == 1)
|
---|
| 671 | {
|
---|
| 672 | int rc;
|
---|
[40280] | 673 | PIC_LOCK(pThis, VINF_IOM_R3_IOPORT_READ);
|
---|
[11264] | 674 | *pu32 = pic_ioport_read(&pThis->aPics[iPic], Port, &rc);
|
---|
| 675 | PIC_UNLOCK(pThis);
|
---|
[1] | 676 | return rc;
|
---|
| 677 | }
|
---|
| 678 | return VERR_IOM_IOPORT_UNUSED;
|
---|
| 679 | }
|
---|
| 680 |
|
---|
| 681 | /**
|
---|
| 682 | * Port I/O Handler for OUT operations.
|
---|
| 683 | *
|
---|
| 684 | * @returns VBox status code.
|
---|
| 685 | *
|
---|
| 686 | * @param pDevIns The device instance.
|
---|
| 687 | * @param pvUser User argument - pointer to the PIC in question.
|
---|
| 688 | * @param uPort Port number used for the IN operation.
|
---|
| 689 | * @param u32 The value to output.
|
---|
| 690 | * @param cb The value size in bytes.
|
---|
| 691 | */
|
---|
| 692 | PDMBOTHCBDECL(int) picIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
|
---|
| 693 | {
|
---|
[11264] | 694 | PDEVPIC pThis = PDMINS_2_DATA(pDevIns, PDEVPIC);
|
---|
[113] | 695 | uint32_t iPic = (uint32_t)(uintptr_t)pvUser;
|
---|
[1] | 696 |
|
---|
| 697 | Assert(iPic == 0 || iPic == 1);
|
---|
| 698 |
|
---|
| 699 | if (cb == 1)
|
---|
| 700 | {
|
---|
| 701 | int rc;
|
---|
[40280] | 702 | PIC_LOCK(pThis, VINF_IOM_R3_IOPORT_WRITE);
|
---|
[11264] | 703 | rc = pic_ioport_write(&pThis->aPics[iPic], Port, u32);
|
---|
| 704 | PIC_UNLOCK(pThis);
|
---|
[1] | 705 | return rc;
|
---|
| 706 | }
|
---|
| 707 | return VINF_SUCCESS;
|
---|
| 708 | }
|
---|
| 709 |
|
---|
| 710 |
|
---|
| 711 | /**
|
---|
| 712 | * Port I/O Handler for IN operations.
|
---|
| 713 | *
|
---|
| 714 | * @returns VBox status code.
|
---|
| 715 | *
|
---|
| 716 | * @param pDevIns The device instance.
|
---|
| 717 | * @param pvUser User argument - pointer to the PIC in question.
|
---|
| 718 | * @param uPort Port number used for the IN operation.
|
---|
| 719 | * @param pu32 Where to store the result.
|
---|
| 720 | * @param cb Number of bytes read.
|
---|
| 721 | */
|
---|
| 722 | PDMBOTHCBDECL(int) picIOPortElcrRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
|
---|
| 723 | {
|
---|
| 724 | if (cb == 1)
|
---|
| 725 | {
|
---|
| 726 | PicState *s = (PicState*)pvUser;
|
---|
[40280] | 727 | PIC_LOCK(PDMINS_2_DATA(pDevIns, PDEVPIC), VINF_IOM_R3_IOPORT_READ);
|
---|
[1] | 728 | *pu32 = s->elcr;
|
---|
[11262] | 729 | PIC_UNLOCK(PDMINS_2_DATA(pDevIns, PDEVPIC));
|
---|
[1] | 730 | return VINF_SUCCESS;
|
---|
| 731 | }
|
---|
[39091] | 732 | NOREF(Port);
|
---|
[1] | 733 | return VERR_IOM_IOPORT_UNUSED;
|
---|
| 734 | }
|
---|
| 735 |
|
---|
| 736 | /**
|
---|
| 737 | * Port I/O Handler for OUT operations.
|
---|
| 738 | *
|
---|
| 739 | * @returns VBox status code.
|
---|
| 740 | *
|
---|
| 741 | * @param pDevIns The device instance.
|
---|
| 742 | * @param pvUser User argument - pointer to the PIC in question.
|
---|
| 743 | * @param uPort Port number used for the IN operation.
|
---|
| 744 | * @param u32 The value to output.
|
---|
| 745 | * @param cb The value size in bytes.
|
---|
| 746 | */
|
---|
| 747 | PDMBOTHCBDECL(int) picIOPortElcrWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
|
---|
| 748 | {
|
---|
| 749 | if (cb == 1)
|
---|
| 750 | {
|
---|
| 751 | PicState *s = (PicState*)pvUser;
|
---|
[40280] | 752 | PIC_LOCK(PDMINS_2_DATA(pDevIns, PDEVPIC), VINF_IOM_R3_IOPORT_WRITE);
|
---|
[1] | 753 | s->elcr = u32 & s->elcr_mask;
|
---|
[11262] | 754 | PIC_UNLOCK(PDMINS_2_DATA(pDevIns, PDEVPIC));
|
---|
[1] | 755 | }
|
---|
[39091] | 756 | NOREF(Port);
|
---|
[1] | 757 | return VINF_SUCCESS;
|
---|
| 758 | }
|
---|
| 759 |
|
---|
| 760 |
|
---|
| 761 | #ifdef IN_RING3
|
---|
| 762 |
|
---|
| 763 | /**
|
---|
| 764 | * PIC status info callback.
|
---|
| 765 | *
|
---|
| 766 | * @param pDevIns The device instance.
|
---|
| 767 | * @param pHlp The output helpers.
|
---|
| 768 | * @param pszArgs The arguments.
|
---|
| 769 | */
|
---|
| 770 | static DECLCALLBACK(void) picInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
|
---|
| 771 | {
|
---|
[11264] | 772 | PDEVPIC pThis = PDMINS_2_DATA(pDevIns, PDEVPIC);
|
---|
[39091] | 773 | NOREF(pszArgs);
|
---|
[1] | 774 |
|
---|
| 775 | /*
|
---|
| 776 | * Show info.
|
---|
| 777 | */
|
---|
[39091] | 778 | for (int i = 0; i < 2; i++)
|
---|
[1] | 779 | {
|
---|
[39091] | 780 | PicState *pPic = &pThis->aPics[i];
|
---|
[36014] | 781 |
|
---|
[1] | 782 | pHlp->pfnPrintf(pHlp, "PIC%d:\n", i);
|
---|
[36014] | 783 | pHlp->pfnPrintf(pHlp, " IMR :%02x ISR :%02x IRR :%02x LIRR:%02x\n",
|
---|
| 784 | pPic->imr, pPic->isr, pPic->irr, pPic->last_irr);
|
---|
| 785 | pHlp->pfnPrintf(pHlp, " Base:%02x PriAdd:%02x RegSel:%02x\n",
|
---|
| 786 | pPic->irq_base, pPic->priority_add, pPic->read_reg_select);
|
---|
| 787 | pHlp->pfnPrintf(pHlp, " Poll:%02x SpMask:%02x IState:%02x\n",
|
---|
| 788 | pPic->poll, pPic->special_mask, pPic->init_state);
|
---|
| 789 | pHlp->pfnPrintf(pHlp, " AEOI:%02x Rotate:%02x FNest :%02x Ini4:%02x\n",
|
---|
[37423] | 790 | pPic->auto_eoi, pPic->rotate_on_auto_eoi,
|
---|
[36014] | 791 | pPic->special_fully_nested_mode, pPic->init4);
|
---|
| 792 | pHlp->pfnPrintf(pHlp, " ELCR:%02x ELMask:%02x\n", pPic->elcr, pPic->elcr_mask);
|
---|
[1] | 793 | }
|
---|
| 794 | }
|
---|
| 795 |
|
---|
| 796 | /**
|
---|
| 797 | * Saves a state of the programmable interrupt controller device.
|
---|
| 798 | *
|
---|
| 799 | * @returns VBox status code.
|
---|
| 800 | * @param pDevIns The device instance.
|
---|
| 801 | * @param pSSMHandle The handle to save the state to.
|
---|
| 802 | */
|
---|
| 803 | static DECLCALLBACK(int) picSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
|
---|
| 804 | {
|
---|
[11264] | 805 | PDEVPIC pThis = PDMINS_2_DATA(pDevIns, PDEVPIC);
|
---|
[11265] | 806 | for (unsigned i = 0; i < RT_ELEMENTS(pThis->aPics); i++)
|
---|
| 807 | {
|
---|
| 808 | SSMR3PutU8(pSSMHandle, pThis->aPics[i].last_irr);
|
---|
| 809 | SSMR3PutU8(pSSMHandle, pThis->aPics[i].irr);
|
---|
| 810 | SSMR3PutU8(pSSMHandle, pThis->aPics[i].imr);
|
---|
| 811 | SSMR3PutU8(pSSMHandle, pThis->aPics[i].isr);
|
---|
| 812 | SSMR3PutU8(pSSMHandle, pThis->aPics[i].priority_add);
|
---|
| 813 | SSMR3PutU8(pSSMHandle, pThis->aPics[i].irq_base);
|
---|
| 814 | SSMR3PutU8(pSSMHandle, pThis->aPics[i].read_reg_select);
|
---|
| 815 | SSMR3PutU8(pSSMHandle, pThis->aPics[i].poll);
|
---|
| 816 | SSMR3PutU8(pSSMHandle, pThis->aPics[i].special_mask);
|
---|
| 817 | SSMR3PutU8(pSSMHandle, pThis->aPics[i].init_state);
|
---|
| 818 | SSMR3PutU8(pSSMHandle, pThis->aPics[i].auto_eoi);
|
---|
| 819 | SSMR3PutU8(pSSMHandle, pThis->aPics[i].rotate_on_auto_eoi);
|
---|
| 820 | SSMR3PutU8(pSSMHandle, pThis->aPics[i].special_fully_nested_mode);
|
---|
| 821 | SSMR3PutU8(pSSMHandle, pThis->aPics[i].init4);
|
---|
| 822 | SSMR3PutU8(pSSMHandle, pThis->aPics[i].elcr);
|
---|
| 823 | }
|
---|
[1] | 824 | return VINF_SUCCESS;
|
---|
| 825 | }
|
---|
| 826 |
|
---|
| 827 |
|
---|
| 828 | /**
|
---|
| 829 | * Loads a saved programmable interrupt controller device state.
|
---|
| 830 | *
|
---|
| 831 | * @returns VBox status code.
|
---|
| 832 | * @param pDevIns The device instance.
|
---|
| 833 | * @param pSSMHandle The handle to the saved state.
|
---|
[22480] | 834 | * @param uVersion The data unit version number.
|
---|
[22793] | 835 | * @param uPass The data pass.
|
---|
[1] | 836 | */
|
---|
[22793] | 837 | static DECLCALLBACK(int) picLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle, uint32_t uVersion, uint32_t uPass)
|
---|
[1] | 838 | {
|
---|
[11265] | 839 | PDEVPIC pThis = PDMINS_2_DATA(pDevIns, PDEVPIC);
|
---|
| 840 |
|
---|
[22480] | 841 | if (uVersion != 1)
|
---|
[11265] | 842 | return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
|
---|
[22793] | 843 | Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
|
---|
[11265] | 844 |
|
---|
| 845 | for (unsigned i = 0; i < RT_ELEMENTS(pThis->aPics); i++)
|
---|
| 846 | {
|
---|
| 847 | SSMR3GetU8(pSSMHandle, &pThis->aPics[i].last_irr);
|
---|
| 848 | SSMR3GetU8(pSSMHandle, &pThis->aPics[i].irr);
|
---|
| 849 | SSMR3GetU8(pSSMHandle, &pThis->aPics[i].imr);
|
---|
| 850 | SSMR3GetU8(pSSMHandle, &pThis->aPics[i].isr);
|
---|
| 851 | SSMR3GetU8(pSSMHandle, &pThis->aPics[i].priority_add);
|
---|
| 852 | SSMR3GetU8(pSSMHandle, &pThis->aPics[i].irq_base);
|
---|
| 853 | SSMR3GetU8(pSSMHandle, &pThis->aPics[i].read_reg_select);
|
---|
| 854 | SSMR3GetU8(pSSMHandle, &pThis->aPics[i].poll);
|
---|
| 855 | SSMR3GetU8(pSSMHandle, &pThis->aPics[i].special_mask);
|
---|
| 856 | SSMR3GetU8(pSSMHandle, &pThis->aPics[i].init_state);
|
---|
| 857 | SSMR3GetU8(pSSMHandle, &pThis->aPics[i].auto_eoi);
|
---|
| 858 | SSMR3GetU8(pSSMHandle, &pThis->aPics[i].rotate_on_auto_eoi);
|
---|
| 859 | SSMR3GetU8(pSSMHandle, &pThis->aPics[i].special_fully_nested_mode);
|
---|
| 860 | SSMR3GetU8(pSSMHandle, &pThis->aPics[i].init4);
|
---|
| 861 | SSMR3GetU8(pSSMHandle, &pThis->aPics[i].elcr);
|
---|
| 862 | }
|
---|
| 863 | return VINF_SUCCESS;
|
---|
[1] | 864 | }
|
---|
| 865 |
|
---|
| 866 |
|
---|
| 867 | /* -=-=-=-=-=- real code -=-=-=-=-=- */
|
---|
| 868 |
|
---|
| 869 | /**
|
---|
| 870 | * Reset notification.
|
---|
| 871 | *
|
---|
| 872 | * @returns VBox status.
|
---|
| 873 | * @param pDevIns The device instance data.
|
---|
| 874 | */
|
---|
| 875 | static DECLCALLBACK(void) picReset(PPDMDEVINS pDevIns)
|
---|
| 876 | {
|
---|
[11264] | 877 | PDEVPIC pThis = PDMINS_2_DATA(pDevIns, PDEVPIC);
|
---|
[1] | 878 | unsigned i;
|
---|
| 879 | LogFlow(("picReset:\n"));
|
---|
[11264] | 880 | pThis->pPicHlpR3->pfnLock(pDevIns, VERR_INTERNAL_ERROR);
|
---|
[1] | 881 |
|
---|
[11264] | 882 | for (i = 0; i < RT_ELEMENTS(pThis->aPics); i++)
|
---|
| 883 | pic_reset(&pThis->aPics[i]);
|
---|
[1] | 884 |
|
---|
[11264] | 885 | PIC_UNLOCK(pThis);
|
---|
[1] | 886 | }
|
---|
| 887 |
|
---|
| 888 |
|
---|
| 889 | /**
|
---|
| 890 | * @copydoc FNPDMDEVRELOCATE
|
---|
| 891 | */
|
---|
| 892 | static DECLCALLBACK(void) picRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
|
---|
| 893 | {
|
---|
[11264] | 894 | PDEVPIC pThis = PDMINS_2_DATA(pDevIns, PDEVPIC);
|
---|
[1] | 895 | unsigned i;
|
---|
| 896 |
|
---|
[11264] | 897 | pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
|
---|
| 898 | pThis->pPicHlpRC = pThis->pPicHlpR3->pfnGetRCHelpers(pDevIns);
|
---|
| 899 | for (i = 0; i < RT_ELEMENTS(pThis->aPics); i++)
|
---|
| 900 | pThis->aPics[i].pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
|
---|
[1] | 901 | }
|
---|
| 902 |
|
---|
| 903 |
|
---|
| 904 | /**
|
---|
| 905 | * @copydoc FNPDMDEVCONSTRUCT
|
---|
| 906 | */
|
---|
[26173] | 907 | static DECLCALLBACK(int) picConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
|
---|
[1] | 908 | {
|
---|
[11264] | 909 | PDEVPIC pThis = PDMINS_2_DATA(pDevIns, PDEVPIC);
|
---|
[1] | 910 | PDMPICREG PicReg;
|
---|
| 911 | int rc;
|
---|
| 912 | bool fGCEnabled;
|
---|
| 913 | bool fR0Enabled;
|
---|
| 914 | Assert(iInstance == 0);
|
---|
| 915 |
|
---|
| 916 | /*
|
---|
| 917 | * Validate and read configuration.
|
---|
| 918 | */
|
---|
[26173] | 919 | if (!CFGMR3AreValuesValid(pCfg, "GCEnabled\0" "R0Enabled\0"))
|
---|
[1] | 920 | return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
|
---|
| 921 |
|
---|
[26173] | 922 | rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fGCEnabled, true);
|
---|
[11263] | 923 | if (RT_FAILURE(rc))
|
---|
[1] | 924 | return PDMDEV_SET_ERROR(pDevIns, rc,
|
---|
| 925 | N_("Configuration error: failed to read GCEnabled as boolean"));
|
---|
| 926 |
|
---|
[26173] | 927 | rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
|
---|
[11263] | 928 | if (RT_FAILURE(rc))
|
---|
[1] | 929 | return PDMDEV_SET_ERROR(pDevIns, rc,
|
---|
| 930 | N_("Configuration error: failed to read R0Enabled as boolean"));
|
---|
| 931 |
|
---|
[11263] | 932 | Log(("DevPIC: fGCEnabled=%RTbool fR0Enabled=%RTbool\n", fGCEnabled, fR0Enabled));
|
---|
[1] | 933 |
|
---|
| 934 | /*
|
---|
| 935 | * Init the data.
|
---|
| 936 | */
|
---|
[11264] | 937 | Assert(RT_ELEMENTS(pThis->aPics) == 2);
|
---|
| 938 | pThis->pDevInsR3 = pDevIns;
|
---|
| 939 | pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
|
---|
| 940 | pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
|
---|
| 941 | pThis->aPics[0].elcr_mask = 0xf8;
|
---|
| 942 | pThis->aPics[1].elcr_mask = 0xde;
|
---|
| 943 | pThis->aPics[0].pDevInsR3 = pDevIns;
|
---|
| 944 | pThis->aPics[1].pDevInsR3 = pDevIns;
|
---|
| 945 | pThis->aPics[0].pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
|
---|
| 946 | pThis->aPics[1].pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
|
---|
| 947 | pThis->aPics[0].pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
|
---|
| 948 | pThis->aPics[1].pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
|
---|
[35073] | 949 | pThis->cRelLogEntries = 0;
|
---|
[1] | 950 |
|
---|
| 951 | /*
|
---|
[11261] | 952 | * Register us as the PIC with PDM.
|
---|
[1] | 953 | */
|
---|
| 954 | PicReg.u32Version = PDM_PICREG_VERSION;
|
---|
[11261] | 955 | PicReg.pfnSetIrqR3 = picSetIrq;
|
---|
| 956 | PicReg.pfnGetInterruptR3 = picGetInterrupt;
|
---|
| 957 |
|
---|
[1] | 958 | if (fGCEnabled)
|
---|
| 959 | {
|
---|
[11261] | 960 | PicReg.pszSetIrqRC = "picSetIrq";
|
---|
| 961 | PicReg.pszGetInterruptRC = "picGetInterrupt";
|
---|
[1] | 962 | }
|
---|
| 963 | else
|
---|
| 964 | {
|
---|
[11261] | 965 | PicReg.pszSetIrqRC = NULL;
|
---|
| 966 | PicReg.pszGetInterruptRC = NULL;
|
---|
[1] | 967 | }
|
---|
| 968 |
|
---|
| 969 | if (fR0Enabled)
|
---|
| 970 | {
|
---|
| 971 | PicReg.pszSetIrqR0 = "picSetIrq";
|
---|
| 972 | PicReg.pszGetInterruptR0 = "picGetInterrupt";
|
---|
| 973 | }
|
---|
| 974 | else
|
---|
| 975 | {
|
---|
| 976 | PicReg.pszSetIrqR0 = NULL;
|
---|
| 977 | PicReg.pszGetInterruptR0 = NULL;
|
---|
| 978 | }
|
---|
| 979 |
|
---|
[26169] | 980 | rc = PDMDevHlpPICRegister(pDevIns, &PicReg, &pThis->pPicHlpR3);
|
---|
[11284] | 981 | AssertLogRelMsgRCReturn(rc, ("PICRegister -> %Rrc\n", rc), rc);
|
---|
[1] | 982 | if (fGCEnabled)
|
---|
[11264] | 983 | pThis->pPicHlpRC = pThis->pPicHlpR3->pfnGetRCHelpers(pDevIns);
|
---|
[11261] | 984 | if (fR0Enabled)
|
---|
[11264] | 985 | pThis->pPicHlpR0 = pThis->pPicHlpR3->pfnGetR0Helpers(pDevIns);
|
---|
[11261] | 986 |
|
---|
[38849] | 987 | /*
|
---|
[39091] | 988 | * Since the PIC helper interface provides access to the PDM lock,
|
---|
| 989 | * we need no device level critical section.
|
---|
[38849] | 990 | */
|
---|
| 991 | rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
|
---|
| 992 | AssertRCReturn(rc, rc);
|
---|
[11261] | 993 |
|
---|
| 994 | /*
|
---|
| 995 | * Register I/O ports and save state.
|
---|
| 996 | */
|
---|
[1] | 997 | rc = PDMDevHlpIOPortRegister(pDevIns, 0x20, 2, (void *)0, picIOPortWrite, picIOPortRead, NULL, NULL, "i8259 PIC #0");
|
---|
[11262] | 998 | if (RT_FAILURE(rc))
|
---|
[1] | 999 | return rc;
|
---|
| 1000 | rc = PDMDevHlpIOPortRegister(pDevIns, 0xa0, 2, (void *)1, picIOPortWrite, picIOPortRead, NULL, NULL, "i8259 PIC #1");
|
---|
[11262] | 1001 | if (RT_FAILURE(rc))
|
---|
[1] | 1002 | return rc;
|
---|
| 1003 | if (fGCEnabled)
|
---|
| 1004 | {
|
---|
[26157] | 1005 | rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x20, 2, 0, "picIOPortWrite", "picIOPortRead", NULL, NULL, "i8259 PIC #0");
|
---|
[11262] | 1006 | if (RT_FAILURE(rc))
|
---|
[1] | 1007 | return rc;
|
---|
[26157] | 1008 | rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0xa0, 2, 1, "picIOPortWrite", "picIOPortRead", NULL, NULL, "i8259 PIC #1");
|
---|
[11262] | 1009 | if (RT_FAILURE(rc))
|
---|
[1] | 1010 | return rc;
|
---|
| 1011 | }
|
---|
| 1012 | if (fR0Enabled)
|
---|
| 1013 | {
|
---|
[2269] | 1014 | rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x20, 2, 0, "picIOPortWrite", "picIOPortRead", NULL, NULL, "i8259 PIC #0");
|
---|
[11262] | 1015 | if (RT_FAILURE(rc))
|
---|
[1] | 1016 | return rc;
|
---|
[2269] | 1017 | rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0xa0, 2, 1, "picIOPortWrite", "picIOPortRead", NULL, NULL, "i8259 PIC #1");
|
---|
[11262] | 1018 | if (RT_FAILURE(rc))
|
---|
[1] | 1019 | return rc;
|
---|
| 1020 | }
|
---|
| 1021 |
|
---|
[11264] | 1022 | rc = PDMDevHlpIOPortRegister(pDevIns, 0x4d0, 1, &pThis->aPics[0],
|
---|
[1] | 1023 | picIOPortElcrWrite, picIOPortElcrRead, NULL, NULL, "i8259 PIC #0 - elcr");
|
---|
[11262] | 1024 | if (RT_FAILURE(rc))
|
---|
[1] | 1025 | return rc;
|
---|
[11264] | 1026 | rc = PDMDevHlpIOPortRegister(pDevIns, 0x4d1, 1, &pThis->aPics[1],
|
---|
[1] | 1027 | picIOPortElcrWrite, picIOPortElcrRead, NULL, NULL, "i8259 PIC #1 - elcr");
|
---|
[11262] | 1028 | if (RT_FAILURE(rc))
|
---|
[1] | 1029 | return rc;
|
---|
| 1030 | if (fGCEnabled)
|
---|
| 1031 | {
|
---|
[11262] | 1032 | RTRCPTR pDataRC = PDMINS_2_DATA_RCPTR(pDevIns);
|
---|
[26157] | 1033 | rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x4d0, 1, pDataRC + RT_OFFSETOF(DEVPIC, aPics[0]),
|
---|
[1] | 1034 | "picIOPortElcrWrite", "picIOPortElcrRead", NULL, NULL, "i8259 PIC #0 - elcr");
|
---|
[11262] | 1035 | if (RT_FAILURE(rc))
|
---|
[1] | 1036 | return rc;
|
---|
[26157] | 1037 | rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x4d1, 1, pDataRC + RT_OFFSETOF(DEVPIC, aPics[1]),
|
---|
[1] | 1038 | "picIOPortElcrWrite", "picIOPortElcrRead", NULL, NULL, "i8259 PIC #1 - elcr");
|
---|
[11262] | 1039 | if (RT_FAILURE(rc))
|
---|
[1] | 1040 | return rc;
|
---|
| 1041 | }
|
---|
| 1042 | if (fR0Enabled)
|
---|
| 1043 | {
|
---|
[11262] | 1044 | RTR0PTR pDataR0 = PDMINS_2_DATA_R0PTR(pDevIns);
|
---|
[2269] | 1045 | rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x4d0, 1, pDataR0 + RT_OFFSETOF(DEVPIC, aPics[0]),
|
---|
[1] | 1046 | "picIOPortElcrWrite", "picIOPortElcrRead", NULL, NULL, "i8259 PIC #0 - elcr");
|
---|
[11262] | 1047 | if (RT_FAILURE(rc))
|
---|
[1] | 1048 | return rc;
|
---|
[2269] | 1049 | rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x4d1, 1, pDataR0 + RT_OFFSETOF(DEVPIC, aPics[1]),
|
---|
[1] | 1050 | "picIOPortElcrWrite", "picIOPortElcrRead", NULL, NULL, "i8259 PIC #1 - elcr");
|
---|
[11262] | 1051 | if (RT_FAILURE(rc))
|
---|
[1] | 1052 | return rc;
|
---|
| 1053 | }
|
---|
| 1054 |
|
---|
[22480] | 1055 | rc = PDMDevHlpSSMRegister(pDevIns, 1 /* uVersion */, sizeof(*pThis), picSaveExec, picLoadExec);
|
---|
[11262] | 1056 | if (RT_FAILURE(rc))
|
---|
[1] | 1057 | return rc;
|
---|
| 1058 |
|
---|
| 1059 |
|
---|
| 1060 | /*
|
---|
| 1061 | * Register the info item.
|
---|
| 1062 | */
|
---|
| 1063 | PDMDevHlpDBGFInfoRegister(pDevIns, "pic", "PIC info.", picInfo);
|
---|
| 1064 |
|
---|
| 1065 | /*
|
---|
| 1066 | * Initialize the device state.
|
---|
| 1067 | */
|
---|
| 1068 | picReset(pDevIns);
|
---|
| 1069 |
|
---|
| 1070 | #ifdef VBOX_WITH_STATISTICS
|
---|
| 1071 | /*
|
---|
| 1072 | * Statistics.
|
---|
| 1073 | */
|
---|
[20572] | 1074 | PDMDevHlpSTAMRegister(pDevIns, &pThis->StatSetIrqGC, STAMTYPE_COUNTER, "/Devices/PIC/SetIrqGC", STAMUNIT_OCCURENCES, "Number of PIC SetIrq calls in GC.");
|
---|
| 1075 | PDMDevHlpSTAMRegister(pDevIns, &pThis->StatSetIrqHC, STAMTYPE_COUNTER, "/Devices/PIC/SetIrqHC", STAMUNIT_OCCURENCES, "Number of PIC SetIrq calls in HC.");
|
---|
[1] | 1076 |
|
---|
[20572] | 1077 | PDMDevHlpSTAMRegister(pDevIns, &pThis->StatClearedActiveIRQ2, STAMTYPE_COUNTER, "/Devices/PIC/Masked/ActiveIRQ2", STAMUNIT_OCCURENCES, "Number of cleared irq 2.");
|
---|
| 1078 | PDMDevHlpSTAMRegister(pDevIns, &pThis->StatClearedActiveMasterIRQ, STAMTYPE_COUNTER, "/Devices/PIC/Masked/ActiveMaster", STAMUNIT_OCCURENCES, "Number of cleared master irqs.");
|
---|
| 1079 | PDMDevHlpSTAMRegister(pDevIns, &pThis->StatClearedActiveSlaveIRQ, STAMTYPE_COUNTER, "/Devices/PIC/Masked/ActiveSlave", STAMUNIT_OCCURENCES, "Number of cleared slave irqs.");
|
---|
[1] | 1080 | #endif
|
---|
| 1081 |
|
---|
| 1082 | return VINF_SUCCESS;
|
---|
| 1083 | }
|
---|
| 1084 |
|
---|
| 1085 |
|
---|
| 1086 | /**
|
---|
| 1087 | * The device registration structure.
|
---|
| 1088 | */
|
---|
| 1089 | const PDMDEVREG g_DeviceI8259 =
|
---|
| 1090 | {
|
---|
| 1091 | /* u32Version */
|
---|
| 1092 | PDM_DEVREG_VERSION,
|
---|
[26165] | 1093 | /* szName */
|
---|
[1] | 1094 | "i8259",
|
---|
[12977] | 1095 | /* szRCMod */
|
---|
[1] | 1096 | "VBoxDDGC.gc",
|
---|
| 1097 | /* szR0Mod */
|
---|
| 1098 | "VBoxDDR0.r0",
|
---|
| 1099 | /* pszDescription */
|
---|
[2781] | 1100 | "Intel 8259 Programmable Interrupt Controller (PIC) Device.",
|
---|
[1] | 1101 | /* fFlags */
|
---|
[12977] | 1102 | PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64 | PDM_DEVREG_FLAGS_PAE36 | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
|
---|
[1] | 1103 | /* fClass */
|
---|
| 1104 | PDM_DEVREG_CLASS_PIC,
|
---|
| 1105 | /* cMaxInstances */
|
---|
| 1106 | 1,
|
---|
| 1107 | /* cbInstance */
|
---|
| 1108 | sizeof(DEVPIC),
|
---|
| 1109 | /* pfnConstruct */
|
---|
| 1110 | picConstruct,
|
---|
| 1111 | /* pfnDestruct */
|
---|
| 1112 | NULL,
|
---|
| 1113 | /* pfnRelocate */
|
---|
| 1114 | picRelocate,
|
---|
| 1115 | /* pfnIOCtl */
|
---|
| 1116 | NULL,
|
---|
| 1117 | /* pfnPowerOn */
|
---|
| 1118 | NULL,
|
---|
| 1119 | /* pfnReset */
|
---|
| 1120 | picReset,
|
---|
| 1121 | /* pfnSuspend */
|
---|
| 1122 | NULL,
|
---|
| 1123 | /* pfnResume */
|
---|
| 1124 | NULL,
|
---|
| 1125 | /* pfnAttach */
|
---|
| 1126 | NULL,
|
---|
| 1127 | /* pfnDetach */
|
---|
| 1128 | NULL,
|
---|
| 1129 | /* pfnQueryInterface. */
|
---|
[12977] | 1130 | NULL,
|
---|
| 1131 | /* pfnInitComplete */
|
---|
| 1132 | NULL,
|
---|
| 1133 | /* pfnPowerOff */
|
---|
| 1134 | NULL,
|
---|
| 1135 | /* pfnSoftReset */
|
---|
| 1136 | NULL,
|
---|
| 1137 | /* u32VersionEnd */
|
---|
| 1138 | PDM_DEVREG_VERSION
|
---|
[1] | 1139 | };
|
---|
| 1140 |
|
---|
| 1141 | #endif /* IN_RING3 */
|
---|
[490] | 1142 | #endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
|
---|
[1] | 1143 |
|
---|