如何在 QEMU 中建模 CPU
本文是基于格维开源社区QEMU训练营-CPU建模而来,原文
QEMU CPU 建模流程:以 RISC-V 为例 - QEMU Camp Tutorial
在原文中,我们需要手动定义 CPUDef 结构体,手动编写 class_init 函数,再手动将其注册到类型数组中。但在较新的 QEMU 版本中,官方提供了极其强大的宏(Macro)。预处理器会在编译时自动帮我们展开这些结构体,这让 CPU 建模变得异常简单。
首先定义CPU名称,打开target/riscv/cpu-qom.h,添加:
1 | #define TYPE_RISCV_CPU_G233 RISCV_CPU_TYPE_NAME("g233-cpu") |
RISCV_CPU_TYPE_NAME 这个宏会在编译时将 "g233" 展开为 "g233-riscv-cpu",这是 QEMU 内部对象树识别该硬件的唯一字符串凭证。
然后使用宏注册CPU蓝图
在cpu.c里找到static const TypeInfo riscv_cpu_type_infos[],插入
1 | #if defined(TARGET_RISCV64) |
在这里,我们让 g233 继承自 TYPE_RISCV_VENDOR_CPU。传入的每一个 .cfg 参数,都会被宏自动打包成静态结构体,并隐式生成 class_init 挂载函数。切记不要再去手动写 class_init,否则会引发重定义报错!
然后可以添加指令集扩展
指令集扩展通过 RISCVCPUConfig 结构体来配置,每个扩展对应一个 bool 类型的成员变量。
这个结构体在 target/riscv/cpu_cfg.h 中定义。
1 | struct RISCVCPUConfig { |
可以看到官方对这部分进行了重构。为了让所有扩展标志位能够统一参与序列化和合并计算,官方引入了 cpu_cfg_fields.h.inc 这个文件。
打开 target/riscv/cpu_cfg_fields.h.inc 文件,在里面加一行:
1 | BOOL_FIELD(ext_g233) |
接下来编译,在终端回到build文件夹,
1 | make -j$(nproc) |
然后坑来了,原文直接执行
1 | qemu-system-riscv64 -cpu help |
结果根本没有g233,因为当我们在终端直接输入 qemu-system-riscv64 时,Linux 会去系统的全局环境变量(如 /usr/bin/)中寻找可执行文件。此时调用的其实是系统自带的、旧版本的 QEMU,而不是新生成的核心。
实际上该执行(在build目录里)
1 | ./qemu-system-riscv64 -cpu help |
输出如下:
1 | huzayn@huzayn-VMware-Virtual-Platform:~/qemu/build$ ./qemu-system-riscv64 -cpu help |
