Reputation: 1265
I am studying Intel VMX through Linux KVM.
And I could NOT clearly understand how does KVM (Linux) schedule multiple VMs running cocurrently in the same host.
For example, there is 1 physical CPU in the host, and there are 2 KVM VMs, each configured with 1 vCPU.
Once they are started, KVM/QEMU configure a VMCS for each vCPU, so there are 2 VMCSes in KVM. Since there is only 1 pCPU, so KVM/Linux has to schedule each vCPU 1 by 1.
My understanding is when vCPUa is running, KVM VMPTRLD VMCS of vCPUa, and run the VM's codes. Then, vCPUb is to be scheduled, KVM will VMPTRST VMCS of vCPUa to somewhere, and VMPTRLD VMCS of vCPUb from somewhere.
By reading KVM's code, I did NOT find where VMPTRLD/VMPTRST happened for vCPU scheduling, and what is 'somewhere'.
Upvotes: 1
Views: 1226
Reputation: 1265
Firstly, KVM will register two callouts for vCPU schedule in and out, like below.
kvm_preempt_ops.sched_in = kvm_sched_in;
kvm_preempt_ops.sched_out = kvm_sched_out;
So, each time, when scheduling happens (have not deeply dived into this), they are called. Take kvm_sched_in()
as an example, it will calls,
static void kvm_sched_in(struct preempt_notifier *pn, int cpu)
{
struct kvm_vcpu *vcpu = preempt_notifier_to_vcpu(pn);
if (vcpu->preempted)
vcpu->preempted = false;
kvm_arch_sched_in(vcpu, cpu);
kvm_arch_vcpu_load(vcpu, cpu);
}
And kvm_arch_vcpu_load()
will play with VMCS, like below.
void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
{
/* Address WBINVD may be executed by guest */
if (need_emulate_wbinvd(vcpu)) {
if (kvm_x86_ops->has_wbinvd_exit())
cpumask_set_cpu(cpu, vcpu->arch.wbinvd_dirty_mask);
else if (vcpu->cpu != -1 && vcpu->cpu != cpu)
smp_call_function_single(vcpu->cpu,
wbinvd_ipi, NULL, 1);
}
kvm_x86_ops->vcpu_load(vcpu, cpu); <<======
Since, .vcpu_load = vmx_vcpu_load,
/*
* Switches to specified vcpu, until a matching vcpu_put(), but assumes
* vcpu mutex is already taken.
*/
static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
u64 phys_addr = __pa(per_cpu(vmxarea, cpu));
if (!vmm_exclusive)
kvm_cpu_vmxon(phys_addr);
else if (vmx->loaded_vmcs->cpu != cpu)
loaded_vmcs_clear(vmx->loaded_vmcs);
if (per_cpu(current_vmcs, cpu) != vmx->loaded_vmcs->vmcs) {
per_cpu(current_vmcs, cpu) = vmx->loaded_vmcs->vmcs;
vmcs_load(vmx->loaded_vmcs->vmcs);
}
That is it.
Upvotes: 1
Reputation: 12455
vmptrld is in vmx_vcpu_load in arch/x86/kvm/vmx.c
vmresume is in vmx_vcpu_run
Upvotes: 2