4. 设备直通核心概念

在 Jailhouse 的分区模型中,设备直通并不是把物理设备“复制”给某个 inmate,而是把设备原本由 Linux 掌控的访问路径整体移交给目标分区。要理解这一过程,需要同时看清四条主线:PCI 设备如何被识别与归属、MMIO 如何映射到分区地址空间、DMA 如何被重映射到安全的内存区域,以及隔离与资源所有权如何保证分区之间互不干扰。这四者共同构成设备直通的最小完整闭环。

一、PCI 设备直通:从枚举到归属转移

PCI 设备直通的第一步是“识别与解绑”。在 Jailhouse 场景中,Linux 作为 root cell 先完成 PCI 枚举,获得设备的 BDF(Bus:Device.Function)、BAR 基址、中断号等信息。随后,Jailhouse 通过配置单元(cell config)声明该设备归属某个 inmate,Linux 侧需要把对应驱动解绑,避免两个分区同时操作同一设备。

设备直通的关键不是“让 inmate 看见设备”,而是“让 inmate 独占设备”。因此,配置中必须明确设备的 BDF、BAR 范围、中断类型(MSI/MSI-X 或 INTx)以及所属分区。Jailhouse 在启动 inmate 时,会把这些资源从 root cell 的视野中移除,并注入到 inmate 的虚拟 PCI 配置空间中。

/* jailhouse cell config 片段:声明 PCI 设备归属 */
.pci_devices = {
    {
        .type = JAILHOUSE_PCI_TYPE_DEVICE,
        .domain = 0x0000,
        .bdf = 0x0000,          /* 00:00.0 */
        .bar_mask = {
            0xfffffff0, 0x00000000,
            0x00000000, 0x00000000,
            0x00000000, 0x00000000,
        },
        .irq = 0x00000010,      /* 中断号 */
    },
},

这段配置表达了三个核心信息:设备身份(BDF)、可访问的 MMIO 窗口(BAR mask)、中断资源(IRQ)。只有三者同时被正确声明,inmate 才能在不触碰其他分区的前提下完成设备初始化。

二、MMIO 映射:把寄存器窗口交给分区

PCI 设备的 BAR 空间本质上是 MMIO 区域。设备直通时,Jailhouse 需要把这段物理地址映射到 inmate 的地址空间,并确保 root cell 不再映射或访问同一区域。MMIO 映射的核心是“地址窗口 + 权限 + 归属”三要素:窗口决定 inmate 能访问哪些寄存器,权限决定读写属性,归属决定谁拥有这段地址。

如果 MMIO 映射不完整,inmate 在读写设备寄存器时会出现异常或静默失败;如果映射重叠,则可能造成两个分区同时写同一寄存器,导致设备状态错乱。因此,Jailhouse 在建立 inmate 地址空间时,会以页为单位检查 MMIO 区域是否与 root cell 或其他 inmate 冲突。

MMIO 映射不是简单的“地址翻译”,而是资源所有权的重新划分。映射完成后,root cell 对该设备的 BAR 访问应被禁止或重定向,否则隔离形同虚设。

三、DMA 重映射:设备访问内存的安全闸门

设备直通中最危险的部分是 DMA。PCI 设备可以绕过 CPU 直接读写物理内存,如果不对 DMA 地址进行限制,设备可能写入 root cell 的内核内存,造成崩溃或安全漏洞。Jailhouse 依赖 IOMMU(如 Intel VT-d、ARM SMMU)进行 DMA 重映射,把设备发出的 DMA 地址翻译到 inmate 拥有的内存区域。

DMA 重映射的关键在于“地址空间隔离”:每个设备被分配一个独立的 IOMMU 域,域内只允许访问该 inmate 的物理页。设备发出的 DMA 请求先经过 IOMMU 查表,若目标地址不在允许范围内,则被拦截并产生错误。这样,即使设备固件或驱动存在缺陷,也无法越界访问其他分区的内存。

/* 查看 IOMMU 分组与设备归属(Linux root cell 侧) */
$ ls /sys/kernel/iommu_groups/
$ find /sys/kernel/iommu_groups/ -name "*00:00.0*"
/sys/kernel/iommu_groups/12/devices/0000:00:00.0

