做购物平台网站需要注意什么/新软件推广
3 VFIO PCI设备操作回调vfio_pci_ops
对VFIO设备文件描述符fd的操作,它调用device->ops的回调,这些回调最终会调用vfio_pci_ops所定义的回调函数。
(1).open_device = vfio_pci_open_device
该函数主要是使能PCI设备,进行初始化设备,并将配置空间拷贝到相关结构体中。
- 调用vfio_pci_open_device(),分别使能PCI设备,复位PCI function,将配置空间/CAP空间内容拷贝到vdev设备对应的结构体,设置MSIX中断情况;
- 调用vfio_pci_core_finish_enable(),主要设置该BAR是否支持mmap,其他不关注。
(2).read = vfio_pci_core_read
对VFIO设备的读写操作包括对配置空间的读写,对BAR空间的读写,以及region特定的读写操作。
对于配置空间的读写,调用vfio_pci_config_rw();对于BAR0~BAR5以及ROM区域的读写,调用vfio_pci_bar_rw();其他区域,默认调用region[i].ops->rw()特定的读写函数。
- 配置空间的读写
对配置空间不同的区域或CAP_ID,进行不同的设置,且有些区域只支持读,这里分几种情况:
对于PCI_CAP_ID_INVALID,调用vfio_raw_config_*()进行读写,主要是调用pci_user_{read|write}_config来处理(与memcpy的差别?);
对于PCI_CAP_ID_INVALID_VIRT,调用vfio_virt_config_*()进行读写,主要是调用memcpy将结构体vdev->config上模拟的内部读取;
对于PCI_CAP_ID和PCI_ECAP_ID,调用vfio_direct_config_*()进行读写,先尝试pci_user_{read|write}_config,若失败再调用memcpy进行读取;
对于PCI_CAP_ID_MSI,暂时不分析;
- 对BAR空间的读写
通过调用vfio_pci_bar_rw()对BAR空间进行读写。调用如下所示:
对于BAR0~BAR5区域的读写,通过vfio_pci_setup_barmap()将BAR区域映射到vdev->barmap[]中,这样在内核态直接访问它;
对于ROM区域的读写,通过pci_map_rom()最终通过io_remap()对ROM区域映射;
对于MSIX区域的读写,暂不分析[待分析]。
(3).mmap = vfio_pci_core_mmap
通过调用vfio_pci_core_mmap()对BAR空间进行映射。调用如下:
当需要映射的区域并不是PCI定义的区域时,会调用区域特定的mmap回调;
当需要映射的区域为PCI定义的区域时,通过函数pci_iomap()将BAR空间映射到vdev->barmap[],并为vma设置回调函数vfio_pci_mmap_ops。
(4).request = vfio_pci_core_request
对于vfio_pci_core_request()函数,若定义vdev->req_trigger,通过eventfd_signal()往虚拟机中注入模拟中断。
(5).unlocked_ioctl = vfio_device_fops_unl_ioctl
QEMU要获取设备的信息并设置设备,需要通过设备API进行调用,它们是通过函数vfio_device_fops_unl_ioctl()来分别对不同的设备API进行处理。
其中VFIO_DEVICE_GET_INFO用于获取设备region数目和中断的数目;
VFIO_DEVICE_GET_REGION_INFO用于获取设备某个region在设备文件描述符fd中的偏移和大小 ;
VFIO_DEVICE_IRQ_INFO用于获取设备对应的中断数目和标志;
VFIO_DEVICE_SET_IRQS用于请求中断并设置中断处理函数,这里在中断章节进行更详细描述。