VirtualBox

Changeset 44681 in vbox for trunk/src/VBox/Devices


Ignore:
Timestamp:
Feb 14, 2013 8:56:49 AM (12 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
83776
Message:

DevIoApic.cpp: rewrote the MMIO write handler, change MMIO registration flags.

File:
1 edited

Legend:

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

    r44679 r44681  
    276276}
    277277
    278 static void ioapic_mem_writel(PIOAPIC pThis, RTGCPHYS addr, uint32_t val)
    279 {
    280     int index;
    281 
    282     addr &= 0xff;
    283     if (addr == 0x00)
    284     {
    285         pThis->ioregsel = val;
    286         return;
    287     }
    288 
    289     if (addr == 0x10)
    290     {
    291 #ifdef DEBUG_IOAPIC
    292         Log(("I/O APIC write: %08x = %08x\n", pThis->ioregsel, val));
    293 #endif
    294         switch (pThis->ioregsel)
     278/** Handles a write to the IOREGSEL register. */
     279static 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}
     285
     286/**
     287 * Handles a write to the IOWIN register.
     288 */
     289static int ioapic_IoWin_w(PIOAPIC pThis, uint32_t u32Value)
     290{
     291    uint32_t const uIoRegSel = pThis->ioregsel;
     292    Log2(("ioapic: IOWIN[%#04x] = %#x\n", uIoRegSel, u32Value));
     293
     294    /*
     295     * IOREGSEL.
     296     */
     297    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    }
     304    /*
     305     * IOREDTBL0..IOREDTBL23.
     306     */
     307    else if (uIoRegSel - UINT32_C(0x10) < IOAPIC_NUM_PINS * 2)
     308    {
     309        uint32_t const  idxIoRedTbl = (uIoRegSel - UINT32_C(0x10)) >> 1;
     310        uint64_t        u64NewValue;
     311        if (!(uIoRegSel & 1))
    295312        {
    296             case 0x00:
    297                 pThis->id = (val >> 24) & 0xff;
    298                 return;
    299 
    300             case 0x01:
    301             case 0x02:
    302                 return;
    303 
    304             default:
    305                 index = (pThis->ioregsel - 0x10) >> 1;
    306                 if (index >= 0 && index < IOAPIC_NUM_PINS)
    307                 {
    308                     if (pThis->ioregsel & 1)
    309                     {
    310                         pThis->ioredtbl[index] &= 0xffffffff;
    311                         pThis->ioredtbl[index] |= (uint64_t)val << 32;
    312                     }
    313                     else
    314                     {
    315                         /* According to IOAPIC spec, vectors should be from 0x10 to 0xfe */
    316                         uint8_t vec = val & 0xff;
    317                         if (   (val & APIC_LVT_MASKED)
    318                             || (vec >= 0x10 && vec < 0xff) )
    319                         {
    320                             pThis->ioredtbl[index] &= ~0xffffffffULL;
    321                             pThis->ioredtbl[index] |= val;
    322                         }
    323                         else
    324                         {
    325                             /*
    326                              * Linux 2.6 kernels has pretty strange function
    327                              * unlock_ExtINT_logic() which writes absolutely
    328                              * bogus (all 0) value into the vector with pretty
    329                              * vague explanation why.  So we just ignore such
    330                              * writes.
    331                              */
    332                             LogRel(("IOAPIC GUEST BUG: bad vector writing %x(sel=%x) to %d\n", val, pThis->ioregsel, index));
    333                         }
    334                     }
    335                     ioapic_service(pThis);
    336                 }
     313            /*
     314             * Low DWORD.
     315             *
     316             * Have to do some sanity checks here because Linux 2.6 kernels
     317             * writes seemingly bogus value (u32Value = 0) in their
     318             * unlock_ExtINT_logic() function. Not sure what it's good for, but
     319             * we ran into trouble with INTVEC = 0.  Luckily the 82093AA specs
     320             * limits the INTVEC range to 0x10 thru 0xfe, so we use this to
     321             * ignore harmful values.
     322             */
     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! */
     326            if (   (u32Value & APIC_LVT_MASKED)
     327                || ((u32Value & UINT32_C(0xff)) - UINT32_C(0x10)) <= UINT32_C(0xee) /* (0xfe - 0x10 = 0xee) */ )
     328                u64NewValue = (pThis->ioredtbl[idxIoRedTbl] & UINT64_C(0xffffffff00000000)) | u32Value;
     329            else
     330            {
     331                LogRel(("IOAPIC GUEST BUG: bad vector writing %x(sel=%x) to %u\n", u32Value, uIoRegSel, idxIoRedTbl));
     332                u64NewValue = pThis->ioredtbl[idxIoRedTbl];
     333            }
    337334        }
    338     }
     335        else
     336        {
     337            /*
     338             * High DWORD.
     339             */
     340            u64NewValue = (pThis->ioredtbl[idxIoRedTbl] & UINT64_C(0x00000000ffffffff)) | ((uint64_t)u32Value << 32);
     341        }
     342
     343        Log(("ioapic: IOREDTBL%u %#018llx -> %#018llx\n", idxIoRedTbl, pThis->ioredtbl[idxIoRedTbl], u64NewValue));
     344        pThis->ioredtbl[idxIoRedTbl] = u64NewValue;
     345
     346        ioapic_service(pThis);
     347    }
     348    /*
     349     * Read-only or unknown registers. Log it.
     350     */
     351    else if (uIoRegSel == 1)
     352        Log(("ioapic: Attempt to write (%#x) to IOAPICVER.\n", u32Value));
     353    else if (uIoRegSel == 2)
     354        Log(("ioapic: Attempt to write (%#x) to IOAPICARB.\n", u32Value));
     355    else
     356        Log(("ioapic: Attempt to write (%#x) to register %#x.\n", u32Value, uIoRegSel));
     357
     358    return VINF_SUCCESS;
    339359}
    340360
     
    376396    STAM_COUNTER_INC(&CTXSUFF(pThis->StatMMIOWrite));
    377397    IOAPIC_LOCK(pThis, VINF_IOM_R3_MMIO_WRITE);
    378     switch (cb)
    379     {
    380         case 1: ioapic_mem_writel(pThis, GCPhysAddr, *(uint8_t  const *)pv); break;
    381         case 2: ioapic_mem_writel(pThis, GCPhysAddr, *(uint16_t const *)pv); break;
    382         case 4: ioapic_mem_writel(pThis, GCPhysAddr, *(uint32_t const *)pv); break;
    383 
    384         default:
    385             IOAPIC_UNLOCK(pThis);
    386             AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */
    387             return VERR_INTERNAL_ERROR;
    388     }
     398
     399    /*
     400     * Fetch the value.
     401     *
     402     * We've told IOM to only give us DWORD accesses.  Observations on AMD
     403     * indicates that unaligned writes get their missing bytes written as zero.
     404     */
     405    Assert(!(GCPhysAddr & 3)); Assert(cb == 4);
     406    uint32_t u32Value = *(uint32_t const *)pv;
     407
     408    /*
     409     * The 0xff mask is because we don't really implement the APICBASE register
     410     * in the PIIX3, so if the guest tries to relocate the IOAPIC via PIIX3 we
     411     * won't know. The I/O APIC address is on the form FEC0xy00h, where xy is
     412     * programmable. Masking 0xff means we cover the y. The x would require
     413     * reregistering MMIO memory, which means the guest is out of luck there.
     414     */
     415    int      rc;
     416    uint32_t offReg = GCPhysAddr & 0xff;
     417    if (offReg == 0)
     418        rc = ioapic_IoRegSel_w(pThis, u32Value);
     419    else if (offReg == 0x10)
     420        rc = ioapic_IoWin_w(pThis, u32Value);
     421    else
     422    {
     423        Log(("ioapicMMIOWrite: Invalid access: offReg=%#x u32Value=%#x\n", offReg, u32Value));
     424        rc = VINF_SUCCESS;
     425    }
     426
    389427    IOAPIC_UNLOCK(pThis);
    390     return VINF_SUCCESS;
     428    return rc;
    391429}
    392430
     
    556594
    557595    /*
     596     * Initialize the state data.
     597     */
     598    pThis->pDevInsR3 = pDevIns;
     599    pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
     600    pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
     601    /* (the rest is done by the reset call at the end) */
     602
     603    /* PDM provides locking via the IOAPIC helpers. */
     604    int rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
     605    AssertRCReturn(rc, rc);
     606
     607    /*
    558608     * Validate and read the configuration.
    559609     */
     
    561611
    562612    uint32_t cCpus;
    563     int rc = CFGMR3QueryU32Def(pCfg, "NumCPUs", &cCpus, 1);
     613    rc = CFGMR3QueryU32Def(pCfg, "NumCPUs", &cCpus, 1);
    564614    if (RT_FAILURE(rc))
    565615        return PDMDEV_SET_ERROR(pDevIns, rc,
     
    568618        return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
    569619                                   N_("Configuration error: Max %u CPUs, %u specified"), UINT8_MAX - 1, cCpus);
     620    pThis->cCpus = (uint8_t)cCpus;
    570621
    571622    bool fRZEnabled;
     
    576627
    577628    Log(("IOAPIC: cCpus=%u fRZEnabled=%RTbool\n", cCpus, fRZEnabled));
    578 
    579     /*
    580      * Initialize the state data.
    581      */
    582     pThis->pDevInsR3 = pDevIns;
    583     pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
    584     pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
    585     pThis->cCpus = (uint8_t)cCpus;
    586     /* (the rest is done by the reset call at the end) */
    587 
    588     /* PDM provides locking via the IOAPIC helpers. */
    589     rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
    590     AssertRCReturn(rc, rc);
    591629
    592630    /*
     
    613651     */
    614652    rc = PDMDevHlpMMIORegister(pDevIns, UINT32_C(0xfec00000), 0x1000, pThis,
    615                                IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
     653                               IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_DWORD_ZEROED,
    616654                               ioapicMMIOWrite, ioapicMMIORead, "I/O APIC Memory");
    617655    if (RT_FAILURE(rc))
Note: See TracChangeset for help on using the changeset viewer.

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