VirtualBox

Changeset 57781 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Sep 16, 2015 11:35:28 AM (9 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
102718
Message:

Devices/Bus/PCI: Improved BAR mapping sanity checking, including appropriate messages to VBox.log if the fake BIOS or the guest requests something impossible. Moved the enabling of PCI I/O and memory command processing to the end of the device setup to reduce the noise. Added (comented out) release logging of each mapping update, plus a lot of cleanups to make the two redundant implementations more similar.

Location:
trunk/src/VBox/Devices/Bus
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Bus/DevPCI.cpp

    r57393 r57781  
    289289                       mappings, we handle specific values as invalid
    290290                       mappings. */
     291                    /* Unconditionally exclude I/O-APIC/HPET/ROM. Pessimistic, but better than causing a mess. */
    291292                    if (last_addr <= new_addr || new_addr == 0 ||
    292                         last_addr == ~0U) {
     293                        (new_addr <= ~0U && last_addr >= 0xfec00000U)) {
    293294                        new_addr = ~0U;
    294295                    }
     
    298299                }
    299300            }
     301            //LogRel(("PCI: config dev %u/%u BAR%i uOld=%#018llx uNew=%#018llx size=%llu\n", d->devfn >> 3, d->devfn & 7, i, r->addr, new_addr, r->size));
    300302            /* now do the real mapping */
    301303            if (new_addr != r->addr) {
     
    877879static void pci_set_io_region_addr(PPCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn, int region_num, uint32_t addr)
    878880{
    879     uint16_t cmd;
    880881    uint32_t ofs;
    881882
     
    885886        ofs = 0x10 + region_num * 4;
    886887
    887     /* Read memory type first. */
    888     uint8_t uRessourceType = pci_config_readb(pGlobals, uBus, uDevFn, ofs);
    889 
    890     /* Read command register. */
    891     cmd = pci_config_readw(pGlobals, uBus, uDevFn, PCI_COMMAND);
    892     if ( region_num == PCI_ROM_SLOT )
    893         cmd |= 2;
    894     else if ((uRessourceType & 0x01) == 1) /* Test if region is I/O space. */
    895         cmd |= 1; /* Enable I/O space access. */
    896     else /* The region is MMIO. */
    897         cmd |= 2; /* Enable MMIO access. */
     888    Log(("Set region address: %02x:%02x.%d region %d address=%lld\n",
     889         uBus, uDevFn >> 3, uDevFn & 7, region_num, addr));
    898890
    899891    /* Write address of the device. */
    900892    pci_config_writel(pGlobals, uBus, uDevFn, ofs, addr);
    901 
    902     /* enable memory mappings */
    903     pci_config_writew(pGlobals, uBus, uDevFn, PCI_COMMAND, cmd);
    904893}
    905894
     
    935924                    pci_set_io_region_addr(pGlobals, uBus, uDevFn, 2, 0x170);
    936925                    pci_set_io_region_addr(pGlobals, uBus, uDevFn, 3, 0x374);
     926                    pci_config_writeb(pGlobals, uBus, uDevFn, PCI_COMMAND,
     927                                      pci_config_readb(pGlobals, uBus, uDevFn, PCI_COMMAND)
     928                                      | PCI_COMMAND_IOACCESS);
    937929                }
    938930                break;
     
    945937                 * Legacy VGA I/O ports are implicitly decoded by a VGA class device. But
    946938                 * only the framebuffer (i.e., a memory region) is explicitly registered via
    947                  * pci_set_io_region_addr, so I/O decoding must be enabled manually.
     939                 * pci_set_io_region_addr, so don't forget to enable I/O decoding.
    948940                 */
    949941                pci_config_writeb(pGlobals, uBus, uDevFn, PCI_COMMAND,
    950942                                  pci_config_readb(pGlobals, uBus, uDevFn, PCI_COMMAND)
    951                                   | 1 /* Enable I/O space access. */);
     943                                  | PCI_COMMAND_IOACCESS | PCI_COMMAND_MEMACCESS);
    952944                break;
    953945            case 0x0800:
     
    962954                        /* MPIC & MPIC2 */
    963955                        pci_set_io_region_addr(pGlobals, uBus, uDevFn, 0, 0x80800000 + 0x00040000);
     956                        pci_config_writeb(pGlobals, uBus, uDevFn, PCI_COMMAND,
     957                                          pci_config_readb(pGlobals, uBus, uDevFn, PCI_COMMAND)
     958                                          | PCI_COMMAND_MEMACCESS);
    964959                    }
    965960                }
     
    971966                    /* macio bridge */
    972967                    pci_set_io_region_addr(pGlobals, uBus, uDevFn, 0, 0x80800000);
     968                    pci_config_writeb(pGlobals, uBus, uDevFn, PCI_COMMAND,
     969                                      pci_config_readb(pGlobals, uBus, uDevFn, PCI_COMMAND)
     970                                      | PCI_COMMAND_MEMACCESS);
    973971                }
    974972                break;
     
    10491047            {
    10501048                /* default memory mappings */
     1049                bool fActiveMemRegion = false;
     1050                bool fActiveIORegion = false;
    10511051                /*
    10521052                 * PCI_NUM_REGIONS is 7 because of the rom region but there are only 6 base address register defined by the PCI spec.
     
    10631063                    pci_config_writel(pGlobals, uBus, uDevFn, u32Address, UINT32_C(0xffffffff));
    10641064                    u32Size = pci_config_readl(pGlobals, uBus, uDevFn, u32Address);
     1065                    bool fIsPio = ((u8RessourceType & PCI_COMMAND_IOACCESS) == PCI_COMMAND_IOACCESS);
    10651066                    /* Clear resource information depending on resource type. */
    1066                     if ((u8RessourceType & 0x01) == 1) /* I/O */
     1067                    if (fIsPio) /* I/O */
    10671068                        u32Size &= ~(0x01);
    10681069                    else                        /* MMIO */
     
    10731074                     * (From PCI implementation note)
    10741075                     */
    1075                     if (((u8RessourceType & 0x01) == 1) && (u32Size & UINT32_C(0xffff0000)) == 0)
     1076                    if (fIsPio && (u32Size & UINT32_C(0xffff0000)) == 0)
    10761077                        u32Size = (~(u32Size | UINT32_C(0xffff0000))) + 1;
    10771078                    else
    10781079                        u32Size = (~u32Size) + 1;
    10791080
    1080                     Log(("%s: Size of region %u for device %d on bus %d is %u\n", __FUNCTION__, i, uDevFn, uBus, u32Size));
     1081                    Log2(("%s: Size of region %u for device %d on bus %d is %u\n", __FUNCTION__, i, uDevFn, uBus, u32Size));
    10811082
    10821083                    if (u32Size)
    10831084                    {
    1084                         if ((u8RessourceType & 0x01) == 1)
     1085                        if (fIsPio)
    10851086                            paddr = &pGlobals->pci_bios_io_addr;
    10861087                        else
    10871088                            paddr = &pGlobals->pci_bios_mem_addr;
    1088                         *paddr = (*paddr + u32Size - 1) & ~(u32Size - 1);
    1089                         Log(("%s: Start address of %s region %u is %#x\n", __FUNCTION__, ((u8RessourceType & 0x01) == 1 ? "I/O" : "MMIO"), i, *paddr));
    1090                         pci_set_io_region_addr(pGlobals, uBus, uDevFn, i, *paddr);
    1091                         *paddr += u32Size;
    1092                         Log(("%s: New address is %#x\n", __FUNCTION__, *paddr));
     1089                        uint32_t uNew = *paddr;
     1090                        uNew = (uNew + u32Size - 1) & ~(u32Size - 1);
     1091                        if (fIsPio)
     1092                            uNew &= UINT32_C(0xffff);
     1093                        /* Unconditionally exclude I/O-APIC/HPET/ROM. Pessimistic, but better than causing a mess. */
     1094                        if (!uNew || (uNew <= UINT32_C(0xffffffff) && uNew + u32Size - 1 >= UINT32_C(0xfec00000)))
     1095                        {
     1096                            LogRel(("PCI: no space left for BAR%u of device %u/%u/%u (vendor=%#06x device=%#06x)\n",
     1097                                    i, uBus, uDevFn >> 3, uDevFn & 7, vendor_id, device_id)); /** @todo make this a VM start failure later. */
     1098                            /* Undo the mapping mess caused by the size probing. */
     1099                            pci_config_writel(pGlobals, uBus, uDevFn, u32Address, UINT32_C(0));
     1100                        }
     1101                        else
     1102                        {
     1103                            Log(("%s: Start address of %s region %u is %#x\n", __FUNCTION__, (fIsPio ? "I/O" : "MMIO"), i, uNew));
     1104                            pci_set_io_region_addr(pGlobals, uBus, uDevFn, i, uNew);
     1105                            if (fIsPio)
     1106                                fActiveIORegion = true;
     1107                            else
     1108                                fActiveMemRegion = true;
     1109                            *paddr = uNew + u32Size;
     1110                            Log2(("%s: New address is %#x\n", __FUNCTION__, *paddr));
     1111                        }
    10931112                    }
    10941113                }
     1114
     1115                /* Update the command word appropriately. */
     1116                pci_config_writeb(pGlobals, uBus, uDevFn, PCI_COMMAND,
     1117                                  pci_config_readb(pGlobals, uBus, uDevFn, PCI_COMMAND)
     1118                                  | (fActiveMemRegion ? PCI_COMMAND_MEMACCESS : 0)
     1119                                  | (fActiveIORegion ? PCI_COMMAND_IOACCESS : 0));
     1120
    10951121                break;
    10961122            }
  • trunk/src/VBox/Devices/Bus/DevPciIch9.cpp

    r57393 r57781  
    894894                {
    895895                    uNew |= ((uint64_t)ich9pciGetDWord(pDev, uConfigReg+4)) << 32;
     896                    /** @todo r=klaus Is this really true? Needs to be fixed properly. */
    896897                    if (uNew > UINT64_C(0x0000010000000000))
    897898                    {
    898                         /* Workaround for REM being unhapping with mapping very lange 64-bit addresses */
    899                         Log(("Ignoring too 64-bit BAR: %llx\n", uNew));
     899                        /* Workaround for REM being unhapping with mapping very long 64-bit addresses */
     900                        LogRel(("Ignoring too long 64-bit BAR: %llx\n", uNew));
    900901                        uNew = INVALID_PCI_ADDRESS;
    901902                    }
     
    913914                       mappings, we handle specific values as invalid
    914915                       mappings. */
    915                     if (uLast <= uNew || uNew == 0 || uLast == INVALID_PCI_ADDRESS)
     916                    /* Unconditionally exclude I/O-APIC/HPET/ROM. Pessimistic, but better than causing a mess. */
     917                    if (uLast <= uNew || uNew == 0 || (uNew <= UINT32_C(0xffffffff) && uLast >= UINT32_C(0xfec00000)))
    916918                        uNew = INVALID_PCI_ADDRESS;
    917919                }
     
    919921                uNew = INVALID_PCI_ADDRESS;
    920922        }
     923        //LogRel(("PCI: config dev %u/%u BAR%i uOld=%#018llx uNew=%#018llx size=%llu\n", pDev->devfn >> 3, pDev->devfn & 7, iRegion, pRegion->addr, uNew, pRegion->size));
    921924        /* now do the real mapping */
    922925        if (uNew != pRegion->addr)
     
    936939            }
    937940        }
     941
     942        if (f64Bit)
     943            iRegion++;
    938944    }
    939945}
     
    16141620    /* Read memory type first. */
    16151621    uint8_t uResourceType = ich9pciConfigRead(pGlobals, uBus, uDevFn, uReg, 1);
    1616     /* Read command register. */
    1617     uint16_t uCmd = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_COMMAND, 2);
    16181622
    16191623    Log(("Set region address: %02x:%02x.%d region %d address=%lld\n",
    16201624         uBus, uDevFn >> 3, uDevFn & 7, iRegion, addr));
    1621 
    1622     if ( iRegion == PCI_ROM_SLOT )
    1623         uCmd |= PCI_COMMAND_MEMACCESS;
    1624     else if ((uResourceType & PCI_ADDRESS_SPACE_IO) == PCI_ADDRESS_SPACE_IO)
    1625         uCmd |= PCI_COMMAND_IOACCESS; /* Enable I/O space access. */
    1626     else /* The region is MMIO. */
    1627         uCmd |= PCI_COMMAND_MEMACCESS; /* Enable MMIO access. */
    16281625
    16291626    bool f64Bit = (uResourceType & PCI_ADDRESS_SPACE_BAR64) != 0;
     
    16331630    if (f64Bit)
    16341631        ich9pciConfigWrite(pGlobals, uBus, uDevFn, uReg + 4, (uint32_t)(addr >> 32), 4);
    1635 
    1636     /* enable memory mappings */
    1637     ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_COMMAND, uCmd, 2);
    16381632}
    16391633
     
    17371731             * Legacy VGA I/O ports are implicitly decoded by a VGA class device. But
    17381732             * only the framebuffer (i.e., a memory region) is explicitly registered via
    1739              * ich9pciSetRegionAddress, so I/O decoding must be enabled manually.
     1733             * ich9pciSetRegionAddress, so don't forget to enable I/O decoding.
    17401734             */
    17411735            uCmd = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_COMMAND, 1);
    17421736            ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_COMMAND,
    1743                                /* Enable I/O space access. */
    1744                                uCmd | PCI_COMMAND_IOACCESS,
     1737                               uCmd | PCI_COMMAND_IOACCESS | PCI_COMMAND_MEMACCESS,
    17451738                               1);
    17461739            break;
    1747        case 0x0604:
     1740        case 0x0604:
    17481741            /* PCI-to-PCI bridge. */
    17491742            AssertMsg(pGlobals->uBus < 255, ("Too many bridges on the bus\n"));
     
    17541747        {
    17551748            /* default memory mappings */
     1749            bool fActiveMemRegion = false;
     1750            bool fActiveIORegion = false;
    17561751            /*
    17571752             * We ignore ROM region here.
     
    17621757
    17631758                /* Calculate size - we write all 1s into the BAR, and then evaluate which bits
    1764                    are cleared. . */
     1759                   are cleared. */
    17651760                uint8_t u8ResourceType = ich9pciConfigRead(pGlobals, uBus, uDevFn, u32Address, 1);
    17661761
     
    18131808                if (cbRegSize64)
    18141809                {
     1810                    /** @todo r=klaus make this code actually handle 64-bit BARs, especially MMIO which can't possibly fit into the memory hole. */
    18151811                    uint32_t  cbRegSize32 = (uint32_t)cbRegSize64;
    18161812                    uint32_t* paddr = fIsPio ? &pGlobals->uPciBiosIo : &pGlobals->uPciBiosMmio;
    1817                     *paddr = (*paddr + cbRegSize32 - 1) & ~(cbRegSize32 - 1);
    1818                     Log(("%s: Start address of %s region %u is %#x\n", __FUNCTION__, (fIsPio ? "I/O" : "MMIO"), iRegion, *paddr));
    1819                     ich9pciSetRegionAddress(pGlobals, uBus, uDevFn, iRegion, *paddr);
    1820                     *paddr += cbRegSize32;
    1821                     Log2(("%s: New address is %#x\n", __FUNCTION__, *paddr));
     1813                    uint32_t uNew = *paddr;
     1814                    uNew = (uNew + cbRegSize32 - 1) & ~(cbRegSize32 - 1);
     1815                    if (fIsPio)
     1816                        uNew &= UINT32_C(0xffff);
     1817                    /* Unconditionally exclude I/O-APIC/HPET/ROM. Pessimistic, but better than causing a mess. */
     1818                    if (!uNew || (uNew <= UINT32_C(0xffffffff) && uNew + cbRegSize32 - 1 >= UINT32_C(0xfec00000)))
     1819                    {
     1820                        LogRel(("PCI: no space left for BAR%u of device %u/%u/%u (vendor=%#06x device=%#06x)\n",
     1821                                iRegion, uBus, uDevFn >> 3, uDevFn & 7, uVendor, uDevice)); /** @todo make this a VM start failure later. */
     1822                        /* Undo the mapping mess caused by the size probing. */
     1823                        ich9pciConfigWrite(pGlobals, uBus, uDevFn, u32Address, UINT32_C(0), 4);
     1824                        if (f64bit)
     1825                            ich9pciConfigWrite(pGlobals, uBus, uDevFn, u32Address+4, UINT32_C(0), 4);
     1826                    }
     1827                    else
     1828                    {
     1829                        Log(("%s: Start address of %s region %u is %#x\n", __FUNCTION__, (fIsPio ? "I/O" : "MMIO"), iRegion, uNew));
     1830                        ich9pciSetRegionAddress(pGlobals, uBus, uDevFn, iRegion, uNew);
     1831                        if (fIsPio)
     1832                            fActiveIORegion = true;
     1833                        else
     1834                            fActiveMemRegion = true;
     1835                        *paddr = uNew + cbRegSize32;
     1836                        Log2(("%s: New address is %#x\n", __FUNCTION__, *paddr));
     1837                    }
    18221838
    18231839                    if (f64bit)
     
    18251841                }
    18261842            }
     1843
     1844            /* Update the command word appropriately. */
     1845            uCmd = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_COMMAND, 2);
     1846            if (fActiveMemRegion)
     1847                uCmd |= PCI_COMMAND_MEMACCESS; /* Enable MMIO access. */
     1848            if (fActiveIORegion)
     1849                uCmd |= PCI_COMMAND_IOACCESS; /* Enable I/O space access. */
     1850            ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_COMMAND, uCmd, 2);
    18271851            break;
    18281852        }
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