/* Jailhouse 启动后,该设备应出现在 inmate 的 IOMMU 域中 */
$ jailhouse cell list
$ jailhouse cell stat inmate1

IOMMU 分组信息可以帮助判断设备是否具备独立直通条件。如果多个设备共享同一 IOMMU 组,单独直通其中一个可能影响同组其他设备,需要谨慎评估。

四、设备隔离与资源所有权

设备隔离的目标是让每个分区只看到并只操作属于自己的设备。Jailhouse 通过“资源所有权表”实现这一点:PCI 设备、MMIO 窗口、中断线、DMA 域、IOMMU 域都被登记为某个分区的资源。当分区启动时,Jailhouse 检查资源是否冲突;当分区运行时,硬件隔离机制(IOMMU、中断重映射、MMIO 权限)持续生效。

资源所有权不仅包括“谁拥有”,还包括“谁不能访问”。例如,root cell 在设备直通后不应再访问该设备的 BAR 和中断,否则会破坏 inmate 的设备状态。Jailhouse 通过配置和运行时检查,确保资源所有权在分区之间清晰划分。

资源类型 直通前归属 直通后归属 隔离机制
PCI 设备(BDF) root cell inmate 配置声明 + 驱动解绑
MMIO BAR 窗口 root cell 地址空间 inmate 地址空间 页表映射 + 权限检查
DMA 地址空间 root cell 物理内存 inmate 物理内存 IOMMU 重映射
中断线 / MSI-X root cell 中断控制器 inmate 中断注入 中断重映射 + 注入
IOMMU 域 root cell 默认域 inmate 独立域 域隔离 + 页表校验

五、典型场景与常见误区

假设一块网卡需要直通给实时分区 inmate1。操作流程如下:首先在 Linux 中确认网卡 BDF 与 IOMMU 分组;然后在 Jailhouse 配置中声明该 PCI 设备归属 inmate1,并填写 BAR mask 与 IRQ;接着解绑 Linux 驱动,停止 root cell 对该设备的访问;最后启动 inmate1,由 inmate 内的驱动完成设备初始化。启动后,inmate1 通过 MMIO 读写网卡寄存器,通过 DMA 收发数据包,中断由 Jailhouse 注入。

常见误区有三个。第一,只声明 PCI 设备却忘记配置 MMIO 窗口,导致 inmate 访问 BAR 时失败。第二,忽略 IOMMU 分组,直通后同组其他设备异常。第三,root cell 未解绑驱动,两个分区同时操作设备,出现随机崩溃或数据损坏。复盘时应优先检查资源所有权表是否完整、IOMMU 域是否独立、中断路径是否只注入目标分区。

设备直通不是“把设备给出去”就结束,而是“把设备从原所有者手中安全地移交给新所有者”。任何一项资源(MMIO、DMA、中断、IOMMU 域)没有完成归属转移,隔离都不完整。
Jailhouse 设备直通核心资源流转 Root Cell (Linux) PCI 枚举 / 驱动 IOMMU 默认域 中断控制器 物理内存管理 直通前:设备所有者 Inmate 分区 设备驱动 MMIO 寄存器访问 DMA 缓冲区 中断处理 直通后:设备所有者 PCI 设备 BDF / BAR / MSI-X MMIO 映射 BAR 窗口 → inmate 地址空间 IOMMU / DMA 重映射 设备 DMA → inmate 物理页 越界访问被拦截 中断重映射与注入 MSI-X → 目标 inmate 解绑 / 移交 归属注入 地址窗口 DMA 请求 安全内存 中断注入 资源所有权表 PCI BDF → inmate MMIO 窗口 → inmate DMA 域 → inmate 中断线 → inmate 冲突检查 + 运行时隔离 配置声明

总结来看,PCI 设备直通解决“设备归属”,MMIO 映射解决“寄存器访问”,DMA 重映射解决“内存安全”,设备隔离与资源所有权解决“互不干扰”。四者缺一不可,共同构成 Jailhouse 设备直通的核心概念体系。理解这四条主线,才能在后续配置与排障中快速定位问题所在。