virtio 框架学习,更新中…

1. virtio 概述

KVM 是必须依赖硬件虚拟化技术辅助(例如 Intel VT-x、AMD-V)的 Hypervisor:

  • CPU:有 VMX rootnon-root 模式的支持,其运行效率是比较高的
  • 内存:有 Intel EPT/AMD NPT 的支持,内存虚拟化的效率也比较高
  • I/O:KVM 客户机的 I/O 操作需要VM-Exit到用户态由 QEMU 进行模拟。传统的方式是使用纯软件的方式来模拟 I/O 设备,效率并不高

为了解决 I/O 虚拟化效率低下的问题,可以在客户机中使用半虚拟化驱动(Paravirtualized Drivers,PV Drivers)来提高客户机的 I/O 性能。目前,KVM 中实现半虚拟化驱动的方式就是采用了virtio这个 Linux 下的设备驱动标准框架。

virtio 是 Linux 平台下一种 I/O 半虚拟化框架,由澳大利亚程序员 Rusty Russell 开发。他当时的目的是支持自己的虚拟化解决方案 Lguest,而在 KVM 中也广泛使用了 Virtio 作为半虚拟化 I/O 框架。

2. 软件方式模拟 I/O 设备

2.1 基本原理

下图是 QEMU 以纯软件方式模拟 I/O 设备的示意图:

  • 当 Guest 中的设备驱动程序发起 I/O 操作请求时,KVM 模块中的 I/O Trap Code 会拦截这次 I/O 请求,经过处理后将本次 I/O 请求的信息存放到 I/O sharing page 中,并通知用户空间的 QEMU
  • QEMU 从 I/O sharing page 中获得 I/O 操作的具体信息后,交由硬件模拟代码(QEMU I/O Emulation Code)来模拟本次 I/O 操作
  • 模拟代码负责和实际的设备驱动进行交互,模拟此次 I/O 操作,获取返回结果并将其放回 I/O Sharing Page 中
  • 最后,KVM 中的 I/O Trap Code 负责读取 I/O Sharing Page 中的操作结果,并将结果返回到客户机中

需要注意的是:

  • 客户机作为一个QEMU 进程,在等待 I/O 时也可能被阻塞
  • 客户机通过 DMA 方式访问大块 I/O 时,QEMU 不会把 I/O 操作结果放到 I/O 共享页中,而是通过内存映射的方式将结果直接写进客户机的内存中,然后通过 KVM 模块告诉客户机 DMA 操作已经完成

2.2 优缺点

  • 优点:可以通过软件模拟出各类硬件设备,而无需修改客户机操作系统
  • 缺点:每次 I/O 操作的路径较长,有较多的VM-EntryVM-Exit发生,需要多次上下文切换,也需要多次数据复制,因此性能较差

3. 半虚拟化 I/O 框架 virtio

3.1 基本原理

如图所示,virtio 分为了前端驱动后端驱动

  • 前端驱动 frontend:如virtio_blkvirtio_net等,是在客户机中存在的驱动程序模块
  • 后端驱动 backend:在 QEMU 中实现

在前后端驱动之间,还定义了两层来支持客户机和 QEMU 之间的通信:

  • virtio 层虚拟队列接口,它在概念上将前端驱动程序附加到后端处理程序。一个前端驱动程序可以使用 0 个或多个队列,具体数量取决于需求

例如:virtio_net网络驱动程序使用两个虚拟队列(接收/发送),而virtio_blk驱动仅使用一个虚拟队列
虚拟队列实际上被实现为客户机操作系统和 Hypervisor 之间的衔接点,但它可以通过任意方式实现,前提是客户机操作系统和 virtio 后端程序都遵循一定的标准,以相互匹配的方式实现它。

  • virtio-ring 层:实现了环形缓冲区(ring buffer),用于保存前端驱动和后端处理程序执行的信息,并且它可以一次性保存前端驱动的多次 I/O 请求,再交由后端驱动批量处理,最后实际调用宿主机中的设备驱动来完成物理层面上的 I/O 操作。

