Chinaunix首页 | 论坛 | 博客
  • 博客访问: 213303
  • 博文数量: 76
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 513
  • 用 户 组: 普通用户
  • 注册时间: 2013-08-23 00:06
个人简介

展示自己、证明自己

文章分类

全部博文(76)

文章存档

2018年(1)

2014年(55)

2013年(20)

我的朋友

分类: C/C++

2014-08-04 10:30:37

qemu-kvm virtio-blk设备
virtio-blk为半虚拟驱动,virtio-blk请求处理过程如下:
1.客户机(virtio-blk设备驱动)读写数据方式vring队列
2.客户机执行Virtqueue队列函数kick通知host宿主机(通过virtio-pci硬件寄存器发送通知)
3.宿主机host截获通知信息
4.宿主机host从vring队列获取读写请求(vring队列内容涉及地址为客户机物理地址)
5.宿主机host处理读写请求
6.宿主机host处理结果添加到vring队列
7.宿主机host发送中断(通过virtio-pci中断)

具体设计代码如下:

1.客户机与宿主机通知
notify函数用于通知host主机队列里面已经有消息存在了,s390采用是hypercall ,而其他体系结构使用写寄存器来通知host主机。
/* the notify function used when creating a virt queue */
static void vp_notify(struct virtqueue *vq)
{
        struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
        struct virtio_pci_vq_info *info = vq->priv;

        /* we write the queue's selector into the notification register to
         * signal the other end */
        iowrite16(info->queue_index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_NOTIFY);
}

2.virtio-blk注册要截获的端口
static void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev,
                            uint16_t vendor, uint16_t device,
                            uint16_t class_code, uint8_t pif)
{
  pci_register_bar(&proxy->pci_dev, 0, size, PCI_BASE_ADDRESS_SPACE_IO,
                           virtio_map);
}

static void virtio_map(PCIDevice *pci_dev, int region_num,
                       pcibus_t addr, pcibus_t size, int type)
{
    VirtIOPCIProxy *proxy = container_of(pci_dev, VirtIOPCIProxy, pci_dev);
    VirtIODevice *vdev = proxy->vdev;
    unsigned config_len = VIRTIO_PCI_REGION_SIZE(pci_dev) + vdev->config_len;

    proxy->addr = addr;

    register_ioport_write(addr, config_len, 1, virtio_pci_config_writeb, proxy);
    register_ioport_write(addr, config_len, 2, virtio_pci_config_writew, proxy);
    register_ioport_write(addr, config_len, 4, virtio_pci_config_writel, proxy);
    register_ioport_read(addr, config_len, 1, virtio_pci_config_readb, proxy);
    register_ioport_read(addr, config_len, 2, virtio_pci_config_readw, proxy);
    register_ioport_read(addr, config_len, 4, virtio_pci_config_readl, proxy);

    if (vdev->config_len)
        vdev->get_config(vdev, vdev->config);
}
3.vmm要截获端口
addr截获端口,val端口存放数值
static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
{
  switch (addr) {
  case VIRTIO_PCI_QUEUE_NOTIFY:
        if (val < VIRTIO_PCI_QUEUE_MAX) {
            virtio_queue_notify(vdev, val);
        }
        break;
}
通过val可得到相应的virtio设备的队列
void virtio_queue_notify(VirtIODevice *vdev, int n)
{       
    virtio_queue_notify_vq(&vdev->vq[n]);
}  
获取队列的请求,处理队列请求
void virtio_queue_notify_vq(VirtQueue *vq)
{           
    if (vq->vring.desc) {
        VirtIODevice *vdev = vq->vdev;
        trace_virtio_queue_notify(vdev, vq - vdev->vq, vq);
        vq->handle_output(vdev, vq);
    }   
}
virio-blk块设备请求数据处理函数,
static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
{
    VirtIOBlock *s = to_virtio_blk(vdev);
    VirtIOBlockReq *req;
    MultiReqBuffer mrb = {
        .num_writes = 0,
        .old_bs = NULL,
    };

    while ((req = virtio_blk_get_request(s))) {
        virtio_blk_handle_request(req, &mrb);
    }

    if (mrb.num_writes > 0) {
        do_multiwrite(mrb.old_bs, mrb.blkreq, mrb.num_writes);
    }

    /*
     * FIXME: Want to check for completions before returning to guest mode,
     * so cached reads and writes are reported as quickly as possible. But
     * that should be done in the generic block layer.
     */
}


static void virtio_blk_handle_request(VirtIOBlockReq *req,
    MultiReqBuffer *mrb)
{
 else if (req->out->type & VIRTIO_BLK_T_OUT) {
        qemu_iovec_init_external(&req->qiov, &req->elem.out_sg[1],
                                 req->elem.out_num - 1);
        virtio_blk_handle_write(mrb->blkreq, &mrb->num_writes,
            req, &mrb->old_bs);
    } else {
        qemu_iovec_init_external(&req->qiov, &req->elem.in_sg[0],
                                 req->elem.in_num - 1);
        virtio_blk_handle_read(req);
    }
}

virtio-blk数据处理完成,把结果放入队列中
static void virtio_blk_req_complete(VirtIOBlockReq *req, int status)
{
    VirtIOBlock *s = req->dev;

    trace_virtio_blk_req_complete(req, status);

    req->in->status = status;
    virtqueue_push(s->vq, &req->elem, req->qiov.size + sizeof(*req->in));
    virtio_notify(&s->vdev, s->vq);
}

宿主机发送中断通知客户机

static void virtio_pci_notify(void *opaque, uint16_t vector)
{
    VirtIOPCIProxy *proxy = opaque;
    if (msix_enabled(&proxy->pci_dev))
        msix_notify(&proxy->pci_dev, vector);
    else
        qemu_set_irq(proxy->pci_dev.irq[0], proxy->vdev->isr & 1);
}

http://blog.csdn.net/zhuriyuxiao/article/details/8824735
阅读(3230) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~