Hypervisor之半虚拟化PCI virtio

1 基本概念
frontend:gpa地址
backend:hva地址
notify host:触发vmexit
desc table:类似于USB主机的TD传输描述符

2 Protocol
2.1 virtio 0.95 - legacy
Legacy模式只使用了PCI的BAR0
Figure 2-1 BAR0指向的寄存器

Hypervisor之半虚拟化PCI virtio_第1张图片

2.2 virtio 1.0
2.2.1 virtio 1.0 PCI能力描述
QNX hypervisor使用了virtio 1.0协议。
capability ID参考:include/uapi/linux/pci_regs.h

struct virtio_pci_cap {
    __u8 cap_vndr;
    __u8 cap_next;
    __u8 cap_len;
    __u8 cfg_type;
    __u8 bar;
    __u8 padding[3];
    __le32 offset;
    __le32 length;
};
根据上述结构体可知,每个能力在PCI配置空间中占用16个字节,并且capability ID(cap_vndr)= 0x09,virtio 1.0中五个cfg_type如下所示。
#define VIRTIO_PCI_CAP_COMMON_CFG    1      /* 占用PCI Bar内存0x38个字节 */
#define VIRTIO_PCI_CAP_NOTIFY_CFG       2      /* 占用PCI Bar内存8个字节 */
#define VIRTIO_PCI_CAP_ISR_CFG              3      /* 占用PCI Bar内存4个字节 */
#define VIRTIO_PCI_CAP_DEVICE_CFG       4      /* 占用PCI Bar内存0x0c个字节 */
#define VIRTIO_PCI_CAP_PCI_CFG              5      /* 占用PCI Bar内存0个字节 */

5个cfg_type仅占用一个PCI Bar,只是地址偏移offset和长度不一样。获取每个能力的offset和长度(都是小端格式),用户空间可以使用libpci库,为简单起见,示例代码中仅读取了4个字节,实际需要读取16个字节。
参数ptr是配置空间偏移0x34地址指向的一个字节。
static bool pci_is_pcie(struct pci_dev *pdev, unsigned char ptr)
{
    unsigned int value;
    unsigned int next_ptr;
    unsigned int cap_id;

    next_ptr = ptr;
    if (0 == ptr) {
        return false;
    }
    do {
        value = pci_read_long(pdev, next_ptr);
        next_ptr = (value >> 8) & 0xff;
        cap_id = value & 0xff;
        /* PCI Express Capability Structure */
        if (cap_id == 0x10) {
            return true;
        }
    } while (next_ptr);

    return false;
}

2.2.2 协议描述
Figure 2-2 vring

Hypervisor之半虚拟化PCI virtio_第2张图片

Figure 2-3 工作原理

Hypervisor之半虚拟化PCI virtio_第3张图片

图片来自于:http://m.blog.chinaunix.net/uid-28541347-id-5819237.html

- virtio 1.0,split模式,包括desc ring、avail ring、used ring
- avail ring,avail->idx 不是desc ring的idx,而是avail->ring的idx,对应的avail->ring[idx]最后一个后端可用的(对前端来说是下一个可用)desc chain的header idx。last_avail_idx也不是desc ring的idx,记录的也是avail->ring的idx,对应的avail->ring[idx]表示上一轮拷贝用到的最后一个desc chain的header idx(avail->ring[idx+1]为本轮拷贝可用的第一个desc chain的header idx)
- used ring,last_used_idx记录的也不是desc ring的idx,而是used->ring的idx,对应used->ring[idx]记录的是上一次后端已经处理好可以给前端释放(对于guest rx来说)的desc chain的header idx

2.3 virtio 1.1
- virtio 1.1,packed模式,将virtio 1.0中的3个ring合成一个

3 passthrough
- DMA重映射由IOMMU负责,根据物理BDF号;Guest中使用的BDF号是虚拟的,VMM负责两者之间的转换
- MMIO映射由EPT负责
- 中断虚拟化,VMM给每个vCPU虚拟一个LAPIC,同时VMM也负责物理LAPIC和虚拟LAPIC的转换;PCI/PCIe设备中断都是level触发;MSI中断绕过了IOAPIC而直接送达LAPIC
- passthrough的目标是实现vmexit-less

4 Abbreviations
fio:flexiable io

你可能感兴趣的:(hypervisor)