static uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len)

{

    VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev);

    uint32_t val = 0;



    /*

     * We only need QEMU PCI config support for the ROM BAR, the MSI and MSIX

     * capabilities, and the multifunction bit below.  We let VFIO handle

     * virtualizing everything else.  Performance is not a concern here.

     */

    if (ranges_overlap(addr, len, PCI_ROM_ADDRESS, 4) ||

        (pdev->cap_present & QEMU_PCI_CAP_MSIX &&

         ranges_overlap(addr, len, pdev->msix_cap, MSIX_CAP_LENGTH)) ||

        (pdev->cap_present & QEMU_PCI_CAP_MSI &&

         ranges_overlap(addr, len, pdev->msi_cap, vdev->msi_cap_size))) {



        val = pci_default_read_config(pdev, addr, len);

    } else {

        if (pread(vdev->fd, &val, len, vdev->config_offset + addr) != len) {

            error_report("%s(%04x:%02x:%02x.%x, 0x%x, 0x%x) failed: %m",

                         __func__, vdev->host.domain, vdev->host.bus,

                         vdev->host.slot, vdev->host.function, addr, len);

            return -errno;

        }

        val = le32_to_cpu(val);

    }



    /* Multifunction bit is virualized in QEMU */

    if (unlikely(ranges_overlap(addr, len, PCI_HEADER_TYPE, 1))) {

        uint32_t mask = PCI_HEADER_TYPE_MULTI_FUNCTION;



        if (len == 4) {

            mask <<= 16;

        }



        if (pdev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) {

            val |= mask;

        } else {

            val &= ~mask;

        }

    }



    DPRINTF("%s(%04x:%02x:%02x.%x, @0x%x, len=0x%x) %x\n", __func__,

            vdev->host.domain, vdev->host.bus, vdev->host.slot,

            vdev->host.function, addr, len, val);



    return val;

}

static uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len)

{

    VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev);

    uint32_t val = 0;



    









    if (ranges_overlap(addr, len, PCI_ROM_ADDRESS, 4) ||

        (pdev->cap_present & QEMU_PCI_CAP_MSIX &&

         ranges_overlap(addr, len, pdev->msix_cap, MSIX_CAP_LENGTH)) ||

        (pdev->cap_present & QEMU_PCI_CAP_MSI &&

         ranges_overlap(addr, len, pdev->msi_cap, vdev->msi_cap_size))) {



        val = pci_default_read_config(pdev, addr, len);

    } else {

        if (pread(vdev->fd, &val, len, vdev->config_offset + addr) != len) {

            error_report("%s(%04x:%02x:%02x.%x, 0x%x, 0x%x) failed: %m",

                         __func__, vdev->host.domain, vdev->host.bus,

                         vdev->host.slot, vdev->host.function, addr, len);

            return -errno;

        }

        val = le32_to_cpu(val);

    }



    

    if (unlikely(ranges_overlap(addr, len, PCI_HEADER_TYPE, 1))) {

        uint32_t mask = PCI_HEADER_TYPE_MULTI_FUNCTION;



        if (len == 4) {

            mask <<= 16;

        }



        if (pdev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) {

            val |= mask;

        } else {

            val &= ~mask;

        }

    }



    DPRINTF("%s(%04x:%02x:%02x.%x, @0x%x, len=0x%x) %x\n", __func__,

            vdev->host.domain, vdev->host.bus, vdev->host.slot,

            vdev->host.function, addr, len, val);



    return val;

}

static uint32_t FUNC_0(PCIDevice *pdev, uint32_t addr, int len)

{

    VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev);

    uint32_t val = 0;



    









    if (ranges_overlap(addr, len, PCI_ROM_ADDRESS, 4) ||

        (pdev->cap_present & QEMU_PCI_CAP_MSIX &&

         ranges_overlap(addr, len, pdev->msix_cap, MSIX_CAP_LENGTH)) ||

        (pdev->cap_present & QEMU_PCI_CAP_MSI &&

         ranges_overlap(addr, len, pdev->msi_cap, vdev->msi_cap_size))) {



        val = pci_default_read_config(pdev, addr, len);

    } else {

        if (pread(vdev->fd, &val, len, vdev->config_offset + addr) != len) {

            error_report("%s(%04x:%02x:%02x.%x, 0x%x, 0x%x) failed: %m",

                         __func__, vdev->host.domain, vdev->host.bus,

                         vdev->host.slot, vdev->host.function, addr, len);

            return -errno;

        }

        val = le32_to_cpu(val);

    }



    

    if (unlikely(ranges_overlap(addr, len, PCI_HEADER_TYPE, 1))) {

        uint32_t mask = PCI_HEADER_TYPE_MULTI_FUNCTION;



        if (len == 4) {

            mask <<= 16;

        }



        if (pdev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) {

            val |= mask;

        } else {

            val &= ~mask;

        }

    }



    DPRINTF("%s(%04x:%02x:%02x.%x, @0x%x, len=0x%x) %x\n", __func__,

            vdev->host.domain, vdev->host.bus, vdev->host.slot,

            vdev->host.function, addr, len, val);



    return val;

}

static uint32_t FUNC_0(PCIDevice *pdev, uint32_t addr, int len)
{ VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev); uint32_t val = 0; if (ranges_overlap(addr, len, PCI_ROM_ADDRESS, 4) ||
(pdev->cap_present & QEMU_PCI_CAP_MSIX &&
ranges_overlap(addr, len, pdev->msix_cap, MSIX_CAP_LENGTH)) ||
(pdev->cap_present & QEMU_PCI_CAP_MSI &&
ranges_overlap(addr, len, pdev->msi_cap, vdev->msi_cap_size))) { val = pci_default_read_config(pdev, addr, len); } else { if (pread(vdev->fd, &val, len, vdev->config_offset + addr) != len) { error_report("%s(%04x:%02x:%02x.%x, 0x%x, 0x%x) failed: %m",
__func__, vdev->host.domain, vdev->host.bus,
vdev->host.slot, vdev->host.function, addr, len); return -errno; } val = le32_to_cpu(val); } if (unlikely(ranges_overlap(addr, len, PCI_HEADER_TYPE, 1))) { uint32_t mask = PCI_HEADER_TYPE_MULTI_FUNCTION; if (len == 4) { mask <<= 16; } if (pdev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) { val |= mask; } else { val &= ~mask; } } DPRINTF("%s(%04x:%02x:%02x.%x, @0x%x, len=0x%x) %x\n", __func__,
vdev->host.domain, vdev->host.bus, vdev->host.slot,
vdev->host.function, addr, len, val); return val; }