这样做就可以根据约定实现批量处理而不是客户机中每次 I/O 请求都需要处理一次,从而提高了客户机与 Hypervisor 之间信息交换的效率

3.2 优缺点

  • 优点:可获得很好的 I/O 性能,接近 Native。所以在使用 KVM 时,如果宿主机和客户机都支持 Virtio,一般都推荐使用 Virtio 以达到更高的 I/O 性能
  • 缺点:必须在客户机中安装前端驱动,且按照 Virtio 的规定格式进行数据传输

4. virtio 的架构

virtio 是半虚拟化的解决方案,是半虚拟化 Hypervisor 的一组通用 I/O 设备的抽象。它提供了一套上层应用与各 Hypervisor 虚拟化设备(KVM、Xen、VMware 等)之间的通信框架和编程接口,减少了跨平台所带来的兼容性问题。客户机需要知道自己运行在虚拟化环境中,进而根据 Virtio 标准和 Hypervisor 协作,从而提高 I/O 性能。

  • 前端驱动:Frontend Driver,是位于客户机内核中的驱动程序模块
  • 后端驱动:Backend Driver,在宿主机用户空间QEMU 中实现

virtio 是半虚拟化驱动框架,可以提供接近 Native 的 I/O 性能,但是客户机中必须安装特定的 virtio 驱动,并按照 virtio 的规定格式进行数据传输

4.1 版本要求

Kernel >= 2.6.25的内核都支持 virtio。由于 virtio 的后端处理程序是在位于用户空间中的 QEMU 中实现的,所以宿主机只需要比较新的内核即可,不需要特别编译 virtio 相关驱动。而客户机需要有特定 virtio 驱动程序的支持,以便客户机处理 I/O 操作请求时调用前端驱动。

客户机内核中关于 virtio 的部分配置如下:

# 需要启用的选项
CONFIG_VIRTIO_PCI=m
CONFIG_VIRTIO_BALLOON=m
CONFIG_VIRTIO_BLK=m
CONFIG_VIRTIO_NET=m
CONFIG_VIRTIO=m
CONFIG_VIRTIO_RING=y

# 其他相关的选项
CONFIG_VIRTIO_VSOCKETS=m
CONFIG_VIRTIO_VSOCKETS_COMMON=m
CONFIG_SCSI_VIRTIO=m
CONFIG_VIRTIO_CONSOLE=m
CONFIG_HW_RANDOM_VIRTIO=m
CONFIG_DRM_VIRTIO_GPU=m
CONFIG_VIRTIO_PCI_LEGACY=y
CONFIG_VIRTIO_INPUT=m
# CONFIG_VIRTIO_MMIO is not set

# 在子机中查看 VIRTIO 相关内核模块
> lsmod | grep virtio
virtio_balloon         18015  0 
virtio_net             28063  0 
virtio_blk             18166  2 
virtio_pci             22934  0 
virtio_ring            22746  4 virtio_blk,virtio_net,virtio_pci,virtio_balloon
virtio                 14959  4 virtio_blk,virtio_net,virtio_pci,virtio_balloon

4.2 层次结构

如图所示,virtio 大致分为三个层次:前端驱动(位于客户机)、后端驱动(位于 QEMU)以及中间的传输层

每一个 virtio 设备(块设备、网卡等)在系统层面看来,都是一个 PCI 设备。这些设备之间有共性部分,也有差异部分。

共性部分

  1. 都需要挂接相应的 buffer 队列操作 virtqueue_ops
  2. 都需要申请若干个 buffer 队列,当执行 I/O 输出时,需要向队列写入数据
  3. 都需要执行 pci_iomap 将设备配置寄存器区间映射到内存区间
  4. 都需要设置中断处理
  5. 等中断来了,都需要从队列读出数据,并通知客户机系统,数据已入队

差异部分

  • 与设备相关联的系统、业务、队列中写入的数据含义各不相同
  • 例如,网卡在内核中是一个net_device,与协议栈系统关联起来。同时,向队列中写入什么数据、数据的含义如何,各个设备也不相同。队列中来了什么数据,是什么含义,如何处理,各个设备也不相同

