虚拟机间共享内存设备规范
虚拟机间共享内存设备(ivshmem)用于在运行不同客户机的多个 QEMU 进程及主机之间 共享一段内存区域。为使所有客户机都能取得该共享内存区域,QEMU 将其建模为 PCI 设备,通过 PCI BAR 向客户机暴露这段内存。
设备可以直接使用主机上的共享内存对象,也可以从 ivshmem 服务器获取对象。
后一种情况下,设备还可以向其他对等设备发送中断,并接收它们发来的中断。
有关通过 QEMU 命令行配置 ivshmem 设备的信息,请参阅 虚拟机间共享内存设备。
ivshmem PCI 设备的客户机接口
设备的厂商 ID 为 1af4,设备 ID 为 1110,修订版本为 1。在 QEMU 2.6.0 之前, 修订版本为 0。
PCI BAR
ivshmem PCI 设备有两个或三个 BAR:
BAR0 包含设备寄存器(256 字节 MMIO)
BAR1 包含 MSI-X 表和 PBA(仅 ivshmem-doorbell)
BAR2 映射共享内存对象
此设备有两种使用方式:
如果只需要共享内存功能,BAR2 即可满足需求。客户机可由此访问共享内存, 并按需使用。
如果还需要对等设备相互发送中断的能力,就需要 BAR0 和 BAR1。通常需要编写 内核驱动来处理中断。当然,设备必须配置为支持中断。
在 QEMU 2.6.0 之前,如果设备配置为支持中断,BAR2 起初可能无效。只有在 ivshmem 服务器提供共享内存后,才能安全地访问它。这些设备的 PCI 修订版本为 0,而不是 1。 客户机软件应等待 IVPosition 寄存器(见下文)的值变为非负数,再访问 BAR2。
修订版本 0 的设备无法告知客户机软件其是否配置为支持中断。
PCI 设备寄存器
BAR 0 包含以下寄存器:
偏移 大小 访问 复位值 功能
0 4 读/写 0 Interrupt Mask
位 0: 对等方中断 (rev 0)
保留 (rev 1)
位 1..31: 保留
4 4 读/写 0 Interrupt Status
位 0: 对等方中断 (rev 0)
保留 (rev 1)
位 1..31: 保留
8 4 只读 0 或 ID IVPosition
12 4 只写 N/A Doorbell
位 0..15: 向量
位 16..31: 对等方 ID
16 240 无 N/A 保留
软件只能按“访问”列规定的方式访问寄存器。读取时应忽略保留位,写入时应保留其值。
对于修订版本 0 的设备,在没有 MSI-X 能力时,Interrupt Status 和 Mask 寄存器共同 控制传统 INTx 中断:当 Status 与 Mask 按位与的结果非零且设备没有 MSI-X 能力时, 拉高 INTx。收到对等设备的中断请求时,Interrupt Status 寄存器的位 0 变为 1。 读取该寄存器会将它清零。
IVPosition 寄存器:若设备未配置中断,其值为零。否则为设备 ID(0 至 65535)。
在 QEMU 2.6.0 之前,复位后短时间内读取该寄存器可能得到 -1。这些设备的 PCI 修订版本为 0,而不是 1。
软件没有可靠的方法确定设备是否配置了中断。IVPosition 为正数意味着支持中断, 但为零时两种情况都有可能。
Doorbell 寄存器:写入该寄存器会请求向对等设备发送中断。写入值的高 16 位指定 目标对等设备的 ID,低 16 位选择中断向量。
如果设备未配置中断,则忽略写入。
如果中断尚未完成设置,则忽略写入。设备无法告知客户机软件设置是否完成。 迁移时,中断可能退回到此状态。
如果所请求 ID 的对等设备未连接,或其已连接的中断向量数不足,则忽略写入。 设备无法告知客户机软件哪些对等设备已连接,或已连接多少中断向量。
随后,对等设备上该向量的中断变为待处理状态。软件无法清除待处理位,因此无法 采用轮询方式操作。
如果对等设备为没有 MSI-X 能力的修订版本 0 设备,其 Interrupt Status 寄存器 置为 1。除非 Interrupt Mask 寄存器将其屏蔽,否则会拉高 INTx。在这种情况下, 设备无法向客户机软件传达中断向量。
存在多个 MSI-X 向量时,可使用不同向量表示发生了不同事件。中断向量的语义由应用决定。
中断基础设施
配置中断后,对等设备除共享内存外,还共享 eventfd 对象。共享资源由 ivshmem 服务器管理。
ivshmem 服务器
服务器监听 UNIX 域套接字。
对于每个新连接的客户端,服务器会:
选取一个 ID,
为中断向量创建 eventfd 文件描述符,
向新客户端发送 ID 和共享内存的文件描述符,
向其他客户端发送新客户端的连接通知(包含发送中断所需的文件描述符),
向新客户端发送其他客户端的连接通知,以及
向新客户端发送中断设置消息(包含接收中断所需的文件描述符)。
第一个连接服务器的客户端获得 ID 零。
客户端断开连接时,服务器向其他客户端发送断开通知。
下一节详细说明协议。
如果服务器在未发送其已连接客户端的断开通知的情况下终止,客户端可以选择继续运行。 它们仍可正常相互通信,但断开时不会收到断开通知,也无法连接新客户端。客户端无法 连接到重启后的服务器。设备无法告知客户机软件服务器是否仍在运行。
示例服务器代码位于 contrib/ivshmem-server/,不可用于生产环境。它假定所有客户端 使用相同数量的中断向量。
独立客户端位于 contrib/ivshmem-client/,可用于调试。
ivshmem 客户端—服务器协议
配置为支持中断的 ivshmem 设备会连接到 ivshmem 服务器。本节详细介绍两者之间的协议。
连接是单向的:服务器向客户端发送消息。每条消息包含一个 8 字节的小端有符号数, 并且可以通过 SCM_RIGHTS 附带一个文件描述符。客户端和服务器遇到错误时均关闭连接。
注意:QEMU 目前不会在出错时立即关闭连接,而是等到字符设备销毁时才关闭。
连接建立后,服务器按顺序发送以下消息:
协议版本号,目前为零。客户端收到无法处理的版本号时,应关闭连接。
客户端 ID,在此服务器的所有客户端中唯一。ID 必须位于 0 至 65535 之间, 因为 Doorbell 寄存器仅为它提供 16 位。
数字 -1,并附带共享内存的文件描述符。
其他现有客户端的连接通知(如有)。消息为一个对等设备 ID(0 至 65535 之间且 不同于自身 ID 的数),重复 N 次。每次附带一个文件描述符,依次用于通过向量 0,..,N-1 向该 ID 的对等设备发送中断。如果客户端配置的向量较少,就关闭多余的 文件描述符;如果配置的向量较多,多余的向量保持未连接状态。
中断设置。消息为客户端自身的 ID,重复 N 次。每次附带一个文件描述符,依次用于 通过向量 0,..,N-1 接收对等设备的中断。如果客户端配置的向量较少,就关闭多余的 文件描述符;如果配置的向量较多,多余的向量保持未连接状态。
此后,服务器发送以下类型的消息:
连接/断开通知,内容为一个对等设备 ID。
如果该数字附带文件描述符,则为连接通知,与第 4 步完全相同。
否则,为该 ID 对等设备的断开通知。
已知问题:
协议在 QEMU 2.5 中发生了不兼容的变化。此前消息采用本机字节序的 long, 且没有版本号。
协议设计较差。
ivshmem 客户端间协议
如上一节所述,配置为支持中断的 ivshmem 设备从服务器接收 eventfd 文件描述符, 用来向对等设备发送中断,以及接收对等设备的中断。
要向对等设备发送中断,设备以本机字节序向相应文件描述符写入 8 字节整数 1。
要接收中断,设备尽可能多地读取并丢弃 8 字节整数。