ivshmem:(Inter-VM shared memory device)
是QEMU
提供的一种宿主机与虚拟机之间或多个虚拟机之间共享内存的特殊设备。它有两种形式:
ivshmem-plain
: 简单的共享内存区域ivshmem-doorbell
: 除了共享内存,还能提供基于中断的通信机制
这种设备在虚拟机内部表现为PCI
设备,共享的内存区域则以PCI BAR
的形式存在。ivshmem
PCI设备提供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
信息来识别相应设备。