1.VRing的初始化
QEMU下的VRing
typedef struct VRing
{//vring中最多有多少各request
unsigned int num;
unsigned int num_default;
//数据对齐比例尺
unsigned int align;
//VRingDesc结构存储对应的gpa
hwaddr desc;
hwaddr avail;
hwaddr used;
} VRing;
VirtQueue在QEMU端的初始化,即virtio_add_queue, virtio最多有1024个虚拟队列,且每个队列最多容纳1024个request单位
if (i == VIRTIO_QUEUE_MAX || queue_size > VIRTQUEUE_MAX_SIZE)
abort();
vdev->vq[i].vring.num = queue_size;
vdev->vq[i].vring.num_default = queue_size;
vdev->vq[i].vring.align = VIRTIO_PCI_VRING_ALIGN;
vdev->vq[i].handle_output = handle_output;
vdev->vq[i].handle_aio_output = NULL;
QEMU初始化了vring.num和handle_output.
回到guest中的virtio驱动, vm_setup_vq负责建立和qemu对应的virtqueue,
info->num = readl(vm_dev->base + VIRTIO_MMIO_QUEUE_NUM_MAX);
上条代码帮助guest获取了vring.num, vring的内存从guest memory中申请:
info->queue = alloc_pages_exact(size, GFP_KERNEL | __GFP_ZERO);
vring_new_virtqueue初始化了guest的结构体vring_virtqueue
struct vring_virtqueue {
struct virtqueue vq;
/* Actual memory layout for this queue */
struct vring vring;
/* Can we use weak barriers? */
bool weak_barriers;
/* Other side has made a mess, don't try any more. */
bool broken;
/* Host supports indirect buffers */
bool indirect;
/* Host publishes avail event idx */
bool event;
/* Head of free buffer list. */
unsigned int free_head;
/* Number we've added since last sync. */
unsigned int num_added;
/* Last used index we've seen. */
u16 last_used_idx;
/* Last written value to avail->flags */
u16 avail_flags_shadow;
/* Last written value to avail->idx in guest byte order */
u16 avail_idx_shadow;
/* How to notify other side. FIXME: commonalize hcalls! */
bool (*notify)(struct virtqueue *vq);
/* Tokens for callbacks. 比如virtblk_req */
void *data[];
};
size = PAGE_ALIGN(vring_size(info->num, VIRTIO_MMIO_VRING_ALIGN));
//guest分配内存给vring
info->queue = alloc_pages_exact(size, GFP_KERNEL | __GFP_ZERO);
其中vring_size可以看出vring的组成形式
static inline unsigned vring_size(unsigned int num, unsigned long align)
{return ((sizeof(struct vring_desc) * num + sizeof(__virtio16) * (3 + num) + ali