当前位置:   article > 正文

virtio驱动如何同设备交互_backend driver virtio 如何读写设备

backend driver virtio 如何读写设备

转载自:http://blog.chinaunix.net/uid-26000137-id-3826914.html

virtio设备是作为pci设备被使用的,因此具有pci设备的所有属性:

virtio header占用pci设备的24字节的配置空间:32 * (0 - 5)
virtio header后面跟随一个device specific的config结构

virtio header包括:
/* A 32-bit r/o bitmask of the features supported by the host */
#define VIRTIO_PCI_HOST_FEATURES 0

/* A 32-bit r/w bitmask of features activated by the guest */
#define VIRTIO_PCI_GUEST_FEATURES 4

/* A 32-bit r/w PFN for the currently selected queue */
#define VIRTIO_PCI_QUEUE_PFN  8

/* A 16-bit r/o queue size for the currently selected queue */
#define VIRTIO_PCI_QUEUE_NUM  12

/* A 16-bit r/w queue selector */
#define VIRTIO_PCI_QUEUE_SEL  14

/* A 16-bit r/w queue notifier */
#define VIRTIO_PCI_QUEUE_NOTIFY  16

/* An 8-bit device status register.  */
#define VIRTIO_PCI_STATUS  18

/* An 8-bit r/o interrupt status register.  Reading the value will

return the
 * current contents of the ISR and will also clear it.  This is

effectively
 * a read-and-acknowledge. */
#define VIRTIO_PCI_ISR   19

/* The bit of the ISR which indicates a device configuration change. */
#define VIRTIO_PCI_ISR_CONFIG  0x2

/* MSI-X registers: only enabled if MSI-X is enabled. */
/* A 16-bit vector for configuration changes. */
#define VIRTIO_MSI_CONFIG_VECTOR        20
/* A 16-bit vector for selected queue notifications. */
#define VIRTIO_MSI_QUEUE_VECTOR         22
/* Vector value used to disable MSI for queue */
#define VIRTIO_MSI_NO_VECTOR            0xffff

每个特定设备还有自己的配置结构体,以上是通用部分

guest读写方式:
/* Select the queue we're interested in */
iowrite16(index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_SEL);

/* Check if queue is either not available or already active. */
num = ioread16(vp_dev->ioaddr + VIRTIO_PCI_QUEUE_NUM);


virtio驱动通过读取和写入这些配置空间实现通用的guest特性,队列,中断等等

方面同qemu-kvm交互的功能

qemu-kvm提供了下面这个函数结构体来响应guest的不同读写请求。
static const MemoryRegionPortio virtio_portio[] = {
    { 0, 0x10000, 1, .write = virtio_pci_config_writeb, },
    { 0, 0x10000, 2, .write = virtio_pci_config_writew, },
    { 0, 0x10000, 4, .write = virtio_pci_config_writel, },
    { 0, 0x10000, 1, .read = virtio_pci_config_readb, },
    { 0, 0x10000, 2, .read = virtio_pci_config_readw, },
    { 0, 0x10000, 4, .read = virtio_pci_config_readl, },
    PORTIO_END_OF_LIST()
};

static const MemoryRegionOps virtio_pci_config_ops = {
    .old_portio = virtio_portio,
    .endianness = DEVICE_LITTLE_ENDIAN,
};

virtio设备作为pci设备被guest识别,guest通过读写pci设备配置空间的信息来

同qemu-kvm交互。

所以实际上是guest为queue分配vring表的空间,然后通过上面这种交互方式将地

址传递给qemu-kvm,qemu-kvm把地址复制给guest选定的queue,这样guest和

qemu-kvm就共用这一片vring表的空间。

guest通过queue发送消息,实际上就是向这一片共享的vring表空间写入信息并标

识为等待qemu-kvm读取,qemu-kvm读取并处理后又将结果写进去(guest写的信息

里面预留空间给qemu-kvm来写了)再标识为已处理,同时发一个中断,guest接到

中断就去读取处理结果。