如果每个 virtio 设备都完整的实现自己的功能,就会造成不必要的代码冗余。针对这个问题,virtio 又设计了virtio_pci模块,以处理所有 virtio 设备的共性部分。这样一来所有的 virtio 设备在系统看来都是一个 PCI 设备,其设备驱动都是virtio_pci

但是,virtio_pci并不能完整的驱动任何一个设备。因此,virtio_pci在调用probe()接管每一个设备时,会根据其virtio_device_id来识别出具体是哪一种设备,然后相应的向内核注册一个 virtio 类型的设备

在注册设备之前,virtio_pci驱动已经为该设备做了许多共性操作,同时还为该设备提供了各种操作的适配接口,这些都通过virtio_config_ops来适配。

4.3 前端代码层次结构

相关源码文件

Kernel 3.10.0中关于 virito 的重要源码文件如下:

drivers/block/virtio_blk.c
drivers/char/hw_random/virtio_rng.c
drivers/char/virtio_console.c
drivers/net/virtio_net.c
drivers/scsi/virtio_scsi.c
drivers/virtio/virtio_balloon.c
drivers/virtio/virtio_mmio.c
drivers/virtio/virtio_pci.c
drivers/virtio/virtio_ring.c
drivers/virtio/virtio.c

include/linux/virtio_caif.h
include/linux/virtio_config.h
include/linux/virtio_console.h
include/linux/virtio_mmio.h
include/linux/virtio_ring.h
include/linux/virtio_scsi.h
include/linux/virtio.h
include/linux/vring.h

include/uapi/linux/virtio_9p.h
include/uapi/linux/virtio_balloon.h
include/uapi/linux/virtio_blk.h
include/uapi/linux/virtio_config.h
include/uapi/linux/virtio_console.h
include/uapi/linux/virtio_ids.h
include/uapi/linux/virtio_net.h
include/uapi/linux/virtio_pci.h
include/uapi/linux/virtio_ring.h
include/uapi/linux/virtio_rng.h

tools/virtio/linux/virtio_config.h
tools/virtio/linux/virtio_ring.h
tools/virtio/linux/virtio.h
tools/virtio/linux/vring.h
tools/virtio/vitrio_test.c
tools/virtio/vringh_test.c

linux-3.10
 ├─ drivers
 |   ├─ block
 |   |   └─ virtio_blk.c
 |   |
 |   ├─ char
 |   |   ├─ hw_random
 |   |   |   └─ virtio_rng.c
 |   |   |
 |   |   └─ virtio_console.c
 |   |
 |   ├─ net
 |   |   └─ virtio_net.c
 |   |
 |   ├─ scsi
 |   |   └─ virtio_scsi.c
 |   |   
 |   └─ virtio
 |       ├─ virtio_balloon.c
 |       ├─ virtio_mmio.c
 |       ├─ virtio_pci.c
 |       ├─ virtio_ring.c
 |       └─ virtio.c 
 |
 ├─ include
 |   ├─ linux
 |   |   ├─ virtio_caif.h
 |   |   ├─ virtio_config.h
 |   |   ├─ virtio_console.h
 |   |   ├─ virtio_mmio.h
 |   |   ├─ virtio_ring.h
 |   |   ├─ virtio_scsi.h
 |   |   ├─ virtio.h
 |   |   └─ vring.h
 |   |
 |   └─ uapi
 |       └─ linux
 |           ├─ virtio_9p.h
 |           ├─ virtio_balloon.h
 |           ├─ virtio_blk.h
 |           ├─ virtio_config.h
 |           ├─ virtio_console.h
 |           ├─ virtio_ids.h
 |           ├─ virtio_net.h
 |           ├─ virtio_pci.h    
 |           ├─ virtio_ring.h
 |           └─ virtio_rng.h
 |
 └─ tools
     └─ virtio
         ├─ linux
         |   ├─ virtio_config.h
         |   ├─ virtio_ring.h
         |   ├─ virtio.h
         |   └─ vring.h
         |
         ├─ virtio_test.c
         └─ vringh_test.c
