VIRTIO的vring收发队列创建流程

针对评审文档那天提出的问题,又看了一下代码,VIRTIO收发队列的创建位置是在GUEST的前端驱动里

 

GUEST前端驱动,以网络设备为例: Virtio-net: PCI 发现后,通过PCI总线分配收发队列

static int virtnet_probe(structvirtio_device *vdev)

{

……

        /*

         * 初始化virtqueue

        * 创建和初始化发送/接收队列

        */

        err = init_vqs(vi);

……

}

 

/*创建和初始化发送/接收队列*/

static int init_vqs(struct virtnet_info*vi)

{

        /*分配*/

        ret = virtnet_alloc_queues(vi);

        if (ret)

                  goto err;

 

        /*通过find vqs来创建vring*/

        ret = virtnet_find_vqs(vi);

        if (ret)

                  goto err_free;

 

……

}

 

/*通过find vqs来创建vring*/

static int virtnet_find_vqs(structvirtnet_info *vi)

{

……

        /*调用的是vp_find_vqs,真正的创建virtqueue内部结构和分配地址,并将地址告诉后端QEMU驱动*/

        ret = vi->vdev->config->find_vqs(vi->vdev,total_vqs, vqs, callbacks, names);

……

}

 

 

VIRTIO PCI总线

static int vp_find_vqs(struct virtio_device*vdev, unsigned nvqs,

                         struct virtqueue *vqs[],

                         vq_callback_t *callbacks[],

                         const char *names[])

{

        int err;

 

        err = vp_try_to_find_vqs(vdev,nvqs, vqs, callbacks, names, true, true);

 

        err = vp_try_to_find_vqs(vdev,nvqs, vqs, callbacks, names, true, false);

 

        return vp_try_to_find_vqs(vdev,nvqs, vqs, callbacks, names, false, false);

}

 

 

 

static int vp_try_to_find_vqs()

{

……

                  /*最核心的是setup_vq()*/

                  vqs[i] = setup_vq(vdev,i, callbacks[i], names[i], msix_vec);

……

}

 

static struct virtqueue *setup_vq(structvirtio_device *vdev, unsigned index,

                                      void (*callback)(struct virtqueue *vq),

                                      const char *name,

                                      u16 msix_vec)

{

        /*设置virtio vring的地址给后端的QEMU*/

        iowrite32(virt_to_phys(info->queue)>> VIRTIO_PCI_QUEUE_ADDR_SHIFT, vp_dev->ioaddr +VIRTIO_PCI_QUEUE_PFN);

}

 

IO读写被后端QEMU截获,进行模拟

 

QEMU后端驱动

static void virtio_ioport_write(void*opaque, uint32_t addr, uint32_t val)

{

……

    switch (addr) {

    case VIRTIO_PCI_QUEUE_PFN:

       pa = (hwaddr)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT;

……

           virtio_queue_set_addr(vdev,vdev->queue_sel, pa);

……

}


还有个细节问题,前端驱动写入的应该是QEUEUGPA“iowrite32(virt_to_phys(info->queue) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT,vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN);”

这个被后端QEMU截获后,QEMU怎么直接使用了GPA呢?哪里完成的GPA->HVA的转换呢?

 

这个是在QEMUvirtqueue中取消息的时候,进行转换的

 

 

QEMU代码,在收到VIRTIO通知后,会通过virtqueue_pop从共享队列中取出消息

 

intvirtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)

{

    /*Now map what we have collected */

    virtqueue_map_sg(elem->in_sg,elem->in_addr, elem->in_num, 1);

    virtqueue_map_sg(elem->out_sg,elem->out_addr, elem->out_num, 0);

}

 

voidvirtqueue_map_sg()

{

 

   for (i = 0; i < num_sg; i++) {

       len = sg[i].iov_len;

       sg[i].iov_base =cpu_physical_memory_map(addr[i], &len, is_write);

       if (sg[i].iov_base == NULL || len != sg[i].iov_len) {

           error_report("virtio: trying to map MMIO memory");

           exit(1);

       }

    }

}

 

/*完成一个GUEST的物理地址GPAHVA的转换*/

void*cpu_physical_memory_map(hwaddr addr,

                             hwaddr *plen,

                             int is_write)

{

   return address_space_map(&address_space_memory,addr, plen, is_write);

}

 

 

Thanks

Feng


VIRTIO官方SPEC在

http://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.html

 

 


  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
virtio是一种用于虚拟化环境中的设备驱动程序框架,它允许虚拟机(VM)与宿主机之间进行高效的通信。以下是virtio的工作流程: 1. 宿主机和虚拟机之间的通信通过虚拟化后的设备进行。这些设备可以是网络适配器、磁盘控制器等。 2. 在虚拟机启动时,它会检测到这些虚拟化设备,并加载virtio驱动程序。 3. 虚拟机中的virtio驱动程序通过设备模拟器(device emulator)与实际的设备进行通信。设备模拟器是一个在宿主机上运行的软件模块,模拟了实际设备的行为。 4. 当虚拟机需要发送数据给宿主机时,它会将数据写入虚拟化设备的队列(queue)。每个队列由一系列描述符(descriptor)组成,每个描述符指向虚拟机内存中的一个缓冲区。 5. 在宿主机上,设备模拟器会轮询这些队列,检查是否有新的描述符需要处理。 6. 当设备模拟器发现有描述符需要处理时,它会读取描述符中的信息,包括要读取或写入的缓冲区地址和长度。 7. 设备模拟器通过直接内存访问(Direct Memory Access,DMA)机制,将数据从虚拟机的内存复制到宿主机的内存,或者相反。 8. 一旦数据传输完成,设备模拟器会更新描述符中的状态,并通知虚拟机。 9. 虚拟机中的virtio驱动程序检查描述符的状态,并采取相应的操作,如读取传输的数据或者继续发送下一批数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值