VirtIO 读书笔记

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/pppaass/article/details/48541397
前言:
提两个概念:
  1.完全虚拟化:在完全虚拟化 中,来宾操作系统运行在位于物理机器上的 hypervisor 之上。来宾操作系统并不知道它已被虚拟化,并且不需要任何更改就可以在该配置下工作。
    2. 半虚拟化:来宾操作系统不仅知道它运行在 hypervisor 之上,还包含让来宾操作系统更高效地过渡到 hypervisor 的代码.

大致架构:
    前端驱动程序(在来宾操作系统中实现),virtio,virtio-ring(通信模块),后端驱动程序(在 hypervisor 中实现)
    1.前端驱动程序:1.截住真正的驱动,2假装真正的驱动 
        创建 virtio_driver 并通过 register_virtio_driver 进行注册开始。virtio_driver 结构定义上层设备驱动程序、驱动程序支持的设备 ID 的列表、一个特性表单(取决于设备类型)和一个回调函数列表。当 hypervisor 识别到与设备列表中的设备 ID 相匹配的新设备时,将调用 probe 函数(由 virtio_driver 对象提供)来传入 virtio_device 对象。将这个对象和设备的管理数据缓存起来(以独立于驱动程序的方式缓存)。
    2 .virtio 还定义了两个层来支持来宾操作系统到 hypervisor 的通信。在顶级(称为 virtio)的是虚拟队列接口,它在概念上将前端驱动程序附加到后端驱动程序。驱动程序可以使用 0 个或多个队列,具体数量取决于需求。例如,virtio 网络驱动程序使用两个虚拟队列(一个用于接收,另一个用于发送),而 virtio 块驱动程序仅使用一个虚拟队列。虚拟队列实际上被实现为跨越来宾操作系统和 hypervisor 的衔接点。但这可以通过任意方式实现,前提是来宾操作系统和 hypervisor 以相同的方式实现它。
    3 .后端驱动程序 会分别调用真正的驱动

Guest 向设备提供 buffer

1.把 buffer 添加到 description table 中,填充 addr,len,flags

2.更新 available ring head

3.更新 available ring 中的 index

4.通知 device,通过写入 virtqueue index 到 Queue Notify 寄存器
Device 使用 buffer 并填充 used ring

device 端使用 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,来判断是否有中断服务需要处理。
阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页