类结构层次

virtio 前端驱动客户机内核中,virtio 的类层次结构如下图所示:

virtio_driver

最顶级的是virtio_driver,在客户机 OS 中表示前端驱动程序,在include/linux/virtio.h中定义:

/**
 * virtio_driver - operations for a virtio I/O driver
 * @driver: underlying device driver (populate name and owner).
 * @id_table: the ids serviced by this driver.
 * @feature_table: an array of feature numbers supported by this driver.
 * @feature_table_size: number of entries in the feature table array.
 * @probe: the function to call when a device is found.  Returns 0 or -errno.
 * @remove: the function to call when a device is removed.
 * @config_changed: optional function to call when the device configuration
 *    changes; may be called in interrupt context.
 */
struct virtio_driver {
    struct device_driver driver;
    const struct virtio_device_id *id_table;
    const unsigned int *feature_table;
    unsigned int feature_table_size;
    int (*probe)(struct virtio_device *dev);
    void (*scan)(struct virtio_device *dev);
    void (*remove)(struct virtio_device *dev);
    void (*config_changed)(struct virtio_device *dev);
#ifdef CONFIG_PM
    int (*freeze)(struct virtio_device *dev);
    int (*restore)(struct virtio_device *dev);
#endif
};
virtio_device_id

每个 virtio 设备都有其对应的virtio_device_id,该结构体在include/linux/mod_devicetable.h中定义:

struct virtio_device_id {
    __u32 device;
    __u32 vendor;
};
#define VIRTIO_DEV_ANY_ID    0xffffffff
virtio_device

与驱动程序匹配的设备由virtio_device封装,它表示在客户机 OS 中的设备,在include/linux/virtio.h中定义:

/**
 * virtio_device - representation of a device using virtio
 * @index: unique position on the virtio bus
 * @dev: underlying device.
 * @id: the device type identification (used to match it with a driver).
 * @config: the configuration ops for this device.
 * @vringh_config: configuration ops for host vrings.
 * @vqs: the list of virtqueues for this device.
 * @features: the features supported by both driver and device.
 * @priv: private pointer for the driver's use.
 */
struct virtio_device {
    int index;
    struct device dev;
    struct virtio_device_id id;
    const struct virtio_config_ops *config;
    const struct vringh_config_ops *vringh_config;
    struct list_head vqs;
    /* Note that this is a Linux set_bit-style bitmap. */
    unsigned long features[1];
    void *priv;
};
virtio_config_ops

每一个virtio_device都有一个virtio_config_ops类型的指针*config,它定义了配置 virtio 设备的操作,该结构体在include/linux/virtio_config.h中定义:

/**
 * virtio_config_ops - operations for configuring a virtio device
 * @get: read the value of a configuration field
 * @set: write the value of a configuration field
 * @get_status: read the status byte
 * @set_status: write the status byte
 * @reset: reset the device
 * @find_vqs: find virtqueues and instantiate them.
 * @del_vqs: free virtqueues found by find_vqs().
 * @get_features: get the array of feature bits for this device.
 * @finalize_features: confirm what device features we'll be using.
 * @bus_name: return the bus name associated with the device
 * @set_vq_affinity: set the affinity for a virtqueue.
 */
struct virtio_config_ops {
    void (*get)(struct virtio_device *vdev, unsigned offset,
            void *buf, unsigned len);
    void (*set)(struct virtio_device *vdev, unsigned offset,
            const void *buf, unsigned len);
    u8 (*get_status)(struct virtio_device *vdev);
    void (*set_status)(struct virtio_device *vdev, u8 status);
    void (*reset)(struct virtio_device *vdev);
    int (*find_vqs)(struct virtio_device *, unsigned nvqs,
            struct virtqueue *vqs[],
            vq_callback_t *callbacks[],
            const char *names[]);
    void (*del_vqs)(struct virtio_device *);
    u32 (*get_features)(struct virtio_device *vdev);
    void (*finalize_features)(struct virtio_device *vdev);
    const char *(*bus_name)(struct virtio_device *vdev);
    int (*set_vq_affinity)(struct virtqueue *vq, int cpu);
};
virtqueue

