---
title: QEMU 与 KVM 协作
url: https://doc.liz6.com/linux-kernel/13-kvm-and-virtualization/03-qemu-and-kvm-collaboration
locale: zh
area: linux-kernel
tags:
- linux-kernel
- KVM与虚拟化
date: 2026-06-30
modified: 2026-06-30
description: '覆盖: QEMU-KVM 进程模型 → KVM_CREATE_VM/KVM_RUN → 内存布局 → vCPU 线程循环 → 设备模拟 → live migration 内核版本: 2.6.20 ~ 6.x'
---

# QEMU 与 KVM 协作

> 覆盖: QEMU-KVM 进程模型 → KVM_CREATE_VM/KVM_RUN → 内存布局 → vCPU 线程循环 → 设备模拟 → live migration
> 内核版本: 2.6.20 ~ 6.x

## 进程模型

```mermaid
flowchart TD
    QEMU["一个 VM = 一个 QEMU 进程"]

    QEMU --> MAIN["🧵 Main 线程<br/>event loop, monitor"]
    QEMU --> IO["🧵 IO 线程 (iothread)<br/>处理 virtio 设备 IO"]
    QEMU --> VCPU["🧵 vCPU 线程 × N<br/>每个执行 KVM_RUN"]
    QEMU --> MIGRATE["🧵 迁移线程<br/>live migration"]

    classDef root fill:#e3f2fd,stroke:#1565c0
    classDef thread fill:#fff3e0,stroke:#ef6c00
    class QEMU root
    class MAIN,IO,VCPU,MIGRATE thread
```

## VM 创建流程

```c
// QEMU → KVM:
kvm_fd = open("/dev/kvm", O_RDWR);

// 1. 创建 VM
vm_fd = ioctl(kvm_fd, KVM_CREATE_VM, 0);

// 2. 分配 guest RAM (QEMU 管理):
guest_ram = mmap(NULL, ram_size, PROT_READ|PROT_WRITE,
                 MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0);

// 3. 注册到 KVM:
struct kvm_userspace_memory_region region = {
    .slot = 0,              // memory slot ID
    .guest_phys_addr = 0,   // guest 物理地址起始
    .memory_size = ram_size,
    .userspace_addr = (uintptr_t)guest_ram,
};
ioctl(vm_fd, KVM_SET_USER_MEMORY_REGION, &region);

// 4. 创建 vCPU:
for (int i = 0; i < num_vcpus; i++) {
    vcpu_fd[i] = ioctl(vm_fd, KVM_CREATE_VCPU, i);
    mmap_size = ioctl(kvm_fd, KVM_GET_VCPU_MMAP_SIZE, 0);
    vcpu->kvm_run = mmap(NULL, mmap_size, ..., vcpu_fd[i], 0);
    // kvm_run 是共享内存: KVM 在这里写 exit_reason 和寄存器状态
}
```

## vCPU 运行循环

```c
// QEMU: kvm_cpu_exec() (accel/kvm/kvm-all.c)
int kvm_cpu_exec(CPUState *cpu) {
    struct kvm_run *run = cpu->kvm_run;
    int ret;

    do {
        // 1. 注入待处理的中断 (如果有)
        if (cpu->interrupt_request)
            kvm_arch_put_registers(cpu);

        // 2. 进入 guest!
        ret = ioctl(cpu->kvm_fd, KVM_RUN, 0);

        // 3. VM exit → 处理:
        switch (run->exit_reason) {
        case KVM_EXIT_IO:
            kvm_handle_io(run->io.port, run->io.direction, run->io.size, run->io.count,
                          run->io.data_offset);
            break;
        case KVM_EXIT_MMIO:
            address_space_rw(run->mmio.phys_addr, ...);
            break;
        case KVM_EXIT_IRQ_WINDOW_OPEN:
            // 可以注入中断了
            break;
        case KVM_EXIT_SHUTDOWN:
            // guest 三重故障 → 停止
            return -1;
        }
    } while (ret == 0);

    return ret;
}
```

## IO 线程与 virtio 处理

```c
// QEMU iothread: 独立的 event loop
//   → epoll on eventfd (virtio kick)
//   → QEMU 处理 virtio 请求:
//       virtio-blk: read/write → 映射到 host 文件 (qcow2/raw)
//       virtio-net: tap fd → 读/写 Linux tun/tap
//
// vhost (绕过 QEMU):
//   ioeventfd + irqfd → 内核直接处理
//   → QEMU 只需配置, 不参与数据路径
```

## Live Migration

```
QEMU + KVM 协作:
  1. 源端: 标记所有 guest RAM 为 read-only
     → 后续写产生 write fault → 记录脏页
  2. 迭代复制: RAM 预拷贝到目标
  3. 脏页收敛: 每轮 dirty rate ↓ → 到阈值
  4. stop-and-copy: 暂停源 VM → 复制最后脏页 + 寄存器状态 → 目标启动
  5. downtime ~100ms (取决于工作负载)
```

---

## 参考

- **源码**: QEMU `accel/kvm/kvm-all.c` (KVM 加速核心), Linux `virt/kvm/kvm_main.c`
- **内核文档**: `Documentation/virt/kvm/api.rst` (ioctl API 手册)

*关键词: KVM_RUN, kvm_run, ioctl, KVM_CREATE_VM, vCPU thread, iothread, live migration*
