我是SO和X86 VMX的新手。 我正在学习X86上的KVM-QEMU,我想知道有关如何获取VM的第一条指令的详细信息,以便VM可以开始运行。 有一些KVM API用于配置和注册一组内存作为VM的物理内存,然后将guest_RIP设置为AAA(例如)。 我不知道何时调用VMLaunch(使用正确配置的VMCS),CPU如何在VMCS中从该RIP获取指令,是通过某些地址转换过程,因此guest_CR3应正确设置为指向HOST为客人分配的内存? 感谢
答案 0 :(得分:0)
我将在QEMU的背景下解释这一点,以及启用KVM加速器时QEMU的运行方式。
您可能知道,在kvm下,通过打开设备节点/dev/kvm
来创建虚拟机。 guest虚拟机将拥有自己的内存,通常与创建它的用户空间进程分开。因此,kvm基本上是一个相当典型的Linux字符设备 - 您使用ioctl()
来创建,运行,修改参数,分配内存以及读写虚拟机的VCPU寄存器。因此,初始设置将通过各种ioctl()
来完成,这将设置KVM以供进一步使用。
就QEMU代码而言,所有执行(无论是KVM还是非KVM)都从以下开始:
KVM架构的初始化通过以下功能实现 - (从 CPUID 收集CPU标志并设置频率等)
完成所有初始化函数后,函数do_kvm_cpu_synchronize_post_init
将尝试根据主机CPU状态同步VCPU寄存器的初始值。它调用另一个函数,
kvm_arch_put_registers
并将VCPU设置为脏。为什么VCPU设置为脏?只有这样,后续函数才会实际初始化VCPU寄存器的值。
此函数kvm_arch_put_registers
是获取VMCS寄存器的所有初始值的关键。如果你看到它的身体,你会发现正在发生的事情: -
特别关注函数kvm_getput_regs
和kvm_put_sregs
- 第一个函数将设置 GPR 和 EFLAGS 的初始值以及 EIP / RIP 寄存器,而第二个函数将设置初始段寄存器值。
访客页面表将根植于 CR3 注册表。这个页面表如何工作?
为此,您需要记住KVM中的 mmu 仅占一级虚拟化(来宾虚拟 - >来宾物理)但不考虑第二级(来宾物理 - >主机物理)。初始RIP将考虑虚拟地址 - 它将被适当地转换为来宾中的物理地址。但是,要将此guest虚拟机物理地址转换为主机物理地址,您需要具有单独的页表。这是一个影子页面表,将与原始页面表(用于转换来宾虚拟 - >来宾物理)一起使用,以执行整个翻译。
需要同步 访客页面表的状态与影子页面表,这有时会出现问题。每当guest虚拟机写入其页表时,也需要在影子页表上执行相应的更改。