/*
函数功能:为目标设备获取一个queue
vdev:目标设备
index:给目标设备使用的queue的编号
callback:queue的回调函数
name:queue的名字
msix_vec:给queue使用的msix vector的编号
*/

  1. static struct virtqueue *setup_vq(struct virtio_device *vdev,
  2. unsigned index, void (*callback)(struct virtqueue *vq),
  3. const char *name, u16 msix_vec)
  4. {
  5. struct virtio_pci_device *vp_dev = to_vp_device(vdev);
  6. struct virtio_pci_vq_info *info;
  7. struct virtqueue *vq;
  8. unsigned long flags, size;
  9. u16 num;
  10. int err;
  11. /* 通知guest我们想要使用的queue的号码 */
  12. iowrite16(index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_SEL);
  13. /* 返回刚刚选中的queue的可用列表数,从而判断该queue是否可用 */
  14. num = ioread16(vp_dev->ioaddr + VIRTIO_PCI_QUEUE_NUM);
  15. /* 如果num为0,则该queue不可用,因为没空闲列表了。
  16. 返回刚刚选中的queue的地址,如果该queue的地址非空,则它已经
  17. 在被使用了,该queue不可用。
  18. */
  19. if (!num || ioread32(vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN))
  20. return ERR_PTR(-ENOENT);
  21. /* allocate and fill out our structure the represents an active
  22. * queue */
  23. info = kmalloc(sizeof(struct virtio_pci_vq_info), GFP_KERNEL);
  24. if (!info)
  25. return ERR_PTR(-ENOMEM);
  26. info->num = num;
  27. info->msix_vector = msix_vec;
  28. size = PAGE_ALIGN(vring_size(num, VIRTIO_PCI_VRING_ALIGN));
  29. /* 为vring表分配空间 */
  30. info->queue = alloc_pages_exact(size, GFP_KERNEL|__GFP_ZERO);
  31. if (info->queue == NULL) {
  32. err = -ENOMEM;
  33. goto out_info;
  34. }
  35. /* activate the queue */
  36. /* 将vring表的地址传递给qemu-kvm,guest将和qemu-kvm通过共享
  37. 这一共同的vring表来完成信息交互:
  38. 1.guest通过queue发信息就是向vring表写入信息并标识为等待
  39. qemu-kvm端virtio驱动读取,同时通过notify设备通知qemu-kvm
  40. 端virtio驱动。
  41. 2.qemu-kvm端virtio驱动处理后将结果也写入vring表(guest发的
  42. 信息预留了返回结果的空间)并标识为已处理,同时发送中断通
  43. 知guest。
  44. 3.guest中断处理函数判明中断类型,读取返回结果。
  45. */
  46. iowrite32(virt_to_phys(info->queue) >>
  47. VIRTIO_PCI_QUEUE_ADDR_SHIFT, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN);
  48. /* create the vring */
  49. /* 创建vring_virtqueue结构体,作为queue和vring协同工作的桥梁,
  50. queue和vring都嵌入在vring_virtqueue结构体之中,返回给驱动的
  51. queue实际就是vring_virtqueue的成员,queue是vring_virtqueue结构体提供给
  52. 上层驱动的接口,vring结构体则负责管理vring表,是操作vring表的接口。
  53. */
  54. vq = vring_new_virtqueue(index, info->num,
  55. VIRTIO_PCI_VRING_ALIGN, vdev,true, info->queue, vp_notify, callback,
  56. name);
  57. if (!vq) {
  58. err = -ENOMEM;
  59. goto out_activate_queue;
  60. }
  61. vq->priv = info;
  62. info->vq = vq;
  63. /* 如果使用msix vector,则将msix vector编号写入到设备的配置空间
  64. 去,再读取的目的就是判断qemu-kvm端是否能够支持。
  65. */
  66. if (msix_vec != VIRTIO_MSI_NO_VECTOR) {
  67. iowrite16(msix_vec, vp_dev->ioaddr +
  68. VIRTIO_MSI_QUEUE_VECTOR);
  69. msix_vec = ioread16(vp_dev->ioaddr +
  70. VIRTIO_MSI_QUEUE_VECTOR);
  71. if (msix_vec == VIRTIO_MSI_NO_VECTOR) {
  72. err = -EBUSY;
  73. goto out_assign;
  74. }
  75. }
  76. if (callback) {
  77. spin_lock_irqsave(&vp_dev->lock, flags);
  78. list_add(&info->node, &vp_dev->virtqueues);
  79. spin_unlock_irqrestore(&vp_dev->lock, flags);
  80. } else {
  81. INIT_LIST_HEAD(&info->node);
  82. }
  83. return vq;
  84. out_assign:
  85. vring_del_virtqueue(vq);
  86. out_activate_queue:
  87. iowrite32(0, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN);
  88. free_pages_exact(info->queue, size);
  89. out_info:
  90. kfree(info);
  91. return ERR_PTR(err);
  92. }



声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/神奇cpp/article/detail/885072
推荐阅读
相关标签
  

闽ICP备14008679号