1. 概述
后端驱动在qemu中实现,为前端驱动提供IO内存并初始化虚拟设备配置信息,与前端驱动交互,通过虚拟队列(环形缓冲区)、IO内存读写、中断等机制完成设备的访问。
2. 后端驱动初始化
后端驱动的主要作用是为前端驱动提供虚拟设备。后端驱动初始化的过程中,在完成虚拟设备注册的同时,完成虚拟设备配置信息的初始化。
2.1 数据结构
后端驱动相关的数据结构非常复杂,但是数据结构之间的联系与前端驱动中各个模块的数据结构的联系有相似之处,列举出其中重要的数据结构及其核心数据项如下:
//虚拟PCI设备信息
struct {
DeviceState qdev; //虚拟设备状态信息
/* PCI config space */
uint8_t *config;
...
/* the following fields are read only */
PCIBus *bus; //msi相关配置信息
char name[64];
PCIIORegion io_regions[PCI_NUM_REGIONS];
...
qemu_irq *irq;
...
/* MemoryRegion container for msix exclusive BAR setup */
MemoryRegion msix_exclusive_bar;
...
};
typedef struct { //proxy类似于前端驱动virtio-pci,框架结构
PCIDevice pci_dev; //包含虚拟PCI设备信息
VirtIODevice *vdev; //virtio子设备信息
MemoryRegion bar; //IO内存基地址结构
...
VirtIOBlkConf blk; //virtio块设备信息
NICConf nic;
uint32_t host_features; //主机设备信息
...
virtio_serial_conf serial; //串口、网络、scsi等配置信息
...
} VirtIOPCIProxy;
struct VirtIODevice //virtio子设备信息
{
const char *name; //设备名,块中为virtio-blk
uint8_t status; //设备状态
uint8_t isr; //中断请求
uint16_t queue_sel; //所选队列号
uint32_t guest_features; //客户机特征
size_t config_len; //配置信息长度
...
uint16_t config_vector; //矢量配置
...
uint32_t (*get_features)(VirtIODevice *vdev, uint32_t requested_features);
... //一系列设备状态/配置处理函数
VirtQueue *vq; //虚拟队列,块设备只有一个
const VirtIOBindings *binding; //virtio ops
void *binding_opaque;
...
};
2.2 后端驱动初始化
后端驱动的初始化流程实际是对上述重要的数据结构进行初始化,设置PCI设备的信息,并结合到virtio设备中,设置主机状态,配置并初始化虚拟队列,为每个块设备绑定一个虚拟队列及队列处理函数,并绑定设备处理函数,以处理IO请求。初始化流程如下:
1). type_register_static():注册一个设备结构,为PCI子设备,调用初始化函数;
2). virtio_blk_init_pci():设备初始化函数,使用PCIDevice结构信息完成后续工作;
-
Virtio_blk_init():初始化VirtIODevice和VirtIOBlock结构信息
1). virtio_common_init():初始化VirtIODevice(vdev)的数据域,设备号、队列号、设备名、虚拟队列等信息;
2). 初