每一个virtqueue包含了对应的virtio_device以及对应的队列操作回调函数,它在include/linux/virtio.h中定义:

/**
 * virtqueue - a queue to register buffers for sending or receiving.
 * @list: the chain of virtqueues for this device
 * @callback: the function to call when buffers are consumed (can be NULL).
 * @name: the name of this virtqueue (mainly for debugging)
 * @vdev: the virtio device this queue was created for.
 * @priv: a pointer for the virtqueue implementation to use.
 * @index: the zero-based ordinal number for this queue.
 * @num_free: number of elements we expect to be able to fit.
 *
 * A note on @num_free: with indirect buffers, each buffer needs one
 * element in the queue, otherwise a buffer will need one element per
 * sg element.
 */
struct virtqueue {
    struct list_head list;
    void (*callback)(struct virtqueue *vq);
    const char *name;
    struct virtio_device *vdev;
    unsigned int index;
    unsigned int num_free;
    void *priv;
};

5. 相关数据结构

5.1 前端 Kernel

virtio_driver

include/linux/virtio.h中定义:

/**
 * virtio_driver - operations for a virtio I/O driver
 * @driver: underlying device driver (populate name and owner).
 * @id_table: the ids serviced by this driver.
 * @feature_table: an array of feature numbers supported by this driver.
 * @feature_table_size: number of entries in the feature table array.
 * @probe: the function to call when a device is found.  Returns 0 or -errno.
 * @remove: the function to call when a device is removed.
 * @config_changed: optional function to call when the device configuration
 *    changes; may be called in interrupt context.
 */
struct virtio_driver {
    struct device_driver driver;
    const struct virtio_device_id *id_table;
    const unsigned int *feature_table;
    unsigned int feature_table_size;
    int (*probe)(struct virtio_device *dev);
    void (*scan)(struct virtio_device *dev);
    void (*remove)(struct virtio_device *dev);
    void (*config_changed)(struct virtio_device *dev);
#ifdef CONFIG_PM
    int (*freeze)(struct virtio_device *dev);
    int (*restore)(struct virtio_device *dev);
#endif
};

这里的virtio_device_id有两个字段:

struct virtio_device_id {
    __u32 device;
    __u32 vendor;
};
#define VIRTIO_DEV_ANY_ID    0xffffffff
virtio_device

include/linux/virtio.h中定义:

/**
 * virtio_device - representation of a device using virtio
 * @index: unique position on the virtio bus
 * @dev: underlying device.
 * @id: the device type identification (used to match it with a driver).
 * @config: the configuration ops for this device.
 * @vringh_config: configuration ops for host vrings.
 * @vqs: the list of virtqueues for this device.
 * @features: the features supported by both driver and device.
 * @priv: private pointer for the driver's use.
 */
struct virtio_device {
    int index;
    struct device dev;
    struct virtio_device_id id;
    const struct virtio_config_ops *config;
    const struct vringh_config_ops *vringh_config;
    struct list_head vqs;
    /* Note that this is a Linux set_bit-style bitmap. */
    unsigned long features[1];
    void *priv;
};
virtio_config_ops

include/linux/virtio_config.h中定义:

