ivshmem:(Inter-VM shared memory device)是QEMU提供的一种宿主机与虚拟机之间或多个虚拟机之间共享内存的特殊设备。它有两种形式:
ivshmem-plain: 简单的共享内存区域
ivshmem-doorbell: 除了共享内存,还能提供基于中断的通信机制
这种设备在虚拟机内部表现为PCI设备,共享的内存区域则以PCI BAR的形式存在。ivshmemPCI设备提供3个BAR:
BAR0: 设备寄存器
BAR1: MSI-X表
BAR2: 共享内存区域
简单共享内存的场景只使用BAR2就足够了。如果需要基于中断实现额外通信,需要用到BAR0和BAR1。这可能需要编写内核驱动在虚拟机内处理中断,宿主机上QEMU进程在启动前需要先启动ivshmem server, 然后让QEMU进程连接到server的unix socket。
具体可以参考官方文档。
本文只讨论ivshmem-plain模式。宿主机上添加ivshmem设备后,虚拟机应用如何找到相应的ivshmem设备呢?
Linux的/sys/bus/pci/devices/目录会列出所有的PCI设备,ivshmem设备也会包含在其中。PCI设备都存在vendor号和device两个标识,vendor表示厂商,device表示厂商内的设备类型。ivshmem设备的vendor号为0x1af4, device号为0x1110,PCI设备的vendor和device号可在这里进行查询。
虚拟机中应用可通过遍历该目录下的具体设备,通过读取vendor和device文件来识别ivshmem设备。
但如果有两种应用都需要使用一个独立的ivshmem设备,虚拟机应用如何识别出应该使用哪个ivshmem设备呢?
因为每个PCI设备都可以由BDF:(Bus, Device, Function)来唯一标识,简单做法可以为每个应用预留好固定BDF地址。BDF地址中,BUS占用8位,Device占用5位,Function占用3位。比如,预留总线pci0的最后两个设备地址0000:00:1e.0和0000:00:1f.0。
有时候无法预留,不同虚拟机上的ivshmem地址可能不同。这种情况可以通过与宿主机上的应用约定好相应的固定内容做为signature写入共享内存头部,虚拟机应用读取共享内存头部的signature信息来识别相应设备。