Linux KVM如何在“英特尔VMX”中调度多个虚拟机?

Linux KVM如何在“英特尔VMX”中调度多个虚拟机?,linux,x86,virtualization,kvm,Linux,X86,Virtualization,Kvm,我正在通过Linux KVM学习英特尔VMX。 我无法清楚地理解KVM(Linux)如何安排多个虚拟机在同一主机上同时运行。 例如,主机中有1个物理CPU,有2个KVM虚拟机,每个虚拟机配置1个vCPU。 一旦启动,KVM/QEMU将为每个vCPU配置一个VMC,因此KVM中有2个VMC。由于只有1个pCPU,因此KVM/Linux必须将每个vCPU安排为1乘1。 我的理解是,当vCPUa运行时,vCPUa的KVM VMPTRLD VMCS,并运行VM的代码。然后,vCPUb将被调度,KVM将v

我正在通过Linux KVM学习英特尔VMX。
我无法清楚地理解KVM(Linux)如何安排多个虚拟机在同一主机上同时运行。
例如,主机中有1个物理CPU,有2个KVM虚拟机,每个虚拟机配置1个vCPU。
一旦启动,KVM/QEMU将为每个vCPU配置一个VMC,因此KVM中有2个VMC。由于只有1个pCPU,因此KVM/Linux必须将每个vCPU安排为1乘1。
我的理解是,当vCPUa运行时,vCPUa的KVM VMPTRLD VMCS,并运行VM的代码。然后,vCPUb将被调度,KVM将vCPUa的VMPTRST VMCS发送到某处,并从某处发送vCPUb的VMPTRLD VMCS。

通过阅读KVM的代码,我没有找到vCPU调度的VMPTRLD/VMPTRST发生在哪里,以及“某处”是什么。

VMPTRLD在arch/x86/KVM/vmx.c中的vmx_vCPU_加载中。

vmresume处于vmx_vcpu_运行状态

vmptrld处于vmx_vcpu_加载状态,在arch/x86/kvm/vmx.c中

vmresume处于vmx_vcpu_运行状态

首先,KVM将为vcpu计划输入和输出注册两个调用,如下所示。
kvm_preempt_ops.sched_in=kvm_sched_in
kvm\u preempt\u ops.sched\u out=kvm\u sched\u out

所以,每次,当调度发生时(我没有深入探讨),它们都被调用。以
kvm\u sched\u in()
为例,它将调用

static void kvm\u sched\u in(结构抢占通知程序*pn,int cpu)
{
结构kvm_vcpu*vcpu=preempt_notifier_to_vcpu(pn);
如果(vcpu->抢占)
vcpu->抢占=假;
kvm_arch_sched_in(vcpu,cpu);
kvm_拱_vcpu_负载(vcpu,cpu);
}
kvm_arch_vcpu_load()
将与VMC一起使用,如下所示

void kvm_arch_vcpu_加载(结构kvm_vcpu*vcpu,内部cpu)
{
/*地址WBINVD可由客人执行*/
if(需要模拟wbinvd(vcpu)){
如果(kvm_x86_ops->has_wbinvd_exit())
cpumask_set_cpu(cpu、vcpu->arch.wbinvd_脏_掩码);
否则如果(vcpu->cpu!=-1&&vcpu->cpu!=cpu)
smp调用单功能(vcpu->cpu,
wbinvd_ipi,空,1);
}
kvm_x86_操作->vcpu_加载(vcpu,cpu);cpu!=cpu)
已加载的_-vmcs_-clear(vmx->已加载的_-vmcs);
如果(每个cpu(当前的cpu)!=vmx->加载的cpu->vmcs){
每_cpu(当前_vmcs,cpu)=vmx->加载的_vmcs->vmcs;
vmcs_-load(vmx->loaded_-vmcs->vmcs);
}

就是这样。

首先,KVM将为vCPU计划输入和输出注册两个调用,如下所示。
kvm\u preempt\u ops.sched\u in=kvm\u sched\u in;

kvm\u preempt\u ops.sched\u out=kvm\u sched\u out;

因此,每次调度发生时(没有深入讨论),都会调用它们。以
kvm\u sched\u in()
为例,它会调用

static void kvm\u sched\u in(结构抢占通知程序*pn,int cpu)
{
结构kvm_vcpu*vcpu=preempt_notifier_to_vcpu(pn);
如果(vcpu->抢占)
vcpu->抢占=假;
kvm_arch_sched_in(vcpu,cpu);
kvm_拱_vcpu_负载(vcpu,cpu);
}
kvm_arch_vcpu_load()
将与VMC一起使用,如下所示

void kvm_arch_vcpu_加载(结构kvm_vcpu*vcpu,内部cpu)
{
/*地址WBINVD可由客人执行*/
if(需要模拟wbinvd(vcpu)){
如果(kvm_x86_ops->has_wbinvd_exit())
cpumask_set_cpu(cpu、vcpu->arch.wbinvd_脏_掩码);
否则如果(vcpu->cpu!=-1&&vcpu->cpu!=cpu)
smp调用单功能(vcpu->cpu,
wbinvd_ipi,空,1);
}
kvm_x86_操作->vcpu_加载(vcpu,cpu);cpu!=cpu)
已加载的_-vmcs_-clear(vmx->已加载的_-vmcs);
如果(每个cpu(当前的cpu)!=vmx->加载的cpu->vmcs){
每_cpu(当前_vmcs,cpu)=vmx->加载的_vmcs->vmcs;
vmcs_-load(vmx->loaded_-vmcs->vmcs);
}

就是这样。

我猜KVM就像主机内核下的进程一样工作,由常规调度器进行调度。它必须需要代码在运行来宾VM和运行主机代码(包括主机上的非VM用户空间进程)之间切换。您是否已经查看了上下文切换函数以查看它们是否支持KVM?这是有道理的,这也是我的猜测。我必须深入了解调度程序代码以了解详细信息,并将在此处更新我的发现。我猜KVM的工作方式类似于主机内核下的进程,由常规调度程序进行调度。它必须需要用于切换的代码运行来宾VM与运行主机代码(包括主机上的非VM用户空间进程)之间的区别。您是否已经查看了上下文切换函数以查看它们是否支持KVM?这是有道理的,这也是我的猜测。我必须深入了解计划程序代码以了解详细信息,将在此处更新我的发现。这有点难以理解,因为支持嵌套虚拟化的所有代码都在同一个文件中,所以对vmptrld和vmresume与来宾VMM正在执行的操作相关。请注意,不需要vmptrst,因为VMCS指针与加载的值保持不变。因此,如何在此pCPU上调度其他VM,或将vCPU迁移到另一个pCPU,这必须更改pCPU上的活动/当前VMCS?这有点难理解,因为所有代码都是o支持嵌套虚拟化在同一个文件中,因此对vmptrld和vmresume的大多数引用都与来宾VMM正在执行的操作相关。请注意,vmptrst不是必需的,因为VMCS指针与加载的值保持不变。那么,如何在此pCPU上调度其他VM,或者将vCPU迁移到另一个pCPU,这将是否必须更改pCPU上的活动/当前VMC?