/**
 * virtio_config_ops - operations for configuring a virtio device
 * @get: read the value of a configuration field
 *    vdev: the virtio_device
 *    offset: the offset of the configuration field
 *    buf: the buffer to write the field value into.
 *    len: the length of the buffer
 * @set: write the value of a configuration field
 *    vdev: the virtio_device
 *    offset: the offset of the configuration field
 *    buf: the buffer to read the field value from.
 *    len: the length of the buffer
 * @get_status: read the status byte
 *    vdev: the virtio_device
 *    Returns the status byte
 * @set_status: write the status byte
 *    vdev: the virtio_device
 *    status: the new status byte
 * @reset: reset the device
 *    vdev: the virtio device
 *    After this, status and feature negotiation must be done again
 *    Device must not be reset from its vq/config callbacks, or in
 *    parallel with being added/removed.
 * @find_vqs: find virtqueues and instantiate them.
 *    vdev: the virtio_device
 *    nvqs: the number of virtqueues to find
 *    vqs: on success, includes new virtqueues
 *    callbacks: array of callbacks, for each virtqueue
 *        include a NULL entry for vqs that do not need a callback
 *    names: array of virtqueue names (mainly for debugging)
 *        include a NULL entry for vqs unused by driver
 *    Returns 0 on success or error status
 * @del_vqs: free virtqueues found by find_vqs().
 * @get_features: get the array of feature bits for this device.
 *    vdev: the virtio_device
 *    Returns the first 32 feature bits (all we currently need).
 * @finalize_features: confirm what device features we'll be using.
 *    vdev: the virtio_device
 *    This gives the final feature bits for the device: it can change
 *    the dev->feature bits if it wants.
 * @bus_name: return the bus name associated with the device
 *    vdev: the virtio_device
 *      This returns a pointer to the bus name a la pci_name from which
 *      the caller can then copy.
 * @set_vq_affinity: set the affinity for a virtqueue.
 */
typedef void vq_callback_t(struct virtqueue *);
struct virtio_config_ops {
    void (*get)(struct virtio_device *vdev, unsigned offset,
            void *buf, unsigned len);
    void (*set)(struct virtio_device *vdev, unsigned offset,
            const void *buf, unsigned len);
    u8 (*get_status)(struct virtio_device *vdev);
    void (*set_status)(struct virtio_device *vdev, u8 status);
    void (*reset)(struct virtio_device *vdev);
    int (*find_vqs)(struct virtio_device *, unsigned nvqs,
            struct virtqueue *vqs[],
            vq_callback_t *callbacks[],
            const char *names[]);
    void (*del_vqs)(struct virtio_device *);
    u32 (*get_features)(struct virtio_device *vdev);
    void (*finalize_features)(struct virtio_device *vdev);
    const char *(*bus_name)(struct virtio_device *vdev);
    int (*set_vq_affinity)(struct virtqueue *vq, int cpu);
};
virtqueue

include/linux/virtio.h中定义:

/**
 * virtqueue - a queue to register buffers for sending or receiving.
 * @list: the chain of virtqueues for this device
 * @callback: the function to call when buffers are consumed (can be NULL).
 * @name: the name of this virtqueue (mainly for debugging)
 * @vdev: the virtio device this queue was created for.
 * @priv: a pointer for the virtqueue implementation to use.
 * @index: the zero-based ordinal number for this queue.
 * @num_free: number of elements we expect to be able to fit.
 *
 * A note on @num_free: with indirect buffers, each buffer needs one
 * element in the queue, otherwise a buffer will need one element per
 * sg element.
 */
struct virtqueue {
    struct list_head list;
    void (*callback)(struct virtqueue *vq);
    const char *name;
    struct virtio_device *vdev;
    unsigned int index;
    unsigned int num_free;
    void *priv;
};

5.2 后端 QEMU

VirtQueue

hw/virtio/virtio.c中定义:

struct VirtQueue
{
    VRing vring;

    /* Next head to pop */
    uint16_t last_avail_idx;

    /* Last avail_idx read from VQ. */
    uint16_t shadow_avail_idx;

    uint16_t used_idx;

    /* Last used index value we have sjjignalled on */
    uint16_t signalled_used;

    /* Last used index value we have signalled on */
    bool signalled_used_valid;

    /* Notification enabled? */
    bool notification;

    uint16_t queue_index;

    int inuse;

    uint16_t vector;
    void (*handle_output)(VirtIODevice *vdev, VirtQueue *vq);
    void (*handle_aio_output)(VirtIODevice *vdev, VirtQueue *vq);
    VirtIODevice *vdev;
    EventNotifier guest_notifier;
    EventNotifier host_notifier;
    QLIST_ENTRY(VirtQueue) node;
};
VRing

hw/virtio/virtio.c中定义:

typedef struct VRing
{
    unsigned int num;
    unsigned int num_default;
    unsigned int align;
    hwaddr desc;
    hwaddr avail;
    hwaddr used;
} VRing;

未完待续…

参考文章

相关博客

  1. Virtio 概述和基本原理(KVM 半虚拟化驱动)| 笑遍世界
  2. Virtio:针对 Linux 的 I/O 虚拟化框架 | IBM Developer
  3. virtio 基本原理 (kvm 半虚拟化驱动) | 开源中国
  4. 说一说虚拟化绕不开的 io 半虚拟化 | 腾讯云加社区
  5. Virtio Vring 工作机制分析 | OenHan
  6. KVM Virtio Block 源代码分析 | OenHan
  7. vring的创建(基于kernel 3.10, qemu2.0.0) - leoufung| CSDN
  8. QEMU 通过virtio接收报文处理流程(QEMU2.0.0)- leoufung | CSDN
  9. VIRTIO 的 vring 收发队列创建流程 - leoufung | CSDN
  10. VIRTIO 中的前后端配合限速分析 - leoufung | CSDN
  11. virtio 路径 | 随便写写

官方文档

  1. Virtio | KVM Documents
  2. virtio: Towards a De-Facto Standard For Virtual I/O Devices - Rusty Russell | PDF
  3. Virtio-blk Performance Improvement | KVM Forum 2012

太初有道 - 博客园

  1. Virtio 前端驱动详解 - 太初有道 | cnblogs
  2. Virtio 后端驱动详解 - 太初有道 | cnblogs
  3. Virtio 前后端 notify 机制详解 - 太初有道 | cnblogs
  4. intel EPT 机制详解 - 太初有道 | cnblogs
  5. KVM 中 EPT 逆向映射机制分析 - 太初有道 | cnblogs
  6. QEMU 进程页表和 EPT 的同步问题 - 太初有道 | cnblogs
  7. KVM vCPU 线程调度问题的讨论 - 太初有道 | cnblogs
  8. virtio 之 vhost 工作原理简析 - 太初有道 | cnblogs
  9. PCI 设备详解一 - 太初有道 | cnblogs

Lauren 的博客

  1. Virtio 原理简介 | Lauren’s blog
  2. Virtio 网络发包过程分析 | Lauren’s blog
  3. virtio 前端通知机制分析 | Lauren’s blog
  4. 也说自旋锁 | Lauren’s blog
  5. 也说自旋锁2 —— qspinlock | Lauren’s blog

其他不错的

  1. Virtio 学习笔记(一):简介 - 瞧见风 | CSDN
  2. Linux 系统检查 virtio 驱动 | 腾讯云文档中心
  3. Virtio 基本概念和设备操作 - Db_Chen | cnblogs
  4. virtio 简介 - supersos | cnblogs
  5. KVM 地址翻译流程及 EPT 页表的建立过程 - 小C爱学习 | cnblogs

团子的小窝

  1. NUMA 与 SMP | 团子的小窝
  2. 系列连载文章 | 团子的小窝

QEMU

  1. QEMU/KVM 中的 tracing 工具 - 瞧见风 | CSDN
  2. QEMU 网络虚拟化分析 | Lauren’s blog
  3. 利用 QEMU GDB 调试 Kernel | Lauren’s blog

Linux 云计算网络

  1. Virtio 简介 | Linux 云计算网络
  2. Linux 网络基础知识划重点版(上)| Linux 云计算网络
  3. Linux 网络基础知识划重点版(下)| Linux 云计算网络
  4. 50 个你必须掌握的 Kubernetes 面试题 | Linux 云计算网络

王子阳 - 中科院信息工程研究所

  1. virtio 学习 | 王子阳
  2. 浮点数拾遗 | 王子阳