RISC-V,PCIe NVMe 透传lkvm

在 RISC-V 生态下将 PCIe NVMe 透传给 lkvm (kvmtool)

速览

核心流程与 x86/ARM64 一致(VFIO 解绑绑定 + --vfio-pci 参数 ),真正的瓶颈不在 kvmtool,而在 RISC-V 平台的 IOMMU 与 AIA 中断支持是否完备


一、前提条件与支持现状

硬件要求

要求
CPU 支持 RISC-V Hypervisor 扩展(H 扩展)
平台 具备 RISC-V IOMMU,PCIe 根复合体与 DMA 设备均受其管理
设备 NVMe 所在的 PCIe 链路受 IOMMU 管控

软件支持进展

RISC-V 的 VFIO 透传经历了从无到有的过程:

时间 进展
2021 年 kvmtool 为 RISC-V 添加 PCI host DT 节点,但当时明确说明"还不能用于透传"------缺少 IOMMU 与中断路由
2024 年底 RISE 项目报告确认 KVM irqbypass 与 IOMMU 支持取得进展
2025 年 9 月 上游 patch 开始将 VFIO 模块加入 RISC-V defconfig
2026 年 8 月 LWN 报道 RISC-V IOMMU 支持二级域硬件脏页跟踪;测试中已通过 vfio-pci + iommufd 将 NVMe 与 e1000e 透传到 L2 guest,同时启用 KVM_VFIO 接口

结论:RISC-V 上的 NVMe VFIO 透传目前已经可用,但依赖较新的内核(建议 6.10+,最好使用包含完整 RISC-V IOMMU 支持的分支,如 Ventana 内核树)以及支持 AIA 的中断控制器。


二、具体操作步骤

步骤 1 · 确认硬件与内核能力

复制代码
# 确认 CPU 支持 Hypervisor 扩展
grep -i isa /proc/cpuinfo        # isa 串中应含小写 'h'
dmesg | grep -i "hypervisor"

# 确认 IOMMU 已启用并工作
dmesg | grep -i iommu
ls /sys/class/iommu/

# 确认 KVM 可用
ls -l /dev/kvm
dmesg | grep -i kvm

步骤 2 · 内核配置要求

Host 内核 .config 需启用以下选项:

复制代码
CONFIG_KVM=y
CONFIG_KVM_VFIO=y
CONFIG_VFIO=y
CONFIG_VFIO_PCI=y
CONFIG_VFIO_PCI_CORE=y
CONFIG_RISCV_IOMMU=y
CONFIG_IOMMUFD=y
CONFIG_IRQ_BYPASS=y
CONFIG_KVM_GENERIC_HARDWARE_UNLOAD=y

建议追加内核启动参数:

复制代码
iommu=pt

步骤 3 · 加载 VFIO 模块

复制代码
sudo modprobe vfio
sudo modprobe vfio-pci

# 确认模块已加载
lsmod | grep vfio

步骤 4 · 定位 NVMe 设备并绑定到 vfio-pci

复制代码
# 1. 找到 NVMe 设备的 PCI BDF 地址和厂商/设备 ID
lspci -nn | grep -i "Non-Volatile\|NVMe"
# 输出示例:
# 0000:01:00.0 Non-Volatile memory controller:
#   Samsung Electronics Co Ltd NVMe SSD Controller [144d:a808]

# 2. 记录设备信息
PCI_BDF="0000:01:00.0"
VENDOR_ID="144d"
DEVICE_ID="a808"

# 3. 确认该设备当前使用的驱动
lspci -k -s $PCI_BDF
# 应显示 "Kernel driver in use: nvme"

# 4. 将设备从 nvme 驱动解绑
echo $PCI_BDF | sudo tee /sys/bus/pci/devices/$PCI_BDF/driver/unbind

# 5. 将厂商/设备 ID 写入 vfio-pci 的 new_id
echo "$VENDOR_ID $DEVICE_ID" | sudo tee /sys/bus/pci/drivers/vfio-pci/new_id

# 6. 绑定到 vfio-pci
echo $PCI_BDF | sudo tee /sys/bus/pci/drivers/vfio-pci/bind

# 7. 验证绑定成功
lspci -k -s $PCI_BDF
# 应显示 "Kernel driver in use: vfio-pci"

# 8. 确认 VFIO 设备节点已生成
ls -l /dev/vfio/
# 应看到类似 /dev/vfio/NN 的组设备节点

⚠️ 注意:若 NVMe 是系统盘则不能直接解绑。需使用额外的 NVMe 卡,或从其他存储启动系统。

步骤 5 · 编译支持 RISC-V 的 kvmtool

复制代码
# 安装依赖
sudo apt-get install libfdt-dev libssl-dev build-essential

# 克隆 kvmtool(建议使用包含 RISC-V 最新支持的分支)
git clone https://github.com/kvmtool/kvmtool.git
cd kvmtool

# 编译(指定 ARCH=riscv)
make ARCH=riscv

# 编译产物为 ./lkvm
./lkvm --help

步骤 6 · 启动虚拟机并透传 NVMe

kvmtool 使用 --vfio-pci 指定要透传的 PCI 设备:

复制代码
sudo ./lkvm run \
  -k /path/to/guest/Image \                    # Guest 内核镜像
  -d /path/to/guest/rootfs.ext4 \              # Guest 根文件系统(可选,也可从透传的 NVMe 启动)
  -m 4096 \                                    # 内存大小 MB
  -c 4 \                                       # vCPU 数量
  --vfio-pci 0000:01:00.0 \                    # 透传 NVMe 设备(关键参数)
  --console serial \
  -p "console=ttyS0 root=/dev/nvme0n1p1 rw"    # Guest 内核参数,从透传的 NVMe 启动

--vfio-pci 可多次指定以透传多个设备:

复制代码
--vfio-pci 0000:01:00.0 --vfio-pci 0000:02:00.0

步骤 7 · 在 Guest 中验证

复制代码
# 查看 PCI 设备,应能看到透传的 NVMe 控制器
lspci -nn | grep -i nvme

# 查看 NVMe 块设备
lsblk
# 应看到 /dev/nvme0n1 等设备节点

# 测试读写
sudo fdisk -l /dev/nvme0n1

三、关键注意事项

1. 中断控制器要求

RISC-V 上的 PCIe MSI/MSI-X 中断透传需要 **AIA(Advanced Interrupt Architecture)**​ 支持,包括 APLIC 与 IMSIC。

若平台只有旧的 PLIC,MSI-X 可能无法正常工作,NVMe 只能退回传统 INTx 中断,性能较差。

2. IOMMU 组限制

VFIO 以 IOMMU 组为单位进行隔离。若 NVMe 与其他设备同组,需将整组设备透传给同一虚拟机,或借助 ACS(Access Control Services)拆分。

复制代码
# 查看设备的 IOMMU 组
readlink /sys/bus/pci/devices/0000:01:00.0/iommu_group

# 查看同组所有设备
ls /sys/bus/pci/devices/0000:01:00.0/iommu_group/devices/

3. 内核版本建议

级别 版本 说明
最低 Linux 6.8+ 包含基础 RISC-V IOMMU 支持
推荐 Linux 6.10+ 或 Ventana Micro Systems 内核分支(含完整 KVM VFIO + irqbypass)
iommufd 路径 Linux 6.2+ 需启用 CONFIG_IOMMUFD

4. 性能优化

  • 启用 iommu=pt(passthrough 模式)以减少 DMA 映射开销
  • 确保 Guest 内核同样启用了 NVMe 驱动与 PCIe 支持
  • 使用 MSI-X 中断(依赖 AIA)而非 INTx

5. 常见问题排查

问题 可能原因 解决方法
--vfio-pci 参数不识别 kvmtool 编译时未包含 VFIO 支持 检查编译配置,确保 vfio/pci.c 被编译进产物
设备绑定 vfio-pci 失败 设备正被占用 / IOMMU 未启用 确认设备未挂载,检查 dmesg | grep -i iommu
Guest 中看不到设备 中断路由问题 / PCI host bridge 未正确配置 检查 Guest 内核是否启用 PCI,查看 dmesg | grep -i pci
NVMe 识别但无法读写 DMA 映射失败 / IOMMU 配置错误 检查 IOMMU 域配置,确认 iommu=pt 生效
性能很差 使用 INTx 而非 MSI-X 确保平台支持 AIA,Guest 启用 MSI-X

四、替代方案

若当前硬件/内核尚不满足 lkvm VFIO 透传条件,可考虑:

  1. QEMU + KVM --- RISC-V 上的 VFIO 支持更成熟,命令为 -device vfio-pci,host=0000:01:00.0
  2. virtio-blk 后端 --- 将 Host 上的 NVMe 作为 virtio-blk 暴露给 Guest(非透传,但兼容性好)
  3. OpenVMM --- 微软开源的 VMM,RISC-V 上亦有 VFIO 支持,文档称 NVMe 控制器可端到端工作

五、总结

在 RISC-V 上将 PCIe NVMe 透传给 lkvm 的核心流程与 x86/ARM64 类似(VFIO 解绑绑定 + --vfio-pci 参数),但关键瓶颈在于 RISC-V 平台的 IOMMU 和 AIA 中断支持是否完备

建议做法:

  • 在具备 RISC-V IOMMU 与 AIA 的硬件平台上,使用 6.10+ 内核尝试
  • 遇到问题时,优先检查 dmesg 中的 IOMMU 与 KVM 相关日志,确认底层依赖是否就绪
相关推荐
Neighbor_OldY1 小时前
【实战复盘】XSS跨站脚本攻击检测与应急处置:存储型/反射型/DOM型从发现到修复的完整指南
网络·安全·web安全
zhengqweasd1 小时前
网站卡死、接口超时的隐性根源
运维·服务器·网络
裕晟资质规划1 小时前
军工保密资质二级申报的四个可量化硬条件:条文位置、数值口径与西安配套企业实务要点
java·服务器·网络·数据库·算法
上学的小垃圾1 小时前
华为eNSP防火墙USG6000V登录管理方式
网络·网络安全·华为
呆呆敲代码的小Y2 小时前
TCP / UDP 对比介绍
网络·网络协议·tcp/ip·udp·tcp·tcp/udp
m0_614523552 小时前
故障排查:移动物体表面贴图为什么会漂移?从稳定纹理到连续帧验收
网络·人工智能·贴图
星栖与芯2 小时前
STM32MP157 M4 指针避坑(三):生命周期与内存踩踏——HardFault 重灾区
java·网络·stm32
SKH.2 小时前
网络(4)HTTP协议与TCP并发服务器
网络·tcp/ip·http
(Charon)2 小时前
【C++】网络缓冲区设计(一):为什么需要Buffer?输入输出缓冲区与统一接口
网络