QEMU中VIRTIO实现
http://39.107.46.219/qemu%E8%99%9A%E6%8B%9F%E5%8C%96%E5%AE%89%E5%85%A8%EF%BC%88%E4%BA%8C%EF%BC%89/
VIRTIO设备
了解QEMU和KVM交互的知道,客户机的IO操作通过KVM处理后再交由QEMU,反馈也如此。这种纯软件的模拟IO设备,增加了IO的延迟。
而Virtio却为虚拟化的IO提供了另一种解决方案:
Virtio在虚拟机系统内核安装前端驱动,在QEMU中实现后端驱动。前后端驱动通过Virtqueue直接通信,从而绕过了KVM内核模块处理,提高了IO操作性能。
QEMU中VIRTIO实现
启动配置设备
-device virtio-scsi-pci
在虚拟机里查看scsi设备lspci
可以看到Virtio-pci设备的相关信息:IO/PORT: 0xc040 (size=64),MemoryAddress: 0xfebf1000(size=4k)
Virtqueue
Virtio使用Virtqueue实现IO机制,每个Virtqueue就是承载大量数据的queue。vring是Virtqueue实现的具体方式;virtio_ring是virtio传出机制的实现,vring引入ving buffer作为数据的载体。
由一组描述符构成描述符表
Available Vring typedef struct VRingAvail { uint16_t flags; uint16_t idx; // 指向下一描述符表的入口 uint16_t ring[0]; // 每一个值是一个索引,指向描述符表中的一个可用描述符 } VRingAvail; VRingUsedElem typedef struct VRingUsedElem { uint32_t id; uint32_t len; } VRingUsedElem; VRingUsed typedef struct VRingUsed { uint16_t flags; uint16_t idx; VRingUsedElem ring[0]; } VRingUsed;
Virtqueue初始化(在Qemu端实现)
在Guest端,virtio驱动中vm_setup_vq
建立与queue对应的Virtqueue
从这里可以看出来vring的内存布局
接着Guest virtio驱动通知Qemu Queue的vring.num
Guest向虚拟设备提供buffer
在virtio驱动virtqueue_add
实现
虚拟设备使用Buffer
QEMU-GUEST交互
所有设备的i/o操作都经由virtio_ioport_write
处理
其中addr是相对于ioport端口地址的偏移, val是写入的数据。
在该函数下断点,运行到vdev被初始化后
outl(0xaa, 0xc040+0x10) // module_init执行
断下的状态
可以看到有三种handle_output:ctrl, event, cmd
而我们handle_output被触发的路径