'virt' 通用虚拟平台(virt)
virt 板是不对应任何真实硬件的平台,专为虚拟机设计。如果只想运行 Linux 等客户机,而不需要重现某款真实硬件的特殊行为和限制,建议使用此板类型。
支持的设备
virt 机器支持以下设备:
最多 512 个通用 RV32GC/RV64GC 核心,可带可选扩展
核心本地中断器(CLINT)
平台级中断控制器(PLIC)
CFI 并行 NOR 闪存
一个兼容 NS16550 的 UART
一个 Google Goldfish RTC
一个 SiFive Test 设备
八个 virtio-mmio 传输设备
一个通用 PCIe 主机桥
允许客户机从 QEMU 获取数据的 fw_cfg 设备
默认 CPU 已启用虚拟机监控器扩展,因此可以直接使用具有该扩展的虚拟机,无需显式声明。
硬件配置信息
如果未指定 -dtb 选项,virt 机器会自动生成设备树二进制文件(“dtb”)并传给客户机。其中提供系统中各种设备的地址、中断线和其他配置信息。客户机软件应从生成的 DTB 中发现设备。
如果用户希望提供自己的 DTB,可以使用 -dtb 选项。这些 DTB 应满足以下要求:
/cpus 节点的子节点数量应与 QEMU 的
-smp选项匹配/memory 的 reg 大小应与 QEMU 通过
-m选择的 ram_size 匹配与 OpenSBI BIOS 镜像配合使用时,应包含 compatible 字符串为 "riscv,clint0" 的 CLINT 设备节点
启动选项
virt 机器可以使用标准 -kernel 功能加载 Linux 内核、VxWorks 内核或 S 模式 U-Boot 引导加载程序,并以默认 OpenSBI 固件镜像作为 -bios。它还支持推荐的 RISC-V 启动流程:使用标准 -bios 功能,由 U-Boot SPL(M 模式)加载 OpenSBI fw_dynamic 固件和 U-Boot proper(S 模式)。
使用闪存设备
默认情况下,第一个闪存设备(pflash0)应包含 S 模式固件代码。它可以配置为只读,第二个闪存设备(pflash1)则可用于存储配置数据。
例如,启动 edk2 的命令如下:
$ qemu-system-riscv64 \
-blockdev node-name=pflash0,driver=file,read-only=on,filename=<edk2_code> \
-blockdev node-name=pflash1,driver=file,filename=<edk2_vars> \
-M virt,pflash0=pflash0,pflash1=pflash1 \
... other args ....
仅对于 TCG 客户机,还可以额外传入 -bios none,从第一个闪存设备(pflash0)启动 M 模式固件,例如:
$ qemu-system-riscv64 \
-bios none \
-blockdev node-name=pflash0,driver=file,read-only=on,filename=<m_mode_code> \
-M virt,pflash0=pflash0 \
... other args ....
用于 pflash 的固件镜像必须恰好为 32 MiB。
riscv-iommu 支持
此板支持通过以下命令行使用 riscv-iommu-pci 设备:
$ qemu-system-riscv64 -M virt -device riscv-iommu-pci (...)
它还支持 riscv-iommu-sys 平台设备:
$ qemu-system-riscv64 -M virt,iommu-sys=on (...)
关于 RISC-V IOMMU 支持的工作方式,请参阅 RISC-V 机器的 IOMMU 支持。
机器专用选项
支持以下机器专用选项:
aclint=[on|off]
此选项为 "on" 时,模拟 ACLINT 设备而不是 SiFive CLINT。未指定时视为 "off"。此选项仅适用于 TCG 加速器。
acpi=[on|off|auto]
此选项为 "on"(默认值)时,生成 ACPI 表,并以固件表 etc/acpi/rsdp 和 etc/acpi/tables 的形式提供。
aia=[none|aplic|aplic-imsic]
此选项允许选择 AIA(高级中断架构)规范定义的中断控制器。"aia=aplic" 选择 APLIC(高级平台级中断控制器)处理有线中断;"aia=aplic-imsic" 选择 APLIC 和 IMSIC(入站消息信号中断控制器),同时处理有线中断和 MSI。未指定时视为 "none",即选择 SiFive PLIC 处理有线中断。
此选项也与 '-accel kvm' 交互。在 KVM 下使用 "aia=aplic-imsic" 时,可以通过 "-accel kvm,kernel-irqchip=split" 将内核 irqchip 设为拆分模式。此时,
virt机器会模拟 APLIC 控制器,而不使用 irqchip 中的 APLIC 控制器。关于全部可用 AIA 模式的更多详情,请参阅 RISC-V 机器的 AIA 支持。aia-guests=nnn
为具有 AIA IMSIC 的客户机(即选择了 "aia=aplic-imsic")模拟的每 hart VS 级 AIA IMSIC 页面数量。未指定时,每 hart VS 级 AIA IMSIC 页面默认数量为 0。
iommu-sys=[on|off]
启用 riscv-iommu-sys 平台设备。默认为 'off'。
运行 Linux 内核
撰写本文时测试了 Linux 主线 v5.12 发布版。要构建可由 virt 机器以 64 位模式启动的 Linux 主线内核,只需使用 defconfig 配置内核:
$ export ARCH=riscv
$ export CROSS_COMPILE=riscv64-linux-
$ make defconfig
$ make
在 QEMU 中使用 virt 机器启动新构建的 Linux 内核:
$ qemu-system-riscv64 -M virt -smp 4 -m 2G \
-display none -serial stdio \
-kernel arch/riscv/boot/Image \
-initrd /path/to/rootfs.cpio \
-append "root=/dev/ram"
要构建可由 virt 机器以 32 位模式启动的 Linux 主线内核,请使用 rv32_defconfig 配置。Linux v5.12 内核需要一个补丁来修复 32 位启动问题。
$ export ARCH=riscv
$ export CROSS_COMPILE=riscv64-linux-
$ curl https://patchwork.kernel.org/project/linux-riscv/patch/20210627135117.28641-1-bmeng.cn@gmail.com/mbox/ > riscv.patch
$ git am riscv.patch
$ make rv32_defconfig
$ make
将上述命令行中的 qemu-system-riscv64 替换为 qemu-system-riscv32,即可启动 32 位 Linux 内核。必须使用包含 32 位应用的根文件系统镜像,内核才能启动到用户空间。
运行 U-Boot
撰写本文时测试了 U-Boot 主线 v2021.04 发布版。要构建可由 virt 机器启动的 S 模式 U-Boot 引导加载程序,请使用 qemu-riscv64_smode_defconfig,命令与上述 Linux 构建命令类似:
$ export CROSS_COMPILE=riscv64-linux-
$ make qemu-riscv64_smode_defconfig
直接启动 64 位 U-Boot S 模式镜像:
$ qemu-system-riscv64 -M virt -smp 4 -m 2G \
-display none -serial stdio \
-kernel /path/to/u-boot.bin
要测试启动运行在 M 模式的 U-Boot SPL,并由它加载将 OpenSBI fw_dynamic 固件和 U-Boot proper(S 模式)打包在一起的 FIT 镜像,请使用 riscv64_spl_defconfig 构建 U-Boot 镜像:
$ export CROSS_COMPILE=riscv64-linux-
$ export OPENSBI=/path/to/opensbi-riscv64-generic-fw_dynamic.bin
$ make qemu-riscv64_spl_defconfig
运行 U-Boot SPL 的最简 QEMU 命令为:
$ qemu-system-riscv64 -M virt -smp 4 -m 2G \
-display none -serial stdio \
-bios /path/to/u-boot-spl \
-device loader,file=/path/to/u-boot.itb,addr=0x80200000
要测试 32 位 U-Boot 镜像,请改用 qemu-riscv32_smode_defconfig 和 riscv32_spl_defconfig 构建,并将上述命令行中的 qemu-system-riscv64 替换为 qemu-system-riscv32,以启动 32 位 U-Boot。
启用 TPM
可按以下步骤将 TPM 设备连接到 virt 板。
首先启动 TPM 模拟器:
$ swtpm socket --tpm2 -t -d --tpmstate dir=/tmp/tpm \
--ctrl type=unixio,path=swtpm-sock
然后使用额外参数启动 QEMU,将 TPM 设备连接到后端:
$ qemu-system-riscv64 \
... other args .... \
-chardev socket,id=chrtpm,path=swtpm-sock \
-tpmdev emulator,id=tpm0,chardev=chrtpm \
-device tpm-tis-device,tpmdev=tpm0
TPM 设备可在内存树和生成的设备树中看到,客户机软件应能访问它。