VirtualBox

Changeset 44684 in vbox for trunk/src/VBox/Devices/PC


Ignore:
Timestamp:
Feb 14, 2013 12:08:46 PM (12 years ago)
Author:
vboxsync
Message:

DevIoApic: Rewrote the MMIO read handler. Mask reserved and read-only bits out of the IOREDTBLn writes.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/PC/DevIoApic.cpp

    r44681 r44684  
    229229}
    230230
    231 static uint32_t ioapic_mem_readl(PIOAPIC pThis, RTGCPHYS addr)
    232 {
    233     uint32_t val = 0;
    234 
    235     addr &= 0xff;
    236     if (addr == 0x00)
    237         val = pThis->ioregsel;
    238     else if (addr == 0x10)
    239     {
    240         switch (pThis->ioregsel)
    241         {
    242             case 0x00:
    243                 val = pThis->id << 24;
    244                 break;
    245 
    246             case 0x01:
    247                 val = 0x11 | ((IOAPIC_NUM_PINS - 1) << 16); /* version 0x11 */
    248                 break;
    249 
    250             case 0x02:
    251                 val = 0;
    252                 break;
    253 
    254             default:
    255             {
    256                 int index = (pThis->ioregsel - 0x10) >> 1;
    257                 if (index >= 0 && index < IOAPIC_NUM_PINS)
    258                 {
    259                     if (pThis->ioregsel & 1)
    260                         val = pThis->ioredtbl[index] >> 32;
    261                     else
    262                         val = pThis->ioredtbl[index] & 0xffffffff;
    263                 }
    264                 else
    265                     val = 0;
    266                 break;
    267             }
    268         }
    269 #ifdef DEBUG_IOAPIC
    270         Log(("I/O APIC read: %08x = %08x\n", pThis->ioregsel, val));
    271 #endif
     231
     232/**
     233 * Handles a read from the IOAPICID register.
     234 */
     235static int ioapic_IoApicId_r(PIOAPIC pThis, uint32_t *pu32Value)
     236{
     237    *pu32Value = (uint32_t)pThis->id << 24;
     238    return VINF_SUCCESS;
     239}
     240
     241
     242/**
     243 * Handles a write to the IOAPICID register.
     244 */
     245static int ioapic_IoApicId_w(PIOAPIC pThis, uint32_t u32Value)
     246{
     247    /* Note! Compared to the 82093AA spec, we've extended the IOAPIC
     248             identification from bits 27:24 to bits 31:24. */
     249    Log(("ioapic: IOAPICID %#x -> %#x\n", pThis->id, u32Value >> 24));
     250    pThis->id = u32Value >> 24;
     251    return VINF_SUCCESS;
     252}
     253
     254
     255/**
     256 * Handles a read from the IOAPICVER register.
     257 */
     258static int ioapic_IoApicVer_r(PIOAPIC pThis, uint32_t *pu32Value)
     259{
     260    *pu32Value = RT_MAKE_U32(0x11, IOAPIC_NUM_PINS - 1); /* (0x11 is the version.) */
     261    return VINF_SUCCESS;
     262}
     263
     264
     265/**
     266 * Handles a read from the IOAPICARB register.
     267 */
     268static int ioapic_IoApicArb_r(PIOAPIC pThis, uint32_t *pu32Value)
     269{
     270    *pu32Value = 0; /* (arbitration winner) */
     271    return VINF_SUCCESS;
     272}
     273
     274
     275/**
     276 * Handles a read from the IOREGSEL register.
     277 */
     278static int ioapic_IoRegSel_r(PIOAPIC pThis, uint32_t *pu32Value)
     279{
     280    *pu32Value = pThis->ioregsel;
     281    return VINF_SUCCESS;
     282}
     283
     284/**
     285 * Handles a write to the IOREGSEL register.
     286 */
     287static int ioapic_IoRegSel_w(PIOAPIC pThis, uint32_t u32Value)
     288{
     289    Log2(("ioapic: IOREGSEL %#04x -> %#04x\n", pThis->ioregsel, u32Value & 0xff));
     290    /* Bits 7:0 are writable, the rest aren't. Confirmed on recent AMD box. */
     291    pThis->ioregsel = u32Value & 0xff;
     292    return VINF_SUCCESS;
     293}
     294
     295
     296/**
     297 * Handles a write to the IOWIN register.
     298 */
     299static int ioapic_IoWin_r(PIOAPIC pThis, uint32_t *pu32Value)
     300{
     301    int             rc = VINF_SUCCESS;
     302    uint32_t const  uIoRegSel = pThis->ioregsel;
     303
     304    if (uIoRegSel == 0)
     305        rc = ioapic_IoApicId_r(pThis, pu32Value);
     306    else if (uIoRegSel == 1)
     307        rc = ioapic_IoApicVer_r(pThis, pu32Value);
     308    else if (uIoRegSel == 2)
     309        rc = ioapic_IoApicArb_r(pThis, pu32Value);
     310    /*
     311     * IOREDTBL0..IOREDTBL23.
     312     */
     313    else if (uIoRegSel - UINT32_C(0x10) < IOAPIC_NUM_PINS * 2)
     314    {
     315        uint32_t const  idxIoRedTbl = (uIoRegSel - UINT32_C(0x10)) >> 1;
     316        uint64_t        u64NewValue;
     317        if (!(uIoRegSel & 1))
     318            /** @todo r=bird: Do we need to emulate DELIVS or/and Remote IRR? */
     319            *pu32Value = RT_LODWORD(pThis->ioredtbl[idxIoRedTbl]);
     320        else
     321            *pu32Value = RT_HIDWORD(pThis->ioredtbl[idxIoRedTbl]);
    272322    }
    273323    else
    274         val = 0;
    275     return val;
    276 }
    277 
    278 /** Handles a write to the IOREGSEL register. */
    279 static int ioapic_IoRegSel_w(PIOAPIC pThis, uint32_t u32Value)
    280 {
    281     Log2(("ioapic: IOREGSEL %#04x -> %#04x\n", pThis->ioregsel, u32Value & 0xff));
    282     pThis->ioregsel = u32Value & 0xff; /* This is what the AMD box does here */
    283     return VINF_SUCCESS;
    284 }
     324    {
     325        Log(("ioapic: Attempt to read from register %#x.\n", uIoRegSel));
     326        *pu32Value = UINT32_MAX;
     327    }
     328
     329    return rc;
     330}
     331
    285332
    286333/**
     
    289336static int ioapic_IoWin_w(PIOAPIC pThis, uint32_t u32Value)
    290337{
    291     uint32_t const uIoRegSel = pThis->ioregsel;
     338    int             rc = VINF_SUCCESS;
     339    uint32_t const  uIoRegSel = pThis->ioregsel;
    292340    Log2(("ioapic: IOWIN[%#04x] = %#x\n", uIoRegSel, u32Value));
    293341
    294342    /*
    295      * IOREGSEL.
     343     * IOAPICID.
    296344     */
    297345    if (uIoRegSel == 0)
    298     {
    299         /* Note! Compared to the 82093AA spec, we've extended the IOAPIC
    300                  identification from bits 27:24 to bits 31:24. */
    301         Log(("ioapic: IOAPICID %#x -> %#x\n", pThis->id, u32Value >> 24));
    302         pThis->id = u32Value >> 24;
    303     }
     346        rc = ioapic_IoApicId_w(pThis, u32Value);
    304347    /*
    305348     * IOREDTBL0..IOREDTBL23.
     
    320363             * limits the INTVEC range to 0x10 thru 0xfe, so we use this to
    321364             * ignore harmful values.
     365             *
     366             * Update: Looking at real hw (recent AMD), they don't reject
     367             * invalid vector numbers, at least not at this point. Could be that
     368             * some other code path needs to refuse something instead.  Results:
     369             *  - Writing 0 to lo+hi -> 0.
     370             *  - Writing ~0 to lo+hi -> 0xff0000000001afff.
     371             *  - Writing ~0 w/ DELMOD set to 011b or 110b (both reserved)
     372             *    results in DELMOD containing the reserved values.
     373             *  - Ditto with same + DELMOD in [0..7], DELMOD is stored as written.
    322374             */
    323             /** @todo see what happens on real HW when doing that. It probably
    324              *        ignores/rejects other values as well. Could be it ignores invalid
    325              *        values on a per sub-register basis, someone need to check this! */
    326375            if (   (u32Value & APIC_LVT_MASKED)
    327376                || ((u32Value & UINT32_C(0xff)) - UINT32_C(0x10)) <= UINT32_C(0xee) /* (0xfe - 0x10 = 0xee) */ )
    328                 u64NewValue = (pThis->ioredtbl[idxIoRedTbl] & UINT64_C(0xffffffff00000000)) | u32Value;
     377                u64NewValue = (pThis->ioredtbl[idxIoRedTbl] & (UINT64_C(0xffffffff00000000) | RT_BIT(14) | RT_BIT(12)))
     378                            | (u32Value & ~(RT_BIT(14) | RT_BIT(12)));
    329379            else
    330380            {
     
    338388             * High DWORD.
    339389             */
    340             u64NewValue = (pThis->ioredtbl[idxIoRedTbl] & UINT64_C(0x00000000ffffffff)) | ((uint64_t)u32Value << 32);
     390            u64NewValue = (pThis->ioredtbl[idxIoRedTbl] & UINT64_C(0x00000000ffffffff))
     391                        | ((uint64_t)(u32Value & UINT32_C(0xff000000)) << 32);
    341392        }
    342393
     
    356407        Log(("ioapic: Attempt to write (%#x) to register %#x.\n", u32Value, uIoRegSel));
    357408
    358     return VINF_SUCCESS;
    359 }
    360 
    361 /* IOAPIC */
     409    return rc;
     410}
     411
    362412
    363413PDMBOTHCBDECL(int) ioapicMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
     
    367417
    368418    STAM_COUNTER_INC(&CTXSUFF(pThis->StatMMIORead));
    369     switch (cb)
    370     {
    371         case 1:
    372             *(uint8_t *)pv = ioapic_mem_readl(pThis, GCPhysAddr);
    373             break;
    374 
    375         case 2:
    376             *(uint16_t *)pv = ioapic_mem_readl(pThis, GCPhysAddr);
    377             break;
    378 
    379         case 4:
    380             *(uint32_t *)pv = ioapic_mem_readl(pThis, GCPhysAddr);
    381             break;
    382 
    383         default:
    384             AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */
    385             IOAPIC_UNLOCK(pThis);
    386             return VERR_INTERNAL_ERROR;
    387     }
     419
     420    /*
     421     * Pass it on to the register read handlers.
     422     * (See 0xff comments in ioapicMMIOWrite.)
     423     */
     424    int      rc;
     425    uint32_t offReg = GCPhysAddr & 0xff;
     426    if (offReg == 0)
     427        rc = ioapic_IoRegSel_r(pThis, (uint32_t *)pv);
     428    else if (offReg == 0x10)
     429        rc = ioapic_IoRegSel_r(pThis, (uint32_t *)pv);
     430    else
     431    {
     432        Log(("ioapicMMIORead: Invalid access: offReg=%#x\n", offReg));
     433        rc = VINF_IOM_MMIO_UNUSED_FF;
     434    }
     435
    388436    IOAPIC_UNLOCK(pThis);
    389     return VINF_SUCCESS;
     437    return rc;
    390438}
    391439
     
    484532    uint32_t     uVal;
    485533
    486     pHlp->pfnPrintf(pHlp, "I/O APIC at %08x:\n", 0xfec00000);
    487     uVal = pThis->id << 24;  /* Would be nice to call ioapic_mem_readl() directly, but that's not so simple. */
    488     pHlp->pfnPrintf(pHlp, "  IOAPICID  : %08x\n", uVal);
    489     pHlp->pfnPrintf(pHlp, "    APIC ID = %02x\n", (uVal >> 24) & 0xff);
    490     uVal = 0x11 | ((IOAPIC_NUM_PINS - 1) << 16);
    491     unsigned max_redir = RT_BYTE3(uVal);
    492     pHlp->pfnPrintf(pHlp, "  IOAPICVER : %08x\n", uVal);
    493     pHlp->pfnPrintf(pHlp, "    version = %02x\n", uVal & 0xff);
    494     pHlp->pfnPrintf(pHlp, "    redirs  = %d\n", RT_BYTE3(uVal) + 1);
    495     uVal = 0;
    496     pHlp->pfnPrintf(pHlp, "  IOAPICARB : %08x\n", uVal);
    497     pHlp->pfnPrintf(pHlp, "    arb ID  = %02x\n", RT_BYTE4(uVal) & 0xff);
    498     Assert(sizeof(pThis->ioredtbl) / sizeof(pThis->ioredtbl[0]) > max_redir);
     534    pHlp->pfnPrintf(pHlp, "I/O APIC at %#010x:\n", 0xfec00000);
     535
     536    ioapic_IoApicId_r(pThis, &uVal);
     537    pHlp->pfnPrintf(pHlp, "  IOAPICID  : %#010x\n", uVal);
     538    pHlp->pfnPrintf(pHlp, "    APIC ID = %#04x\n", (uVal >> 24) & 0xff);
     539
     540    ioapic_IoApicVer_r(pThis, &uVal);
     541    unsigned iLastRedir = RT_BYTE3(uVal);
     542    pHlp->pfnPrintf(pHlp, "  IOAPICVER : %#010x\n", uVal);
     543    pHlp->pfnPrintf(pHlp, "    version = %#04x\n", uVal & 0xff);
     544    pHlp->pfnPrintf(pHlp, "    redirs  = %u\n", iLastRedir + 1);
     545
     546    ioapic_IoApicArb_r(pThis, &uVal);
     547    pHlp->pfnPrintf(pHlp, "  IOAPICARB : %#0108x\n", uVal);
     548    pHlp->pfnPrintf(pHlp, "    arb ID  = %#04x\n", RT_BYTE4(uVal));
     549
     550    Assert(sizeof(pThis->ioredtbl) / sizeof(pThis->ioredtbl[0]) > iLastRedir);
    499551    pHlp->pfnPrintf(pHlp, "I/O redirection table\n");
    500552    pHlp->pfnPrintf(pHlp, " idx dst_mode dst_addr mask trigger rirr polarity dlvr_st dlvr_mode vector\n");
    501     for (unsigned i = 0; i <= max_redir; ++i)
     553    for (unsigned i = 0; i <= iLastRedir; ++i)
    502554    {
    503555        static const char * const s_apszDModes[] =
     
    508560        pHlp->pfnPrintf(pHlp, "  %02d   %s      %02x     %d    %s   %d   %s  %s     %s   %3d (%016llx)\n",
    509561                        i,
    510                         pThis->ioredtbl[i] & (1 << 11) ? "log " : "phys",           /* dest mode */
     562                        pThis->ioredtbl[i] & RT_BIT(11) ? "log " : "phys",          /* dest mode */
    511563                        (int)(pThis->ioredtbl[i] >> 56),                            /* dest addr */
    512564                        (int)(pThis->ioredtbl[i] >> 16) & 1,                        /* mask */
    513                         pThis->ioredtbl[i] & (1 << 15) ? "level" : "edge ",         /* trigger */
     565                        pThis->ioredtbl[i] & RT_BIT(15) ? "level" : "edge ",        /* trigger */
    514566                        (int)(pThis->ioredtbl[i] >> 14) & 1,                        /* remote IRR */
    515                         pThis->ioredtbl[i] & (1 << 13) ? "activelo" : "activehi",   /* polarity */
    516                         pThis->ioredtbl[i] & (1 << 12) ? "pend" : "idle",           /* delivery status */
     567                        pThis->ioredtbl[i] & RT_BIT(13) ? "activelo" : "activehi",  /* polarity */
     568                        pThis->ioredtbl[i] & RT_BIT(12) ? "pend" : "idle",          /* delivery status */
    517569                        s_apszDModes[(pThis->ioredtbl[i] >> 8) & 0x07],             /* delivery mode */
    518570                        (int)pThis->ioredtbl[i] & 0xff,                             /* vector */
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette