在什么情况下ioctlKVM_RUNreturns?

In which conditions the ioctl KVM_RUN returns?

https://github.com/qemu/qemu/blob/stable-4.2/cpus.c#L1290 中有一个非常重要的 Qemu 片段。我想这是 KVM 上 CPU 的事件循环。

代码如下:

static void *qemu_kvm_cpu_thread_fn(void *arg)
{
    CPUState *cpu = arg;
    int r;

    rcu_register_thread();

    qemu_mutex_lock_iothread();
    qemu_thread_get_self(cpu->thread);
    cpu->thread_id = qemu_get_thread_id();
    cpu->can_do_io = 1;
    current_cpu = cpu;

    r = kvm_init_vcpu(cpu);
    if (r < 0) {
        error_report("kvm_init_vcpu failed: %s", strerror(-r));
        exit(1);
    }

    kvm_init_cpu_signals(cpu);

    /* signal CPU creation */
    cpu->created = true;
    qemu_cond_signal(&qemu_cpu_cond);
    qemu_guest_random_seed_thread_part2(cpu->random_seed);

    do {
        if (cpu_can_run(cpu)) {
            r = kvm_cpu_exec(cpu);
            if (r == EXCP_DEBUG) {
                cpu_handle_guest_debug(cpu);
            }
        }
        qemu_wait_io_event(cpu);
    } while (!cpu->unplug || cpu_can_run(cpu));

    qemu_kvm_destroy_vcpu(cpu);
    cpu->created = false;
    qemu_cond_signal(&qemu_cpu_cond);
    qemu_mutex_unlock_iothread();
    rcu_unregister_thread();
    return NULL;
}

我对 do 循环很感兴趣。它在一个循环中调用 kvm_cpu_exec,定义如下:https://github.com/qemu/qemu/blob/stable-4.2/accel/kvm/kvm-all.c#L2285

kvm_cpu_exec 的某一点,它调用 run_ret = kvm_vcpu_ioctl(cpu, KVM_RUN, 0);,它调用此处记录的 KVM_RUN ioctl:https://www.kernel.org/doc/Documentation/virtual/kvm/api.txt

4.10 KVM_RUN

Capability: basic
Architectures: all
Type: vcpu ioctl
Parameters: none
Returns: 0 on success, -1 on error
Errors:
EINTR: an unmasked signal is pending

This ioctl is used to run a guest virtual cpu. While there are no
explicit parameters, there is an implicit parameter block that can be
obtained by mmap()ing the vcpu fd at offset 0, with the size given by
KVM_GET_VCPU_MMAP_SIZE. The parameter block is formatted as a 'struct
kvm_run' (see below).

我很难理解这个 ioctl 是否会阻止执行?在哪些情况下 returns?

我想了解一下正在发生的事情。给定行 qemu_wait_io_event(cpu),看起来至少 ioctl 会 return 每次事件是 read/written to/from CPU。不知道,一头雾水

KVM API 设计要求 VM 中的每个虚拟 CPU 在控制该 VM 的程序(如 QEMU)中有一个关联的用户空间线程(该程序通常称为“虚拟机” Monitor" 或 VMM,它不一定是 QEMU;其他示例是 kvmtool 和 firecracker)。

该线程的行为与 QEMU 中的普通用户空间线程一样,直到它生成 KVM_RUN ioctl。此时内核使用该线程在与该线程关联的 vCPU 上执行客户代码。这一直持续到遇到某些情况,这意味着来宾执行无法继续进行。 (一个常见的情况是“来宾对 QEMU 正在模拟的设备进行了内存访问”。)此时,内核停止 运行ning 来宾代码在此线程上,而是使其 return 来自 KVM_RUN ioctl。 QEMU 中的代码然后查看 return 代码等以找出它为什么重新获得控制权,处理任何情况,然后循环返回再次调用 KVM_RUN 以请求内核继续 运行 访客代码。

通常在 运行 虚拟机时,您会发现几乎所有时间线程都在 KVM_RUN ioctl 中,运行 宁真正的来宾代码。偶尔执行会 return,QEMU 会花费尽可能少的时间做任何它需要做的事情,然后循环并再次 运行s guest 代码。提高 VM 效率的一种方法是尽量确保这些“VM 出口”的数量尽可能少(例如,通过仔细选择给 guest 的网络或块设备类型)。