之前的文章<<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中断机制的使用。
