VirtualBox

Ignore:
Timestamp:
Jul 8, 2020 4:33:03 PM (5 years ago)
Author:
vboxsync
Message:

PCnet: Reworked TMD access to better match real hardware (see bugref:9768).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Network/DevPCNet.cpp

    r82968 r85113  
    621621        uint32_t trc:4;         /**< transmit retry count */
    622622        uint32_t res:12;        /**< reserved */
    623         uint32_t tdr:10;        /**< ??? */
     623        uint32_t tdr:10;        /**< time domain reflectometry */
    624624        uint32_t rtry:1;        /**< retry error */
    625625        uint32_t lcar:1;        /**< loss of carrier */
     
    762762
    763763/**
    764  * Load transmit message descriptor
    765  * Make sure we read the own flag first.
     764 * Load transmit message descriptor (TMD) if we own it.
     765 * Makes sure we read the OWN bit first, which requires issuing two reads if
     766 * the OWN bit is laid out in the second (D)WORD in memory.
    766767 *
    767768 * @param   pDevIns     The device instance.
    768769 * @param pThis         adapter private data
    769770 * @param addr          physical address of the descriptor
    770  * @param fRetIfNotOwn  return immediately after reading the own flag if we don't own the descriptor
    771771 * @return              true if we own the descriptor, false otherwise
    772772 */
    773 DECLINLINE(bool) pcnetTmdLoad(PPDMDEVINS pDevIns, PPCNETSTATE pThis, TMD *tmd, RTGCPHYS32 addr, bool fRetIfNotOwn)
    774 {
    775     uint8_t    ownbyte;
    776 
     773DECLINLINE(bool) pcnetTmdTryLoad(PPDMDEVINS pDevIns, PPCNETSTATE pThis, TMD *tmd, RTGCPHYS32 addr)
     774{
     775    /* Convert the in-memory format to the internal layout which corresponds to SWSTYLE=2.
     776     * Do not touch tmd if the OWN bit is not set (i.e. we don't own the descriptor).
     777     */
    777778    if (RT_UNLIKELY(BCR_SWSTYLE(pThis) == 0))
    778779    {
     780        uint16_t xda[4];    /* Corresponds to memory layout, last word unused. */
     781
     782        /* For SWSTYLE=0, the OWN bit is in the second WORD we need and must be read before the first WORD. */
     783        PDMDevHlpPhysRead(pDevIns, addr + sizeof(uint16_t), (void*)&xda[1], 2 * sizeof(uint16_t));
     784        if (!(xda[1] & RT_BIT(15)))
     785            return false;
     786        PDMDevHlpPhysRead(pDevIns, addr, (void*)&xda[0], sizeof(uint16_t));
     787        ((uint32_t *)tmd)[0] = (uint32_t)xda[0] | ((uint32_t)(xda[1] & 0x00ff) << 16);  /* TMD0, buffer address. */
     788        ((uint32_t *)tmd)[1] = (uint32_t)xda[2] | ((uint32_t)(xda[1] & 0xff00) << 16);  /* TMD1, buffer size and control bits. */
     789        ((uint32_t *)tmd)[2] = 0;   /* TMD2, status bits, set on error but not read. */
     790        ((uint32_t *)tmd)[3] = 0;   /* TMD3, user data, never accessed. */
     791    }
     792    else if (RT_LIKELY(BCR_SWSTYLE(pThis) != 3))
     793    {
     794        /* For SWSTYLE=2, the OWN bit is in the second DWORD we need and must be read first. */
     795        uint32_t xda[2];
     796        PDMDevHlpPhysRead(pDevIns, addr + sizeof(uint32_t), (void*)&xda[1], sizeof(uint32_t));
     797        if (!(xda[1] & RT_BIT(31)))
     798            return false;
     799        PDMDevHlpPhysRead(pDevIns, addr, (void*)&xda[0], sizeof(uint32_t));
     800        ((uint32_t *)tmd)[0] = xda[0];  /* TMD0, buffer address. */
     801        ((uint32_t *)tmd)[1] = xda[1];  /* TMD1, buffer size and control bits. */
     802        ((uint32_t *)tmd)[2] = 0;       /* TMD2, status bits, set on error but not read. */
     803        ((uint32_t *)tmd)[3] = 0;       /* TMD3, user data, never accessed. */
     804    }
     805    else
     806    {
     807        /* For SWSTYLE=3, the OWN bit is in the first DWORD we need, therefore a single read suffices. */
     808        uint32_t xda[2];
     809        PDMDevHlpPhysRead(pDevIns, addr + sizeof(uint32_t), (void*)&xda, sizeof(xda));
     810        if (!(xda[0] & RT_BIT(31)))
     811            return false;
     812        ((uint32_t *)tmd)[0] = xda[1];  /* TMD0, buffer address. */
     813        ((uint32_t *)tmd)[1] = xda[0];  /* TMD1, buffer size and control bits. */
     814        ((uint32_t *)tmd)[2] = 0;       /* TMD2, status bits, set on error but not read. */
     815        ((uint32_t *)tmd)[3] = 0;       /* TMD3, user data, never accessed. */
     816    }
     817
     818    return !!tmd->tmd1.own;
     819}
     820
     821/**
     822 * Loads an entire transmit message descriptor. Used for logging/debugging.
     823 *
     824 * @param pDevIns       The device instance.
     825 * @param pThis         Adapter private data
     826 * @param addr          Physical address of the descriptor
     827 */
     828DECLINLINE(void) pcnetTmdLoadAll(PPDMDEVINS pDevIns, PPCNETSTATE pThis, TMD *tmd, RTGCPHYS32 addr)
     829{
     830    /* Convert the in-memory format to the internal layout which corresponds to SWSTYLE=2. */
     831    if (RT_UNLIKELY(BCR_SWSTYLE(pThis) == 0))
     832    {
    779833        uint16_t xda[4];
    780834
    781         PDMDevHlpPhysRead(pDevIns, addr+3, &ownbyte, 1);
    782         if (!(ownbyte & 0x80) && fRetIfNotOwn)
    783             return false;
    784         PDMDevHlpPhysRead(pDevIns, addr, (void*)&xda[0], sizeof(xda));
    785         ((uint32_t *)tmd)[0] = (uint32_t)xda[0] | ((uint32_t)(xda[1] & 0x00ff) << 16);
    786         ((uint32_t *)tmd)[1] = (uint32_t)xda[2] | ((uint32_t)(xda[1] & 0xff00) << 16);
    787         ((uint32_t *)tmd)[2] = (uint32_t)xda[3] << 16;
    788         ((uint32_t *)tmd)[3] = 0;
     835        /* For SWSTYLE=0, we have to do a bit of work. */
     836        PDMDevHlpPhysRead(pDevIns, addr, (void*)&xda, sizeof(xda));
     837        ((uint32_t *)tmd)[0] = (uint32_t)xda[0] | ((uint32_t)(xda[1] & 0x00ff) << 16);  /* TMD0, buffer address. */
     838        ((uint32_t *)tmd)[1] = (uint32_t)xda[2] | ((uint32_t)(xda[1] & 0xff00) << 16);  /* TMD1, buffer size and control bits. */
     839        ((uint32_t *)tmd)[2] = (uint32_t)xda[3] << 16;                                  /* TMD2, status bits. */
     840        ((uint32_t *)tmd)[3] = 0;                                           /* TMD3, user data, not present for SWSTYLE=1. */
    789841    }
    790842    else if (RT_LIKELY(BCR_SWSTYLE(pThis) != 3))
    791843    {
    792         PDMDevHlpPhysRead(pDevIns, addr+7, &ownbyte, 1);
    793         if (!(ownbyte & 0x80) && fRetIfNotOwn)
    794             return false;
    795         PDMDevHlpPhysRead(pDevIns, addr, (void*)tmd, 16);
     844        /* For SWSTYLE=2, simply read the TMD as is. */
     845        PDMDevHlpPhysRead(pDevIns, addr, (void*)tmd, sizeof(*tmd));
    796846    }
    797847    else
    798848    {
     849        /* For SWSTYLE=3, swap the first and third DWORD around. */
    799850        uint32_t xda[4];
    800         PDMDevHlpPhysRead(pDevIns, addr+7, &ownbyte, 1);
    801         if (!(ownbyte & 0x80) && fRetIfNotOwn)
    802             return false;
    803         PDMDevHlpPhysRead(pDevIns, addr, (void*)&xda[0], sizeof(xda));
    804         ((uint32_t *)tmd)[0] = xda[2];
    805         ((uint32_t *)tmd)[1] = xda[1];
    806         ((uint32_t *)tmd)[2] = xda[0];
    807         ((uint32_t *)tmd)[3] = xda[3];
    808     }
    809     /* Double check the own bit; guest drivers might be buggy and lock prefixes in the recompiler are ignored by other threads. */
    810 #ifdef DEBUG
    811     if (tmd->tmd1.own == 1 && !(ownbyte & 0x80))
    812         Log(("pcnetTmdLoad: own bit flipped while reading!!\n"));
    813 #endif
    814     if (!(ownbyte & 0x80))
    815         tmd->tmd1.own = 0;
    816 
    817     return !!tmd->tmd1.own;
     851        PDMDevHlpPhysRead(pDevIns, addr, (void*)&xda, sizeof(xda));
     852        ((uint32_t *)tmd)[0] = xda[2];  /* TMD0, buffer address. */
     853        ((uint32_t *)tmd)[1] = xda[1];  /* TMD1, buffer size and control bits. */
     854        ((uint32_t *)tmd)[2] = xda[0];  /* TMD2, status bits. */
     855        ((uint32_t *)tmd)[3] = xda[3];  /* TMD3, user data. */
     856    }
    818857}
    819858
    820859/**
    821860 * Store transmit message descriptor and hand it over to the host (the VM guest).
    822  * Make sure that all data are transmitted before we clear the own flag.
     861 * Make sure the cleared OWN bit gets written last.
    823862 */
    824863DECLINLINE(void) pcnetTmdStorePassHost(PPDMDEVINS pDevIns, PPCNETSTATE pThis, TMD *tmd, RTGCPHYS32 addr)
     
    827866    if (RT_UNLIKELY(BCR_SWSTYLE(pThis) == 0))
    828867    {
    829         uint16_t xda[4];
    830         xda[0] =   ((uint32_t *)tmd)[0]        & 0xffff;
     868        uint16_t xda[4];    /* Corresponds to memory layout, only two words used. */
     869
     870        /* For SWSTYLE=0, write the status word first, then the word containing the OWN bit. */
    831871        xda[1] = ((((uint32_t *)tmd)[0] >> 16) &   0xff) | ((((uint32_t *)tmd)[1]>>16) & 0xff00);
    832         xda[2] =   ((uint32_t *)tmd)[1]        & 0xffff;
     872        xda[1] &= ~RT_BIT(15);
    833873        xda[3] =   ((uint32_t *)tmd)[2] >> 16;
    834         xda[1] |=  0x8000;
    835         pcnetPhysWrite(pDevIns, pThis, addr, (void*)&xda[0], sizeof(xda));
    836         xda[1] &= ~0x8000;
    837         pcnetPhysWrite(pDevIns, pThis, addr+3, (uint8_t*)xda + 3, 1);
     874        /** @todo: The WORD containing status bits may not need to be written unless the ERR bit is set. */
     875        pcnetPhysWrite(pDevIns, pThis, addr + 3 * sizeof(uint16_t), (void*)&xda[3], sizeof(uint16_t));
     876        pcnetPhysWrite(pDevIns, pThis, addr + 1 * sizeof(uint16_t), (void*)&xda[1], sizeof(uint16_t));
    838877    }
    839878    else if (RT_LIKELY(BCR_SWSTYLE(pThis) != 3))
    840879    {
    841         ((uint32_t*)tmd)[1] |=  0x80000000;
    842         pcnetPhysWrite(pDevIns, pThis, addr, (void*)tmd, 12);
    843         ((uint32_t*)tmd)[1] &= ~0x80000000;
    844         pcnetPhysWrite(pDevIns, pThis, addr+7, (uint8_t*)tmd + 7, 1);
     880        /* For SWSTYLE=0, write TMD2 first, then TMD1. */
     881        /** @todo: The DWORD containing status bits may not need to be written unless the ERR bit is set. */
     882        pcnetPhysWrite(pDevIns, pThis, addr + 2 * sizeof(uint32_t), (uint32_t*)tmd + 2, sizeof(uint32_t));
     883        ((uint32_t*)tmd)[1] &= ~RT_BIT(31);
     884        pcnetPhysWrite(pDevIns, pThis, addr + 1 * sizeof(uint32_t), (uint32_t*)tmd + 1, sizeof(uint32_t));
    845885    }
    846886    else
    847887    {
    848         uint32_t xda[3];
     888        uint32_t xda[2];
     889
     890        /* For SWSTYLE=3, two DWORDs can be written in one go because the OWN bit is last. */
    849891        xda[0] = ((uint32_t *)tmd)[2];
    850892        xda[1] = ((uint32_t *)tmd)[1];
    851         xda[2] = ((uint32_t *)tmd)[0];
    852         xda[1] |=  0x80000000;
    853         pcnetPhysWrite(pDevIns, pThis, addr, (void*)&xda[0], sizeof(xda));
    854         xda[1] &= ~0x80000000;
    855         pcnetPhysWrite(pDevIns, pThis, addr+7, (uint8_t*)xda + 7, 1);
     893        xda[1] &= ~RT_BIT(31);
     894        pcnetPhysWrite(pDevIns, pThis, addr, (void*)&xda, sizeof(xda));
    856895    }
    857896    STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatTmdStore), a);
     
    18001839        RTGCPHYS32 cxda = pcnetTdraAddr(pThis, CSR_XMTRC(pThis));
    18011840
    1802         if (!pcnetTmdLoad(pDevIns, pThis, tmd, PHYSADDR(pThis, cxda), true))
     1841        if (!pcnetTmdTryLoad(pDevIns, pThis, tmd, PHYSADDR(pThis, cxda)))
    18031842        {
    18041843            STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatTdtePoll), a);
     
    18621901        RTGCPHYS32 addrDesc = pcnetTdraAddr(pThis, iDesc);
    18631902
    1864         if (!pcnetTmdLoad(pDevIns, pThis, &tmd, PHYSADDR(pThis, addrDesc), true))
     1903        if (!pcnetTmdTryLoad(pDevIns, pThis, &tmd, PHYSADDR(pThis, addrDesc)))
    18651904        {
    18661905            STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatTxLenCalc), a);
     
    22932332static void pcnetXmitRead1stSlow(PPDMDEVINS pDevIns, RTGCPHYS32 GCPhysFrame, unsigned cbFrame, PPDMSCATTERGATHER pSgBuf)
    22942333{
    2295     AssertFailed(); /* This path is not supposed to be taken atm */
    2296 
    22972334    pSgBuf->cbUsed = cbFrame;
    22982335    for (uint32_t iSeg = 0; ; iSeg++)
    22992336    {
    2300         Assert(iSeg < pSgBuf->cSegs);
     2337        if (iSeg >= pSgBuf->cSegs)
     2338        {
     2339            AssertFailed();
     2340            LogRelMax(10, ("PCnet: pcnetXmitRead1stSlow: segment overflow -> ignoring\n"));
     2341            return;
     2342        }
     2343
    23012344        uint32_t cbRead = (uint32_t)RT_MIN(cbFrame, pSgBuf->aSegs[iSeg].cbSeg);
    23022345        PDMDevHlpPhysRead(pDevIns, GCPhysFrame, pSgBuf->aSegs[iSeg].pvSeg, cbRead);
     
    23152358static void pcnetXmitReadMoreSlow(PPDMDEVINS pDevIns, RTGCPHYS32 GCPhysFrame, unsigned cbFrame, PPDMSCATTERGATHER pSgBuf)
    23162359{
    2317     AssertFailed(); /* This path is not supposed to be taken atm */
    2318 
    23192360    /* Find the segment which we'll put the next byte into. */
    23202361    size_t      off    = pSgBuf->cbUsed;
     
    23252366        offSeg += pSgBuf->aSegs[iSeg].cbSeg;
    23262367        iSeg++;
    2327         Assert(iSeg < pSgBuf->cSegs);
     2368        if (iSeg >= pSgBuf->cSegs)
     2369        {
     2370            AssertFailed();
     2371            LogRelMax(10, ("PCnet: pcnetXmitReadMoreSlow: segment overflow #1 -> ignoring\n"));
     2372            return;
     2373        }
    23282374    }
    23292375
     
    23482394    for (;; iSeg++)
    23492395    {
    2350         Assert(iSeg < pSgBuf->cSegs);
     2396        if (iSeg >= pSgBuf->cSegs)
     2397        {
     2398            AssertFailed();
     2399            LogRelMax(10, ("PCnet: pcnetXmitReadMoreSlow: segment overflow #2 -> ignoring\n"));
     2400            return;
     2401        }
    23512402
    23522403        uint32_t cbRead = (uint32_t)RT_MIN(pSgBuf->aSegs[iSeg].cbSeg, cbFrame);
     
    26342685                    CSR_XMTRC(pThis)--;
    26352686
    2636                 TMD dummy;
    2637                 if (!pcnetTdtePoll(pDevIns, pThis, &dummy))
     2687                TMD tmdNext;
     2688                if (!pcnetTdtePoll(pDevIns, pThis, &tmdNext))
    26382689                {
    26392690                    /*
     
    26562707
    26572708                /*
    2658                  * The next tmd.
     2709                 * The next tmd is already loaded.
    26592710                 */
    26602711#ifdef VBOX_WITH_STATISTICS
    26612712                cBuffers++;
    26622713#endif
    2663                 pcnetTmdLoad(pDevIns, pThis, &tmd, PHYSADDR(pThis, CSR_CXDA(pThis)), false);
     2714                tmd = tmdNext;
    26642715                cb = 4096 - tmd.tmd1.bcnt;
    26652716                if (   !fDropFrame
    2666                     && pSgBuf->cbUsed + cb <= MAX_FRAME) /** @todo this used to be ... + cb < MAX_FRAME. */
     2717                    && pSgBuf->cbUsed + cb <= pSgBuf->cbAvailable)
    26672718                    pcnetXmitReadMore(pDevIns, PHYSADDR(pThis, tmd.tmd0.tbadr), cb, pSgBuf);
    26682719                else
     
    28582909    {
    28592910        TMD tmd;
    2860         pcnetTmdLoad(pDevIns, pThis, &tmd, PHYSADDR(pThis, CSR_CXDA(pThis)), false);
     2911        pcnetTmdLoadAll(pDevIns, pThis, &tmd, PHYSADDR(pThis, CSR_CXDA(pThis)));
    28612912        Log10(("#%d pcnetPollTimer: TMDLOAD %#010x\n", PCNET_INST_NR, PHYSADDR(pThis, CSR_CXDA(pThis))));
    28622913        PRINT_TMD(&tmd);
     
    43104361        {
    43114362            TMD tmd;
    4312             pcnetTmdLoad(pDevIns, pThis, &tmd, PHYSADDR(pThis, GCPhys), false);
     4363            pcnetTmdLoadAll(pDevIns, pThis, &tmd, PHYSADDR(pThis, GCPhys));
    43134364            pHlp->pfnPrintf(pHlp,
    43144365                            "%04x %RX32:%c%c TBADR=%08RX32 BCNT=%03x OWN=%d "
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