首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

Virtio 基本概念和设备操作(3)

Virtio 基本概念和设备操作(3)

Used RingUsed ring 指向 device(host)使用过的 buffers。Used ring 和 Available ring 之间在内存中的分布会有一定间隙,从而避免了 host 和 guest 两端由于 cache 的影响而会写入到 virtqueue 结构体的同一部分的情况。
flags 用于 device 告诉 guest 再次添加 buffer 到 available ring 时不再提醒,也就是说 guest 添加 buffers 到 available ring 时不必进行 kick 操作。
Used vring element 包含 id 和 len,id 指向 descriptor chain 的入口,与之前 guest 写入到 available ring 的入口项一致。
len 为写入到 buffer 中的字节数。
1
2
3
4
5
6
struct vring_used_elem {
    /* Index of start of used descriptor chain. */
    __u32 id;
    /* Total length of the descriptor chain which was used (written to) */
    __u32 len;
};




Virtio 设备操作设备的初始化1. 重启设备状态,状态位写入 0
2. 设置状态为 ACKNOWLEDGE,guest(driver)端当前已经识别到了设备
3. 设置状态为 Driver,guest 知道如何驱动当前设备
4. 设备特定的安装和配置:特征位的协商,virtqueue 的安装,可选的 MSI-X 的安装,读写设备专属的配置空间等
5. 设置状态为 Driver_OK 或者 Failed(如果中途出现错误)
6. 当前设备初始化完毕,可以进行配置和使用
设备的安装和配置设备操作包括两个部分:driver(guest)提供 buffers 给设备,处理 device(host)使用过的 buffers。
初始化 virtqueue该部分代码的实现在 virtio-pci.c 里 setup_vps()里面,具体为:
1.选择 virtqueue 的索引,写入 Queue Select 寄存器
2.读取 queue size 寄存器获得 virtqueue 的可用数目
3.分配并清零 4096 字节对齐的连续物理内存用于存放 virtqueue(调用 alloc_pages_exact()).把内存地址除以 4096 写入 Queue Address 寄存器(VIRTIO_PCI_QUEUE_ADDR_SHIFT)
4.可选情况下,如果 MSI-X 中断机制启用,选择一个向量用于 virtqueue 请求的中断,把对应向量的 MSI-X 表格入口号写入 Queue Vector 寄存器域,然后再次读取该域以确认返回正确值。
Virtqueue 所需要的字节数由下面的公式获得:
1
2
3
((sizeof(struct vring_desc) * num
+ sizeof(__u16) * (3 + num) + align - 1) & ~(align – 1))
+ sizeof(__u16) * 3 + sizeof(struct vring_used_elem) * num




其中,num 为 virtqueue 的数目。
Guest 向设备提供 buffer1.把 buffer 添加到 description table 中,填充 addr,len,flags
2.更新 available ring head
3.更新 available ring 中的 index
4.通知 device,通过写入 virtqueue index 到 Queue Notify 寄存器
Device 使用 buffer 并填充 used ringdevice 端使用 buffer 后填充 used ring 的过程如下:
1.virtqueue_pop()——从描述符表格(descriptor table)中找到 available ring 中添加的 buffers,映射内存
2.从分散-聚集的 buffer 读取数据
3.virtqueue_fill()——取消内存映射,更新 ring[idx]中的 id 和 len 字段
4.virtqueue_flush()——更新 vring_used 中的 idx
5.virtio_notify()——如果需要的话,在 ISR 状态位写入 1,通知 guest 描述符已经使用
中断处理在 MSI-X 关闭的情况下,设备端会设置 ISR bit lower bit 并发送 PCI 中断给客户机,
客户机端会读取 ISR lower bit,同时会清零 ,如果 lower bit 为 0,则无中断.
如果有中断,遍历一遍该设备每个 virtqueue 上的 used rings,来判断是否有中断服务需要处理。
在 MSI-X 开启的情况下,设备端会为设备请求一个 MSI-X interrupt message 并设置 Queue Vector 寄存器的值为 MSI-X table entry,如果 Queue Vector 为 NO_VECTOR,不再请求 interrupt message。
客户机端会遍历映射到该 MSI-X vector 每个 virtqueue 上的 used rings,来判断是否有中断服务需要处理。
Config Changed设备端如果改变其 configure space,也存在两种情况。
客户机端会在 MSI-X 关闭的情况下,读取 ISR 高位,判断是否为 1,扫描所有 virtqueue 上的 used rings,触发驱动对 config changed 的处理函数。在 MSI-X 开启的情况下,与中断相同,同样请求 MSI-X interrupt message,将 Configuration Vector 设置为 MSI-X table entry。
总结virtio 是 KVM 虚拟化技术中 IO 虚拟化的一个重要框架,现在有很多虚拟设备都使用了 virtio。本文着重介绍了 virtio 的基本概念和设备操作,可以方便读者更深一层地理解 virtio,同时也对 virtio 感兴趣的朋友能够从本文中获取帮助。
返回列表