<div dir="ltr"><div><div><div><div><div>Hi guys,<br><br>I've been working with qemu kvm for a while and now I need to 
passthrough PCI devices. I did all required procedures to make this 
work: enabled iommu, modprobed vfio module, binded device to vfio and 
checked that vfio group was indeed created, etc...
But when I start qemu with any pci devices I get the error message:<div><div class="gmail-post-text">

<blockquote>
  <p><i>vfio: Failed to read device config space</i></p>
</blockquote>By looking into qemu code I found out that the error was coming from a call to pread to read the pci device's file descriptor. It fails with errno '<b>Illegal seek</b>'. Offset being used is 0x70000000000, and this offset seems to be the same for all devices and also in different machines. I also wrote some code to test reading the pci device file descriptor from outside of the qemu code and the pread also fails with 'illegal seek' error. This was done on a generic linux kernel v4.7.8 compiled with uClibc for an embedded system.<br><br>If I install ubuntu 16.04 (kernel v4.4.0) on the same machine and repeat the steps, pci passthrough works fine and the pread on my test code also works perfectly.<br><br>This is the code I am using to test reading the device fd with pread:<br><br><br></div></div><span style="font-family:monospace,monospace">#include <unistd.h><br>#include <stdio.h><br>#include <errno.h><br>#include <fcntl.h><br>#include <linux/vfio.h><br>#include <sys/ioctl.h><br>#include <sys/mman.h><br><br>#define BUF_SIZE 4096<br><br>int main(){<br>    char buf[BUF_SIZE], buf1[BUF_SIZE], buf2[BUF_SIZE];<br>    <br>    int ret,group_fd, fd, fd2;<br>    size_t nbytes = BUF_SIZE;<br>    ssize_t bytes_read;<br>    int iommu1, iommu2;<br>    unsigned long offset;<br>    int container, group, device, i;<br>    struct vfio_group_status group_status = { .argsz = sizeof(group_status) };<br>    struct vfio_iommu_type1_info iommu_info = { .argsz = sizeof(iommu_info) };<br>    struct vfio_iommu_type1_dma_map dma_map = { .argsz = sizeof(dma_map) };<br>    struct vfio_device_info device_info = { .argsz = sizeof(device_info) };<br>    struct vfio_region_info reg = { .argsz = sizeof(reg) }; <br><br>    container = open("/dev/vfio/vfio",O_RDWR);<br>    printf("Container = %d\n",container);<br>    if(ioctl(container,VFIO_GET_API_VERSION)!=VFIO_API_VERSION){<br>        printf("Unknown api version: %m\n");<br>    }<br>    group_fd = open("/dev/vfio/1",O_RDWR);<br>    printf("Group fd = %d\n", group_fd);<br>    ioctl(group_fd, VFIO_GROUP_GET_STATUS, &group_status);<br>    if (!(group_status.flags & VFIO_GROUP_FLAGS_VIABLE)){<br>        printf("Group not viable\n");<br>        getchar();<br>        return 1;<br>    }<br>    ret = ioctl(group_fd, VFIO_GROUP_SET_CONTAINER,&container);<br>    ret = ioctl(container,VFIO_SET_IOMMU,VFIO_TYPE1_IOMMU);<br>    <br>    ioctl(container, VFIO_IOMMU_GET_INFO, &iommu_info);<br>    <br>    /* Allocate some space and setup a DMA mapping */        <br>    dma_map.vaddr = (unsigned long int) mmap(0, 1024 * 1024, PROT_READ | PROT_WRITE,MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);<br>    dma_map.size = 1024 * 1024;<br>    dma_map.iova = 0; /* 1MB starting at 0x0 from device view */<br>    dma_map.flags = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE;<br> <br>    ioctl(container, VFIO_IOMMU_MAP_DMA, &dma_map);<br>    <br>    printf("\n\nGETTING DEVICE FD\n");<br>    fd = ioctl(group_fd,VFIO_GROUP_GET_DEVICE_FD,"0000:01:00.0");<br><br><br>    ioctl(fd, VFIO_DEVICE_GET_INFO, &device_info); <br>    for (i = 0; i < device_info.num_regions; i++) {<br>        reg.index = i;<br> <br>        ioctl(fd, VFIO_DEVICE_GET_REGION_INFO, &reg);<br> <br>        /* Setup mappings... read/write offsets, mmaps<br>        * For PCI devices, config space is a region */<br>    }<br><br>    for (i = 0; i < device_info.num_irqs; i++) {<br>        struct vfio_irq_info irq = { .argsz = sizeof(irq) };<br><br>        irq.index = i;<br> <br>        ioctl(fd, VFIO_DEVICE_GET_IRQ_INFO, &irq);<br><br>    }<br><br><br>    reg.index = VFIO_PCI_CONFIG_REGION_INDEX;<br><br>    printf("VFIO_DEVICE_GET_REGION_INFO = %lu",VFIO_DEVICE_GET_REGION_INFO);<br>    ret = ioctl(fd, VFIO_DEVICE_GET_REGION_INFO, &reg);<br>    <br>    offset = reg.offset;<br>    printf("offset is %lx\n",offset);<br>    /*ret = read(group_fd,buf,nbytes);<br>    printf("Read from group fd, ret is %d: %m\n",ret);<br>    printf("CONFIG SPACE: \n");<br>    printf("%s\n",buf);*/<br>    printf("Fd = %d\n",fd);<br> <br>    //printf("VFIO_GROUP_GET_DEV_ID = %lu\n",VFIO_GROUP_GET_DEVICE_FD);<br>    ret = read(fd,buf,nbytes);<br>    printf("Ret from read is = %d, buf = %s\n",ret,buf);<br>    if(ret<1){<br>        printf("ERROR: %m \n");<br>    }<br><br>    ret = pread(fd,buf,nbytes,offset);<br><br>    printf("Ret from pread is = %d\n",ret);<br>    if(ret<1){<br>        printf("ERROR: %m \n");<br>    }<br>    printf("TESTING PREAD ON A COMMON FILE\n");<br>    fd2 = open("/sys/bus/pci/devices/0000:01:00.0/device",O_RDONLY);<br>    printf("FD2 = %d\n",fd2);<br>    ret = read(fd2,buf1,nbytes);<br>    if(ret<0){<br>        printf("ERROR: %m\n");<br>    }<br>    printf("Result from read: ret = %d, content = %s\n",ret,buf1);<br>    ret = pread(fd2,buf2,nbytes,2);<br>    if(ret<0){<br>        printf("ERROR: %m\n");<br>    }<br>    printf("Result from pread: ret = %d, content = %s\n",ret,buf2);<br>    close(fd2);<br>    getchar();<br>    close(fd);<br>    close(container);<br>    close(group_fd);<br>    return 0;<br>}</span><br><br><br></div>Something weird I noticed that might be related to this  is that on ubuntu the iommu groups for some devices are very different from the manually compiled kernel. There are a few devices that on ubuntu have a large iommu_group while in the generic kernel the iommu group is composed by only one device ( and this is in the same machine btw!). Is this normal?<br></div>Other thing I tried was using 0 as offset to pread and this gives me the same error even though a normal read works fine....<br><br></div>Any ideas? Please help!  T.T<br><br></div>Cheers,<br><br></div>Ingrid<br><div><div><div><br><div><br></div></div></div></div></div>