VirtualBox

Changeset 91022 in vbox for trunk/src


Ignore:
Timestamp:
Aug 31, 2021 8:11:28 AM (3 years ago)
Author:
vboxsync
Message:

DevPCnet: Handle AMD drivers which disable PCI bus mastering around setting CSR0.INIT (see bugref:10088).

File:
1 edited

Legend:

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

    r90447 r91022  
    15961596    Log(("#%d pcnetR3Init: init_addr=%#010x\n", PCNET_INST_NR, PHYSADDR(pThis, CSR_IADR(pThis))));
    15971597
     1598    /* If intialization was invoked with PCI bus mastering disabled, it's not going to
     1599     * go very well. Better report an error.
     1600     */
     1601    if (PCNET_IS_PCI(pThis))
     1602    {
     1603        PPDMPCIDEV pPciDev = pDevIns->apPciDevs[0];
     1604        uint8_t uCmd = PDMPciDevGetByte(pPciDev, 0x04);
     1605
     1606        if (!(uCmd & 4))
     1607        {
     1608            pThis->aCSR[0] |=  0x0801;       /* Set the MERR bit instead of IDON. */
     1609            LogRel(("PCnet#%d: Warning: Initialization failed due to disabled PCI bus mastering.\n", PCNET_INST_NR));
     1610            return;
     1611        }
     1612    }
     1613
    15981614    /** @todo Documentation says that RCVRL and XMTRL are stored as two's complement!
    15991615     *        Software is allowed to write these registers directly. */
     
    29542970#ifdef IN_RING3
    29552971                if (!CSR_INIT(pThis) && (val & 1))
    2956                     pcnetR3Init(pDevIns, pThis, pThisCC);
     2972                {
     2973                    bool    fDelayInit = false;
     2974
     2975                    /* Many PCnet drivers disable PCI bus mastering before setting the INIT bit and
     2976                     * then immediately enable it back again. This is done to work around a silicon
     2977                     * bug that could cause a PCI bus hang under some circumstances. The bug only
     2978                     * existed in the early PCI chips (Am79C970 PCnet-PCI) but many drivers apply the
     2979                     * workaround to all PCnet PCI models. Drivers written by AMD generally do this
     2980                     * (DOS, Windows, OS/2). PCnet drivers in Windows 2000 and XP are new enough to
     2981                     * not apply the workaround to our emulated PCnet-PCI II (Am79C970A) and
     2982                     * PCnet-FAST III (Am79C973).
     2983                     *
     2984                     * The AMDPCnet32 drivers for NeXTSTEP/OpenStep (notably OS 4.2) cpompletely fail
     2985                     * unless we delay the initialization until after bus mastering is re-enabled.
     2986                     */
     2987                    if (PCNET_IS_PCI(pThis))
     2988                    {
     2989                        PPDMPCIDEV pPciDev = pDevIns->apPciDevs[0];
     2990                        uint8_t uCmd = PDMPciDevGetByte(pPciDev, 0x04);
     2991
     2992                        /* Recognize situation with PCI bus mastering disabled and setting
     2993                         * INIT bit without also setting STRT.
     2994                         */
     2995                        if (!(uCmd & 4) && !(val & 2))
     2996                            fDelayInit = true;
     2997                    }
     2998
     2999                    if (!fDelayInit)
     3000                        pcnetR3Init(pDevIns, pThis, pThisCC);
     3001                    else
     3002                    {
     3003                        LogRel(("PCnet#%d: Delaying INIT due to disabled PCI bus mastering\n", PCNET_INST_NR));
     3004                        pThis->aCSR[0] |=  0x0001;  /* Set INIT and MERR bits. */
     3005                        pThis->aCSR[6] = 1;         /* Set a flag in read-only CSR6. */
     3006                    }
     3007                }
    29573008#endif
    29583009
     
    31413192}
    31423193
    3143 static uint32_t pcnetCSRReadU16(PPDMDEVINS pDevIns, PPCNETSTATE pThis, uint32_t u32RAP)
     3194static VBOXSTRICTRC pcnetCSRReadU16(PPDMDEVINS pDevIns, PPCNETSTATE pThis, PPCNETSTATECC pThisCC, uint32_t u32RAP, uint32_t *pu32)
    31443195{
    31453196    uint32_t val;
     
    31473198    {
    31483199        case 0:
     3200            /* Check if delayed initialization needs to run. */
     3201            if (RT_UNLIKELY(pThis->aCSR[6] == 1))
     3202            {
     3203#ifndef IN_RING3
     3204                return VINF_IOM_R3_IOPORT_READ;
     3205#else
     3206                /* This is the second half of delayed initialization required
     3207                 * to work around guest drivers that temporarily disable PCI bus
     3208                 * mastering around setting the INIT bit in CSR0.
     3209                 * See pcnetCSRWriteU16() for details.
     3210                 */
     3211                pcnetR3Init(pDevIns, pThis, pThisCC);
     3212                Assert(pThis->aCSR[6] != 1);
     3213#endif
     3214            }
    31493215            pcnetUpdateIrq(pDevIns, pThis);
    31503216            val = pThis->aCSR[0];
     
    31533219            break;
    31543220        case 16:
    3155             return pcnetCSRReadU16(pDevIns, pThis, 1);
     3221            return pcnetCSRReadU16(pDevIns, pThis, pThisCC, 1, pu32);
    31563222        case 17:
    3157             return pcnetCSRReadU16(pDevIns, pThis, 2);
     3223            return pcnetCSRReadU16(pDevIns, pThis, pThisCC, 2, pu32);
    31583224        case 58:
    3159             return pcnetBCRReadU16(pThis, BCR_SWS);
     3225            *pu32 = pcnetBCRReadU16(pThis, BCR_SWS);
     3226            return VINF_SUCCESS;
    31603227        case 68:    /* Custom register to pass link speed to driver */
    3161             return pcnetLinkSpd(pThis->u32LinkSpeed);
     3228            *pu32 = pcnetLinkSpd(pThis->u32LinkSpeed);
     3229            return VINF_SUCCESS;
    31623230        case 88:
    31633231            val = pThis->aCSR[89];
     
    31683236            val = pThis->aCSR[u32RAP];
    31693237    }
     3238    *pu32 = val;
    31703239    Log8(("#%d pcnetCSRReadU16: rap=%d val=%#06x\n", PCNET_INST_NR, u32RAP, val));
    3171     return val;
     3240    return VINF_SUCCESS;
    31723241}
    31733242
     
    36163685}
    36173686
    3618 static uint32_t pcnetIoPortReadU8(PPDMDEVINS pDevIns, PPCNETSTATE pThis, uint32_t addr)
    3619 {
    3620     uint32_t val = UINT32_MAX;
     3687static VBOXSTRICTRC pcnetIoPortReadU8(PPDMDEVINS pDevIns, PPCNETSTATE pThis, uint32_t addr, uint32_t *val)
     3688{
     3689    *val = UINT32_MAX;
    36213690
    36223691    if (RT_LIKELY(!BCR_DWIO(pThis)))
     
    36263695            case 0x04: /* RESET */
    36273696                pcnetSoftReset(pThis);
    3628                 val = 0;
     3697                *val = 0;
    36293698                break;
    36303699        }
    36313700    }
    36323701    else
    3633         Log(("#%d pcnetIoPortReadU8: addr=%#010x val=%#06x BCR_DWIO !!\n", PCNET_INST_NR, addr, val & 0xff));
     3702        Log(("#%d pcnetIoPortReadU8: addr=%#010x val=%#06x BCR_DWIO !!\n", PCNET_INST_NR, addr, *val & 0xff));
    36343703
    36353704    pcnetUpdateIrq(pDevIns, pThis);
    36363705
    3637     Log6(("#%d pcnetIoPortReadU8: addr=%#010x val=%#06x\n", PCNET_INST_NR, addr, val & 0xff));
    3638     return val;
     3706    Log6(("#%d pcnetIoPortReadU8: addr=%#010x val=%#06x\n", PCNET_INST_NR, addr, *val & 0xff));
     3707    return VINF_SUCCESS;
    36393708}
    36403709
     
    36673736}
    36683737
    3669 static uint32_t pcnetIoPortReadU16(PPDMDEVINS pDevIns, PPCNETSTATE pThis, PPCNETSTATECC pThisCC, uint32_t addr)
    3670 {
    3671     uint32_t val = ~0U;
     3738static VBOXSTRICTRC pcnetIoPortReadU16(PPDMDEVINS pDevIns, PPCNETSTATE pThis, PPCNETSTATECC pThisCC, uint32_t addr, uint32_t *val)
     3739{
     3740    VBOXSTRICTRC rc = VINF_SUCCESS;
     3741
     3742    *val = ~0U;
    36723743
    36733744    if (RT_LIKELY(!BCR_DWIO(pThis)))
     
    36813752                    pcnetPollTimer(pDevIns, pThis, pThisCC);
    36823753
    3683                 val = pcnetCSRReadU16(pDevIns, pThis, pThis->u32RAP);
     3754                rc = pcnetCSRReadU16(pDevIns, pThis, pThisCC, pThis->u32RAP, val);
    36843755                if (pThis->u32RAP == 0)  // pcnetUpdateIrq() already called by pcnetCSRReadU16()
    36853756                    goto skip_update_irq;
    36863757                break;
    36873758            case 0x02: /* RAP */
    3688                 val = pThis->u32RAP;
     3759                *val = pThis->u32RAP;
    36893760                goto skip_update_irq;
    36903761            case 0x04: /* RESET */
    36913762                pcnetSoftReset(pThis);
    3692                 val = 0;
     3763                *val = 0;
    36933764                break;
    36943765            case 0x06: /* BDP */
    3695                 val = pcnetBCRReadU16(pThis, pThis->u32RAP);
     3766                *val = pcnetBCRReadU16(pThis, pThis->u32RAP);
    36963767                break;
    36973768        }
    36983769    }
    36993770    else
    3700         Log(("#%d pcnetIoPortReadU16: addr=%#010x val=%#06x BCR_DWIO !!\n", PCNET_INST_NR, addr, val & 0xffff));
     3771        Log(("#%d pcnetIoPortReadU16: addr=%#010x val=%#06x BCR_DWIO !!\n", PCNET_INST_NR, addr, *val & 0xffff));
    37013772
    37023773    pcnetUpdateIrq(pDevIns, pThis);
    37033774
    37043775skip_update_irq:
    3705     Log6(("#%d pcnetIoPortReadU16: addr=%#010x val=%#06x\n", PCNET_INST_NR, addr, val & 0xffff));
    3706     return val;
     3776    Log6(("#%d pcnetIoPortReadU16: addr=%#010x val=%#06x\n", PCNET_INST_NR, addr, *val & 0xffff));
     3777    return rc;
    37073778}
    37083779
     
    37413812}
    37423813
    3743 static uint32_t pcnetIoPortReadU32(PPDMDEVINS pDevIns, PPCNETSTATE pThis, PPCNETSTATECC pThisCC, uint32_t addr)
    3744 {
    3745     uint32_t val = ~0U;
     3814static VBOXSTRICTRC pcnetIoPortReadU32(PPDMDEVINS pDevIns, PPCNETSTATE pThis, PPCNETSTATECC pThisCC, uint32_t addr, uint32_t *val)
     3815{
     3816    VBOXSTRICTRC rc = VINF_SUCCESS;
     3817
     3818    *val = ~0U;
    37463819
    37473820    if (RT_LIKELY(BCR_DWIO(pThis)))
     
    37553828                    pcnetPollTimer(pDevIns, pThis, pThisCC);
    37563829
    3757                 val = pcnetCSRReadU16(pDevIns, pThis, pThis->u32RAP);
     3830                rc = pcnetCSRReadU16(pDevIns, pThis, pThisCC, pThis->u32RAP, val);
    37583831                if (pThis->u32RAP == 0)  // pcnetUpdateIrq() already called by pcnetCSRReadU16()
    37593832                    goto skip_update_irq;
    37603833                break;
    37613834            case 0x04: /* RAP */
    3762                 val = pThis->u32RAP;
     3835                *val = pThis->u32RAP;
    37633836                goto skip_update_irq;
    37643837            case 0x08: /* RESET */
    37653838                pcnetSoftReset(pThis);
    3766                 val = 0;
     3839                *val = 0;
    37673840                break;
    37683841            case 0x0c: /* BDP */
    3769                 val = pcnetBCRReadU16(pThis, pThis->u32RAP);
     3842                *val = pcnetBCRReadU16(pThis, pThis->u32RAP);
    37703843                break;
    37713844        }
    37723845    }
    37733846    else
    3774         Log(("#%d pcnetIoPortReadU32: addr=%#010x val=%#010x !BCR_DWIO !!\n", PCNET_INST_NR, addr, val));
     3847        Log(("#%d pcnetIoPortReadU32: addr=%#010x val=%#010x !BCR_DWIO !!\n", PCNET_INST_NR, addr, *val));
    37753848    pcnetUpdateIrq(pDevIns, pThis);
    37763849
    37773850skip_update_irq:
    3778     Log6(("#%d pcnetIoPortReadU32: addr=%#010x val=%#010x\n", PCNET_INST_NR, addr, val));
    3779     return val;
     3851    Log6(("#%d pcnetIoPortReadU32: addr=%#010x val=%#010x\n", PCNET_INST_NR, addr, *val));
     3852    return rc;
    37803853}
    37813854
     
    37883861    PPCNETSTATE     pThis   = PDMDEVINS_2_DATA(pDevIns, PPCNETSTATE);
    37893862    PPCNETSTATECC   pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PPCNETSTATECC);
    3790     VBOXSTRICTRC    rc      = VINF_SUCCESS;
     3863    VBOXSTRICTRC    rc;
    37913864    STAM_PROFILE_ADV_START(&pThis->CTX_SUFF_Z(StatIORead), a);
    37923865    Assert(PDMDevHlpCritSectIsOwner(pDevIns, &pThis->CritSect));
     
    37953868    switch (cb)
    37963869    {
    3797         case 1: *pu32 = pcnetIoPortReadU8(pDevIns, pThis, offPort); break;
    3798         case 2: *pu32 = pcnetIoPortReadU16(pDevIns, pThis, pThisCC, offPort); break;
    3799         case 4: *pu32 = pcnetIoPortReadU32(pDevIns, pThis, pThisCC, offPort); break;
     3870        case 1: rc = pcnetIoPortReadU8(pDevIns, pThis, offPort, pu32); break;
     3871        case 2: rc = pcnetIoPortReadU16(pDevIns, pThis, pThisCC, offPort, pu32); break;
     3872        case 4: rc = pcnetIoPortReadU32(pDevIns, pThis, pThisCC, offPort, pu32); break;
    38003873        default:
    38013874            rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "pcnetIoPortRead: unsupported op size: offset=%#10x cb=%u\n", offPort, cb);
     
    38463919}
    38473920
    3848 static uint32_t pcnetR3MmioReadU8(PPCNETSTATE pThis, RTGCPHYS addr)
    3849 {
    3850     uint32_t val = ~0U;
     3921static VBOXSTRICTRC pcnetR3MmioReadU8(PPCNETSTATE pThis, RTGCPHYS addr, uint8_t *val)
     3922{
     3923    *val = 0xff;
    38513924    if (!(addr & 0x10))
    3852         val = pcnetAPROMReadU8(pThis, addr);
    3853     Log6(("#%d pcnetR3MmioReadU8: addr=%#010x val=%#04x\n", PCNET_INST_NR, addr, val & 0xff));
    3854     return val;
     3925        *val = pcnetAPROMReadU8(pThis, addr);
     3926    Log6(("#%d pcnetR3MmioReadU8: addr=%#010x val=%#04x\n", PCNET_INST_NR, addr, *val));
     3927    return VINF_SUCCESS;
    38553928}
    38563929
     
    38743947}
    38753948
    3876 static uint32_t pcnetR3MmioReadU16(PPDMDEVINS pDevIns, PPCNETSTATE pThis, PPCNETSTATECC pThisCC, RTGCPHYS addr)
    3877 {
    3878     uint32_t val = ~0U;
     3949static VBOXSTRICTRC pcnetR3MmioReadU16(PPDMDEVINS pDevIns, PPCNETSTATE pThis, PPCNETSTATECC pThisCC, RTGCPHYS addr, uint16_t *val)
     3950{
     3951    VBOXSTRICTRC rcStrict;
     3952    uint32_t val32 = ~0U;
    38793953
    38803954    if (addr & 0x10)
    3881         val = pcnetIoPortReadU16(pDevIns, pThis, pThisCC, addr & 0x0f);
     3955    {
     3956        rcStrict = pcnetIoPortReadU16(pDevIns, pThis, pThisCC, addr & 0x0f, &val32);
     3957        if (rcStrict == VINF_IOM_R3_IOPORT_READ)
     3958            rcStrict = VINF_IOM_R3_MMIO_READ;
     3959    }
    38823960    else
    38833961    {
    3884         val = pcnetAPROMReadU8(pThis, addr+1);
    3885         val <<= 8;
    3886         val |= pcnetAPROMReadU8(pThis, addr);
    3887     }
    3888     Log6(("#%d pcnetR3MmioReadU16: addr=%#010x val = %#06x\n", PCNET_INST_NR, addr, val & 0xffff));
    3889     return val;
     3962        val32 = pcnetAPROMReadU8(pThis, addr+1);
     3963        val32 <<= 8;
     3964        val32 |= pcnetAPROMReadU8(pThis, addr);
     3965        rcStrict = VINF_SUCCESS;
     3966    }
     3967    *val = (uint16_t)val32;
     3968    Log6(("#%d pcnetR3MmioReadU16: addr=%#010x val = %#06x\n", PCNET_INST_NR, addr, *val));
     3969    return rcStrict;
    38903970}
    38913971
     
    39113991}
    39123992
    3913 static uint32_t pcnetR3MmioReadU32(PPDMDEVINS pDevIns, PPCNETSTATE pThis, PPCNETSTATECC pThisCC, RTGCPHYS addr)
    3914 {
    3915     uint32_t val;
     3993static VBOXSTRICTRC pcnetR3MmioReadU32(PPDMDEVINS pDevIns, PPCNETSTATE pThis, PPCNETSTATECC pThisCC, RTGCPHYS addr, uint32_t *val)
     3994{
     3995    VBOXSTRICTRC rcStrict;
    39163996
    39173997    if (addr & 0x10)
    3918         val = pcnetIoPortReadU32(pDevIns, pThis, pThisCC, addr & 0x0f);
     3998    {
     3999        rcStrict = pcnetIoPortReadU32(pDevIns, pThis, pThisCC, addr & 0x0f, val);
     4000        if (rcStrict == VINF_IOM_R3_IOPORT_READ)
     4001            rcStrict = VINF_IOM_R3_MMIO_READ;
     4002    }
    39194003    else
    39204004    {
    3921         val  = pcnetAPROMReadU8(pThis, addr+3);
    3922         val <<= 8;
    3923         val |= pcnetAPROMReadU8(pThis, addr+2);
    3924         val <<= 8;
    3925         val |= pcnetAPROMReadU8(pThis, addr+1);
    3926         val <<= 8;
    3927         val |= pcnetAPROMReadU8(pThis, addr  );
    3928     }
    3929     Log6(("#%d pcnetR3MmioReadU32: addr=%#010x val=%#010x\n", PCNET_INST_NR, addr, val));
    3930     return val;
     4005        uint32_t    val32;
     4006
     4007        val32  = pcnetAPROMReadU8(pThis, addr+3);
     4008        val32 <<= 8;
     4009        val32 |= pcnetAPROMReadU8(pThis, addr+2);
     4010        val32 <<= 8;
     4011        val32 |= pcnetAPROMReadU8(pThis, addr+1);
     4012        val32 <<= 8;
     4013        val32 |= pcnetAPROMReadU8(pThis, addr  );
     4014        *val = val32;
     4015        rcStrict = VINF_SUCCESS;
     4016    }
     4017    Log6(("#%d pcnetR3MmioReadU32: addr=%#010x val=%#010x\n", PCNET_INST_NR, addr, *val));
     4018    return rcStrict;
    39314019}
    39324020
     
    39514039        switch (cb)
    39524040        {
    3953             case 1:  *(uint8_t  *)pv = pcnetR3MmioReadU8 (pThis, off); break;
    3954             case 2:  *(uint16_t *)pv = pcnetR3MmioReadU16(pDevIns, pThis, pThisCC, off); break;
    3955             case 4:  *(uint32_t *)pv = pcnetR3MmioReadU32(pDevIns, pThis, pThisCC, off); break;
     4041            case 1:  rc = pcnetR3MmioReadU8 (pThis, off, (uint8_t *)pv); break;
     4042            case 2:  rc = pcnetR3MmioReadU16(pDevIns, pThis, pThisCC, off, (uint16_t *)pv); break;
     4043            case 4:  rc = pcnetR3MmioReadU32(pDevIns, pThis, pThisCC, off, (uint32_t *)pv); break;
    39564044            default:
    39574045                rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "pcnetR3MmioRead: unsupported op size: address=%RGp cb=%u\n", off, cb);
     
    52445332    PDMPciDevSetByte(pPciDev, 0x06,     0x80); /* status */
    52455333    PDMPciDevSetByte(pPciDev, 0x07,     0x02);
    5246     PDMPciDevSetByte(pPciDev, 0x08,     pThis->uDevType == DEV_AM79C973 ? 0x40 : 0x10); /* revision */
     5334    PDMPciDevSetByte(pPciDev, 0x08,     pThis->uDevType == DEV_AM79C973 ? 0x40 : 0x16); /* revision */
    52475335    PDMPciDevSetByte(pPciDev, 0x09,     0x00);
    52485336    PDMPciDevSetByte(pPciDev, 0x0a,     0x00); /* ethernet network controller */
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