diff options
Diffstat (limited to 'src/VBox/Devices/PC/DevPIC.cpp')
-rw-r--r-- | src/VBox/Devices/PC/DevPIC.cpp | 686 |
1 files changed, 329 insertions, 357 deletions
diff --git a/src/VBox/Devices/PC/DevPIC.cpp b/src/VBox/Devices/PC/DevPIC.cpp index a95f0bad..10fe2a0c 100644 --- a/src/VBox/Devices/PC/DevPIC.cpp +++ b/src/VBox/Devices/PC/DevPIC.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -13,8 +13,35 @@ * Foundation, in version 2 as it comes in the "COPYING" file of the * VirtualBox OSE distribution. VirtualBox OSE is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * ------------------------------------------------------------------- + * + * This code is based on: + * + * QEMU 8259 interrupt controller emulation + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * */ + /******************************************************************************* * Header Files * *******************************************************************************/ @@ -44,58 +71,21 @@ (pThis)->CTX_SUFF(pPicHlp)->pfnUnlock((pThis)->CTX_SUFF(pDevIns)) -#ifndef VBOX_DEVICE_STRUCT_TESTCASE -/******************************************************************************* -* Internal Functions * -*******************************************************************************/ -RT_C_DECLS_BEGIN - -PDMBOTHCBDECL(void) picSetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel, uint32_t uTagSrc); -PDMBOTHCBDECL(int) picGetInterrupt(PPDMDEVINS pDevIns, uint32_t *puTagSrc); -PDMBOTHCBDECL(int) picIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb); -PDMBOTHCBDECL(int) picIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb); -PDMBOTHCBDECL(int) picIOPortElcrRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb); -PDMBOTHCBDECL(int) picIOPortElcrWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb); - -RT_C_DECLS_END -#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */ - - -/* - * QEMU 8259 interrupt controller emulation - * - * Copyright (c) 2003-2004 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - /* debug PIC */ #define DEBUG_PIC /*#define DEBUG_IRQ_COUNT*/ -typedef struct PicState { - uint8_t last_irr; /* edge detection */ - uint8_t irr; /* interrupt request register */ - uint8_t imr; /* interrupt mask register */ - uint8_t isr; /* interrupt service register */ - uint8_t priority_add; /* highest irq priority */ +/** + * The instance data of one (1) PIC. + */ +typedef struct PICSTATE +{ + uint8_t last_irr; /**< edge detection */ + uint8_t irr; /**< interrupt request register */ + uint8_t imr; /**< interrupt mask register */ + uint8_t isr; /**< interrupt service register */ + uint8_t priority_add; /**< highest irq priority */ uint8_t irq_base; uint8_t read_reg_select; uint8_t poll; @@ -104,8 +94,8 @@ typedef struct PicState { uint8_t auto_eoi; uint8_t rotate_on_auto_eoi; uint8_t special_fully_nested_mode; - uint8_t init4; /* true if 4 byte init */ - uint8_t elcr; /* PIIX edge/trigger selection*/ + uint8_t init4; /**< true if 4 byte init */ + uint8_t elcr; /**< PIIX edge/trigger selection*/ uint8_t elcr_mask; /** Pointer to the device instance, R3 Ptr. */ PPDMDEVINSR3 pDevInsR3; @@ -113,19 +103,23 @@ typedef struct PicState { PPDMDEVINSR0 pDevInsR0; /** Pointer to the device instance, RC Ptr. */ PPDMDEVINSRC pDevInsRC; - RTRCPTR Alignment0; /**< Structure size alignment. */ + /** The PIC index (0 or 1). */ + uint8_t idxPic; + uint8_t abAlignment0[3]; /**< Alignment padding. */ /** The IRQ tags and source IDs for each (tracing purposes). */ uint32_t auTags[8]; +} PICSTATE; +/** Pointer to the state of one PIC. */ +typedef PICSTATE *PPICSTATE; -} PicState; /** - * A PIC device instance data. + * The whole PIC device instance data. */ typedef struct DEVPIC { /** The two interrupt controllers. */ - PicState aPics[2]; + PICSTATE aPics[2]; /** Pointer to the device instance - R3 Ptr. */ PPDMDEVINSR3 pDevInsR3; /** Pointer to the PIC R3 helpers. */ @@ -148,128 +142,140 @@ typedef struct DEVPIC STAMCOUNTER StatClearedActiveMasterIRQ; STAMCOUNTER StatClearedActiveSlaveIRQ; #endif -} DEVPIC, *PDEVPIC; +} DEVPIC; +/** Pointer to the whole PIC instance data. */ +typedef DEVPIC *PDEVPIC; #ifndef VBOX_DEVICE_STRUCT_TESTCASE #ifdef LOG_ENABLED -static inline void DumpPICState(PicState *s, const char *szFn) +DECLINLINE(void) DumpPICState(PPICSTATE pPic, const char *pszFn) { - PDEVPIC pThis = PDMINS_2_DATA(s->CTX_SUFF(pDevIns), PDEVPIC); + PDEVPIC pThis = PDMINS_2_DATA(pPic->CTX_SUFF(pDevIns), PDEVPIC); Log2(("%s: pic%d: elcr=%x last_irr=%x irr=%x imr=%x isr=%x irq_base=%x\n", - szFn, (&pThis->aPics[0] == s) ? 0 : 1, - s->elcr, s->last_irr, s->irr, s->imr, s->isr, s->irq_base)); + pszFn, (&pThis->aPics[0] == pPic) ? 0 : 1, + pPic->elcr, pPic->last_irr, pPic->irr, pPic->imr, pPic->isr, pPic->irq_base)); } #else # define DumpPICState(pThis, szFn) do { } while (0) #endif /* set irq level. If an edge is detected, then the IRR is set to 1 */ -static inline void pic_set_irq1(PicState *s, int irq, int level, uint32_t uTagSrc) +DECLINLINE(void) pic_set_irq1(PPICSTATE pPic, int irq, int level, uint32_t uTagSrc) { - int mask; Log(("pic_set_irq1: irq=%d level=%d\n", irq, level)); - mask = 1 << irq; - if (s->elcr & mask) { + int mask = 1 << irq; + if (pPic->elcr & mask) + { /* level triggered */ - if (level) { - Log2(("pic_set_irq1(ls) irr=%d irrnew=%d\n", s->irr, s->irr | mask)); - s->irr |= mask; - s->last_irr |= mask; - } else { - Log2(("pic_set_irq1(lc) irr=%d irrnew=%d\n", s->irr, s->irr & ~mask)); - s->irr &= ~mask; - s->last_irr &= ~mask; + if (level) + { + Log2(("pic_set_irq1(ls) irr=%d irrnew=%d\n", pPic->irr, pPic->irr | mask)); + pPic->irr |= mask; + pPic->last_irr |= mask; + } + else + { + Log2(("pic_set_irq1(lc) irr=%d irrnew=%d\n", pPic->irr, pPic->irr & ~mask)); + pPic->irr &= ~mask; + pPic->last_irr &= ~mask; } - } else { + } + else + { /* edge triggered */ - if (level) { - if ((s->last_irr & mask) == 0) + if (level) + { + if ((pPic->last_irr & mask) == 0) { - Log2(("pic_set_irq1 irr=%x last_irr=%x\n", s->irr | mask, s->last_irr)); - s->irr |= mask; + Log2(("pic_set_irq1 irr=%x last_irr=%x\n", pPic->irr | mask, pPic->last_irr)); + pPic->irr |= mask; } - s->last_irr |= mask; - } else { - s->irr &= ~mask; - s->last_irr &= ~mask; + pPic->last_irr |= mask; + } + else + { + pPic->irr &= ~mask; + pPic->last_irr &= ~mask; } } /* Save the tag. */ if (level) { - if (!s->auTags[irq]) - s->auTags[irq] = uTagSrc; + if (!pPic->auTags[irq]) + pPic->auTags[irq] = uTagSrc; else - s->auTags[irq] |= RT_BIT_32(31); + pPic->auTags[irq] |= RT_BIT_32(31); } - DumpPICState(s, "pic_set_irq1"); + DumpPICState(pPic, "pic_set_irq1"); } /* return the highest priority found in mask (highest = smallest number). Return 8 if no irq */ -static inline int get_priority(PicState *s, int mask) +DECLINLINE(int) get_priority(PPICSTATE pPic, int mask) { int priority; if (mask == 0) return 8; priority = 0; - while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0) + while ((mask & (1 << ((priority + pPic->priority_add) & 7))) == 0) priority++; return priority; } /* return the pic wanted interrupt. return -1 if none */ -static int pic_get_irq(PicState *s) +static int pic_get_irq(PPICSTATE pPic) { - PicState *pics = &(PDMINS_2_DATA(s->CTX_SUFF(pDevIns), PDEVPIC))->aPics[0]; int mask, cur_priority, priority; - Log(("pic_get_irq%d: mask=%x\n", (s == pics) ? 0 : 1, s->irr & ~s->imr)); - DumpPICState(s, "pic_get_irq"); + Log(("pic_get_irq%d: mask=%x\n", pPic->idxPic, pPic->irr & ~pPic->imr)); + DumpPICState(pPic, "pic_get_irq"); - mask = s->irr & ~s->imr; - priority = get_priority(s, mask); + mask = pPic->irr & ~pPic->imr; + priority = get_priority(pPic, mask); Log(("pic_get_irq: priority=%x\n", priority)); if (priority == 8) return -1; /* compute current priority. If special fully nested mode on the master, the IRQ coming from the slave is not taken into account for the priority computation. */ - mask = s->isr; - if (s->special_fully_nested_mode && s == &pics[0]) + mask = pPic->isr; + if (pPic->special_fully_nested_mode && pPic->idxPic == 0) mask &= ~(1 << 2); - cur_priority = get_priority(s, mask); - 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)); - if (priority < cur_priority) { + cur_priority = get_priority(pPic, mask); + Log(("pic_get_irq%d: cur_priority=%x pending=%d\n", pPic->idxPic, + cur_priority, (priority == 8) ? -1 : (priority + pPic->priority_add) & 7)); + if (priority < cur_priority) + { /* higher priority found: an irq should be generated */ - return (priority + s->priority_add) & 7; - } else { - return -1; + return (priority + pPic->priority_add) & 7; } + return -1; } /* raise irq to CPU if necessary. must be called every time the active irq may change */ static int pic_update_irq(PDEVPIC pThis) { - PicState *pics = &pThis->aPics[0]; int irq2, irq; /* first look at slave pic */ - irq2 = pic_get_irq(&pics[1]); + irq2 = pic_get_irq(&pThis->aPics[1]); Log(("pic_update_irq irq2=%d\n", irq2)); - if (irq2 >= 0) { + if (irq2 >= 0) + { /* if irq request by slave pic, signal master PIC */ - pic_set_irq1(&pics[0], 2, 1, pics[1].auTags[irq2]); - } else { + pic_set_irq1(&pThis->aPics[0], 2, 1, pThis->aPics[1].auTags[irq2]); + } + else + { /* If not, clear the IR on the master PIC. */ - pic_set_irq1(&pics[0], 2, 0, 0 /*uTagSrc*/); + pic_set_irq1(&pThis->aPics[0], 2, 0, 0 /*uTagSrc*/); } /* look at requested irq */ - irq = pic_get_irq(&pics[0]); + irq = pic_get_irq(&pThis->aPics[0]); if (irq >= 0) { /* If irq 2 is pending on the master pic, then there must be one pending on the slave pic too! Otherwise we'll get @@ -278,12 +284,8 @@ static int pic_update_irq(PDEVPIC pThis) if (irq != 2 || irq2 != -1) { #if defined(DEBUG_PIC) - int i; - for(i = 0; i < 2; i++) { - Log(("pic%d: imr=%x irr=%x padd=%d\n", - i, pics[i].imr, pics[i].irr, - pics[i].priority_add)); - } + for (int i = 0; i < 2; i++) + Log(("pic%d: imr=%x irr=%x padd=%d\n", i, pThis->aPics[i].imr, pThis->aPics[i].irr, pThis->aPics[i].priority_add)); Log(("pic: cpu_interrupt\n")); #endif pThis->CTX_SUFF(pPicHlp)->pfnSetInterruptFF(pThis->CTX_SUFF(pDevIns)); @@ -297,8 +299,8 @@ static int pic_update_irq(PDEVPIC pThis) /* if this was the only pending irq, then we must clear the interrupt ff flag */ pThis->CTX_SUFF(pPicHlp)->pfnClearInterruptFF(pThis->CTX_SUFF(pDevIns)); - /** @note Is this correct? */ - pics[0].irr &= ~(1 << 2); + /** @todo Is this correct? */ + pThis->aPics[0].irr &= ~(1 << 2); /* Call ourselves again just in case other interrupts are pending */ return pic_update_irq(pThis); @@ -315,10 +317,10 @@ static int pic_update_irq(PDEVPIC pThis) } /** @note if an interrupt line state changes from unmasked to masked, then it must be deactivated when currently pending! */ -static void pic_update_imr(PDEVPIC pThis, PicState *s, uint8_t val) +static void pic_update_imr(PDEVPIC pThis, PPICSTATE pPic, uint8_t val) { int irq, intno; - PicState *pActivePIC; + PPICSTATE pActivePIC; /* Query the current pending irq, if any. */ pActivePIC = &pThis->aPics[0]; @@ -331,7 +333,8 @@ static void pic_update_imr(PDEVPIC pThis, PicState *s, uint8_t val) } /* Update IMR */ - s->imr = val; + Log(("pic_update_imr: pic%u %#x -> %#x\n", pPic->idxPic, pPic->imr, val)); + pPic->imr = val; /* If an interrupt is pending and now masked, then clear the FF flag. */ if ( irq >= 0 @@ -393,19 +396,21 @@ PDMBOTHCBDECL(void) picSetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel, uint32_t /* acknowledge interrupt 'irq' */ -static inline void pic_intack(PicState *s, int irq) +DECLINLINE(void) pic_intack(PPICSTATE pPic, int irq) { - if (s->auto_eoi) { - if (s->rotate_on_auto_eoi) - s->priority_add = (irq + 1) & 7; - } else { - s->isr |= (1 << irq); + if (pPic->auto_eoi) + { + if (pPic->rotate_on_auto_eoi) + pPic->priority_add = (irq + 1) & 7; } + else + pPic->isr |= (1 << irq); + /* We don't clear a level sensitive interrupt here */ - if (!(s->elcr & (1 << irq))) + if (!(pPic->elcr & (1 << irq))) { - Log2(("pic_intack: irr=%x irrnew=%x\n", s->irr, s->irr & ~(1 << irq))); - s->irr &= ~(1 << irq); + Log2(("pic_intack: irr=%x irrnew=%x\n", pPic->irr, pPic->irr & ~(1 << irq))); + pPic->irr &= ~(1 << irq); } } @@ -435,9 +440,8 @@ PDMBOTHCBDECL(int) picGetInterrupt(PPDMDEVINS pDevIns, uint32_t *puTagSrc) if (irq == 2) { irq2 = pic_get_irq(&pThis->aPics[1]); - if (irq2 >= 0) { + if (irq2 >= 0) pic_intack(&pThis->aPics[1], irq2); - } else { /* Interrupt went away or is now masked. */ @@ -473,165 +477,172 @@ PDMBOTHCBDECL(int) picGetInterrupt(PPDMDEVINS pDevIns, uint32_t *puTagSrc) return intno; } -static void pic_reset(PicState *s) +static void pic_reset(PPICSTATE pPic) { - PPDMDEVINSR3 pDevInsR3 = s->pDevInsR3; - PPDMDEVINSR0 pDevInsR0 = s->pDevInsR0; - PPDMDEVINSRC pDevInsRC = s->pDevInsRC; - int elcr_mask = s->elcr_mask; - int elcr = s->elcr; - - memset(s, 0, sizeof(PicState)); - - s->elcr = elcr; - s->elcr_mask = elcr_mask; - s->pDevInsRC = pDevInsRC; - s->pDevInsR0 = pDevInsR0; - s->pDevInsR3 = pDevInsR3; + PPDMDEVINSR3 pDevInsR3 = pPic->pDevInsR3; + PPDMDEVINSR0 pDevInsR0 = pPic->pDevInsR0; + PPDMDEVINSRC pDevInsRC = pPic->pDevInsRC; + int elcr_mask = pPic->elcr_mask; + int elcr = pPic->elcr; + + memset(pPic, 0, sizeof(*pPic)); + + pPic->elcr = elcr; + pPic->elcr_mask = elcr_mask; + pPic->pDevInsRC = pDevInsRC; + pPic->pDevInsR0 = pDevInsR0; + pPic->pDevInsR3 = pDevInsR3; } -static int pic_ioport_write(void *opaque, uint32_t addr, uint32_t val) +static int pic_ioport_write(PDEVPIC pThis, PPICSTATE pPic, uint32_t addr, uint32_t val) { - PicState *s = (PicState*)opaque; - PDEVPIC pThis = PDMINS_2_DATA(s->CTX_SUFF(pDevIns), PDEVPIC); int rc = VINF_SUCCESS; - int priority, cmd, irq; + int irq; Log(("pic_write: addr=0x%02x val=0x%02x\n", addr, val)); addr &= 1; - if (addr == 0) { - if (val & 0x10) { + if (addr == 0) + { + if (val & 0x10) + { /* init */ - pic_reset(s); + pic_reset(pPic); /* deassert a pending interrupt */ pThis->CTX_SUFF(pPicHlp)->pfnClearInterruptFF(pThis->CTX_SUFF(pDevIns)); - s->init_state = 1; - s->init4 = val & 1; + pPic->init_state = 1; + pPic->init4 = val & 1; if (val & 0x02) AssertReleaseMsgFailed(("single mode not supported")); if (val & 0x08) if (pThis->cRelLogEntries++ < 64) LogRel(("pic_write: Level sensitive IRQ setting ignored.\n")); - } else if (val & 0x08) { + } + else if (val & 0x08) + { if (val & 0x04) - s->poll = 1; + pPic->poll = 1; if (val & 0x02) - s->read_reg_select = val & 1; + pPic->read_reg_select = val & 1; if (val & 0x40) - s->special_mask = (val >> 5) & 1; - } else { - cmd = val >> 5; - switch(cmd) { - case 0: - case 4: - s->rotate_on_auto_eoi = cmd >> 2; - break; - case 1: /* end of interrupt */ - case 5: + pPic->special_mask = (val >> 5) & 1; + } + else + { + int cmd = val >> 5; + switch (cmd) { - priority = get_priority(s, s->isr); - if (priority != 8) { - irq = (priority + s->priority_add) & 7; - Log(("pic_write: EOI prio=%d irq=%d\n", priority, irq)); - s->isr &= ~(1 << irq); - if (cmd == 5) - s->priority_add = (irq + 1) & 7; + case 0: + case 4: + pPic->rotate_on_auto_eoi = cmd >> 2; + break; + case 1: /* end of interrupt */ + case 5: + { + int priority = get_priority(pPic, pPic->isr); + if (priority != 8) { + irq = (priority + pPic->priority_add) & 7; + Log(("pic_write: EOI prio=%d irq=%d\n", priority, irq)); + pPic->isr &= ~(1 << irq); + if (cmd == 5) + pPic->priority_add = (irq + 1) & 7; + rc = pic_update_irq(pThis); + Assert(rc == VINF_SUCCESS); + DumpPICState(pPic, "eoi"); + } + break; + } + case 3: + { + irq = val & 7; + Log(("pic_write: EOI2 for irq %d\n", irq)); + pPic->isr &= ~(1 << irq); rc = pic_update_irq(pThis); Assert(rc == VINF_SUCCESS); - DumpPICState(s, "eoi"); + DumpPICState(pPic, "eoi2"); + break; } - break; + case 6: + { + pPic->priority_add = (val + 1) & 7; + Log(("pic_write: lowest priority %d (highest %d)\n", val & 7, pPic->priority_add)); + rc = pic_update_irq(pThis); + Assert(rc == VINF_SUCCESS); + break; + } + case 7: + { + irq = val & 7; + Log(("pic_write: EOI3 for irq %d\n", irq)); + pPic->isr &= ~(1 << irq); + pPic->priority_add = (irq + 1) & 7; + rc = pic_update_irq(pThis); + Assert(rc == VINF_SUCCESS); + DumpPICState(pPic, "eoi3"); + break; + } + default: + /* no operation */ + break; } - case 3: - { - irq = val & 7; - Log(("pic_write: EOI2 for irq %d\n", irq)); - s->isr &= ~(1 << irq); + } + } + else + { + switch (pPic->init_state) + { + case 0: + /* normal mode */ + pic_update_imr(pThis, pPic, val); + rc = pic_update_irq(pThis); Assert(rc == VINF_SUCCESS); - DumpPICState(s, "eoi2"); break; - } - case 6: - { - s->priority_add = (val + 1) & 7; - Log(("pic_write: lowest priority %d (highest %d)\n", val & 7, s->priority_add)); - rc = pic_update_irq(pThis); - Assert(rc == VINF_SUCCESS); + case 1: + pPic->irq_base = val & 0xf8; + pPic->init_state = 2; + Log(("pic_write: set irq base to %x\n", pPic->irq_base)); break; - } - case 7: - { - irq = val & 7; - Log(("pic_write: EOI3 for irq %d\n", irq)); - s->isr &= ~(1 << irq); - s->priority_add = (irq + 1) & 7; - rc = pic_update_irq(pThis); - Assert(rc == VINF_SUCCESS); - DumpPICState(s, "eoi3"); + case 2: + if (pPic->init4) + pPic->init_state = 3; + else + pPic->init_state = 0; break; - } - default: - /* no operation */ + case 3: + pPic->special_fully_nested_mode = (val >> 4) & 1; + pPic->auto_eoi = (val >> 1) & 1; + pPic->init_state = 0; + Log(("pic_write: special_fully_nested_mode=%d auto_eoi=%d\n", pPic->special_fully_nested_mode, pPic->auto_eoi)); break; - } - } - } else { - switch(s->init_state) { - case 0: - { - /* normal mode */ - pic_update_imr(pThis, s, val); - - rc = pic_update_irq(pThis); - Assert(rc == VINF_SUCCESS); - break; - } - case 1: - s->irq_base = val & 0xf8; - s->init_state = 2; - Log(("pic_write: set irq base to %x\n", s->irq_base)); - break; - case 2: - if (s->init4) { - s->init_state = 3; - } else { - s->init_state = 0; - } - break; - case 3: - s->special_fully_nested_mode = (val >> 4) & 1; - s->auto_eoi = (val >> 1) & 1; - s->init_state = 0; - Log(("pic_write: special_fully_nested_mode=%d auto_eoi=%d\n", s->special_fully_nested_mode, s->auto_eoi)); - break; } } return rc; } -static uint32_t pic_poll_read (PicState *s, uint32_t addr1) +static uint32_t pic_poll_read(PPICSTATE pPic, uint32_t addr1) { - PDEVPIC pThis = PDMINS_2_DATA(s->CTX_SUFF(pDevIns), PDEVPIC); - PicState *pics = &pThis->aPics[0]; - int ret; + PDEVPIC pThis = RT_FROM_MEMBER(pPic, DEVPIC, aPics[pPic->idxPic]); - ret = pic_get_irq(s); - if (ret >= 0) { - if (addr1 >> 7) { + int ret = pic_get_irq(pPic); + if (ret >= 0) + { + if (addr1 >> 7) + { Log2(("pic_poll_read: clear slave irq (isr)\n")); - pics[0].isr &= ~(1 << 2); - pics[0].irr &= ~(1 << 2); + pThis->aPics[0].isr &= ~(1 << 2); + pThis->aPics[0].irr &= ~(1 << 2); } Log2(("pic_poll_read: clear irq %d (isr)\n", ret)); - s->irr &= ~(1 << ret); - s->isr &= ~(1 << ret); + pPic->irr &= ~(1 << ret); + pPic->isr &= ~(1 << ret); if (addr1 >> 7 || ret != 2) pic_update_irq(pThis); - } else { + } + else + { ret = 0; pic_update_irq(pThis); } @@ -640,9 +651,8 @@ static uint32_t pic_poll_read (PicState *s, uint32_t addr1) } -static uint32_t pic_ioport_read(void *opaque, uint32_t addr1, int *pRC) +static uint32_t pic_ioport_read(PPICSTATE pPic, uint32_t addr1, int *pRC) { - PicState *s = (PicState*)opaque; unsigned int addr; int ret; @@ -650,18 +660,22 @@ static uint32_t pic_ioport_read(void *opaque, uint32_t addr1, int *pRC) addr = addr1; addr &= 1; - if (s->poll) { - ret = pic_poll_read(s, addr1); - s->poll = 0; - } else { - if (addr == 0) { - if (s->read_reg_select) - ret = s->isr; + if (pPic->poll) + { + ret = pic_poll_read(pPic, addr1); + pPic->poll = 0; + } + else + { + if (addr == 0) + { + if (pPic->read_reg_select) + ret = pPic->isr; else - ret = s->irr; - } else { - ret = s->imr; + ret = pPic->irr; } + else + ret = pPic->imr; } Log(("pic_read: addr=0x%02x val=0x%02x\n", addr1, ret)); return ret; @@ -669,18 +683,10 @@ static uint32_t pic_ioport_read(void *opaque, uint32_t addr1, int *pRC) -/* -=-=-=-=-=- wrappers / stuff -=-=-=-=-=- */ +/* -=-=-=-=-=- I/O ports -=-=-=-=-=- */ /** - * Port I/O Handler for IN operations. - * - * @returns VBox status code. - * - * @param pDevIns The device instance. - * @param pvUser User argument - pointer to the PIC in question. - * @param uPort Port number used for the IN operation. - * @param pu32 Where to store the result. - * @param cb Number of bytes read. + * @callback_method_impl{FNIOMIOPORTIN} */ PDMBOTHCBDECL(int) picIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb) { @@ -699,16 +705,9 @@ PDMBOTHCBDECL(int) picIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port return VERR_IOM_IOPORT_UNUSED; } + /** - * Port I/O Handler for OUT operations. - * - * @returns VBox status code. - * - * @param pDevIns The device instance. - * @param pvUser User argument - pointer to the PIC in question. - * @param uPort Port number used for the IN operation. - * @param u32 The value to output. - * @param cb The value size in bytes. + * @callback_method_impl{FNIOMIOPORTOUT} */ PDMBOTHCBDECL(int) picIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb) { @@ -721,7 +720,7 @@ PDMBOTHCBDECL(int) picIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Por { int rc; PIC_LOCK(pThis, VINF_IOM_R3_IOPORT_WRITE); - rc = pic_ioport_write(&pThis->aPics[iPic], Port, u32); + rc = pic_ioport_write(pThis, &pThis->aPics[iPic], Port, u32); PIC_UNLOCK(pThis); return rc; } @@ -730,23 +729,15 @@ PDMBOTHCBDECL(int) picIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Por /** - * Port I/O Handler for IN operations. - * - * @returns VBox status code. - * - * @param pDevIns The device instance. - * @param pvUser User argument - pointer to the PIC in question. - * @param uPort Port number used for the IN operation. - * @param pu32 Where to store the result. - * @param cb Number of bytes read. + * @callback_method_impl{FNIOMIOPORTIN, ELCR} */ PDMBOTHCBDECL(int) picIOPortElcrRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb) { if (cb == 1) { - PicState *s = (PicState*)pvUser; + PPICSTATE pPic = (PPICSTATE)pvUser; PIC_LOCK(PDMINS_2_DATA(pDevIns, PDEVPIC), VINF_IOM_R3_IOPORT_READ); - *pu32 = s->elcr; + *pu32 = pPic->elcr; PIC_UNLOCK(PDMINS_2_DATA(pDevIns, PDEVPIC)); return VINF_SUCCESS; } @@ -754,24 +745,17 @@ PDMBOTHCBDECL(int) picIOPortElcrRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT return VERR_IOM_IOPORT_UNUSED; } + /** - * Port I/O Handler for OUT operations. - * - * @returns VBox status code. - * - * @param pDevIns The device instance. - * @param pvUser User argument - pointer to the PIC in question. - * @param uPort Port number used for the IN operation. - * @param u32 The value to output. - * @param cb The value size in bytes. + * @callback_method_impl{FNIOMIOPORTOUT, ELCR} */ PDMBOTHCBDECL(int) picIOPortElcrWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb) { if (cb == 1) { - PicState *s = (PicState*)pvUser; + PPICSTATE pPic = (PPICSTATE)pvUser; PIC_LOCK(PDMINS_2_DATA(pDevIns, PDEVPIC), VINF_IOM_R3_IOPORT_WRITE); - s->elcr = u32 & s->elcr_mask; + pPic->elcr = u32 & pPic->elcr_mask; PIC_UNLOCK(PDMINS_2_DATA(pDevIns, PDEVPIC)); } NOREF(Port); @@ -782,11 +766,7 @@ PDMBOTHCBDECL(int) picIOPortElcrWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT #ifdef IN_RING3 /** - * PIC status info callback. - * - * @param pDevIns The device instance. - * @param pHlp The output helpers. - * @param pszArgs The arguments. + * @callback_method_impl{FNDBGFINFOHANDLERDEV} */ static DECLCALLBACK(void) picInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs) { @@ -798,7 +778,7 @@ static DECLCALLBACK(void) picInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const */ for (int i = 0; i < 2; i++) { - PicState *pPic = &pThis->aPics[i]; + PPICSTATE pPic = &pThis->aPics[i]; pHlp->pfnPrintf(pHlp, "PIC%d:\n", i); pHlp->pfnPrintf(pHlp, " IMR :%02x ISR :%02x IRR :%02x LIRR:%02x\n", @@ -814,48 +794,41 @@ static DECLCALLBACK(void) picInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const } } + +/* -=-=-=-=-=- Saved State -=-=-=-=-=- */ + /** - * Saves a state of the programmable interrupt controller device. - * - * @returns VBox status code. - * @param pDevIns The device instance. - * @param pSSMHandle The handle to save the state to. + * @callback_method_impl{FNSSMDEVSAVEEXEC} */ -static DECLCALLBACK(int) picSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle) +static DECLCALLBACK(int) picSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM) { PDEVPIC pThis = PDMINS_2_DATA(pDevIns, PDEVPIC); for (unsigned i = 0; i < RT_ELEMENTS(pThis->aPics); i++) { - SSMR3PutU8(pSSMHandle, pThis->aPics[i].last_irr); - SSMR3PutU8(pSSMHandle, pThis->aPics[i].irr); - SSMR3PutU8(pSSMHandle, pThis->aPics[i].imr); - SSMR3PutU8(pSSMHandle, pThis->aPics[i].isr); - SSMR3PutU8(pSSMHandle, pThis->aPics[i].priority_add); - SSMR3PutU8(pSSMHandle, pThis->aPics[i].irq_base); - SSMR3PutU8(pSSMHandle, pThis->aPics[i].read_reg_select); - SSMR3PutU8(pSSMHandle, pThis->aPics[i].poll); - SSMR3PutU8(pSSMHandle, pThis->aPics[i].special_mask); - SSMR3PutU8(pSSMHandle, pThis->aPics[i].init_state); - SSMR3PutU8(pSSMHandle, pThis->aPics[i].auto_eoi); - SSMR3PutU8(pSSMHandle, pThis->aPics[i].rotate_on_auto_eoi); - SSMR3PutU8(pSSMHandle, pThis->aPics[i].special_fully_nested_mode); - SSMR3PutU8(pSSMHandle, pThis->aPics[i].init4); - SSMR3PutU8(pSSMHandle, pThis->aPics[i].elcr); + SSMR3PutU8(pSSM, pThis->aPics[i].last_irr); + SSMR3PutU8(pSSM, pThis->aPics[i].irr); + SSMR3PutU8(pSSM, pThis->aPics[i].imr); + SSMR3PutU8(pSSM, pThis->aPics[i].isr); + SSMR3PutU8(pSSM, pThis->aPics[i].priority_add); + SSMR3PutU8(pSSM, pThis->aPics[i].irq_base); + SSMR3PutU8(pSSM, pThis->aPics[i].read_reg_select); + SSMR3PutU8(pSSM, pThis->aPics[i].poll); + SSMR3PutU8(pSSM, pThis->aPics[i].special_mask); + SSMR3PutU8(pSSM, pThis->aPics[i].init_state); + SSMR3PutU8(pSSM, pThis->aPics[i].auto_eoi); + SSMR3PutU8(pSSM, pThis->aPics[i].rotate_on_auto_eoi); + SSMR3PutU8(pSSM, pThis->aPics[i].special_fully_nested_mode); + SSMR3PutU8(pSSM, pThis->aPics[i].init4); + SSMR3PutU8(pSSM, pThis->aPics[i].elcr); } return VINF_SUCCESS; } /** - * Loads a saved programmable interrupt controller device state. - * - * @returns VBox status code. - * @param pDevIns The device instance. - * @param pSSMHandle The handle to the saved state. - * @param uVersion The data unit version number. - * @param uPass The data pass. + * @callback_method_impl{FNSSMDEVLOADEXEC} */ -static DECLCALLBACK(int) picLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle, uint32_t uVersion, uint32_t uPass) +static DECLCALLBACK(int) picLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass) { PDEVPIC pThis = PDMINS_2_DATA(pDevIns, PDEVPIC); @@ -865,33 +838,30 @@ static DECLCALLBACK(int) picLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle, for (unsigned i = 0; i < RT_ELEMENTS(pThis->aPics); i++) { - SSMR3GetU8(pSSMHandle, &pThis->aPics[i].last_irr); - SSMR3GetU8(pSSMHandle, &pThis->aPics[i].irr); - SSMR3GetU8(pSSMHandle, &pThis->aPics[i].imr); - SSMR3GetU8(pSSMHandle, &pThis->aPics[i].isr); - SSMR3GetU8(pSSMHandle, &pThis->aPics[i].priority_add); - SSMR3GetU8(pSSMHandle, &pThis->aPics[i].irq_base); - SSMR3GetU8(pSSMHandle, &pThis->aPics[i].read_reg_select); - SSMR3GetU8(pSSMHandle, &pThis->aPics[i].poll); - SSMR3GetU8(pSSMHandle, &pThis->aPics[i].special_mask); - SSMR3GetU8(pSSMHandle, &pThis->aPics[i].init_state); - SSMR3GetU8(pSSMHandle, &pThis->aPics[i].auto_eoi); - SSMR3GetU8(pSSMHandle, &pThis->aPics[i].rotate_on_auto_eoi); - SSMR3GetU8(pSSMHandle, &pThis->aPics[i].special_fully_nested_mode); - SSMR3GetU8(pSSMHandle, &pThis->aPics[i].init4); - SSMR3GetU8(pSSMHandle, &pThis->aPics[i].elcr); + SSMR3GetU8(pSSM, &pThis->aPics[i].last_irr); + SSMR3GetU8(pSSM, &pThis->aPics[i].irr); + SSMR3GetU8(pSSM, &pThis->aPics[i].imr); + SSMR3GetU8(pSSM, &pThis->aPics[i].isr); + SSMR3GetU8(pSSM, &pThis->aPics[i].priority_add); + SSMR3GetU8(pSSM, &pThis->aPics[i].irq_base); + SSMR3GetU8(pSSM, &pThis->aPics[i].read_reg_select); + SSMR3GetU8(pSSM, &pThis->aPics[i].poll); + SSMR3GetU8(pSSM, &pThis->aPics[i].special_mask); + SSMR3GetU8(pSSM, &pThis->aPics[i].init_state); + SSMR3GetU8(pSSM, &pThis->aPics[i].auto_eoi); + SSMR3GetU8(pSSM, &pThis->aPics[i].rotate_on_auto_eoi); + SSMR3GetU8(pSSM, &pThis->aPics[i].special_fully_nested_mode); + SSMR3GetU8(pSSM, &pThis->aPics[i].init4); + SSMR3GetU8(pSSM, &pThis->aPics[i].elcr); } return VINF_SUCCESS; } -/* -=-=-=-=-=- real code -=-=-=-=-=- */ +/* -=-=-=-=-=- PDMDEVREG -=-=-=-=-=- */ /** - * Reset notification. - * - * @returns VBox status. - * @param pDevIns The device instance data. + * @interface_method_impl{PDMDEVREG,pfnReset} */ static DECLCALLBACK(void) picReset(PPDMDEVINS pDevIns) { @@ -908,7 +878,7 @@ static DECLCALLBACK(void) picReset(PPDMDEVINS pDevIns) /** - * @copydoc FNPDMDEVRELOCATE + * @interface_method_impl{PDMDEVREG,pfnRelocate} */ static DECLCALLBACK(void) picRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta) { @@ -923,12 +893,11 @@ static DECLCALLBACK(void) picRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta) /** - * @copydoc FNPDMDEVCONSTRUCT + * @interface_method_impl{PDMDEVREG,pfnConstruct} */ static DECLCALLBACK(int) picConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg) { PDEVPIC pThis = PDMINS_2_DATA(pDevIns, PDEVPIC); - PDMPICREG PicReg; int rc; bool fGCEnabled; bool fR0Enabled; @@ -967,11 +936,14 @@ static DECLCALLBACK(int) picConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMN pThis->aPics[1].pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns); pThis->aPics[0].pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns); pThis->aPics[1].pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns); - pThis->cRelLogEntries = 0; + pThis->aPics[0].idxPic = 0; + pThis->aPics[1].idxPic = 1; + pThis->cRelLogEntries = 0; /* * Register us as the PIC with PDM. */ + PDMPICREG PicReg; PicReg.u32Version = PDM_PICREG_VERSION; PicReg.pfnSetIrqR3 = picSetIrq; PicReg.pfnGetInterruptR3 = picGetInterrupt; @@ -1133,7 +1105,7 @@ const PDMDEVREG g_DeviceI8259 = NULL, /* pfnRelocate */ picRelocate, - /* pfnIOCtl */ + /* pfnMemSetup */ NULL, /* pfnPowerOn */ NULL, |