VirtualMachine 的第一条指令是如何获取的(在 KVM-QEMU 中)

How is the first instruction of VirtualMachine is fetched (in KVM-QEMU)

我是 SO 和 X86 VMX 的新手。 我正在学习X86上的KVM-QEMU,我想知道如何获取VM的第一条指令的详细信息,以便VM可以启动运行。 有KVM API 可以配置和注册一组内存作为VM 的物理内存,然后将guest_RIP 设置为AAA(例如)。 我不知道什么时候调用 VMLaunch(使用正确配置的 VMCS),CPU 如何从 VMCS 中的 RIP 获取指令,是通过一些地址转换过程,所以 guest_CR3 应该是否正确设置为指向为来宾分配的主机内存? 谢谢

我将在 QEMU 的上下文中解释这一点,以及在启用 KVM 加速器时 QEMU 如何运行。

你可能知道,在kvm下,虚拟机是通过打开一个设备节点/dev/kvm来创建的。来宾将拥有自己的内存,并且通常与创建它的用户空间进程分开。所以基本上 kvm 的结构是一个相当典型的 Linux 字符设备——你使用 ioctl()s 来创建、运行、修改参数、分配内存以及读写 VCPU 虚拟机的寄存器。因此,初始设置将通过各种 ioctl() 完成,这些设置将设置 KVM 以供进一步使用。

就QEMU代码而言,所有执行(无论是KVM还是non-KVM)都从:

开始

vl.c start of everything

KVM 架构的初始化通过以下函数进行——(从 CPUID 收集 CPU 标志并设置频率等)

kvm_arch_init_vcpu

完成所有初始化函数后,函数do_kvm_cpu_synchronize_post_init 将尝试根据主机CPU 状态同步VCPU 寄存器的初始值。它调用另一个函数, kvm_arch_put_registers 并将 VCPU 设置为 dirty。为什么 VCPU 设置为 dirty ?只有这样,后续函数才会真正初始化 VCPU 寄存器的值。

这个函数kvm_arch_put_registers是获取VMCS寄存器所有初始值的关键。如果你看到它的body,你就会明白发生了什么:-

kvm_arch_put_registers

特别关注函数,kvm_getput_regskvm_put_sregs - 第一个函数将设置 GPRsEFLAGS 以及 EIP/RIP 寄存器,而第二个函数将设置初始段寄存器值。

访客页面 table 将植根于 CR3 寄存器。这个页面 table 如何运作?

为此,你需要记住KVM中的mmu只占一级虚拟化(guest virtual -> guest physical),不占第二级(来宾物理 -> 主机物理)。初始 RIP 将说明虚拟地址 - 它将适当地转换为访客中的物理地址。但是,要将此访客物理地址转换为主机物理地址,您需要有一个单独的页面table。这是一个 影子页面 table,将与 原始页面 table 结合使用(将访客虚拟-> 客体)来执行整个翻译。

需要 同步 访客页面 tableshadow 的状态page table 这有时会成为一个问题。每当来宾写入其页面 table 时,也需要在影子页面 tables 上执行相应的更改。