vfio 通过VFIO_DEVICE_GET_REGION_INFO得到io信息,然后mmap到user space使用

在qemu/hw/vfio 中的common.c 中
int vfio_get_region_info(VFIODevice *vbasedev, int index,
                         struct vfio_region_info **info)
{
    size_t argsz = sizeof(struct vfio_region_info);

    *info = g_malloc0(argsz);

    (*info)->index = index;
retry:
    (*info)->argsz = argsz;

    if (ioctl(vbasedev->fd, VFIO_DEVICE_GET_REGION_INFO, *info)) {
        g_free(*info);
        *info = NULL;
        return -errno;
    }

    return 0;
}
vfio_get_region_info 中是通过VFIO_DEVICE_GET_REGION_INFO 来得到设备io的信息,这里的info是是一个字符串。从
device = ioctl(group, VFIO_GROUP_GET_DEVICE_FD, "0000:06:0d.0");中可以看出info 通过bus:device:fn表示一个pcie的device.
VFIO_DEVICE_GET_REGION_INFO 这个ioctl对应kernel中的vfio_pci_ioctl 中的命令
static long vfio_pci_ioctl(void *device_data,
               unsigned int cmd, unsigned long arg)
{
     else if (cmd == VFIO_DEVICE_GET_REGION_INFO) {
        struct pci_dev *pdev = vdev->pdev;
        struct vfio_region_info info;
        struct vfio_info_cap caps = { .buf = NULL, .size = 0 };
        int i, ret;

        minsz = offsetofend(struct vfio_region_info, offset);

        if (copy_from_user(&info, (void __user *)arg, minsz))
            return -EFAULT;

        if (info.argsz < minsz)
            return -EINVAL;

        switch (info.index) {
        case VFIO_PCI_CONFIG_REGION_INDEX:
            info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index);
            info.size = pdev->cfg_size;
            info.flags = VFIO_REGION_INFO_FLAG_READ |
                     VFIO_REGION_INFO_FLAG_WRITE;
            break;
        case VFIO_PCI_BAR0_REGION_INDEX ... VFIO_PCI_BAR5_REGION_INDEX:
            info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index);
            info.size = pci_resource_len(pdev, info.index);
            if (!info.size) {
                info.flags = 0;
                break;
            }

            info.flags = VFIO_REGION_INFO_FLAG_READ |
                     VFIO_REGION_INFO_FLAG_WRITE;
            if (vdev->bar_mmap_supported[info.index]) {
                info.flags |= VFIO_REGION_INFO_FLAG_MMAP;
                if (info.index == vdev->msix_bar) {
                    ret = msix_sparse_mmap_cap(vdev, &caps);
                    if (ret)
                        return ret;
                }
            }

            break;
        case VFIO_PCI_ROM_REGION_INDEX:
        case VFIO_PCI_VGA_REGION_INDEX:
        return copy_to_user((void __user *)arg, &info, minsz) ?
            -EFAULT : 0;

    }
}
从中可以看到 io总共分为9种
enum {
    VFIO_PCI_BAR0_REGION_INDEX,
    VFIO_PCI_BAR1_REGION_INDEX,
    VFIO_PCI_BAR2_REGION_INDEX,
    VFIO_PCI_BAR3_REGION_INDEX,
    VFIO_PCI_BAR4_REGION_INDEX,
    VFIO_PCI_BAR5_REGION_INDEX,
    VFIO_PCI_ROM_REGION_INDEX,
    VFIO_PCI_CONFIG_REGION_INDEX,
    VFIO_PCI_VGA_REGION_INDEX,
    VFIO_PCI_NUM_REGIONS = 9 /* Fixed user ABI, region indexes >=9 use */
                 /* device specific cap to define content. */
};
我们这里以VFIO_PCI_BAR0_REGION_INDEX 为例,在这里只是准备好了struct vfio_region_info info的offset和size,并设置了info.flags |= VFIO_REGION_INFO_FLAG_MMAP;
最终的通过vfio_pci_mmap中的remap_pfn_range来将bar空间映射到user space,这样就可以在user space直接访问pcie的bar空间.

总结一下io空间都是通过ioctl先拿到io的信息后,通过mmap 到user space,让其直接时候io 空间


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值