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被觸發的路徑