RISC-V 机器的 IOMMU 支持

QEMU 基于 RISC-V IOMMU 1.0 规范 iommu1.0.0 实现仿真。

包括 PCI 参考设备 riscv-iommu-pci 和平台总线设备 riscv-iommu-sys, 供 QEMU RISC-V 开发板使用。virt 机器兼容两者。

riscv-iommu-pci 参考设备

按 iommu1.0.0 的“Integrating an IOMMU as a PCIe device”一节实现: PCI 基类 08h、子类 06h、编程接口 00h。

作为参考设备,不实现规范之外的内容,使用 QEMU 的通用默认 PCI ID 1b36:0014。

在 virt 机器中添加:

$ qemu-system-riscv64 -M virt -device riscv-iommu-pci,[optional_pci_opts] (...)

这会按照额外 PCI 参数(如总线地址)添加设备。 RISC-V IOMMU 的行为由规范定义,但其操作方式取决于操作系统。

Linux 内核 v6.13 合入 IOMMU 支持,主线内核可使用 QEMU 仿真实现基本 PCIe IOMMU 功能。

截至 v6.17,尚不支持 VFIO 直通等功能。有一个尚未合入的 VFIO RFC 系列, 可使用 Ventana Micro Systems 公开内核仓库 ventana-linux 测试 VFIO。

v6.13+ 驱动通过 IOMMU 为系统中所有符合条件的卡创建 IOMMU 组, 不受命令行中设备添加顺序等因素影响。

因此,对当前内核驱动而言,以下命令等效:

$ qemu-system-riscv64 \
      -M virt,aia=aplic-imsic,aia-guests=5 \
      -device riscv-iommu-pci,addr=1.0 \
      -device e1000e,netdev=net1 -netdev user,id=net1,net=192.168.0.0/24 \
      -device e1000e,netdev=net2 -netdev user,id=net2,net=192.168.200.0/24 \
      (...)

$ qemu-system-riscv64 \
      -M virt,aia=aplic-imsic,aia-guests=5 \
      -device e1000e,netdev=net1 -netdev user,id=net1,net=192.168.0.0/24 \
      -device e1000e,netdev=net2 -netdev user,id=net2,net=192.168.200.0/24 \
      -device riscv-iommu-pci,addr=3.0 \
      (...)

两者都会为两个 e1000e 创建 IOMMU 组。

以下选项控制设备能力:

  • bus:IOMMU 所用总线。

  • ioatc-limit:地址转换缓存大小,默认 2Mb。

  • intremap:启用/禁用 MSI。

  • ats:启用 ATS。

  • off:复位后的转换模式;on 禁用 DMA,off 为 BARE 直通。

  • s-stage:启用 s-stage。

  • g-stage:启用 g-stage。

  • hpm-counters:硬件性能计数器数量,最大和默认均为 31,设 0 禁用 HPM。

  • vendor-id/device-id:PCI 设备 ID,默认 1b36:0014(Redhat)。

riscv-iommu-sys 设备

以平台总线设备形式实现 RISC-V IOMMU,供 RISC-V 开发板使用。

virt 默认禁用,通过 iommu-sys 机器选项启用:

$ qemu-system-riscv64 -M virt,iommu-sys=on (...)

virt 不提供通过 QEMU 命令行配置此设备能力的选项,固定使用以下设置:

  • ioatc-limit:默认 2Mb。

  • intremap:启用。

  • ats:启用。

  • off:on,禁用 DMA。

  • s-stage:启用。

  • g-stage:启用。