• virtio-blk简易驱动


    virtio 是一种 I/O 半虚拟化解决方案,是一套通用 I/O 设备虚拟化的程序,是对半虚拟化 Hypervisor 中的一组通用 I/O 设备的抽象。对比其他设备有宿主计算机模拟,virtio设备效率更高。

    virtio架构图:

    最上面一排是不同的设备,如块设备,网络设备,控制台等

    virtio 层属于控制层,负责设备跟宿主OS之间的通知机制(kick,notify)和控制流程,而 virtio-vring 则负责具体数据流转发。

    vring 包含三个部分,描述符数组 desc,可用的 available ring 和使用过的 used ring。

    1. struct vring_desc {
    2. /* Address (guest-physical). */
    3. u64 addr;
    4. /* Length. */
    5. u32 len;
    6. /* The flags as indicated above. */
    7. u16 flags;
    8. /* We chain unused descriptors via this, too */
    9. u16 next;
    10. };

    vring描述符结构。

    1. struct vring_avail {
    2. u16 flags;
    3. u16 idx;
    4. u16 ring[];
    5. };
    6. struct vring_used_elem {
    7. /* Index of start of used descriptor chain. */
    8. u32 id;
    9. /* Total length of the descriptor chain which was used (written to) */
    10. u32 len;
    11. };
    12. struct vring_used {
    13. u16 flags;
    14. u16 idx;
    15. struct vring_used_elem ring[];
    16. };

    avail跟used结构。

    1. static inline void vring_init(struct vring *vr, unsigned int num, void *p,
    2. unsigned long align)
    3. {
    4. vr->num = num;
    5. vr->desc = p;
    6. vr->avail = (void *)((char *)p + num*sizeof(struct vring_desc));
    7. vr->used = (void *)(((unsigned long)&vr->avail->ring[num] + sizeof(u16)
    8. + align-1) & ~(align - 1));
    9. }
    10. static inline unsigned vring_size(unsigned int num, unsigned long align)
    11. {
    12. return ((sizeof(struct vring_desc) * num + sizeof(u16) * (3 + num)
    13. + align - 1) & ~(align - 1))
    14. + sizeof(u16) * 3 + sizeof(struct vring_used_elem) * num;
    15. }

    vring_size计算vring需要的内存大小,num是vring的描述符数量,为2^N,如128,256,512等。

    首先放的是num个描述符vring_desc,然后是vring_avail,在vring_avail结尾有个16字位的used_event,因此是是(3+num)。之后放得是vring_used,同样,后面有个16位的avail_event,因此也是sizeof(u16) * 3。

    vring_used需要4K对齐。

    used_event用来通知宿主os,读取到哪里了。avail_event用来通知宿主os,写到哪里了。

    设置avail_event,用来通知宿主os有新命令需要处理。宿主os完成之后产生中断,处理完成之后设置used_event,表示数据处理过了,这样宿主os才会有数据的时候继续发生中断。

    desc 用于存储一些关联的描述符,每个描述符记录一个对 buffer 的描述,available ring 则用于 guest 端表示当前有哪些描述符是可用的,而 used ring 则表示 host 端哪些描述符已经被使用。

    Virtio 使用 virtqueue 来实现 I/O 机制,每个 virtqueue 就是一个承载大量数据的队列,具体使用多少个队列取决于需求,例如,virtio 网络驱动程序(virtio-net)使用两个队列(一个用于接受,另一个用于发送),而 virtio 块驱动程序(virtio-blk)仅使用一个队列。

    比如读取硬盘。取得virtqueue队列,virtio-blk就一个队列。然后往里面添加3条结构化数据。

    1. struct addr_size {
    2. unsigned long vp_addr; /* 物理地址 */
    3. u32 vp_size; /* 大小 */
    4. u32 vp_flag; /*标记,如读,写*/
    5. };

    第一条是请求命令数据:

    1. struct blk_outhdr {
    2. /* VIRTIO_BLK_T* */
    3. u32 type;
    4. /* io priority. */
    5. u32 ioprio;
    6. /* Sector (ie. 512 byte offset) */
    7. u64 sector;
    8. };

    告诉驱动是读还是写(type),优先级,扇区号。

    第二条是输出缓冲区,即扇区读取到哪里,缓冲区大小。

    第三条就1个字节,用来指示操作结果,0表示成功。

    module/blk/virtio_blk.c

    1. struct blk_req {
    2. struct blk_outhdr hdr;
    3. uchar status;
    4. };
    5. static struct blk_req rq;
    6. static void virtio_blk_read(ulong sector)
    7. {
    8. struct addr_size phys[3];
    9. rq.hdr.type = VIRTIO_BLK_T_IN;
    10. rq.hdr.ioprio = 0;
    11. rq.hdr.sector = sector;
    12. phys[0].vp_addr = V2P((ulong)&rq.hdr);
    13. phys[0].vp_size = sizeof(rq.hdr);
    14. phys[0].vp_flag = VRING_DESC_F_READ;
    15. phys[1].vp_addr = V2P((ulong)buf);
    16. phys[1].vp_size = 512;
    17. phys[1].vp_flag = VRING_DESC_F_WRITE;
    18. uchar status = 0;
    19. phys[2].vp_addr = V2P((ulong)&rq.status);
    20. phys[2].vp_size = sizeof(status);
    21. pyhs[2].vp_flag = VRING_DESC_F_WRITE;
    22. virtio_to_queue(to_virtio_dev_t(&pci_vblk), 0, phys, 3, &rq);
    23. }

    virtio_to_queue把3个描述符写入vring,然后kick通知宿主os。

    libs/libvirtio/virtio.c

    1. int
    2. virtio_to_queue(virtio_dev_t dev, int q
  • 相关阅读:
    三步教你Linux手动创建应用快捷方式
    集合排序 List.sort
    GoLang读写数据---上
    webstorm 中使用 Eslint+Prettier统一代码风格
    DOM节点
    Windows下DOS窗口修改编码
    Spring循环依赖问题——从源码画流程图
    本地部署 EmotiVoice易魔声 多音色提示控制TTS
    python Plotly可视化
    Mistral 7B 比Llama 2更好的开源大模型 (三)
  • 原文地址:https://blog.csdn.net/lingshengxiyou/article/details/127773008