跳转至

QEMU 训练营 2026 专业阶段总结

主要贡献者


背景介绍

我是一名电子信息专业的学生,对计算机体系结构有兴趣,之前学 XV6 课程的时候接触到了 QEMU,但是一直停留在最基础的使用阶段,看到 QEMU 训练营的招募后,我觉得这是一个难得的动手机会,于是报名参加了 GPGPU 方向的实验。

专业阶段

我选择了 GPGPU 设备建模 方向。实验任务是实现一个教育用途的 GPU 设备模型,通过 QTest 框架的 17 个测题来验证正确性。

GPGPU 是一个 PCIe 设备,核心数据结构是 GPGPUState:

 struct GPGPUState {
      PCIDevice parent_obj;           // PCI 设备基类
      MemoryRegion ctrl_mmio;         // BAR0: 控制寄存器
      MemoryRegion vram;              // BAR2: 显存
      uint8_t *vram_ptr;              // 显存后端存储
      uint32_t global_ctrl;           // 设备使能/复位
      uint32_t global_status;         // 就绪/忙碌/错误
      GPGPUKernelParams kernel;       // 内核分发参数
      GPGPUSIMTContext simt;          // 线程上下文
  };

关键理解:QEMU 的设备模型本质上是"维护状态 + 响应读写"。BAR 空间通过 MemoryRegionOps 关联回调函数,宿主机侧 QTest 通过 qpci_io_readl/writel 触发这些回调,直接读写 MMIO 寄存器——整个过程无需客户机操作系统参与。

RISC-V SIMT 解释器的设计

GPU 核心用一个精简的 RISC-V 解释器模拟。每个 warp 包含 32 个 lane,锁步执行同一条指令:

while (lane->active && cycles < max_cycles) {
      uint32_t inst = ldl_le_p(s->vram_ptr + lane->pc);
      switch (OPCODE(inst)) {
      case OPCODE_LUI:       lane->gpr[rd] = UTYPE_IMM(inst);         break;
      case OPCODE_STORE:     stl_le_p(vram + addr, rs2_val);          break;
      case OPCODE_OP_FP:     /* FADD.S / FMUL.S / narrow-convert */   break;
      case OPCODE_SYSTEM:    /* CSRRS(mhartid) / EBREAK */            break;
      }
      lane->pc += 4;
  }

线程通过 mhartid CSR 获取自己的三维 ID:

mhartid 位域: [31:13] block_id [12:5] warp_id [4:0] lane_id

这相当于 CUDA 的 threadIdx + blockIdx 被编码进一个硬件寄存器,内核代码通过一条 csrrs 指令就能拿到自己的完整身份。

内核分发流程的分发流程如下:

测试 → 写 VRAM 上传内核代码 → 配置 grid/block 维度 → 写 DISPATCH 寄存器触发执行:

  BAR2 VRAM                 BAR0 控制寄存器
  ┌──────────────┐          ┌──────────────────┐
  │ 0x0000: code │          │ GRID_DIM  = 1x1x1│
  │ 0x1000: data │          │ BLOCK_DIM = 8x1x1│
  └──────────────┘          │ KERNEL_ADDR = 0  │
                            │ DISPATCH = 1 ────→ 触发 gpgpu_core_exec_kernel()
                            └──────────────────┘

总结

最大收获是从零理解了 QEMU 设备模型的完整链路:PCI 设备注册 → BAR 空间映射 → MMIO 读写回调 → QOS 测试框架自动发现和验证。以前看 QEMU 源码总觉得庞杂无从下手,现在至少有一条清晰的路径了。