public inbox for kvm@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] [RFC] Activate VMX on demand
@ 2008-11-03 16:19 Alexander Graf
  2008-11-04 10:36 ` Avi Kivity
  0 siblings, 1 reply; 6+ messages in thread
From: Alexander Graf @ 2008-11-03 16:19 UTC (permalink / raw)
  To: kvm; +Cc: avi, Sander.Vanleeuwen, kraxel, anthony, zach

This patch moves the actual VMX enablement from the initialization
of the module to the creation of a VCPU.

With this approach, KVM can be easily autoloaded and does not block
other VMMs while being modprobe'd.
This improves the user experience a lot, since now other VMMs can
run, even though KVM is loaded, so users do not have to manually
load/unload KVM or any other VMM module.

Compared to the previously suggested approach "2", which would
introduce a complete framework that brings almost no benefit,
this approach enables coexistence of multiple VMMs without much
intervention. Thanks to Gerd for pointing that out.

I verified that this approach works with VirtualBox.

Signed-off-by: Alexander Graf <agraf@suse.de>

---
 arch/x86/kvm/vmx.c |   82 +++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 75 insertions(+), 7 deletions(-)

diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 64e2439..2c48590 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -116,6 +116,9 @@ static struct page *vmx_msr_bitmap;
 static DECLARE_BITMAP(vmx_vpid_bitmap, VMX_NR_VPIDS);
 static DEFINE_SPINLOCK(vmx_vpid_lock);
 
+static int vmx_usage_count = 0;
+static DEFINE_SPINLOCK(vmx_usage_lock);
+
 static struct vmcs_config {
 	int size;
 	int order;
@@ -1059,10 +1062,68 @@ static __init int vmx_disabled_by_bios(void)
 	/* locked but not enabled */
 }
 
-static void hardware_enable(void *garbage)
+static void __vmx_off(void *garbage)
+{
+	asm volatile (__ex(ASM_VMX_VMXOFF) : : : "cc");
+	write_cr4(read_cr4() & ~X86_CR4_VMXE);
+}
+
+static void vmx_off(void)
+{
+	if (!vmx_usage_count)
+		return;
+
+	spin_lock(&vmx_usage_lock);
+
+	vmx_usage_count--;
+	if (vmx_usage_count == 0)
+		on_each_cpu(__vmx_off, NULL, 1);
+	
+	spin_unlock(&vmx_usage_lock);
+}
+
+static void __vmx_on(void *garbage)
 {
 	int cpu = raw_smp_processor_id();
 	u64 phys_addr = __pa(per_cpu(vmxarea, cpu));
+
+	write_cr4(read_cr4() | X86_CR4_VMXE); /* FIXME: not cpu hotplug safe */
+	asm volatile (ASM_VMX_VMXON_RAX
+		      : : "a"(&phys_addr), "m"(phys_addr)
+		      : "memory", "cc");
+}
+
+static void __vmx_check(void *r)
+{
+	if (read_cr4() & X86_CR4_VMXE)
+		*((int*)r) = -EBUSY;
+}
+
+static int vmx_on(void)
+{
+	int r = 0;
+	spin_lock(&vmx_usage_lock);
+	vmx_usage_count++;
+	if (vmx_usage_count == 1) {
+		on_each_cpu(__vmx_check, &r, 1);
+		if (r)
+			goto out_1;
+
+		on_each_cpu(__vmx_on, NULL, 1);
+	}
+
+	goto out;
+
+out_1:
+	vmx_usage_count--;
+out:
+	spin_unlock(&vmx_usage_lock);
+	return r;
+}
+
+static void hardware_enable(void *garbage)
+{
+	int cpu = raw_smp_processor_id();
 	u64 old;
 
 	INIT_LIST_HEAD(&per_cpu(vcpus_on_cpu, cpu));
@@ -1075,10 +1136,9 @@ static void hardware_enable(void *garbage)
 		wrmsrl(MSR_IA32_FEATURE_CONTROL, old |
 		       FEATURE_CONTROL_LOCKED |
 		       FEATURE_CONTROL_VMXON_ENABLED);
-	write_cr4(read_cr4() | X86_CR4_VMXE); /* FIXME: not cpu hotplug safe */
-	asm volatile (ASM_VMX_VMXON_RAX
-		      : : "a"(&phys_addr), "m"(phys_addr)
-		      : "memory", "cc");
+
+	if (vmx_usage_count)
+		__vmx_on(garbage);
 }
 
 static void vmclear_local_vcpus(void)
@@ -1094,8 +1154,9 @@ static void vmclear_local_vcpus(void)
 static void hardware_disable(void *garbage)
 {
 	vmclear_local_vcpus();
-	asm volatile (__ex(ASM_VMX_VMXOFF) : : : "cc");
-	write_cr4(read_cr4() & ~X86_CR4_VMXE);
+
+	if (vmx_usage_count)
+		__vmx_off(garbage);
 }
 
 static __init int adjust_vmx_controls(u32 ctl_min, u32 ctl_opt,
@@ -3490,6 +3551,7 @@ static void vmx_free_vcpu(struct kvm_vcpu *vcpu)
 	kfree(vmx->guest_msrs);
 	kvm_vcpu_uninit(vcpu);
 	kmem_cache_free(kvm_vcpu_cache, vmx);
+	vmx_off();
 }
 
 static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
@@ -3501,6 +3563,10 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
 	if (!vmx)
 		return ERR_PTR(-ENOMEM);
 
+	err = vmx_on();
+	if (err)
+		goto free_vmx;
+
 	allocate_vpid(vmx);
 
 	err = kvm_vcpu_init(&vmx->vcpu, kvm, id);
@@ -3550,6 +3616,8 @@ uninit_vcpu:
 	kvm_vcpu_uninit(&vmx->vcpu);
 free_vcpu:
 	kmem_cache_free(kvm_vcpu_cache, vmx);
+free_vmx:
+	vmx_off();
 	return ERR_PTR(err);
 }
 
-- 
1.6.0.2


^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2008-11-04 14:38 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-11-03 16:19 [PATCH] [RFC] Activate VMX on demand Alexander Graf
2008-11-04 10:36 ` Avi Kivity
2008-11-04 13:13   ` Alexander Graf
2008-11-04 13:37     ` Avi Kivity
2008-11-04 13:44       ` Alexander Graf
2008-11-04 14:38         ` Avi Kivity

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox