资讯动态

virto 半虚拟化技术mmio和pcie 俩种方式优缺点对比

发布时间:2026/9/30 6:34:06 来源:尧图企业网站定制
简单介绍virtiovirtio 是半虚拟化通信方式一种标准协议 其中linux 系统中vhost是virtio的一种实现方式参照源码src/kernel/linux/v6.1_mt8676/co_common/drivers/vhost/virito底层实现方式有2种一种是mmio方式称为virtio-mmio 一种是pcie方式 称为virtio-pcie。virtio-mmio和virtio-pcie 主要是通过一种标准的协议实现前端FE发现后端BE建立这种前后端的联系。 这样前后端通信的时候才知道数据传递的时候把数据放到什么地址。V35和V4 平台 底层virtio通过mmio方式实现这种逻辑比较简单。 V5 谦川通过pcie方式实现 这种逻辑复杂但是可扩展性强。virtio-pcie、virtio-mmio底层实现代码都是在各自必选的vm里面qvm nbl_vm 下图是touch 驱动基于vhost是实现方式。 上层的virtio-touch 前后端是谦川开发实现touch的逻辑底层通过vhost通信 linux 开源代码1. vhost_dev_init“初始化后端设备结构体分配资源重置状态”。2. vring 里的 “环”avail 环、used 环本质就是索引环—— 环里只存「desc 的编号索引」而不是 desc 本身更不是实际数据。3. desc 里面有数据的信息以及指向数据buff的地址4. 前端程序加载后初始化desc buff 这个desc buffer 就是vq的 buffer。前端程序把空闲 Buffer 的索引填入Avail Ring。通信的时候先从ava ring环上获取一个vq index就是获取desc buffer index 然后把数据写入vq buffer 中 然后把这个vq buffer加入 used ring 环中。5、 数据放入used ring环后host通过vhost signal 进入hyphyp触发中断通知前端取数据 这个中断是前端注册的中断。6、 guest 前端读取used ring 上的数据同时把buffer index 进入avaliable ring 环中。struct vhost_virtqueuestruct vhost_virtqueue 是 Host 侧 vhost 驱动与 Guest 侧 virtio 驱动之间的 “数据交互桥梁”Guest 侧通过 virtio 协议创建 vringdesc/avail/used 三环存放触摸事件的缓冲区描述符Host 侧通过 vhost_virtqueue 访问 Guest 的 vring写入触摸事件、通知 Guest 读取核心作用屏蔽 Guest/Host 的地址空间隔离让 Host 能安全、标准化地操作 Guest 的 vring。desc 是具体存放数据信息 avali和used是数据环 每个环上是一个个desc指向的数据地址就是desc-addr/* The virtqueue structure describes a queue attached to a device. */struct vhost_virtqueue {struct vhost_dev *dev;/* The actual ring of buffers. */struct mutex mutex;unsigned int num;vring_desc_t __user *desc; ###Guest 用户态的描述符环指针物理地址映射Guest 初始化Host 只读定义数据缓冲区的元信息地址、长度、标志vring_avail_t __user *avail; ###Guest 用户态的可用环指针vring_used_t __user *used;const struct vhost_iotlb_map *meta_iotlb[VHOST_NUM_ADDRS];struct file *kick;struct vhost_vring_call call_ctx;struct eventfd_ctx *error_ctx;struct eventfd_ctx *log_ctx;struct vhost_poll poll;/* The routine to call when the Guest pings us, or timeout. */vhost_work_fn_t handle_kick;/* Last available index we saw.* Values are limited to 0x7fff, and the high bit is used as* a wrap counter when using VIRTIO_F_RING_PACKED. */u16 last_avail_idx; ##Host 最后处理的可用环索引/* Caches available index value from user. */u16 avail_idx;/* Last index we used.* Values are limited to 0x7fff, and the high bit is used as* a wrap counter when using VIRTIO_F_RING_PACKED. */u16 last_used_idx;/* Used flags */u16 used_flags;/* Last used index value we have signalled on */u16 signalled_used;/* Last used index value we have signalled on */bool signalled_used_valid;/* Log writes to used structure. */bool log_used;u64 log_addr;struct iovec iov[UIO_MAXIOV];struct iovec iotlb_iov[64];struct iovec *indirect;struct vring_used_elem *heads;/* Protected by virtqueue mutex. */struct vhost_iotlb *umem;struct vhost_iotlb *iotlb;void *private_data;u64 acked_features;u64 acked_backend_features;/* Log write descriptors */void __user *log_base;struct vhost_log *log;struct iovec log_iov[64];/* Ring endianness. Defaults to legacy native endianness.* Set to true when starting a modern virtio device. */bool is_le;#ifdef CONFIG_VHOST_CROSS_ENDIAN_LEGACY/* Ring endianness requested by userspace for cross-endian support. */bool user_be;#endifu32 busyloop_timeout;};在 VirtIO 半虚拟化技术中MMIO 和 PCIe 本质上是 VirtIO 协议挂载的两种不同总线载体它们的核心差异可以概括为MMIO 是轻量级虚拟总线专为纯虚拟化场景设计PCIe 是通用物理总线兼顾虚拟化与物理设备兼容。下面从多个维度展开详细对比一、核心差异对比表表格总线类型轻量级虚拟总线纯软件抽象标准 PCIe 总线可模拟或直通设备发现通过设备树Device Tree或 ACPI 静态枚举通过 PCIe 配置空间动态枚举热插拔❌ 不支持✅ 支持基于 PCIe 热插拔机制物理设备映射❌ 不能用于真实物理外设✅ 可映射真实物理设备如 SR-IOV VF实现复杂度低直接内存映射无需模拟 PCI 桥/配置空间高需模拟 PCI 主桥、配置空间、中断路由等中断机制通常使用共享中断线如 GIC SPI支持 MSI / MSI-X多向量中断配置空间无标准配置空间寄存器直接 MMIO 映射有标准 PCIe 配置空间Vendor ID、Device ID、BAR 等典型应用AWS Firecracker、嵌入式/轻量级 HypervisorQEMU/KVM、云数据中心、生产级虚拟化平台性能控制面略轻少一层 PCI 模拟开销数据面性能相当都走 Virtqueue 共享内存控制面稍重二、深入解析1. 设备发现机制MMIO设备地址和中断号在启动时通过设备树Device Tree或 ACPI 静态告知 Guest OSGuest 通过扫描固定地址范围的 MMIO 区域来发现设备。PCIeGuest OS 通过标准 PCIe 枚举流程读取配置空间的 Vendor ID / Device ID动态发现设备和物理 PCIe 设备的发现流程完全一致。2. 热插拔能力MMIO由于是静态映射不支持热插拔。设备必须在 VM 启动前就定义好。PCIe原生支持 PCIe 热插拔机制可以在 VM 运行时动态添加/移除 VirtIO 设备。3. 与物理设备的兼容性这是两者最本质的区别MMIO完全是为虚拟机设计的虚拟总线无法对应任何真实物理设备。Guest 内部能明确知道自己运行在虚拟化环境中。PCIeGuest OS无法区分VirtIO-PCI 设备是虚拟的还是物理的。这意味着同一个 VirtIO 驱动可以同时服务于虚拟设备和物理设备如 vDPA 场景。可以无缝切换到 SR-IOV VF 直通模式Guest 无需修改驱动。4. 中断机制MMIO通常依赖 GIC 的共享中断线SPI中断向量数量有限多设备共享时可能产生中断风暴。PCIe支持MSI / MSI-X每个 Virtqueue 可以分配独立的中断向量显著降低中断延迟和 CPU 开销。5. 实现复杂度MMIO实现极其简单。Hypervisor 只需在 Guest 的物理地址空间中划出一段 MMIO 区域拦截 Guest 对该区域的读写即可。无需模拟 PCI 桥、配置空间、BAR 分配等复杂逻辑。PCIe需要完整模拟 PCIe 设备的配置空间、BAR 寄存器、中断路由INTx / MSI / MSI-X、PCIe 能力结构等。QEMU 中 PCI 设备模拟的代码量远大于 MMIO 设备。三、数据面性能两者几乎一致需要特别强调的是MMIO 和 PCIe 的差异主要在控制面设备发现、配置、中断数据面性能几乎相同。因为 VirtIO 的核心优化——Virtqueue 共享内存 零拷贝——与底层总线无关。无论挂载在 MMIO 还是 PCIe 上数据收发都通过以下路径文本编辑Guest 前端驱动 → Virtqueue共享内存 → Hypervisor 后端驱动 → 物理设备控制面的差异如 PCIe 配置空间模拟的开销只在设备初始化时产生一次性成本运行时对吞吐量/延迟的影响微乎其微。四、选型建议表格轻量级微 VM如 Firecracker、嵌入式 HypervisorVirtIO-MMIO实现简单、启动快、资源占用少生产级云平台如 OpenStack、KVMVirtIO-PCIe支持热插拔、MSI-X、与物理设备兼容vDPA / 硬件卸载场景VirtIO-PCIe可无缝切换到 SR-IOV VF 或 DPU 卸载车载 Hypervisor如 QNX Hypervisor、ACRN视具体需求若 Guest 数量少且静态配置 → MMIO 足够若需要动态设备管理 → PCIe五、一句话总结VirtIO-MMIO 是轻量级虚拟专用通道实现简单但不支持热插拔和物理映射VirtIO-PCIe 是通用标准高速公路实现复杂但兼容物理设备、支持热插拔和 MSI-X。数据面性能两者相当差异主要在控制面。QNX的hypvisor2.1和2.2 中的virtio 使用那种方法 mmioQNX Hypervisor 2.1/2.2 中的 VirtIO 同时支持 MMIO 和 PCIe 两种总线类型并非只使用 MMIO但在 ARM 车载平台如高通 SA8155上MMIO 是更常见且默认的配置方式。一、官方文档证据1. 默认是 PCI但 ARM 平台通常配置为 MMIOQNX 官方文档对vdev virtio-net的描述非常明确Normally this device appears as aPCI device, but if you specify thelocandintroptions, the guest will see it as amemory-mapped I/O deviceat the specified location.翻译过来就是不指定loc/intr→ 设备以 PCI 形式暴露给 GuestGuest 通过 PCI 配置空间枚举发现指定loc基地址intr中断号→ 设备以 MMIO 形式暴露给 GuestGuest 通过设备树静态发现2. ARM 平台的典型配置就是 MMIOQNX 官方给出的 ARM 平台 virtio-net 配置示例文本编辑vdev virtio-net loc 0x1c0c0000 # MMIO 基地址 intr gic:40 # GIC 中断号 mac aa:aa:aa:aa:aa:aa name p2p peer /dev/vdevpeers/vp0官方注释也明确写了Thelocandintrgic options are forARM only. The guest will see the virtio-net vdev as amemory-mapped I/O deviceat the specified location.3. GPU 虚拟化的场景也印证了这一点在高通 SA8155P 平台上QNX Hypervisor 的 virtio-gpu 设备配置ASG 模式设备必须定义为MMIO 类型配置loc、intr、vram_loc、vram_size等参数。Pipe 模式设备可配置为MMIO 或 PCI 类型。高通以太网的虚拟化举例loc0x1c0c0000MMIO 寄存器基地址与官方文档示例完全一致intrgic:41绑定 GIC 中断号 41peer/dev/vdevpeer/vp0对端节点路径指向 Host 侧的 vp0 接口mac02:47:57:4d:00:99Guest 侧虚拟网卡的 MAC 地址namela_to_host该 vdev 在 Guest 内的节点名称二、为什么 ARM 车载平台偏爱 MMIO这和我们之前讨论的 VirtIO-MMIO vs VirtIO-PCI 的优缺点直接相关表格静态配置车载场景 Guest OS 数量固定、设备拓扑不变无需 PCI 的动态枚举能力实现简单MMIO 无需模拟 PCI 桥、配置空间、BAR 分配Hypervisor 代码量更小设备树友好ARM Linux/Android Guest 通过设备树Device Tree静态描述 MMIO 设备与物理 ARM 板的驱动加载方式一致中断路由清晰直接绑定 GIC SPI 中断号无需模拟 PCI INTx/MSI 路由确定性更高没有 PCI 枚举的不确定性启动流程更可预测符合车规功能安全要求三、两种总线在 QNX Hypervisor 中的配置对比MMIO 配置ARM 平台典型用法conf编辑# *.qvmconf 配置文件 vdev virtio-net loc 0x1c0c0000 # MMIO 寄存器基地址 intr gic:40 # GIC 中断号 mac aa:bb:cc:dd:ee:ffGuest 侧设备树节点dts编辑virtio_net1c0c0000 { compatible virtio,mmio; reg 0x0 0x1c0c0000 0x0 0x200; interrupts GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH; };PCI 配置x86 或 ARM 可选conf编辑# *.qvmconf 配置文件 — 不指定 loc/intr vdev virtio-net mac aa:bb:cc:dd:ee:ff # 自动以 PCI 设备形式暴露Guest 侧通过lspci可看到文本编辑B000:D02:F00 vid/did: 1af4/1041 VirtIO Network Device其中1af4是 VirtIO 标准的 Vendor ID。四、QNX Guest 驱动侧的适配QNX 的devnp-virtio.so网络驱动同时支持两种模式bash编辑# MMIO 模式指定 smem共享内存基地址和 irq io-pkt-v6-hc -d virtio smem0xf0c00000,irq58 # PCI 模式指定 pci 实例号或自动检测所有 PCI VirtIO 设备 io-pkt-v4-hc -d virtio pci0两个选项互斥——pci和smem不能同时使用。五、一句话总结QNX Hypervisor 2.1/2.2 的 VirtIO 同时支持 MMIO 和 PCI 两种总线通过配置文件中是否指定loc/intr参数来切换。在 ARM 车载平台如 SA8155上由于静态配置、实现简单、设备树友好等原因MMIO 是更常见且官方推荐的方式在 x86 平台或需要 PCI 兼容性的场景下则使用 PCI 总线

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