997 字
5 分钟
QEMU 热迁移
2025-09-01
无标签

🏗️ QEMU 热迁移的分层架构设计#

📋 分层结构#

┌─────────────────────────────────────┐
│     通用迁移层 (migration/)          │  ← 您之前看到的代码
│  - 传输协议管理                      │
│  - 调度和流控                        │
│  - 错误处理                          │
└─────────────────────────────────────┘
              ↕️ VMState接口
┌─────────────────────────────────────┐
│   架构特定层 (target/*/machine.c)    │  ← 架构相关处理
│  - CPU寄存器状态                     │
│  - 架构特定控制状态                   │
│  - 特殊功能寄存器                     │
└─────────────────────────────────────┘

🎯 架构相关处理的关键组件#

1️⃣ VMState 描述符(每个架构都有)#

RISC-V 架构示例:#

const VMStateDescription vmstate_riscv_cpu = {
    .name = "cpu",
    .version_id = 10,
    .minimum_version_id = 10,
    .post_load = riscv_cpu_post_load,
    .fields = (const VMStateField[]) {
        VMSTATE_UINTTL_ARRAY(env.gpr, RISCVCPU, 32),      // 32个通用寄存器
        VMSTATE_UINT64_ARRAY(env.fpr, RISCVCPU, 32),      // 32个浮点寄存器
        VMSTATE_UINTTL(env.pc, RISCVCPU),                 // 程序计数器
        VMSTATE_UINT64(env.mstatus, RISCVCPU),            // 机器状态寄存器
        VMSTATE_UINT64(env.mip, RISCVCPU),                // 中断挂起寄存器
        VMSTATE_UINT64(env.mie, RISCVCPU),                // 中断使能寄存器
        // ... 更多RISC-V特定状态
    }
};

x86 架构示例:#

const VMStateDescription vmstate_x86_cpu = {
    .name = "cpu",
    .version_id = 12,
    .minimum_version_id = 11,
    .pre_save = cpu_pre_save,
    .post_load = cpu_post_load,
    .fields = (const VMStateField[]) {
        VMSTATE_UINTTL_ARRAY(env.regs, X86CPU, CPU_NB_REGS),  // 通用寄存器
        VMSTATE_UINTTL(env.eip, X86CPU),                      // 指令指针
        VMSTATE_UINTTL(env.eflags, X86CPU),                   // 标志寄存器
        VMSTATE_SEGMENT_ARRAY(env.segs, X86CPU, 6),           // 段寄存器
        VMSTATE_UINTTL(env.cr[0], X86CPU),                    // 控制寄存器
        // ... 更多x86特定状态(FPU、SSE、AVX等)
    }
};

2️⃣ 架构状态注册机制#

// 在CPU创建时(cpu-target.c)
if (qdev_get_vmsd(DEVICE(cpu)) == NULL) {
    vmstate_register(NULL, cpu->cpu_index, &vmstate_cpu_common, cpu);  // 通用CPU状态
}
if (cpu->cc->sysemu_ops->legacy_vmsd != NULL) {
    vmstate_register(NULL, cpu->cpu_index, cpu->cc->sysemu_ops->legacy_vmsd, cpu);  // 架构特定状态
}

3️⃣ CPU 状态同步#

// 在关键迁移点调用
void cpu_synchronize_all_states(void)
{
    CPUState *cpu;
    
    CPU_FOREACH(cpu) {
        cpu_synchronize_state(cpu);  // 同步每个CPU的架构特定状态
    }
}

🔄 架构相关代码的调用时机#

📍 在迁移流程中的关键调用点#

// 1. 迁移设置阶段 - migration_thread()
qemu_savevm_state_setup(s->to_dst_file);

QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
    // 遍历所有注册的VMState处理器,包括每个CPU的架构特定状态
    vmstate_save(f, se, ms->vmdesc);  // ← 架构特定代码在这里被调用
}

// 2. 迁移完成阶段 - migration_completion_precopy()
cpu_synchronize_all_states();  // ← 同步所有CPU的架构状态
qemu_savevm_state_complete_precopy(s->to_dst_file, false, s->block_inactive);

// 保存所有架构特定的CPU状态

🎯 实际的架构差异处理#

不同架构保存的状态完全不同:#

架构特有状态示例
RISC-V特权级寄存器、PMP 配置、Vector 扩展状态
x 86段寄存器、FPU、SSE/AVX、控制寄存器
ARM协处理器寄存器、NEON 状态、安全扩展
PowerPCSPR 寄存器、AltiVec、Book 3 S 特定状态

架构特定的后处理:#

// RISC-V架构的迁移后处理
static int pmp_post_load(void *opaque, int version_id)
{
    RISCVCPU *cpu = opaque;
    CPURISCVState *env = &cpu->env;
    
    // 重新计算PMP规则
    for (i = 0; i < MAX_RISCV_PMPS; i++) {
        pmp_update_rule_addr(env, i);  // RISC-V特有的PMP处理
    }
    pmp_update_rule_nums(env);
    
    return 0;
}

🔍 为什么您之前没看到架构相关代码?#

📂 代码组织策略#

  1. 抽象层分离: 迁移框架 (migration/) 专注于传输机制
  2. 插件化设计: 架构特定代码通过 VMState 接口插入
  3. 统一调用: 通过 qemu_savevm_state_* 系列函数统一调用

🔗 关键连接点#

// 在migration_thread中的关键调用
qemu_savevm_state_setup(s->to_dst_file);     // 设置阶段:注册所有VMState
qemu_savevm_state_iterate(s->to_dst_file);   // 迭代阶段:保存可迭代状态  
cpu_synchronize_all_states();               // 同步阶段:确保架构状态一致
qemu_savevm_state_complete_precopy();        // 完成阶段:保存所有架构状态

🎯 实际架构相关工作#

✅ 每次迁移都会处理的架构特定内容:#

  • CPU 寄存器: 通用寄存器、特殊寄存器、控制寄存器
  • 浮点状态: FPU、SIMD、向量寄存器状态
  • 特权状态: 特权级别、内存管理、中断状态
  • 扩展功能: 架构特定的扩展(如 x 86 的 AVX、ARM 的 NEON 等)
  • 系统寄存器: CSR、MSR、协处理器寄存器等

🔧 架构适配机制#

  • 编译时适配: 每个架构编译进对应的 machine. c
  • 运行时注册: CPU 创建时自动注册其 VMState 描述符
  • 统一接口: 通过 VMState 框架提供统一的保存/恢复接口

这种设计使得通用迁移代码可以处理所有架构,而架构特定细节则由对应的 target 代码负责!

[1 tool called]