Luc*_*lla 5 c virtualization kvm qemu virtual-machine
我正在写一个关于 qemu 内部结构的开源文档,所以如果你帮助我,你就是在帮助 Qemu 项目的发展
我找到的最接近的答案是:在哪些条件下 ioctl KVM_RUN 返回?
这是在 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;
}
Run Code Online (Sandbox Code Playgroud)
你可以在这里看到:
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));
Run Code Online (Sandbox Code Playgroud)
每次 KVM 返回时,它都会为 Qemu 提供模拟的机会。我认为当来宾上的内核尝试访问 PCIe 设备时,主机上的 KVM 将返回。我不知道KVM怎么知道如何返回。也许 KVM 维护 PCIe 设备的地址,并告诉 Intel 的 VT-D 或 AMD 的 IOV 哪些地址应该生成异常。有人可以澄清这一点吗?
好吧,从 的外观来看qemu_kvm_cpu_thread_fn,唯一可以模拟 PCIe 访问的地方是qemu_wait_io_event(cpu),它的定义如下: https: //github.com/qemu/qemu/blob/stable-4.2/cpus.c#L1266和此处定义的调用qemu_wait_io_event_common: https: //github.com/qemu/qemu/blob/stable-4.2/cpus.c#L1241process_queued_cpu_work此处定义的调用:https: //github.com/qemu/qemu/blob/stable-4.2 /cpus-common.c#L309
让我们看看执行队列函数的代码:
while (cpu->queued_work_first != NULL) {
wi = cpu->queued_work_first;
cpu->queued_work_first = wi->next;
if (!cpu->queued_work_first) {
cpu->queued_work_last = NULL;
}
qemu_mutex_unlock(&cpu->work_mutex);
if (wi->exclusive) {
/* Running work items outside the BQL avoids the following deadlock:
* 1) start_exclusive() is called with the BQL taken while another
* CPU is running; 2) cpu_exec in the other CPU tries to takes the
* BQL, so it goes to sleep; start_exclusive() is sleeping too, so
* neither CPU can proceed.
*/
qemu_mutex_unlock_iothread();
start_exclusive();
wi->func(cpu, wi->data);
Run Code Online (Sandbox Code Playgroud)
看起来,qemu_kvm_cpu_thread_fn当 KVM 返回时,VCPU 线程拥有的唯一权力就是执行排队的函数:
wi->func(cpu, wi->data);
Run Code Online (Sandbox Code Playgroud)
这意味着 PCIe 设备必须不断地将自身排队作为 qemu 执行的函数。我不明白它会如何运作。
能够在该 cpu 上排队工作的功能已run_on_cpu在其名称中列出。通过在 VSCode 上搜索,我发现了一些对工作进行排队的函数,但没有一个与 PCIe 甚至仿真相关。我发现的最好的函数是这个显然修补指令的函数:https://github.com/qemu/qemu/blob/stable-4.2/hw/i386/kvmvapic.c#L446。很好,我也想知道。
KVM 下的设备模拟(所有设备,不仅仅是 PCI)由“switch (run-> exit_reason)”在 kvm_cpu_exec() 内。qemu_wait_io_event() 不相关。
想知道执行如何“模拟 PCI 设备上的寄存器读取”吗?在 gdb 下运行 QEMU,在您正在使用的以太网 PCI 卡的寄存器读/写函数上设置一个断点,然后当您进入调试器时查看堆栈回溯。(编译 QEMU --enable-debug 以获得此类事情的更好调试信息。)
PS:如果您出于教育目的而检查 QEMU 内部结构,您最好使用当前代码,而不是一年前的版本。
| 归档时间: |
|
| 查看次数: |
4089 次 |
| 最近记录: |