之前的文章<<QEMU虚拟机内识别ivshmem设备>>介绍了在虚拟机内通过用户态程序访问ivshmem
设备的共享内存。在虚拟机之间或者宿主机与虚拟机之间通过共享内存进行通信的情形下,共享内存的两端必须依赖轮询方式来实现通知机制。这种方式是ivshmem
提供的ivshmem-plain
的使用方式。除此之外,ivshmem
还提供了ivshmem-doorbell
的使用方式,它提供了基于中断的通知机制。
ivshmem-doorbell
提供了两种中断方式,一种是传统的基于INTx
的中断, 它主要使用BAR0
的Interrupt Mask
和Interrupt Status
两个寄存器;另一种是基于MSI-X
的中断,它主要使用BAR0
的IVPosition
和Doorbell
两个寄存器。参考共享的设备端叫做peer
。IVPosition
寄存器存储该peer
的数字标识符(0-65535), 称做peer_id
。该寄存器为只读寄存器。而Doorbell
寄存器为只写寄存器。ivshmem-doorbell
支持多个中断向量,写入Doorbell
寄存器则触发共享该内存的某个peer
的某个中断。Doorbell
为32
位,低16
位为peer_id
,而高16
位为中断向量号(这里是从0
开始的顺序号,而非PCI
驱动在Guest虚拟机内部所申请的向量号)。
使用ivshmem-doorbell
机制需要运行ivshmem-server
。ivshmem-server
根据参数创建共享内存,并通过监听本地UNIX DOMAIN SOCKET
等待共享内存的peer
来连接。添加了ivshmem-doorbell
设备的QEMU
进程会连接该socket
, 从而获取ivshmem-server
所分配的一个peer_id
。ivshmem-doorbell
支持多个中断向量,ivshmem-server
会为ivshmem
虚拟PCI
设备支持的每个中断向量创建一个eventfd
,并将共享内存以及为所有客户端中断向量所创建的eventfd
都通过SCM_RIGHTS
机制传递给所有客户端进程。这样所有的peer
便都具备了独立的两两之间的通知通道。之后在虚拟机内通过触发ivshmem
虚拟PCI
设备的DOORBELL
寄存器的写入,虚拟机的QEMU
进程便会通过DOORBELL
寄存器中的peer_id
和中断向量号来找到相应的eventfd
,从而通知到对端的QEMU
进程来产生相应的PCI
中断。
要使用中断机制,用户态程序是无能为力的,需要编写相应的PCI
驱动来实现。本文通过一个简单的PCI
驱动示例来说明ivshmem-doorbell
的MSI-X
中断机制的使用。