Skip to contentSkip to conversation

KVM: Decouple Intel VT implementation from base kvm

PATCH In review Avi Kivity 4 participants 49 messages Nov 27, 2006 – Nov 30, 2006 KVM

lore
Share & tools
lore

Avi Kivity

author
#0 lore raw

cover KVM: Decouple Intel VT implementation from base kvm

This patchset prepares kvm for multiple architecture implementations. The kvm.ko module is split into kvm.ko and kvm-intel.ko, and a function vector is used to dispatch arch specific operations to the arch module.

Signature · 8 lines
error compiling committee.c: too many arguments to function


-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
author
#1 lore raw

PATCH 1/38 KVM: Create kvm-intel.ko module

This patch lays the foundation for arch-independent kvm: it creates the kvm-intel.ko module and prepares an arch function vector for the arch-specific implementation.

drivers/kvm/kvm.h +7 -0
Index: linux-2.6/drivers/kvm/kvm.h
===================================================================
@@ -235,11 +235,18 @@ struct kvm_stat {
 	u32 irq_exits;
 };
 
+struct kvm_arch_ops {
+};
+
 extern struct kvm_stat kvm_stat;
+extern struct kvm_arch_ops *kvm_arch_ops;
 
 #define kvm_printf(kvm, fmt ...) printk(KERN_DEBUG fmt)
 #define vcpu_printf(vcpu, fmt...) kvm_printf(vcpu->kvm, fmt)
 
+void kvm_init_arch(struct kvm_arch_ops *ops);
+void kvm_exit_arch(void);
+
 void kvm_mmu_destroy(struct kvm_vcpu *vcpu);
 int kvm_mmu_init(struct kvm_vcpu *vcpu);
 
drivers/kvm/kvm_main.c +13 -0
Index: linux-2.6/drivers/kvm/kvm_main.c
===================================================================
@@ -41,6 +41,7 @@
 MODULE_AUTHOR("Qumranet");
 MODULE_LICENSE("GPL");
 
+struct kvm_arch_ops *kvm_arch_ops;
 struct kvm_stat kvm_stat;
 
 static struct kvm_stats_debugfs_item {
@@ -3611,6 +3612,15 @@ static void kvm_exit_debug(void)
 
 hpa_t bad_page_address;
 
+void kvm_init_arch(struct kvm_arch_ops *ops)
+{
+	kvm_arch_ops = ops;
+}
+
+void kvm_exit_arch(void)
+{
+}
+
 static __init int kvm_init(void)
 {
 	static struct page *bad_page;
@@ -3670,3 +3680,6 @@ static __exit void kvm_exit(void)
 
 module_init(kvm_init)
 module_exit(kvm_exit)
+
+EXPORT_SYMBOL_GPL(kvm_init_arch);
+EXPORT_SYMBOL_GPL(kvm_exit_arch);
drivers/kvm/vmx.c new file +39 -0
Index: linux-2.6/drivers/kvm/vmx.c
===================================================================
@@ -0,0 +1,39 @@
+/*
+ * Kernel-based Virtual Machine driver for Linux
+ *
+ * This module enables machines with Intel VT-x extensions to run virtual
+ * machines without emulation or binary translation.
+ *
+ * Copyright (C) 2006 Qumranet, Inc.
+ *
+ * Authors:
+ *   Avi Kivity   <avi-atKUWr5tajBWk0Htik3J/[email protected]>
+ *   Yaniv Kamay  <yaniv-atKUWr5tajBWk0Htik3J/[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "kvm.h"
+#include <linux/module.h>
+
+MODULE_AUTHOR("Qumranet");
+MODULE_LICENSE("GPL");
+
+static struct kvm_arch_ops vmx_arch_ops = {
+};
+
+static int __init vmx_init(void)
+{
+	kvm_init_arch(&vmx_arch_ops);
+	return 0;
+}
+
+static void __exit vmx_exit(void)
+{
+	kvm_exit_arch();
+}
+
+module_init(vmx_init)
+module_exit(vmx_exit)
drivers/kvm/Kconfig +10 -2
Index: linux-2.6/drivers/kvm/Kconfig
===================================================================
@@ -6,8 +6,9 @@ config KVM
 	depends on X86 && EXPERIMENTAL
 	---help---
 	  Support hosting fully virtualized guest machines using hardware
-	  virtualization extensions.  You will need a fairly recent Intel
-	  processor equipped with VT extensions.
+	  virtualization extensions.  You will need a fairly recent
+	  processor equipped with virtualization extensions. You will also
+	  need to select one or more of the processor modules below.
 
 	  This module provides access to the hardware capabilities through
 	  a character device node named /dev/kvm.
@@ -16,3 +17,10 @@ config KVM
 	  will be called kvm.
 
 	  If unsure, say N.
+
+config KVM_INTEL
+	tristate "KVM for Intel processors support"
+	depends on KVM
+	---help---
+	  Provides support for KVM on Intel processors equipped with the VT
+	  extensions.
drivers/kvm/Makefile +2 -0
Index: linux-2.6/drivers/kvm/Makefile
===================================================================
@@ -4,3 +4,5 @@
 
 kvm-objs := kvm_main.o mmu.o x86_emulate.o
 obj-$(CONFIG_KVM) += kvm.o
+kvm-intel-objs = vmx.o
+obj-$(CONFIG_KVM_INTEL) += kvm-intel.o

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

#2 lore raw

Re: [PATCH 1/38] KVM: Create kvm-intel.ko module

drivers/kvm/kvm.h

Quoted 2 lines · Avi Kivity
drivers/kvm/kvm.h +0 -0

please move this from drivers/kvm/ to kernel/kvm/ [or even into a toplevel kvm/ directory] - KVM is not a "driver", KVM enhances the core Linux kernel with hypervisor functionality.

Guest paravirtualization drivers (once KVM implements them) can go into drivers/kvm/.

Ingo

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

#3 lore raw

Re: [PATCH 1/38] KVM: Create kvm-intel.ko module

Quoted 9 lines · Ingo Molnar

drivers/kvm/kvm.h

Quoted 2 lines · Avi Kivity
drivers/kvm/kvm.h +0 -0

please move this from drivers/kvm/ to kernel/kvm/ [or even into a toplevel kvm/ directory] - KVM is not a "driver", KVM enhances the core Linux kernel with hypervisor functionality.

Actually it's exactly a driver. It's a character driver that exposes the virtualization features of modern x86 hardware. Pretty similar to things like the msr or mtrr driver that expose cpu features as character drivers aswell.

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

#4 lore raw

Re: [PATCH 1/38] KVM: Create kvm-intel.ko module

Quoted 6 lines · Christoph Hellwig
Quoted 3 lines

please move this from drivers/kvm/ to kernel/kvm/ [or even into a toplevel kvm/ directory] - KVM is not a "driver", KVM enhances the core Linux kernel with hypervisor functionality.

Actually it's exactly a driver. It's a character driver that exposes the virtualization features of modern x86 hardware. [...]

you are fundamentally wrong. In the end KVM is a fundamental and complex infrastructure that enables Linux to provide full hardware capabilities to another OS via the resources of this OS. This concept justifies a system call and a place in linux/kernel/. It's not fundamentally limited to x86 either. Full virtualization (and paravirtualization) makes sense on any platform. And there's no reason KVM be limited to full virtualization alone - both paravirtualization and accelerated guest drivers need a sane hypercall API.

Quoted 2 lines

[...] Pretty similar to things like the msr or mtrr driver that expose cpu features as character drivers aswell.

you can expose everything as character drivers and ioctls, but that doesnt make it the right solution. It might /start out/ as a driver, because that's an easy to hack model, but the moment something becomes important enough (and virtualization certainly is such a model) it demands a system call.

Just like inotify started out as an ioctl hack, but then was (rightfully) moved to the system-call space. [ Which btw. was on your request ;-) ]

Ingo

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

#5 lore raw

Re: [PATCH 1/38] KVM: Create kvm-intel.ko module

Quoted 8 lines · On Thu, 30 Nov 2006 16:44:25 +0100 Ingo Molnar <[email protected]> wrote:
Quoted 2 lines

[...] Pretty similar to things like the msr or mtrr driver that expose cpu features as character drivers aswell.

you can expose everything as character drivers and ioctls, but that doesnt make it the right solution. It might /start out/ as a driver, because that's an easy to hack model, but the moment something becomes important enough (and virtualization certainly is such a model) it demands a system call.

Actually fourteen syscalls and counting, and some of those have `mode' arguments.

It's a fat, complex, presumably arch-specific, presumably frequently-changing API. So whatever we do will be unpleasant - that's unavoidable in this case, I suspect.

(hmm, the interface isn't versioned at present - should it be?)

Maybe, perhaps, one day it _should_ be a syscall API. But right now if we did that it would become a versioned syscall API with obsolete slots and various other warts.

I get the feeling we'd be best off if we were to revisit this in a year or so.

#6 lore raw

Re: [PATCH 1/38] KVM: Create kvm-intel.ko module

Quoted 9 lines · Andrew Morton

It's a fat, complex, presumably arch-specific, presumably frequently-changing API. So whatever we do will be unpleasant - that's unavoidable in this case, I suspect.

(hmm, the interface isn't versioned at present - should it be?)

Maybe, perhaps, one day it _should_ be a syscall API. But right now if we did that it would become a versioned syscall API with obsolete slots and various other warts.

yeah, very much agreed. For example the paravirtualization/accelerator downcalls/upcalls in KVM dont exist yet, so there's little to standardize. Once we see it from lhype & KVM how these things look like we can design a sane kernel interface around it. But i'm against the notion that KVM is 'just' a device. It's not, and it /will/ grow into something fundamental.

Quoted 2 lines

I get the feeling we'd be best off if we were to revisit this in a year or so.

yeah. I'd suggest merging it as-is into v2.6.20. In a year we'll have some real APIs to think about.

Ingo

#7 lore raw

Re: [PATCH 1/38] KVM: Create kvm-intel.ko module

Quoted 5 lines · Ingo Molnar
Quoted 2 lines

I get the feeling we'd be best off if we were to revisit this in a year or so.

yeah. I'd suggest merging it as-is into v2.6.20. In a year we'll have some real APIs to think about.

Agreed. And because of that I think keeping it in drivers/ for now makes a lot of sense - it's just a driver we can deprecate if/when things have evolved into a real infrastructure.

#8 lore raw

Re: [PATCH 1/38] KVM: Create kvm-intel.ko module

Quoted 10 lines · Christoph Hellwig
Quoted 5 lines · Ingo Molnar
Quoted 2 lines

I get the feeling we'd be best off if we were to revisit this in a year or so.

yeah. I'd suggest merging it as-is into v2.6.20. In a year we'll have some real APIs to think about.

Agreed. And because of that I think keeping it in drivers/ for now makes a lot of sense - it's just a driver we can deprecate if/when things have evolved into a real infrastructure.

yeah, with that understanding there's zero objections from me.

Ingo

author
#9 lore raw

PATCH 2/38 KVM: Make /dev/registration happen when the arch specific module is loaded

In reply to Avi Kivity

This avoids exposing the driver capabilities before they are loaded.

drivers/kvm/kvm.h +1 -1
Index: linux-2.6/drivers/kvm/kvm.h
===================================================================
@@ -244,7 +244,7 @@ extern struct kvm_arch_ops *kvm_arch_ops
 #define kvm_printf(kvm, fmt ...) printk(KERN_DEBUG fmt)
 #define vcpu_printf(vcpu, fmt...) kvm_printf(vcpu->kvm, fmt)
 
-void kvm_init_arch(struct kvm_arch_ops *ops);
+int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module);
 void kvm_exit_arch(void);
 
 void kvm_mmu_destroy(struct kvm_vcpu *vcpu);
drivers/kvm/kvm_main.c +14 -10
Index: linux-2.6/drivers/kvm/kvm_main.c
===================================================================
@@ -3558,7 +3558,6 @@ static int kvm_dev_mmap(struct file *fil
 }
 
 static struct file_operations kvm_chardev_ops = {
-	.owner		= THIS_MODULE,
 	.open		= kvm_dev_open,
 	.release        = kvm_dev_release,
 	.unlocked_ioctl = kvm_dev_ioctl,
@@ -3612,13 +3611,26 @@ static void kvm_exit_debug(void)
 
 hpa_t bad_page_address;
 
-void kvm_init_arch(struct kvm_arch_ops *ops)
+int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module)
 {
+	int r;
+
 	kvm_arch_ops = ops;
+	kvm_chardev_ops.owner = module;
+
+	r = misc_register(&kvm_dev);
+	if (r) {
+		printk (KERN_ERR "kvm: misc device register failed\n");
+		goto out_free;
+	}
+
+out_free:
+	return r;
 }
 
 void kvm_exit_arch(void)
 {
+	misc_deregister(&kvm_dev);
 }
 
 static __init int kvm_init(void)
@@ -3644,13 +3656,6 @@ static __init int kvm_init(void)
 	on_each_cpu(kvm_enable, 0, 0, 1);
 	register_reboot_notifier(&kvm_reboot_notifier);
 
-	r = misc_register(&kvm_dev);
-	if (r) {
-		printk (KERN_ERR "kvm: misc device register failed\n");
-		goto out_free;
-	}
-
-
 	if ((bad_page = alloc_page(GFP_KERNEL)) == NULL) {
 		r = -ENOMEM;
 		goto out_free;
@@ -3671,7 +3676,6 @@ out:
 static __exit void kvm_exit(void)
 {
 	kvm_exit_debug();
-	misc_deregister(&kvm_dev);
 	unregister_reboot_notifier(&kvm_reboot_notifier);
 	on_each_cpu(kvm_disable, 0, 0, 1);
 	free_kvm_area();
drivers/kvm/vmx.c +1 -1
Index: linux-2.6/drivers/kvm/vmx.c
===================================================================
@@ -26,7 +26,7 @@ static struct kvm_arch_ops vmx_arch_ops 
 
 static int __init vmx_init(void)
 {
-	kvm_init_arch(&vmx_arch_ops);
+	kvm_init_arch(&vmx_arch_ops, THIS_MODULE);
 	return 0;
 }
 

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

author
#10 lore raw
In reply to Avi Kivity
Quoted 5 lines · Avi Kivity

This patchset prepares kvm for multiple architecture implementations. The kvm.ko module is split into kvm.ko and kvm-intel.ko, and a function vector is used to dispatch arch specific operations to the arch module.

It should be noted that the patchset is bisect friendly (and will even boot a guest for you at any point in the set).

Signature · 8 lines
error compiling committee.c: too many arguments to function


-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
author
#11 lore raw

PATCH 3/38 KV: Make hardware detection an arch operation

In reply to Avi Kivity
drivers/kvm/kvm.h +2 -0
Index: linux-2.6/drivers/kvm/kvm.h
===================================================================
@@ -236,6 +236,8 @@ struct kvm_stat {
 };
 
 struct kvm_arch_ops {
+	int (*cpu_has_kvm_support)(void);          /* __init */
+	int (*disabled_by_bios)(void);             /* __init */
 };
 
 extern struct kvm_stat kvm_stat;
drivers/kvm/kvm_main.c +10 -23
Index: linux-2.6/drivers/kvm/kvm_main.c
===================================================================
@@ -527,12 +527,6 @@ static void free_vmcs(struct vmcs *vmcs)
 	free_pages((unsigned long)vmcs, vmcs_descriptor.order);
 }
 
-static __init int cpu_has_kvm_support(void)
-{
-	unsigned long ecx = cpuid_ecx(1);
-	return test_bit(5, &ecx); /* CPUID.1:ECX.VMX[bit 5] -> VT */
-}
-
 static __exit void free_kvm_area(void)
 {
 	int cpu;
@@ -559,14 +553,6 @@ static __init int alloc_kvm_area(void)
 	return 0;
 }
 
-static __init int vmx_disabled_by_bios(void)
-{
-	u64 msr;
-
-	rdmsrl(MSR_IA32_FEATURE_CONTROL, msr);
-	return (msr & 5) == 1; /* locked but not enabled */
-}
-
 static __init void kvm_enable(void *garbage)
 {
 	int cpu = raw_smp_processor_id();
@@ -3616,6 +3602,16 @@ int kvm_init_arch(struct kvm_arch_ops *o
 	int r;
 
 	kvm_arch_ops = ops;
+
+	if (!kvm_arch_ops->cpu_has_kvm_support()) {
+		printk(KERN_ERR "kvm: no hardware support\n");
+		return -EOPNOTSUPP;
+	}
+	if (kvm_arch_ops->disabled_by_bios()) {
+		printk(KERN_ERR "kvm: disabled by bios\n");
+		return -EOPNOTSUPP;
+	}
+
 	kvm_chardev_ops.owner = module;
 
 	r = misc_register(&kvm_dev);
@@ -3638,15 +3634,6 @@ static __init int kvm_init(void)
 	static struct page *bad_page;
 	int r = 0;
 
-	if (!cpu_has_kvm_support()) {
-		printk(KERN_ERR "kvm: no hardware support\n");
-		return -EOPNOTSUPP;
-	}
-	if (vmx_disabled_by_bios()) {
-		printk(KERN_ERR "kvm: disabled by bios\n");
-		return -EOPNOTSUPP;
-	}
-
 	kvm_init_debug();
 
 	setup_vmcs_descriptor();
drivers/kvm/vmx.c +18 -0
Index: linux-2.6/drivers/kvm/vmx.c
===================================================================
@@ -18,10 +18,28 @@
 #include "kvm.h"
 #include <linux/module.h>
 
+#define MSR_IA32_FEATURE_CONTROL 		0x03a
+
 MODULE_AUTHOR("Qumranet");
 MODULE_LICENSE("GPL");
 
+static __init int cpu_has_kvm_support(void)
+{
+	unsigned long ecx = cpuid_ecx(1);
+	return test_bit(5, &ecx); /* CPUID.1:ECX.VMX[bit 5] -> VT */
+}
+
+static __init int vmx_disabled_by_bios(void)
+{
+	u64 msr;
+
+	rdmsrl(MSR_IA32_FEATURE_CONTROL, msr);
+	return (msr & 5) == 1; /* locked but not enabled */
+}
+
 static struct kvm_arch_ops vmx_arch_ops = {
+	.cpu_has_kvm_support = cpu_has_kvm_support,
+	.disabled_by_bios = vmx_disabled_by_bios,
 };
 
 static int __init vmx_init(void)

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

author
#12 lore raw

PATCH 4/38 KVM: Make the per-cpu enable/disable functions arch operations

In reply to Avi Kivity
drivers/kvm/kvm.h +2 -0
Index: linux-2.6/drivers/kvm/kvm.h
===================================================================
@@ -238,6 +238,8 @@ struct kvm_stat {
 struct kvm_arch_ops {
 	int (*cpu_has_kvm_support)(void);          /* __init */
 	int (*disabled_by_bios)(void);             /* __init */
+	void (*hardware_enable)(void *dummy);      /* __init */
+	void (*hardware_disable)(void *dummy);
 };
 
 extern struct kvm_stat kvm_stat;
drivers/kvm/kvm_main.c +10 -28
Index: linux-2.6/drivers/kvm/kvm_main.c
===================================================================
@@ -135,7 +135,6 @@ static const u32 vmx_msr_index[] = {
 #define CR0_RESEVED_BITS 0xffffffff1ffaffc0ULL
 #define LMSW_GUEST_MASK 0x0eULL
 #define CR4_RESEVED_BITS (~((1ULL << 11) - 1))
-#define CR4_VMXE 0x2000
 #define CR8_RESEVED_BITS (~0x0fULL)
 #define EFER_RESERVED_BITS 0xfffffffffffff2fe
 
@@ -300,7 +299,8 @@ static void reload_tss(void)
 #endif
 }
 
-static DEFINE_PER_CPU(struct vmcs *, vmxarea);
+DEFINE_PER_CPU(struct vmcs *, vmxarea);
+EXPORT_SYMBOL_GPL(per_cpu__vmxarea); /* temporary hack */
 static DEFINE_PER_CPU(struct vmcs *, current_vmcs);
 
 static struct vmcs_descriptor {
@@ -553,26 +553,6 @@ static __init int alloc_kvm_area(void)
 	return 0;
 }
 
-static __init void kvm_enable(void *garbage)
-{
-	int cpu = raw_smp_processor_id();
-	u64 phys_addr = __pa(per_cpu(vmxarea, cpu));
-	u64 old;
-
-	rdmsrl(MSR_IA32_FEATURE_CONTROL, old);
-	if ((old & 5) == 0)
-		/* enable and lock */
-		wrmsrl(MSR_IA32_FEATURE_CONTROL, old | 5);
-	write_cr4(read_cr4() | CR4_VMXE); /* FIXME: not cpu hotplug safe */
-	asm volatile (ASM_VMX_VMXON_RAX : : "a"(&phys_addr), "m"(phys_addr)
-		      : "memory", "cc");
-}
-
-static void kvm_disable(void *garbage)
-{
-	asm volatile (ASM_VMX_VMXOFF : : : "cc");
-}
-
 static int kvm_dev_open(struct inode *inode, struct file *filp)
 {
 	struct kvm *kvm = kzalloc(sizeof(struct kvm), GFP_KERNEL);
@@ -3565,8 +3545,8 @@ static int kvm_reboot(struct notifier_bl
 		 * Some (well, at least mine) BIOSes hang on reboot if
 		 * in vmx root mode.
 		 */
-		printk(KERN_INFO "kvm: exiting vmx mode\n");
-		on_each_cpu(kvm_disable, 0, 0, 1);
+		printk(KERN_INFO "kvm: exiting hardware virtualization\n");
+		on_each_cpu(kvm_arch_ops->hardware_disable, 0, 0, 1);
 	}
 	return NOTIFY_OK;
 }
@@ -3612,6 +3592,9 @@ int kvm_init_arch(struct kvm_arch_ops *o
 		return -EOPNOTSUPP;
 	}
 
+	on_each_cpu(kvm_arch_ops->hardware_enable, 0, 0, 1);
+	register_reboot_notifier(&kvm_reboot_notifier);
+
 	kvm_chardev_ops.owner = module;
 
 	r = misc_register(&kvm_dev);
@@ -3627,6 +3610,9 @@ out_free:
 void kvm_exit_arch(void)
 {
 	misc_deregister(&kvm_dev);
+
+	unregister_reboot_notifier(&kvm_reboot_notifier);
+	on_each_cpu(kvm_arch_ops->hardware_disable, 0, 0, 1);
 }
 
 static __init int kvm_init(void)
@@ -3640,8 +3626,6 @@ static __init int kvm_init(void)
 	r = alloc_kvm_area();
 	if (r)
 		goto out;
-	on_each_cpu(kvm_enable, 0, 0, 1);
-	register_reboot_notifier(&kvm_reboot_notifier);
 
 	if ((bad_page = alloc_page(GFP_KERNEL)) == NULL) {
 		r = -ENOMEM;
@@ -3663,8 +3647,6 @@ out:
 static __exit void kvm_exit(void)
 {
 	kvm_exit_debug();
-	unregister_reboot_notifier(&kvm_reboot_notifier);
-	on_each_cpu(kvm_disable, 0, 0, 1);
 	free_kvm_area();
 	__free_page(pfn_to_page(bad_page_address >> PAGE_SHIFT));
 }
drivers/kvm/vmx.c +24 -0
Index: linux-2.6/drivers/kvm/vmx.c
===================================================================
@@ -23,6 +23,8 @@
 MODULE_AUTHOR("Qumranet");
 MODULE_LICENSE("GPL");
 
+DECLARE_PER_CPU(struct vmcs *, vmxarea);
+
 static __init int cpu_has_kvm_support(void)
 {
 	unsigned long ecx = cpuid_ecx(1);
@@ -37,9 +39,31 @@ static __init int vmx_disabled_by_bios(v
 	return (msr & 5) == 1; /* locked but not enabled */
 }
 
+static __init void hardware_enable(void *garbage)
+{
+	int cpu = raw_smp_processor_id();
+	u64 phys_addr = __pa(per_cpu(vmxarea, cpu));
+	u64 old;
+
+	rdmsrl(MSR_IA32_FEATURE_CONTROL, old);
+	if ((old & 5) == 0)
+		/* enable and lock */
+		wrmsrl(MSR_IA32_FEATURE_CONTROL, old | 5);
+	write_cr4(read_cr4() | CR4_VMXE); /* FIXME: not cpu hotplug safe */
+	asm volatile (ASM_VMX_VMXON_RAX : : "a"(&phys_addr), "m"(phys_addr)
+		      : "memory", "cc");
+}
+
+static void hardware_disable(void *garbage)
+{
+	asm volatile (ASM_VMX_VMXOFF : : : "cc");
+}
+
 static struct kvm_arch_ops vmx_arch_ops = {
 	.cpu_has_kvm_support = cpu_has_kvm_support,
 	.disabled_by_bios = vmx_disabled_by_bios,
+	.hardware_enable = hardware_enable,
+	.hardware_disable = hardware_disable,
 };
 
 static int __init vmx_init(void)
drivers/kvm/vmx.h +2 -0
Index: linux-2.6/drivers/kvm/vmx.h
===================================================================
@@ -284,4 +284,6 @@ enum vmcs_field {
 
 #define AR_RESERVD_MASK 0xfffe0f00
 
+#define CR4_VMXE 0x2000
+
 #endif

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

author
#13 lore raw

PATCH 5/38 KVM: Make the hardware setup operations (non-percpu) arch operations

In reply to Avi Kivity
drivers/kvm/kvm.h +2 -0
Index: linux-2.6/drivers/kvm/kvm.h
===================================================================
@@ -240,6 +240,8 @@ struct kvm_arch_ops {
 	int (*disabled_by_bios)(void);             /* __init */
 	void (*hardware_enable)(void *dummy);      /* __init */
 	void (*hardware_disable)(void *dummy);
+	int (*hardware_setup)(void);               /* __init */
+	void (*hardware_unsetup)(void);            /* __exit */
 };
 
 extern struct kvm_stat kvm_stat;
drivers/kvm/kvm_main.c +17 -50

149 lines not on this page · raw message

drivers/kvm/vmx.c +59 -0

74 lines not on this page · raw message

drivers/kvm/vmx.h +2 -0
Index: linux-2.6/drivers/kvm/vmx.h
===================================================================
@@ -286,4 +286,6 @@ enum vmcs_field {
 
 #define CR4_VMXE 0x2000
 
+#define MSR_IA32_VMX_BASIC_MSR   		0x480
+
 #endif

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

author
#14 lore raw

PATCH 6/38 KVM: Make the guest debugger an arch operation

In reply to Avi Kivity
drivers/kvm/kvm.h +3 -0
Index: linux-2.6/drivers/kvm/kvm.h
===================================================================
@@ -242,6 +242,9 @@ struct kvm_arch_ops {
 	void (*hardware_disable)(void *dummy);
 	int (*hardware_setup)(void);               /* __init */
 	void (*hardware_unsetup)(void);            /* __exit */
+
+	int (*set_guest_debug)(struct kvm_vcpu *vcpu,
+			       struct kvm_debug_guest *dbg);
 };
 
 extern struct kvm_stat kvm_stat;
drivers/kvm/kvm_main.c +5 -38

70 lines not on this page · raw message

drivers/kvm/vmx.c +46 -0

58 lines not on this page · raw message

author
#15 lore raw

PATCH 7/38 KVM: Make msr accessors arch operations

In reply to Avi Kivity
drivers/kvm/kvm.h +4 -0
Index: linux-2.6/drivers/kvm/kvm.h
===================================================================
@@ -245,6 +245,8 @@ struct kvm_arch_ops {
 
 	int (*set_guest_debug)(struct kvm_vcpu *vcpu,
 			       struct kvm_debug_guest *dbg);
+	int (*get_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata);
+	int (*set_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
 };
 
 extern struct kvm_stat kvm_stat;
@@ -401,6 +403,8 @@ static inline struct kvm_mmu_page *page_
 #define ASM_VMX_VMXOFF            ".byte 0x0f, 0x01, 0xc4"
 #define ASM_VMX_VMXON_RAX         ".byte 0xf3, 0x0f, 0xc7, 0x30"
 
+#define MSR_IA32_TIME_STAMP_COUNTER		0x010
+
 #ifdef __x86_64__
 
 /*
drivers/kvm/kvm_main.c +10 -117

195 lines not on this page · raw message

drivers/kvm/vmx.c +142 -0

154 lines not on this page · raw message

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

author
#16 lore raw

PATCH 8/38 KVM: Make the segment accessors arch operations

In reply to Avi Kivity
drivers/kvm/kvm.h +4 -0
Index: linux-2.6/drivers/kvm/kvm.h
===================================================================
@@ -247,6 +247,10 @@ struct kvm_arch_ops {
 			       struct kvm_debug_guest *dbg);
 	int (*get_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata);
 	int (*set_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
+	void (*get_segment)(struct kvm_vcpu *vcpu,
+			    struct kvm_segment *var, int seg);
+	void (*set_segment)(struct kvm_vcpu *vcpu,
+			    struct kvm_segment *var, int seg);
 };
 
 extern struct kvm_stat kvm_stat;
drivers/kvm/kvm_main.c +25 -72

149 lines not on this page · raw message

drivers/kvm/vmx.c +58 -0

82 lines not on this page · raw message

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

author
#17 lore raw

PATCH 9/38 KVM: Cache guest cr4 in vcpu structure

In reply to Avi Kivity

This eliminates needing to have an arch operation to get cr4.

drivers/kvm/kvm.h +5 -10
Index: linux-2.6/drivers/kvm/kvm.h
===================================================================
@@ -168,6 +168,7 @@ struct kvm_vcpu {
 
 	unsigned long cr2;
 	unsigned long cr3;
+	unsigned long cr4;
 	unsigned long cr8;
 	u64 shadow_efer;
 	u64 apic_base;
@@ -335,20 +336,14 @@ static inline int is_long_mode(void)
 	return vmcs_read32(VM_ENTRY_CONTROLS) & VM_ENTRY_CONTROLS_IA32E_MASK;
 }
 
-static inline unsigned long guest_cr4(void)
+static inline int is_pae(struct kvm_vcpu *vcpu)
 {
-	return (vmcs_readl(CR4_READ_SHADOW) & KVM_GUEST_CR4_MASK) |
-		(vmcs_readl(GUEST_CR4) & ~KVM_GUEST_CR4_MASK);
+	return vcpu->cr4 & CR4_PAE_MASK;
 }
 
-static inline int is_pae(void)
+static inline int is_pse(struct kvm_vcpu *vcpu)
 {
-	return guest_cr4() & CR4_PAE_MASK;
-}
-
-static inline int is_pse(void)
-{
-	return guest_cr4() & CR4_PSE_MASK;
+	return vcpu->cr4 & CR4_PSE_MASK;
 }
 
 static inline unsigned long guest_cr0(void)
drivers/kvm/kvm_main.c +9 -8
Index: linux-2.6/drivers/kvm/kvm_main.c
===================================================================
@@ -940,7 +940,7 @@ static void set_cr0(struct kvm_vcpu *vcp
 #ifdef __x86_64__
 		if ((vcpu->shadow_efer & EFER_LME)) {
 			u32 guest_cs_ar;
-			if (!is_pae()) {
+			if (!is_pae(vcpu)) {
 				printk(KERN_DEBUG "set_cr0: #GP, start paging "
 				       "in long mode while PAE is disabled\n");
 				inject_gp(vcpu);
@@ -956,7 +956,7 @@ static void set_cr0(struct kvm_vcpu *vcp
 			}
 		} else
 #endif
-		if (is_pae() &&
+		if (is_pae(vcpu) &&
 			    pdptrs_have_reserved_bits_set(vcpu, vcpu->cr3)) {
 			printk(KERN_DEBUG "set_cr0: #GP, pdptrs "
 			       "reserved bits\n");
@@ -993,6 +993,7 @@ static void __set_cr4(struct kvm_vcpu *v
 	vmcs_writel(CR4_READ_SHADOW, cr4);
 	vmcs_writel(GUEST_CR4, cr4 | (vcpu->rmode.active ?
 		    KVM_RMODE_VM_CR4_ALWAYS_ON : KVM_PMODE_VM_CR4_ALWAYS_ON));
+	vcpu->cr4 = cr4;
 }
 
 static void set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
@@ -1010,7 +1011,7 @@ static void set_cr4(struct kvm_vcpu *vcp
 			inject_gp(vcpu);
 			return;
 		}
-	} else if (is_paging() && !is_pae() && (cr4 & CR4_PAE_MASK)
+	} else if (is_paging() && !is_pae(vcpu) && (cr4 & CR4_PAE_MASK)
 		   && pdptrs_have_reserved_bits_set(vcpu, vcpu->cr3)) {
 		printk(KERN_DEBUG "set_cr4: #GP, pdptrs reserved bits\n");
 		inject_gp(vcpu);
@@ -1041,7 +1042,7 @@ static void set_cr3(struct kvm_vcpu *vcp
 			inject_gp(vcpu);
 			return;
 		}
-		if (is_paging() && is_pae() &&
+		if (is_paging() && is_pae(vcpu) &&
 		    pdptrs_have_reserved_bits_set(vcpu, cr3)) {
 			printk(KERN_DEBUG "set_cr3: #GP, pdptrs "
 			       "reserved bits\n");
@@ -1902,7 +1903,7 @@ unsigned long realmode_get_cr(struct kvm
 	case 3:
 		return vcpu->cr3;
 	case 4:
-		return guest_cr4();
+		return vcpu->cr4;
 	default:
 		vcpu_printf(vcpu, "%s: unexpected cr %u\n", __FUNCTION__, cr);
 		return 0;
@@ -1924,7 +1925,7 @@ void realmode_set_cr(struct kvm_vcpu *vc
 		set_cr3(vcpu, val);
 		break;
 	case 4:
-		set_cr4(vcpu, mk_cr_64(guest_cr4(), val));
+		set_cr4(vcpu, mk_cr_64(vcpu->cr4, val));
 		break;
 	default:
 		vcpu_printf(vcpu, "%s: unexpected cr %u\n", __FUNCTION__, cr);
@@ -2844,7 +2845,7 @@ static int kvm_dev_ioctl_get_sregs(struc
 	sregs->cr0 = guest_cr0();
 	sregs->cr2 = vcpu->cr2;
 	sregs->cr3 = vcpu->cr3;
-	sregs->cr4 = guest_cr4();
+	sregs->cr4 = vcpu->cr4;
 	sregs->cr8 = vcpu->cr8;
 	sregs->efer = vcpu->shadow_efer;
 	sregs->apic_base = vcpu->apic_base;
@@ -2912,7 +2913,7 @@ static int kvm_dev_ioctl_set_sregs(struc
 	vmcs_writel(GUEST_CR0,
 		    (sregs->cr0 & ~KVM_GUEST_CR0_MASK) | KVM_VM_CR0_ALWAYS_ON);
 
-	mmu_reset_needed |=  guest_cr4() != sregs->cr4;
+	mmu_reset_needed |= vcpu->cr4 != sregs->cr4;
 	__set_cr4(vcpu, sregs->cr4);
 
 	if (mmu_reset_needed)
drivers/kvm/mmu.c +2 -2
Index: linux-2.6/drivers/kvm/mmu.c
===================================================================
@@ -564,7 +564,7 @@ static int paging64_init_context(struct 
 {
 	struct kvm_mmu *context = &vcpu->mmu;
 
-	ASSERT(is_pae());
+	ASSERT(is_pae(vcpu));
 	context->new_cr3 = paging_new_cr3;
 	context->page_fault = paging64_page_fault;
 	context->inval_page = paging_inval_page;
@@ -618,7 +618,7 @@ static int init_kvm_mmu(struct kvm_vcpu 
 		return nonpaging_init_context(vcpu);
 	else if (is_long_mode())
 		return paging64_init_context(vcpu);
-	else if (is_pae())
+	else if (is_pae(vcpu))
 		return paging32E_init_context(vcpu);
 	else
 		return paging32_init_context(vcpu);
drivers/kvm/paging_tmpl.h +3 -3
Index: linux-2.6/drivers/kvm/paging_tmpl.h
===================================================================
@@ -70,7 +70,7 @@ static void FNAME(init_walker)(struct gu
 	hpa = safe_gpa_to_hpa(vcpu, vcpu->cr3 & PT64_BASE_ADDR_MASK);
 	walker->table = kmap_atomic(pfn_to_page(hpa >> PAGE_SHIFT), KM_USER0);
 
-	ASSERT((!is_long_mode() && is_pae()) ||
+	ASSERT((!is_long_mode() && is_pae(vcpu)) ||
 	       (vcpu->cr3 & ~(PAGE_MASK | CR3_FLAGS_MASK)) == 0);
 
 	walker->table = (pt_element_t *)( (unsigned long)walker->table |
@@ -133,7 +133,7 @@ static pt_element_t *FNAME(fetch_guest)(
 		    !is_present_pte(walker->table[index]) ||
 		    (walker->level == PT_DIRECTORY_LEVEL &&
 		     (walker->table[index] & PT_PAGE_SIZE_MASK) &&
-		     (PTTYPE == 64 || is_pse())))
+		     (PTTYPE == 64 || is_pse(vcpu))))
 			return &walker->table[index];
 		if (walker->level != 3 || is_long_mode())
 			walker->inherited_ar &= walker->table[index];
@@ -369,7 +369,7 @@ static gpa_t FNAME(gva_to_gpa)(struct kv
 
 	if (walker.level == PT_DIRECTORY_LEVEL) {
 		ASSERT((guest_pte & PT_PAGE_SIZE_MASK));
-		ASSERT(PTTYPE == 64 || is_pse());
+		ASSERT(PTTYPE == 64 || is_pse(vcpu));
 
 		gpa = (guest_pte & PT_DIR_BASE_ADDR_MASK) | (vaddr &
 			(PT_LEVEL_MASK(PT_PAGE_TABLE_LEVEL) | ~PAGE_MASK));
drivers/kvm/kvm_vmx.h new file +20 -0
Index: linux-2.6/drivers/kvm/kvm_vmx.h
===================================================================
@@ -0,0 +1,20 @@
+#ifndef __KVM_VMX_H
+#define __KVM_VMX_H
+
+static inline void vmcs_write16(unsigned long field, u16 value)
+{
+	vmcs_writel(field, value);
+}
+
+static inline void vmcs_write64(unsigned long field, u64 value)
+{
+#ifdef __x86_64__
+	vmcs_writel(field, value);
+#else
+	vmcs_writel(field, value);
+	asm volatile ("");
+	vmcs_writel(field+1, value >> 32);
+#endif
+}
+
+#endif

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

author
#18 lore raw

PATCH 10/38 KVM: Cache guest cr0 in vcpu structure

In reply to Avi Kivity

This eliminates needing to have an arch operation to get cr0.

drivers/kvm/kvm.h +3 -9
Index: linux-2.6/drivers/kvm/kvm.h
===================================================================
@@ -41,7 +41,6 @@
 	 | CR0_NW_MASK | CR0_CD_MASK)
 #define KVM_VM_CR0_ALWAYS_ON \
 	(CR0_PG_MASK | CR0_PE_MASK | CR0_WP_MASK | CR0_NE_MASK)
-
 #define KVM_GUEST_CR4_MASK \
 	(CR4_PSE_MASK | CR4_PAE_MASK | CR4_PGE_MASK | CR4_VMXE_MASK | CR4_VME_MASK)
 #define KVM_PMODE_VM_CR4_ALWAYS_ON (CR4_VMXE_MASK | CR4_PAE_MASK)
@@ -166,6 +165,7 @@ struct kvm_vcpu {
 	unsigned long regs[NR_VCPU_REGS]; /* for rsp: vcpu_load_rsp_rip() */
 	unsigned long rip;      /* needs vcpu_load_rsp_rip() */
 
+	unsigned long cr0;
 	unsigned long cr2;
 	unsigned long cr3;
 	unsigned long cr4;
@@ -346,20 +346,14 @@ static inline int is_pse(struct kvm_vcpu
 	return vcpu->cr4 & CR4_PSE_MASK;
 }
 
-static inline unsigned long guest_cr0(void)
-{
-	return (vmcs_readl(CR0_READ_SHADOW) & KVM_GUEST_CR0_MASK) |
-		(vmcs_readl(GUEST_CR0) & ~KVM_GUEST_CR0_MASK);
-}
-
 static inline unsigned guest_cpl(void)
 {
 	return vmcs_read16(GUEST_CS_SELECTOR) & SELECTOR_RPL_MASK;
 }
 
-static inline int is_paging(void)
+static inline int is_paging(struct kvm_vcpu *vcpu)
 {
-	return guest_cr0() & CR0_PG_MASK;
+	return vcpu->cr0 & CR0_PG_MASK;
 }
 
 static inline int is_page_fault(u32 intr_info)
drivers/kvm/kvm_main.c +16 -12
Index: linux-2.6/drivers/kvm/kvm_main.c
===================================================================
@@ -875,9 +875,9 @@ static void __set_cr0(struct kvm_vcpu *v
 
 #ifdef __x86_64__
 	if (vcpu->shadow_efer & EFER_LME) {
-		if (!is_paging() && (cr0 & CR0_PG_MASK))
+		if (!is_paging(vcpu) && (cr0 & CR0_PG_MASK))
 			enter_lmode(vcpu);
-		if (is_paging() && !(cr0 & CR0_PG_MASK))
+		if (is_paging(vcpu) && !(cr0 & CR0_PG_MASK))
 			exit_lmode(vcpu);
 	}
 #endif
@@ -885,6 +885,7 @@ static void __set_cr0(struct kvm_vcpu *v
 	vmcs_writel(CR0_READ_SHADOW, cr0);
 	vmcs_writel(GUEST_CR0,
 		    (cr0 & ~KVM_GUEST_CR0_MASK) | KVM_VM_CR0_ALWAYS_ON);
+	vcpu->cr0 = cr0;
 }
 
 static int pdptrs_have_reserved_bits_set(struct kvm_vcpu *vcpu,
@@ -918,7 +919,7 @@ static void set_cr0(struct kvm_vcpu *vcp
 {
 	if (cr0 & CR0_RESEVED_BITS) {
 		printk(KERN_DEBUG "set_cr0: 0x%lx #GP, reserved bits 0x%lx\n",
-		       cr0, guest_cr0());
+		       cr0, vcpu->cr0);
 		inject_gp(vcpu);
 		return;
 	}
@@ -936,7 +937,7 @@ static void set_cr0(struct kvm_vcpu *vcp
 		return;
 	}
 
-	if (!is_paging() && (cr0 & CR0_PG_MASK)) {
+	if (!is_paging(vcpu) && (cr0 & CR0_PG_MASK)) {
 #ifdef __x86_64__
 		if ((vcpu->shadow_efer & EFER_LME)) {
 			u32 guest_cs_ar;
@@ -975,7 +976,7 @@ static void set_cr0(struct kvm_vcpu *vcp
 
 static void lmsw(struct kvm_vcpu *vcpu, unsigned long msw)
 {
-	unsigned long cr0 = guest_cr0();
+	unsigned long cr0 = vcpu->cr0;
 
 	if ((msw & CR0_PE_MASK) && !(cr0 & CR0_PE_MASK)) {
 		enter_pmode(vcpu);
@@ -986,6 +987,7 @@ static void lmsw(struct kvm_vcpu *vcpu, 
 
 	vmcs_writel(GUEST_CR0, (vmcs_readl(GUEST_CR0) & ~LMSW_GUEST_MASK)
 				| (msw & LMSW_GUEST_MASK));
+	vcpu->cr0 = (vcpu->cr0 & ~0xfffful) | msw;
 }
 
 static void __set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
@@ -1011,7 +1013,7 @@ static void set_cr4(struct kvm_vcpu *vcp
 			inject_gp(vcpu);
 			return;
 		}
-	} else if (is_paging() && !is_pae(vcpu) && (cr4 & CR4_PAE_MASK)
+	} else if (is_paging(vcpu) && !is_pae(vcpu) && (cr4 & CR4_PAE_MASK)
 		   && pdptrs_have_reserved_bits_set(vcpu, vcpu->cr3)) {
 		printk(KERN_DEBUG "set_cr4: #GP, pdptrs reserved bits\n");
 		inject_gp(vcpu);
@@ -1042,7 +1044,7 @@ static void set_cr3(struct kvm_vcpu *vcp
 			inject_gp(vcpu);
 			return;
 		}
-		if (is_paging() && is_pae(vcpu) &&
+		if (is_paging(vcpu) && is_pae(vcpu) &&
 		    pdptrs_have_reserved_bits_set(vcpu, cr3)) {
 			printk(KERN_DEBUG "set_cr3: #GP, pdptrs "
 			       "reserved bits\n");
@@ -1897,7 +1899,7 @@ unsigned long realmode_get_cr(struct kvm
 {
 	switch (cr) {
 	case 0:
-		return guest_cr0();
+		return vcpu->cr0;
 	case 2:
 		return vcpu->cr2;
 	case 3:
@@ -1915,7 +1917,7 @@ void realmode_set_cr(struct kvm_vcpu *vc
 {
 	switch (cr) {
 	case 0:
-		set_cr0(vcpu, mk_cr_64(guest_cr0(), val));
+		set_cr0(vcpu, mk_cr_64(vcpu->cr0, val));
 		*rflags = vmcs_readl(GUEST_RFLAGS);
 		break;
 	case 2:
@@ -2264,7 +2266,8 @@ void set_efer(struct kvm_vcpu *vcpu, u64
 		return;
 	}
 
-	if (is_paging() && (vcpu->shadow_efer & EFER_LME) != (efer & EFER_LME)) {
+	if (is_paging(vcpu)
+	    && (vcpu->shadow_efer & EFER_LME) != (efer & EFER_LME)) {
 		printk(KERN_DEBUG "set_efer: #GP, change LME while paging\n");
 		inject_gp(vcpu);
 		return;
@@ -2842,7 +2845,7 @@ static int kvm_dev_ioctl_get_sregs(struc
 	get_dtable(gdt, GDTR);
 #undef get_dtable
 
-	sregs->cr0 = guest_cr0();
+	sregs->cr0 = vcpu->cr0;
 	sregs->cr2 = vcpu->cr2;
 	sregs->cr3 = vcpu->cr3;
 	sregs->cr4 = vcpu->cr4;
@@ -2906,12 +2909,13 @@ static int kvm_dev_ioctl_set_sregs(struc
 #endif
 	vcpu->apic_base = sregs->apic_base;
 
-	mmu_reset_needed |= guest_cr0() != sregs->cr0;
+	mmu_reset_needed |= vcpu->cr0 != sregs->cr0;
 	vcpu->rmode.active = ((sregs->cr0 & CR0_PE_MASK) == 0);
 	update_exception_bitmap(vcpu);
 	vmcs_writel(CR0_READ_SHADOW, sregs->cr0);
 	vmcs_writel(GUEST_CR0,
 		    (sregs->cr0 & ~KVM_GUEST_CR0_MASK) | KVM_VM_CR0_ALWAYS_ON);
+	vcpu->cr0 = sregs->cr0;
 
 	mmu_reset_needed |= vcpu->cr4 != sregs->cr4;
 	__set_cr4(vcpu, sregs->cr4);
drivers/kvm/mmu.c +4 -4
Index: linux-2.6/drivers/kvm/mmu.c
===================================================================
@@ -138,9 +138,9 @@
 #define PT_DIRECTORY_LEVEL 2
 #define PT_PAGE_TABLE_LEVEL 1
 
-static int is_write_protection(void)
+static int is_write_protection(struct kvm_vcpu *vcpu)
 {
-	return guest_cr0() & CR0_WP_MASK;
+	return vcpu->cr0 & CR0_WP_MASK;
 }
 
 static int is_cpuid_PSE36(void)
@@ -321,7 +321,7 @@ static void nonpaging_flush(struct kvm_v
 	root = kvm_mmu_alloc_page(vcpu, 0);
 	ASSERT(VALID_PAGE(root));
 	vcpu->mmu.root_hpa = root;
-	if (is_paging())
+	if (is_paging(vcpu))
 		root |= (vcpu->cr3 & (CR3_PCD_MASK | CR3_WPT_MASK));
 	vmcs_writel(GUEST_CR3, root);
 }
@@ -614,7 +614,7 @@ static int init_kvm_mmu(struct kvm_vcpu 
 	ASSERT(vcpu);
 	ASSERT(!VALID_PAGE(vcpu->mmu.root_hpa));
 
-	if (!is_paging())
+	if (!is_paging(vcpu))
 		return nonpaging_init_context(vcpu);
 	else if (is_long_mode())
 		return paging64_init_context(vcpu);
drivers/kvm/paging_tmpl.h +1 -1
Index: linux-2.6/drivers/kvm/paging_tmpl.h
===================================================================
@@ -251,7 +251,7 @@ static int FNAME(fix_write_pf)(struct kv
 		 * supervisor write protection is enabled.
 		 */
 		if (!writable_shadow) {
-			if (is_write_protection())
+			if (is_write_protection(vcpu))
 				return 0;
 			*shadow_ent &= ~PT_USER_MASK;
 		}

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

author
#19 lore raw

PATCH 11/38 KVM: Add get_segment_base() arch accessor

In reply to Avi Kivity

This could have been implemented in terms of the existing get_segment(), but that make unnecessary vmx accesses.

drivers/kvm/kvm.h +1 -0
Index: linux-2.6/drivers/kvm/kvm.h
===================================================================
@@ -248,6 +248,7 @@ struct kvm_arch_ops {
 			       struct kvm_debug_guest *dbg);
 	int (*get_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata);
 	int (*set_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
+	u64 (*get_segment_base)(struct kvm_vcpu *vcpu, int seg);
 	void (*get_segment)(struct kvm_vcpu *vcpu,
 			    struct kvm_segment *var, int seg);
 	void (*set_segment)(struct kvm_vcpu *vcpu,
drivers/kvm/kvm_main.c +14 -7
Index: linux-2.6/drivers/kvm/kvm_main.c
===================================================================
@@ -1776,12 +1776,19 @@ static int emulator_cmpxchg_emulated(uns
 	return emulator_write_emulated(addr, new, bytes, ctxt);
 }
 
+static unsigned long get_segment_base(struct kvm_vcpu *vcpu, int seg)
+{
+	return kvm_arch_ops->get_segment_base(vcpu, seg);
+}
+
 static void report_emulation_failure(struct x86_emulate_ctxt *ctxt)
 {
 	static int reported;
 	u8 opcodes[4];
 	unsigned long rip = vmcs_readl(GUEST_RIP);
-	unsigned long rip_linear = rip + vmcs_readl(GUEST_CS_BASE);
+	unsigned long rip_linear;
+
+	rip_linear = rip + get_segment_base(ctxt->vcpu, VCPU_SREG_CS);
 
 	if (reported)
 		return;
@@ -1835,14 +1842,14 @@ static int emulate_instruction(struct kv
 		emulate_ctxt.es_base = 0;
 		emulate_ctxt.ss_base = 0;
 	} else {
-		emulate_ctxt.cs_base = vmcs_readl(GUEST_CS_BASE);
-		emulate_ctxt.ds_base = vmcs_readl(GUEST_DS_BASE);
-		emulate_ctxt.es_base = vmcs_readl(GUEST_ES_BASE);
-		emulate_ctxt.ss_base = vmcs_readl(GUEST_SS_BASE);
+		emulate_ctxt.cs_base = get_segment_base(vcpu, VCPU_SREG_CS);
+		emulate_ctxt.ds_base = get_segment_base(vcpu, VCPU_SREG_DS);
+		emulate_ctxt.es_base = get_segment_base(vcpu, VCPU_SREG_ES);
+		emulate_ctxt.ss_base = get_segment_base(vcpu, VCPU_SREG_SS);
 	}
 
-	emulate_ctxt.gs_base = vmcs_readl(GUEST_GS_BASE);
-	emulate_ctxt.fs_base = vmcs_readl(GUEST_FS_BASE);
+	emulate_ctxt.gs_base = get_segment_base(vcpu, VCPU_SREG_GS);
+	emulate_ctxt.fs_base = get_segment_base(vcpu, VCPU_SREG_FS);
 
 	vcpu->mmio_is_write = 0;
 	r = x86_emulate_memop(&emulate_ctxt, &emulate_ops);
drivers/kvm/vmx.c +8 -0
Index: linux-2.6/drivers/kvm/vmx.c
===================================================================
@@ -309,6 +309,13 @@ static __exit void hardware_unsetup(void
 	free_kvm_area();
 }
 
+static u64 vmx_get_segment_base(struct kvm_vcpu *vcpu, int seg)
+{
+	struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
+
+	return vmcs_readl(sf->base);
+}
+
 static void vmx_get_segment(struct kvm_vcpu *vcpu,
 			    struct kvm_segment *var, int seg)
 {
@@ -367,6 +374,7 @@ static struct kvm_arch_ops vmx_arch_ops 
 	.set_guest_debug = set_guest_debug,
 	.get_msr = vmx_get_msr,
 	.set_msr = vmx_set_msr,
+	.get_segment_base = vmx_get_segment_base,
 	.get_segment = vmx_get_segment,
 	.set_segment = vmx_set_segment,
 };

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

author
#20 lore raw

PATCH 12/38 KVM: Add idt and gdt descriptor accessors

In reply to Avi Kivity
drivers/kvm/kvm.h +9 -0
Index: linux-2.6/drivers/kvm/kvm.h
===================================================================
@@ -236,6 +236,11 @@ struct kvm_stat {
 	u32 irq_exits;
 };
 
+struct descriptor_table {
+	u16 limit;
+	unsigned long base;
+} __attribute__((packed));
+
 struct kvm_arch_ops {
 	int (*cpu_has_kvm_support)(void);          /* __init */
 	int (*disabled_by_bios)(void);             /* __init */
@@ -253,6 +258,10 @@ struct kvm_arch_ops {
 			    struct kvm_segment *var, int seg);
 	void (*set_segment)(struct kvm_vcpu *vcpu,
 			    struct kvm_segment *var, int seg);
+	void (*get_idt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
+	void (*set_idt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
+	void (*get_gdt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
+	void (*set_gdt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
 };
 
 extern struct kvm_stat kvm_stat;
drivers/kvm/kvm_main.c +14 -19
Index: linux-2.6/drivers/kvm/kvm_main.c
===================================================================
@@ -155,11 +155,6 @@ struct vmx_msr_entry *find_msr_entry(str
 }
 EXPORT_SYMBOL_GPL(find_msr_entry);
 
-struct descriptor_table {
-	u16 limit;
-	unsigned long base;
-} __attribute__((packed));
-
 static void get_gdt(struct descriptor_table *table)
 {
 	asm ("sgdt %0" : "=m"(*table));
@@ -2827,6 +2822,7 @@ static void get_segment(struct kvm_vcpu 
 static int kvm_dev_ioctl_get_sregs(struct kvm *kvm, struct kvm_sregs *sregs)
 {
 	struct kvm_vcpu *vcpu;
+	struct descriptor_table dt;
 
 	if (sregs->vcpu < 0 || sregs->vcpu >= KVM_MAX_VCPUS)
 		return -EINVAL;
@@ -2844,13 +2840,12 @@ static int kvm_dev_ioctl_get_sregs(struc
 	get_segment(vcpu, &sregs->tr, VCPU_SREG_TR);
 	get_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR);
 
-#define get_dtable(var, table) \
-	sregs->var.limit = vmcs_read32(GUEST_##table##_LIMIT), \
-		sregs->var.base = vmcs_readl(GUEST_##table##_BASE)
-
-	get_dtable(idt, IDTR);
-	get_dtable(gdt, GDTR);
-#undef get_dtable
+	kvm_arch_ops->get_idt(vcpu, &dt);
+	sregs->idt.limit = dt.limit;
+	sregs->idt.base = dt.base;
+	kvm_arch_ops->get_gdt(vcpu, &dt);
+	sregs->gdt.limit = dt.limit;
+	sregs->gdt.base = dt.base;
 
 	sregs->cr0 = vcpu->cr0;
 	sregs->cr2 = vcpu->cr2;
@@ -2879,6 +2874,7 @@ static int kvm_dev_ioctl_set_sregs(struc
 	struct kvm_vcpu *vcpu;
 	int mmu_reset_needed = 0;
 	int i;
+	struct descriptor_table dt;
 
 	if (sregs->vcpu < 0 || sregs->vcpu >= KVM_MAX_VCPUS)
 		return -EINVAL;
@@ -2896,13 +2892,12 @@ static int kvm_dev_ioctl_set_sregs(struc
 	set_segment(vcpu, &sregs->tr, VCPU_SREG_TR);
 	set_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR);
 
-#define set_dtable(var, table) \
-	vmcs_write32(GUEST_##table##_LIMIT, sregs->var.limit), \
-	vmcs_writel(GUEST_##table##_BASE, sregs->var.base)
-
-	set_dtable(idt, IDTR);
-	set_dtable(gdt, GDTR);
-#undef set_dtable
+	dt.limit = sregs->idt.limit;
+	dt.base = sregs->idt.base;
+	kvm_arch_ops->set_idt(vcpu, &dt);
+	dt.limit = sregs->gdt.limit;
+	dt.base = sregs->gdt.base;
+	kvm_arch_ops->set_gdt(vcpu, &dt);
 
 	vcpu->cr2 = sregs->cr2;
 	mmu_reset_needed |= vcpu->cr3 != sregs->cr3;
drivers/kvm/vmx.c +28 -0
Index: linux-2.6/drivers/kvm/vmx.c
===================================================================
@@ -363,6 +363,30 @@ static void vmx_set_segment(struct kvm_v
 	vmcs_write32(sf->ar_bytes, ar);
 }
 
+static void vmx_get_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
+{
+	dt->limit = vmcs_read32(GUEST_IDTR_LIMIT);
+	dt->base = vmcs_readl(GUEST_IDTR_BASE);
+}
+
+static void vmx_set_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
+{
+	vmcs_write32(GUEST_IDTR_LIMIT, dt->limit);
+	vmcs_writel(GUEST_IDTR_BASE, dt->base);
+}
+
+static void vmx_get_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
+{
+	dt->limit = vmcs_read32(GUEST_GDTR_LIMIT);
+	dt->base = vmcs_readl(GUEST_GDTR_BASE);
+}
+
+static void vmx_set_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
+{
+	vmcs_write32(GUEST_GDTR_LIMIT, dt->limit);
+	vmcs_writel(GUEST_GDTR_BASE, dt->base);
+}
+
 static struct kvm_arch_ops vmx_arch_ops = {
 	.cpu_has_kvm_support = cpu_has_kvm_support,
 	.disabled_by_bios = vmx_disabled_by_bios,
@@ -377,6 +401,10 @@ static struct kvm_arch_ops vmx_arch_ops 
 	.get_segment_base = vmx_get_segment_base,
 	.get_segment = vmx_get_segment,
 	.set_segment = vmx_set_segment,
+	.get_idt = vmx_get_idt,
+	.set_idt = vmx_set_idt,
+	.get_gdt = vmx_get_gdt,
+	.set_gdt = vmx_set_gdt,
 };
 
 static int __init vmx_init(void)

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

author
#21 lore raw

PATCH 13/38 KVM: Make syncing the register file to the vcpu structure an arch operation

In reply to Avi Kivity

This copies any general purpose guest registers maintained by the hardware to the vcpu structure (and back).

drivers/kvm/kvm.h +2 -0
Index: linux-2.6/drivers/kvm/kvm.h
===================================================================
@@ -262,6 +262,8 @@ struct kvm_arch_ops {
 	void (*set_idt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
 	void (*get_gdt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
 	void (*set_gdt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
+	void (*cache_regs)(struct kvm_vcpu *vcpu);
+	void (*decache_regs)(struct kvm_vcpu *vcpu);
 };
 
 extern struct kvm_stat kvm_stat;
drivers/kvm/kvm_main.c +12 -32

105 lines not on this page · raw message

drivers/kvm/vmx.c +22 -0
Index: linux-2.6/drivers/kvm/vmx.c
===================================================================
@@ -180,6 +180,26 @@ static int vmx_set_msr(struct kvm_vcpu *
 	return 0;
 }
 
+/*
+ * Sync the rsp and rip registers into the vcpu structure.  This allows
+ * registers to be accessed by indexing vcpu->regs.
+ */
+static void vcpu_load_rsp_rip(struct kvm_vcpu *vcpu)
+{
+	vcpu->regs[VCPU_REGS_RSP] = vmcs_readl(GUEST_RSP);
+	vcpu->rip = vmcs_readl(GUEST_RIP);
+}
+
+/*
+ * Syncs rsp and rip back into the vmcs.  Should be called after possible
+ * modification.
+ */
+static void vcpu_put_rsp_rip(struct kvm_vcpu *vcpu)
+{
+	vmcs_writel(GUEST_RSP, vcpu->regs[VCPU_REGS_RSP]);
+	vmcs_writel(GUEST_RIP, vcpu->rip);
+}
+
 static int set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg)
 {
 	unsigned long dr7 = 0x400;
@@ -405,6 +425,8 @@ static struct kvm_arch_ops vmx_arch_ops 
 	.set_idt = vmx_set_idt,
 	.get_gdt = vmx_get_gdt,
 	.set_gdt = vmx_set_gdt,
+	.cache_regs = vcpu_load_rsp_rip,
+	.decache_regs = vcpu_put_rsp_rip,
 };
 
 static int __init vmx_init(void)

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

author
#22 lore raw

PATCH 14/38 KVM: Make the vcpu execution loop an arch operation

In reply to Avi Kivity
drivers/kvm/kvm.h +71 -0
Index: linux-2.6/drivers/kvm/kvm.h
===================================================================
@@ -264,6 +264,9 @@ struct kvm_arch_ops {
 	void (*set_gdt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
 	void (*cache_regs)(struct kvm_vcpu *vcpu);
 	void (*decache_regs)(struct kvm_vcpu *vcpu);
+
+	int (*run)(struct kvm_vcpu *vcpu, struct kvm_run *run);
+	unsigned long vmx_return; /* temporary hack */
 };
 
 extern struct kvm_stat kvm_stat;
@@ -306,6 +309,11 @@ unsigned long realmode_get_cr(struct kvm
 void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long value,
 		     unsigned long *rflags);
 
+void load_msrs(struct vmx_msr_entry *e, int n);
+void save_msrs(struct vmx_msr_entry *e, int n);
+void kvm_resched(struct kvm_vcpu *vcpu);
+int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu);
+
 int kvm_read_guest(struct kvm_vcpu *vcpu,
 	       gva_t addr,
 	       unsigned long size,
@@ -398,6 +406,69 @@ static inline struct kvm_mmu_page *page_
 	return (struct kvm_mmu_page *)page->private;
 }
 
+static inline u16 read_fs(void)
+{
+	u16 seg;
+	asm ("mov %%fs, %0" : "=g"(seg));
+	return seg;
+}
+
+static inline u16 read_gs(void)
+{
+	u16 seg;
+	asm ("mov %%gs, %0" : "=g"(seg));
+	return seg;
+}
+
+static inline u16 read_ldt(void)
+{
+	u16 ldt;
+	asm ("sldt %0" : "=g"(ldt));
+	return ldt;
+}
+
+static inline void load_fs(u16 sel)
+{
+	asm ("mov %0, %%fs" : : "rm"(sel));
+}
+
+static inline void load_gs(u16 sel)
+{
+	asm ("mov %0, %%gs" : : "rm"(sel));
+}
+
+#ifndef load_ldt
+static inline void load_ldt(u16 sel)
+{
+	asm ("lldt %0" : : "g"(sel));
+}
+#endif
+
+#ifdef __x86_64__
+static inline unsigned long read_msr(unsigned long msr)
+{
+	u64 value;
+
+	rdmsrl(msr, value);
+	return value;
+}
+#endif
+
+static inline void fx_save(void *image)
+{
+	asm ("fxsave (%0)":: "r" (image));
+}
+
+static inline void fx_restore(void *image)
+{
+	asm ("fxrstor (%0)":: "r" (image));
+}
+
+static inline void fpu_init(void)
+{
+	asm ("finit");
+}
+
 #define ASM_VMX_VMCLEAR_RAX       ".byte 0x66, 0x0f, 0xc7, 0x30"
 #define ASM_VMX_VMLAUNCH          ".byte 0x0f, 0x01, 0xc2"
 #define ASM_VMX_VMRESUME          ".byte 0x0f, 0x01, 0xc3"
drivers/kvm/kvm_main.c +19 -398

518 lines not on this page · raw message

drivers/kvm/kvm_vmx.h +10 -0
Index: linux-2.6/drivers/kvm/kvm_vmx.h
===================================================================
@@ -17,4 +17,14 @@ static inline void vmcs_write64(unsigned
 #endif
 }
 
+#ifdef __x86_64__
+/*
+ * avoid save/load MSR_SYSCALL_MASK and MSR_LSTAR by std vt
+ * mechanism (cpu bug AA24)
+ */
+#define NR_BAD_MSRS 2
+#else
+#define NR_BAD_MSRS 0
+#endif
+
 #endif
drivers/kvm/vmx.c +327 -0

345 lines not on this page · raw message

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

author
#23 lore raw

PATCH 15/38 KVM: Move the vmx exit handlers to vmx.c

In reply to Avi Kivity
drivers/kvm/kvm.h +22 -1
Index: linux-2.6/drivers/kvm/kvm.h
===================================================================
@@ -266,6 +266,7 @@ struct kvm_arch_ops {
 	void (*decache_regs)(struct kvm_vcpu *vcpu);
 
 	int (*run)(struct kvm_vcpu *vcpu, struct kvm_run *run);
+	void (*skip_emulated_instruction)(struct kvm_vcpu *vcpu);
 	unsigned long vmx_return; /* temporary hack */
 };
 
@@ -300,6 +301,14 @@ static inline struct page *gfn_to_page(s
 struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn);
 void mark_page_dirty(struct kvm *kvm, gfn_t gfn);
 
+enum emulation_result {
+	EMULATE_DONE,       /* no further processing */
+	EMULATE_DO_MMIO,      /* kvm_run filled with mmio request */
+	EMULATE_FAIL,         /* can't emulate this instruction */
+};
+
+int emulate_instruction(struct kvm_vcpu *vcpu, struct kvm_run *run,
+			unsigned long cr2, u16 error_code);
 void realmode_lgdt(struct kvm_vcpu *vcpu, u16 size, unsigned long address);
 void realmode_lidt(struct kvm_vcpu *vcpu, u16 size, unsigned long address);
 void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,
@@ -309,10 +318,22 @@ unsigned long realmode_get_cr(struct kvm
 void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long value,
 		     unsigned long *rflags);
 
+void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
+void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr0);
+void set_cr4(struct kvm_vcpu *vcpu, unsigned long cr0);
+void set_cr8(struct kvm_vcpu *vcpu, unsigned long cr0);
+void lmsw(struct kvm_vcpu *vcpu, unsigned long msw);
+
+void inject_gp(struct kvm_vcpu *vcpu);
+
+#ifdef __x86_64__
+void set_efer(struct kvm_vcpu *vcpu, u64 efer);
+#endif
+
+
 void load_msrs(struct vmx_msr_entry *e, int n);
 void save_msrs(struct vmx_msr_entry *e, int n);
 void kvm_resched(struct kvm_vcpu *vcpu);
-int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu);
 
 int kvm_read_guest(struct kvm_vcpu *vcpu,
 	       gva_t addr,
drivers/kvm/kvm_main.c +18 -430

553 lines not on this page · raw message

drivers/kvm/vmx.c +408 -3

431 lines not on this page · raw message

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

author
#24 lore raw

PATCH 16/38 KVM: Make vcpu_setup() an arch operation

In reply to Avi Kivity
drivers/kvm/kvm.h +40 -1
Index: linux-2.6/drivers/kvm/kvm.h
===================================================================
@@ -153,6 +153,17 @@ enum {
 	NR_VCPU_REGS
 };
 
+enum {
+	VCPU_SREG_CS,
+	VCPU_SREG_DS,
+	VCPU_SREG_ES,
+	VCPU_SREG_FS,
+	VCPU_SREG_GS,
+	VCPU_SREG_SS,
+	VCPU_SREG_TR,
+	VCPU_SREG_LDTR,
+};
+
 struct kvm_vcpu {
 	struct kvm *kvm;
 	struct vmcs *vmcs;
@@ -266,8 +277,8 @@ struct kvm_arch_ops {
 	void (*decache_regs)(struct kvm_vcpu *vcpu);
 
 	int (*run)(struct kvm_vcpu *vcpu, struct kvm_run *run);
+	int (*vcpu_setup)(struct kvm_vcpu *vcpu);
 	void (*skip_emulated_instruction)(struct kvm_vcpu *vcpu);
-	unsigned long vmx_return; /* temporary hack */
 };
 
 extern struct kvm_stat kvm_stat;
@@ -324,12 +335,18 @@ void set_cr4(struct kvm_vcpu *vcpu, unsi
 void set_cr8(struct kvm_vcpu *vcpu, unsigned long cr0);
 void lmsw(struct kvm_vcpu *vcpu, unsigned long msw);
 
+void __set_efer(struct kvm_vcpu *vcpu, u64 efer);
+void __set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
+void __set_cr4(struct kvm_vcpu *vcpu, unsigned long cr0);
+
+int rmode_tss_base(struct kvm* kvm); /* temporary hack */
 void inject_gp(struct kvm_vcpu *vcpu);
 
 #ifdef __x86_64__
 void set_efer(struct kvm_vcpu *vcpu, u64 efer);
 #endif
 
+void fx_init(struct kvm_vcpu *vcpu);
 
 void load_msrs(struct vmx_msr_entry *e, int n);
 void save_msrs(struct vmx_msr_entry *e, int n);
@@ -348,6 +365,12 @@ int kvm_write_guest(struct kvm_vcpu *vcp
 void vmcs_writel(unsigned long field, unsigned long value);
 unsigned long vmcs_readl(unsigned long field);
 
+static inline struct page *_gfn_to_page(struct kvm *kvm, gfn_t gfn)
+{
+	struct kvm_memory_slot *slot = gfn_to_memslot(kvm, gfn);
+	return (slot) ? slot->phys_mem[gfn - slot->base_gfn] : 0;
+}
+
 static inline u16 vmcs_read16(unsigned long field)
 {
 	return vmcs_readl(field);
@@ -465,6 +488,11 @@ static inline void load_ldt(u16 sel)
 }
 #endif
 
+static inline void get_idt(struct descriptor_table *table)
+{
+	asm ("sidt %0" : "=m"(*table));
+}
+
 #ifdef __x86_64__
 static inline unsigned long read_msr(unsigned long msr)
 {
@@ -490,6 +518,11 @@ static inline void fpu_init(void)
 	asm ("finit");
 }
 
+static inline u32 get_rdx_init_val(void)
+{
+	return 0x600; /* P6 family */
+}
+
 #define ASM_VMX_VMCLEAR_RAX       ".byte 0x66, 0x0f, 0xc7, 0x30"
 #define ASM_VMX_VMLAUNCH          ".byte 0x0f, 0x01, 0xc2"
 #define ASM_VMX_VMRESUME          ".byte 0x0f, 0x01, 0xc3"
@@ -502,6 +535,12 @@ static inline void fpu_init(void)
 
 #define MSR_IA32_TIME_STAMP_COUNTER		0x010
 
+#define TSS_IOPB_BASE_OFFSET 0x66
+#define TSS_BASE_SIZE 0x68
+#define TSS_IOPB_SIZE (65536 / 8)
+#define TSS_REDIRECTION_SIZE (256 / 8)
+#define RMODE_TSS_SIZE (TSS_BASE_SIZE + TSS_REDIRECTION_SIZE + TSS_IOPB_SIZE + 1)
+
 #ifdef __x86_64__
 
 /*
drivers/kvm/kvm_main.c +14 -322

438 lines not on this page · raw message

drivers/kvm/vmx.c +279 -3

318 lines not on this page · raw message

drivers/kvm/vmx.h +5 -0
Index: linux-2.6/drivers/kvm/vmx.h
===================================================================
@@ -287,5 +287,10 @@ enum vmcs_field {
 #define CR4_VMXE 0x2000
 
 #define MSR_IA32_VMX_BASIC_MSR   		0x480
+#define MSR_IA32_FEATURE_CONTROL 		0x03a
+#define MSR_IA32_VMX_PINBASED_CTLS_MSR		0x481
+#define MSR_IA32_VMX_PROCBASED_CTLS_MSR		0x482
+#define MSR_IA32_VMX_EXIT_CTLS_MSR		0x483
+#define MSR_IA32_VMX_ENTRY_CTLS_MSR		0x484
 
 #endif

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

author
#25 lore raw

PATCH 17/38 KVM: Make __set_cr0() (and dependencies) arch operations

In reply to Avi Kivity
drivers/kvm/kvm.h +3 -2
Index: linux-2.6/drivers/kvm/kvm.h
===================================================================
@@ -269,6 +269,7 @@ struct kvm_arch_ops {
 			    struct kvm_segment *var, int seg);
 	void (*set_segment)(struct kvm_vcpu *vcpu,
 			    struct kvm_segment *var, int seg);
+	void (*set_cr0)(struct kvm_vcpu *vcpu, unsigned long cr0);
 	void (*get_idt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
 	void (*set_idt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
 	void (*get_gdt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
@@ -279,6 +280,8 @@ struct kvm_arch_ops {
 	int (*run)(struct kvm_vcpu *vcpu, struct kvm_run *run);
 	int (*vcpu_setup)(struct kvm_vcpu *vcpu);
 	void (*skip_emulated_instruction)(struct kvm_vcpu *vcpu);
+
+	void (*update_exception_bitmap)(struct kvm_vcpu *vcpu); /* hack */
 };
 
 extern struct kvm_stat kvm_stat;
@@ -336,10 +339,8 @@ void set_cr8(struct kvm_vcpu *vcpu, unsi
 void lmsw(struct kvm_vcpu *vcpu, unsigned long msw);
 
 void __set_efer(struct kvm_vcpu *vcpu, u64 efer);
-void __set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
 void __set_cr4(struct kvm_vcpu *vcpu, unsigned long cr0);
 
-int rmode_tss_base(struct kvm* kvm); /* temporary hack */
 void inject_gp(struct kvm_vcpu *vcpu);
 
 #ifdef __x86_64__
drivers/kvm/kvm_main.c +5 -182

219 lines not on this page · raw message

drivers/kvm/vmx.c +175 -1

200 lines not on this page · raw message

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

author
#26 lore raw

PATCH 18/38 KVM: Make __set_cr4() an arch operation

In reply to Avi Kivity
drivers/kvm/kvm.h +1 -1
Index: linux-2.6/drivers/kvm/kvm.h
===================================================================
@@ -270,6 +270,7 @@ struct kvm_arch_ops {
 	void (*set_segment)(struct kvm_vcpu *vcpu,
 			    struct kvm_segment *var, int seg);
 	void (*set_cr0)(struct kvm_vcpu *vcpu, unsigned long cr0);
+	void (*set_cr4)(struct kvm_vcpu *vcpu, unsigned long cr4);
 	void (*get_idt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
 	void (*set_idt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
 	void (*get_gdt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
@@ -339,7 +340,6 @@ void set_cr8(struct kvm_vcpu *vcpu, unsi
 void lmsw(struct kvm_vcpu *vcpu, unsigned long msw);
 
 void __set_efer(struct kvm_vcpu *vcpu, u64 efer);
-void __set_cr4(struct kvm_vcpu *vcpu, unsigned long cr0);
 
 void inject_gp(struct kvm_vcpu *vcpu);
 
drivers/kvm/kvm_main.c +2 -11
Index: linux-2.6/drivers/kvm/kvm_main.c
===================================================================
@@ -645,15 +645,6 @@ void lmsw(struct kvm_vcpu *vcpu, unsigne
 }
 EXPORT_SYMBOL_GPL(lmsw);
 
-void __set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
-{
-	vmcs_writel(CR4_READ_SHADOW, cr4);
-	vmcs_writel(GUEST_CR4, cr4 | (vcpu->rmode.active ?
-		    KVM_RMODE_VM_CR4_ALWAYS_ON : KVM_PMODE_VM_CR4_ALWAYS_ON));
-	vcpu->cr4 = cr4;
-}
-EXPORT_SYMBOL_GPL(__set_cr4);
-
 void set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
 {
 	if (cr4 & CR4_RESEVED_BITS) {
@@ -680,7 +671,7 @@ void set_cr4(struct kvm_vcpu *vcpu, unsi
 		inject_gp(vcpu);
 		return;
 	}
-	__set_cr4(vcpu, cr4);
+	kvm_arch_ops->set_cr4(vcpu, cr4);
 	spin_lock(&vcpu->kvm->lock);
 	kvm_mmu_reset_context(vcpu);
 	spin_unlock(&vcpu->kvm->lock);
@@ -1624,7 +1615,7 @@ static int kvm_dev_ioctl_set_sregs(struc
 	vcpu->cr0 = sregs->cr0;
 
 	mmu_reset_needed |= vcpu->cr4 != sregs->cr4;
-	__set_cr4(vcpu, sregs->cr4);
+	kvm_arch_ops->set_cr4(vcpu, sregs->cr4);
 
 	if (mmu_reset_needed)
 		kvm_mmu_reset_context(vcpu);
drivers/kvm/vmx.c +10 -1
Index: linux-2.6/drivers/kvm/vmx.c
===================================================================
@@ -545,6 +545,14 @@ static void vmx_set_cr0(struct kvm_vcpu 
 	vcpu->cr0 = cr0;
 }
 
+static void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
+{
+	vmcs_writel(CR4_READ_SHADOW, cr4);
+	vmcs_writel(GUEST_CR4, cr4 | (vcpu->rmode.active ?
+		    KVM_RMODE_VM_CR4_ALWAYS_ON : KVM_PMODE_VM_CR4_ALWAYS_ON));
+	vcpu->cr4 = cr4;
+}
+
 static u64 vmx_get_segment_base(struct kvm_vcpu *vcpu, int seg)
 {
 	struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
@@ -872,7 +880,7 @@ static int vmx_vcpu_setup(struct kvm_vcp
 
 	vcpu->cr0 = 0x60000010;
 	vmx_set_cr0(vcpu, vcpu->cr0); // enter rmode
-	__set_cr4(vcpu, 0);
+	vmx_set_cr4(vcpu, 0);
 #ifdef __x86_64__
 	__set_efer(vcpu, 0);
 #endif
@@ -1597,6 +1605,7 @@ static struct kvm_arch_ops vmx_arch_ops 
 	.get_segment = vmx_get_segment,
 	.set_segment = vmx_set_segment,
 	.set_cr0 = vmx_set_cr0,
+	.set_cr4 = vmx_set_cr4,
 	.get_idt = vmx_get_idt,
 	.set_idt = vmx_set_idt,
 	.get_gdt = vmx_get_gdt,

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

author
#27 lore raw

PATCH 19/38 KVM: Make __set_efer() an arch operation

In reply to Avi Kivity
drivers/kvm/kvm.h +1 -2
Index: linux-2.6/drivers/kvm/kvm.h
===================================================================
@@ -271,6 +271,7 @@ struct kvm_arch_ops {
 			    struct kvm_segment *var, int seg);
 	void (*set_cr0)(struct kvm_vcpu *vcpu, unsigned long cr0);
 	void (*set_cr4)(struct kvm_vcpu *vcpu, unsigned long cr4);
+	void (*set_efer)(struct kvm_vcpu *vcpu, u64 efer);
 	void (*get_idt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
 	void (*set_idt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
 	void (*get_gdt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
@@ -339,8 +340,6 @@ void set_cr4(struct kvm_vcpu *vcpu, unsi
 void set_cr8(struct kvm_vcpu *vcpu, unsigned long cr0);
 void lmsw(struct kvm_vcpu *vcpu, unsigned long msw);
 
-void __set_efer(struct kvm_vcpu *vcpu, u64 efer);
-
 void inject_gp(struct kvm_vcpu *vcpu);
 
 #ifdef __x86_64__
drivers/kvm/kvm_main.c +1 -26
Index: linux-2.6/drivers/kvm/kvm_main.c
===================================================================
@@ -525,31 +525,6 @@ void guest_write_tsc(u64 guest_tsc)
 }
 EXPORT_SYMBOL_GPL(guest_write_tsc);
 
-#ifdef __x86_64__
-
-void __set_efer(struct kvm_vcpu *vcpu, u64 efer)
-{
-	struct vmx_msr_entry *msr = find_msr_entry(vcpu, MSR_EFER);
-
-	vcpu->shadow_efer = efer;
-	if (efer & EFER_LMA) {
-		vmcs_write32(VM_ENTRY_CONTROLS,
-				     vmcs_read32(VM_ENTRY_CONTROLS) |
-				     VM_ENTRY_CONTROLS_IA32E_MASK);
-		msr->data = efer;
-
-	} else {
-		vmcs_write32(VM_ENTRY_CONTROLS,
-				     vmcs_read32(VM_ENTRY_CONTROLS) &
-				     ~VM_ENTRY_CONTROLS_IA32E_MASK);
-
-		msr->data = efer & ~EFER_LME;
-	}
-}
-EXPORT_SYMBOL_GPL(__set_efer);
-
-#endif
-
 static int pdptrs_have_reserved_bits_set(struct kvm_vcpu *vcpu,
 					 unsigned long cr3)
 {
@@ -1602,7 +1577,7 @@ static int kvm_dev_ioctl_set_sregs(struc
 
 	mmu_reset_needed |= vcpu->shadow_efer != sregs->efer;
 #ifdef __x86_64__
-	__set_efer(vcpu, sregs->efer);
+	kvm_arch_ops->set_efer(vcpu, sregs->efer);
 #endif
 	vcpu->apic_base = sregs->apic_base;
 
drivers/kvm/vmx.c +26 -1
Index: linux-2.6/drivers/kvm/vmx.c
===================================================================
@@ -553,6 +553,30 @@ static void vmx_set_cr4(struct kvm_vcpu 
 	vcpu->cr4 = cr4;
 }
 
+#ifdef __x86_64__
+
+static void vmx_set_efer(struct kvm_vcpu *vcpu, u64 efer)
+{
+	struct vmx_msr_entry *msr = find_msr_entry(vcpu, MSR_EFER);
+
+	vcpu->shadow_efer = efer;
+	if (efer & EFER_LMA) {
+		vmcs_write32(VM_ENTRY_CONTROLS,
+				     vmcs_read32(VM_ENTRY_CONTROLS) |
+				     VM_ENTRY_CONTROLS_IA32E_MASK);
+		msr->data = efer;
+
+	} else {
+		vmcs_write32(VM_ENTRY_CONTROLS,
+				     vmcs_read32(VM_ENTRY_CONTROLS) &
+				     ~VM_ENTRY_CONTROLS_IA32E_MASK);
+
+		msr->data = efer & ~EFER_LME;
+	}
+}
+
+#endif
+
 static u64 vmx_get_segment_base(struct kvm_vcpu *vcpu, int seg)
 {
 	struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
@@ -882,7 +906,7 @@ static int vmx_vcpu_setup(struct kvm_vcp
 	vmx_set_cr0(vcpu, vcpu->cr0); // enter rmode
 	vmx_set_cr4(vcpu, 0);
 #ifdef __x86_64__
-	__set_efer(vcpu, 0);
+	vmx_set_efer(vcpu, 0);
 #endif
 
 	return 0;
@@ -1606,6 +1630,7 @@ static struct kvm_arch_ops vmx_arch_ops 
 	.set_segment = vmx_set_segment,
 	.set_cr0 = vmx_set_cr0,
 	.set_cr4 = vmx_set_cr4,
+	.set_efer = vmx_set_efer,
 	.get_idt = vmx_get_idt,
 	.set_idt = vmx_set_idt,
 	.get_gdt = vmx_get_gdt,

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

#28 lore raw

Re: [PATCH 19/38] KVM: Make __set_efer() an arch operation

drivers/kvm/kvm_main.c static int kvm_dev_ioctl_set_sregs(struc · line 1581

Quoted 4 lines · Avi Kivity

#ifdef __x86_64__

drivers/kvm/kvm_main.c +1 -1
-	__set_efer(vcpu, sregs->efer);
+	kvm_arch_ops->set_efer(vcpu, sregs->efer);
 #endif

I think it would be much better to make ->set_efer a noop for 32bit, and have different operation vectors for 32 vs 64 bit.

drivers/kvm/vmx.c static int vmx_vcpu_setup(struct kvm_vcp · line 910

Quoted 4 lines

#ifdef __x86_64__

drivers/kvm/vmx.c +1 -1
-	__set_efer(vcpu, 0);
+	vmx_set_efer(vcpu, 0);
 #endif

Similarly vmx_set_efer should just become a noop on 32bit.

author
#29 lore raw

Re: [PATCH 19/38] KVM: Make __set_efer() an arch operation

Quoted 12 lines · Christoph Hellwig

drivers/kvm/kvm_main.c static int kvm_dev_ioctl_set_sregs(struc · line 1581

Quoted 5 lines · Avi Kivity

#ifdef __x86_64__

drivers/kvm/kvm_main.c +1 -1
-	__set_efer(vcpu, sregs->efer);
+	kvm_arch_ops->set_efer(vcpu, sregs->efer);
 #endif

I think it would be much better to make ->set_efer a noop for 32bit, and have different operation vectors for 32 vs 64 bit.

Okay. I'll submit an incremental patch as part of a larger cleanup I'm planning.

Quoted 8 lines

drivers/kvm/vmx.c static int vmx_vcpu_setup(struct kvm_vcp · line 910

Quoted 5 lines

#ifdef __x86_64__

drivers/kvm/vmx.c +1 -1
-	__set_efer(vcpu, 0);
+	vmx_set_efer(vcpu, 0);
 #endif

Similarly vmx_set_efer should just become a noop on 32bit.

Ok.

Signature · 8 lines
error compiling committee.c: too many arguments to function


-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
author
#30 lore raw

PATCH 20/38 KVM: Make set_cr3() and tlb flushing arch operations

In reply to Avi Kivity
drivers/kvm/kvm.h +3 -0
Index: linux-2.6/drivers/kvm/kvm.h
===================================================================
@@ -270,6 +270,7 @@ struct kvm_arch_ops {
 	void (*set_segment)(struct kvm_vcpu *vcpu,
 			    struct kvm_segment *var, int seg);
 	void (*set_cr0)(struct kvm_vcpu *vcpu, unsigned long cr0);
+	void (*set_cr3)(struct kvm_vcpu *vcpu, unsigned long cr3);
 	void (*set_cr4)(struct kvm_vcpu *vcpu, unsigned long cr4);
 	void (*set_efer)(struct kvm_vcpu *vcpu, u64 efer);
 	void (*get_idt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
@@ -279,6 +280,8 @@ struct kvm_arch_ops {
 	void (*cache_regs)(struct kvm_vcpu *vcpu);
 	void (*decache_regs)(struct kvm_vcpu *vcpu);
 
+	void (*flush_tlb)(struct kvm_vcpu *vcpu);
+
 	int (*run)(struct kvm_vcpu *vcpu, struct kvm_run *run);
 	int (*vcpu_setup)(struct kvm_vcpu *vcpu);
 	void (*skip_emulated_instruction)(struct kvm_vcpu *vcpu);
drivers/kvm/mmu.c +5 -7
Index: linux-2.6/drivers/kvm/mmu.c
===================================================================
@@ -323,7 +323,7 @@ static void nonpaging_flush(struct kvm_v
 	vcpu->mmu.root_hpa = root;
 	if (is_paging(vcpu))
 		root |= (vcpu->cr3 & (CR3_PCD_MASK | CR3_WPT_MASK));
-	vmcs_writel(GUEST_CR3, root);
+	kvm_arch_ops->set_cr3(vcpu, root);
 }
 
 static gpa_t nonpaging_gva_to_gpa(struct kvm_vcpu *vcpu, gva_t vaddr)
@@ -386,7 +386,7 @@ static int nonpaging_init_context(struct
 	context->shadow_root_level = PT32E_ROOT_LEVEL;
 	context->root_hpa = kvm_mmu_alloc_page(vcpu, 0);
 	ASSERT(VALID_PAGE(context->root_hpa));
-	vmcs_writel(GUEST_CR3, context->root_hpa);
+	kvm_arch_ops->set_cr3(vcpu, context->root_hpa);
 	return 0;
 }
 
@@ -539,9 +539,7 @@ static void paging_inval_page(struct kvm
 			table[index] = 0;
 			release_pt_page_64(vcpu, page_addr, PT_PAGE_TABLE_LEVEL);
 
-			//flush tlb
-			vmcs_writel(GUEST_CR3, vcpu->mmu.root_hpa |
-				    (vcpu->cr3 & (CR3_PCD_MASK | CR3_WPT_MASK)));
+			kvm_arch_ops->flush_tlb(vcpu);
 			return;
 		}
 	}
@@ -574,7 +572,7 @@ static int paging64_init_context(struct 
 	context->shadow_root_level = PT64_ROOT_LEVEL;
 	context->root_hpa = kvm_mmu_alloc_page(vcpu, 0);
 	ASSERT(VALID_PAGE(context->root_hpa));
-	vmcs_writel(GUEST_CR3, context->root_hpa |
+	kvm_arch_ops->set_cr3(vcpu, context->root_hpa |
 		    (vcpu->cr3 & (CR3_PCD_MASK | CR3_WPT_MASK)));
 	return 0;
 }
@@ -592,7 +590,7 @@ static int paging32_init_context(struct 
 	context->shadow_root_level = PT32E_ROOT_LEVEL;
 	context->root_hpa = kvm_mmu_alloc_page(vcpu, 0);
 	ASSERT(VALID_PAGE(context->root_hpa));
-	vmcs_writel(GUEST_CR3, context->root_hpa |
+	kvm_arch_ops->set_cr3(vcpu, context->root_hpa |
 		    (vcpu->cr3 & (CR3_PCD_MASK | CR3_WPT_MASK)));
 	return 0;
 }
drivers/kvm/vmx.c +13 -0
Index: linux-2.6/drivers/kvm/vmx.c
===================================================================
@@ -545,6 +545,11 @@ static void vmx_set_cr0(struct kvm_vcpu 
 	vcpu->cr0 = cr0;
 }
 
+static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
+{
+	vmcs_writel(GUEST_CR3, cr3);
+}
+
 static void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
 {
 	vmcs_writel(CR4_READ_SHADOW, cr4);
@@ -1614,6 +1619,11 @@ again:
 	return 0;
 }
 
+static void vmx_flush_tlb(struct kvm_vcpu *vcpu)
+{
+	vmcs_writel(GUEST_CR3, vmcs_readl(GUEST_CR3));
+}
+
 static struct kvm_arch_ops vmx_arch_ops = {
 	.cpu_has_kvm_support = cpu_has_kvm_support,
 	.disabled_by_bios = vmx_disabled_by_bios,
@@ -1629,6 +1639,7 @@ static struct kvm_arch_ops vmx_arch_ops 
 	.get_segment = vmx_get_segment,
 	.set_segment = vmx_set_segment,
 	.set_cr0 = vmx_set_cr0,
+	.set_cr3 = vmx_set_cr3,
 	.set_cr4 = vmx_set_cr4,
 	.set_efer = vmx_set_efer,
 	.get_idt = vmx_get_idt,
@@ -1638,6 +1649,8 @@ static struct kvm_arch_ops vmx_arch_ops 
 	.cache_regs = vcpu_load_rsp_rip,
 	.decache_regs = vcpu_put_rsp_rip,
 
+	.flush_tlb = vmx_flush_tlb,
+
 	.run = vmx_vcpu_run,
 	.skip_emulated_instruction = skip_emulated_instruction,
 	.vcpu_setup = vmx_vcpu_setup,

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

author
#31 lore raw

PATCH 21/38 KVM: Make inject_page_fault() an arch operation

In reply to Avi Kivity
drivers/kvm/kvm.h +2 -0
Index: linux-2.6/drivers/kvm/kvm.h
===================================================================
@@ -281,6 +281,8 @@ struct kvm_arch_ops {
 	void (*decache_regs)(struct kvm_vcpu *vcpu);
 
 	void (*flush_tlb)(struct kvm_vcpu *vcpu);
+	void (*inject_page_fault)(struct kvm_vcpu *vcpu,
+				  unsigned long addr, u32 err_code);
 
 	int (*run)(struct kvm_vcpu *vcpu, struct kvm_run *run);
 	int (*vcpu_setup)(struct kvm_vcpu *vcpu);
drivers/kvm/mmu.c +1 -26
Index: linux-2.6/drivers/kvm/mmu.c
===================================================================
@@ -455,32 +455,7 @@ static void inject_page_fault(struct kvm
 			      u64 addr,
 			      u32 err_code)
 {
-	u32 vect_info = vmcs_read32(IDT_VECTORING_INFO_FIELD);
-
-	pgprintk("inject_page_fault: 0x%llx err 0x%x\n", addr, err_code);
-
-	++kvm_stat.pf_guest;
-
-	if (is_page_fault(vect_info)) {
-		printk(KERN_DEBUG "inject_page_fault: "
-		       "double fault 0x%llx @ 0x%lx\n",
-		       addr, vmcs_readl(GUEST_RIP));
-		vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, 0);
-		vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
-			     DF_VECTOR |
-			     INTR_TYPE_EXCEPTION |
-			     INTR_INFO_DELIEVER_CODE_MASK |
-			     INTR_INFO_VALID_MASK);
-		return;
-	}
-	vcpu->cr2 = addr;
-	vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, err_code);
-	vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
-		     PF_VECTOR |
-		     INTR_TYPE_EXCEPTION |
-		     INTR_INFO_DELIEVER_CODE_MASK |
-		     INTR_INFO_VALID_MASK);
-
+	kvm_arch_ops->inject_page_fault(vcpu, addr, err_code);
 }
 
 static inline int fix_read_pf(u64 *shadow_ent)
drivers/kvm/vmx.c +31 -0
Index: linux-2.6/drivers/kvm/vmx.c
===================================================================
@@ -1624,6 +1624,36 @@ static void vmx_flush_tlb(struct kvm_vcp
 	vmcs_writel(GUEST_CR3, vmcs_readl(GUEST_CR3));
 }
 
+static void vmx_inject_page_fault(struct kvm_vcpu *vcpu,
+				  unsigned long addr,
+				  u32 err_code)
+{
+	u32 vect_info = vmcs_read32(IDT_VECTORING_INFO_FIELD);
+
+	++kvm_stat.pf_guest;
+
+	if (is_page_fault(vect_info)) {
+		printk(KERN_DEBUG "inject_page_fault: "
+		       "double fault 0x%lx @ 0x%lx\n",
+		       addr, vmcs_readl(GUEST_RIP));
+		vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, 0);
+		vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
+			     DF_VECTOR |
+			     INTR_TYPE_EXCEPTION |
+			     INTR_INFO_DELIEVER_CODE_MASK |
+			     INTR_INFO_VALID_MASK);
+		return;
+	}
+	vcpu->cr2 = addr;
+	vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, err_code);
+	vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
+		     PF_VECTOR |
+		     INTR_TYPE_EXCEPTION |
+		     INTR_INFO_DELIEVER_CODE_MASK |
+		     INTR_INFO_VALID_MASK);
+
+}
+
 static struct kvm_arch_ops vmx_arch_ops = {
 	.cpu_has_kvm_support = cpu_has_kvm_support,
 	.disabled_by_bios = vmx_disabled_by_bios,
@@ -1650,6 +1680,7 @@ static struct kvm_arch_ops vmx_arch_ops 
 	.decache_regs = vcpu_put_rsp_rip,
 
 	.flush_tlb = vmx_flush_tlb,
+	.inject_page_fault = vmx_inject_page_fault,
 
 	.run = vmx_vcpu_run,
 	.skip_emulated_instruction = skip_emulated_instruction,

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

author
#32 lore raw

PATCH 22/38 KVM: Make inject_gp() an arch operation

In reply to Avi Kivity
drivers/kvm/kvm.h +2 -2
Index: linux-2.6/drivers/kvm/kvm.h
===================================================================
@@ -284,6 +284,8 @@ struct kvm_arch_ops {
 	void (*inject_page_fault)(struct kvm_vcpu *vcpu,
 				  unsigned long addr, u32 err_code);
 
+	void (*inject_gp)(struct kvm_vcpu *vcpu, unsigned err_code);
+
 	int (*run)(struct kvm_vcpu *vcpu, struct kvm_run *run);
 	int (*vcpu_setup)(struct kvm_vcpu *vcpu);
 	void (*skip_emulated_instruction)(struct kvm_vcpu *vcpu);
@@ -345,8 +347,6 @@ void set_cr4(struct kvm_vcpu *vcpu, unsi
 void set_cr8(struct kvm_vcpu *vcpu, unsigned long cr0);
 void lmsw(struct kvm_vcpu *vcpu, unsigned long msw);
 
-void inject_gp(struct kvm_vcpu *vcpu);
-
 #ifdef __x86_64__
 void set_efer(struct kvm_vcpu *vcpu, u64 efer);
 #endif
drivers/kvm/kvm_main.c +2 -10
Index: linux-2.6/drivers/kvm/kvm_main.c
===================================================================
@@ -485,18 +485,10 @@ void vmcs_writel(unsigned long field, un
 }
 EXPORT_SYMBOL_GPL(vmcs_writel);
 
-void inject_gp(struct kvm_vcpu *vcpu)
+static void inject_gp(struct kvm_vcpu *vcpu)
 {
-	printk(KERN_DEBUG "inject_general_protection: rip 0x%lx\n",
-	       vmcs_readl(GUEST_RIP));
-	vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, 0);
-	vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
-		     GP_VECTOR |
-		     INTR_TYPE_EXCEPTION |
-		     INTR_INFO_DELIEVER_CODE_MASK |
-		     INTR_INFO_VALID_MASK);
+	kvm_arch_ops->inject_gp(vcpu, 0);
 }
-EXPORT_SYMBOL_GPL(inject_gp);
 
 /*
  * reads and returns guest's timestamp counter "register"
drivers/kvm/vmx.c +16 -2
Index: linux-2.6/drivers/kvm/vmx.c
===================================================================
@@ -80,6 +80,18 @@ static void skip_emulated_instruction(st
 			     interruptibility & ~3);
 }
 
+static void vmx_inject_gp(struct kvm_vcpu *vcpu, unsigned error_code)
+{
+	printk(KERN_DEBUG "inject_general_protection: rip 0x%lx\n",
+	       vmcs_readl(GUEST_RIP));
+	vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, error_code);
+	vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
+		     GP_VECTOR |
+		     INTR_TYPE_EXCEPTION |
+		     INTR_INFO_DELIEVER_CODE_MASK |
+		     INTR_INFO_VALID_MASK);
+}
+
 static void reload_tss(void)
 {
 #ifndef __x86_64__
@@ -1318,7 +1330,7 @@ static int handle_rdmsr(struct kvm_vcpu 
 	u64 data;
 
 	if (vmx_get_msr(vcpu, ecx, &data)) {
-		inject_gp(vcpu);
+		vmx_inject_gp(vcpu, 0);
 		return 1;
 	}
 
@@ -1336,7 +1348,7 @@ static int handle_wrmsr(struct kvm_vcpu 
 		| ((u64)(vcpu->regs[VCPU_REGS_RDX] & -1u) << 32);
 
 	if (vmx_set_msr(vcpu, ecx, data) != 0) {
-		inject_gp(vcpu);
+		vmx_inject_gp(vcpu, 0);
 		return 1;
 	}
 
@@ -1682,6 +1694,8 @@ static struct kvm_arch_ops vmx_arch_ops 
 	.flush_tlb = vmx_flush_tlb,
 	.inject_page_fault = vmx_inject_page_fault,
 
+	.inject_gp = vmx_inject_gp,
+
 	.run = vmx_vcpu_run,
 	.skip_emulated_instruction = skip_emulated_instruction,
 	.vcpu_setup = vmx_vcpu_setup,

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

author
#33 lore raw

PATCH 23/38 KVM: Use the idt and gdt accessors in realmode emulation

In reply to Avi Kivity
drivers/kvm/kvm_main.c +6 -4
Index: linux-2.6/drivers/kvm/kvm_main.c
===================================================================
@@ -1225,14 +1225,16 @@ static u64 mk_cr_64(u64 curr_cr, u32 new
 
 void realmode_lgdt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base)
 {
-	vmcs_writel(GUEST_GDTR_BASE, base);
-	vmcs_write32(GUEST_GDTR_LIMIT, limit);
+	struct descriptor_table dt = { limit, base };
+
+	kvm_arch_ops->set_gdt(vcpu, &dt);
 }
 
 void realmode_lidt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base)
 {
-	vmcs_writel(GUEST_IDTR_BASE, base);
-	vmcs_write32(GUEST_IDTR_LIMIT, limit);
+	struct descriptor_table dt = { limit, base };
+
+	kvm_arch_ops->set_idt(vcpu, &dt);
 }
 
 void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

author
#34 lore raw

PATCH 24/38 KVM: Use the general purpose register accessors rather than direct access

In reply to Avi Kivity
drivers/kvm/kvm_main.c +9 -5
Index: linux-2.6/drivers/kvm/kvm_main.c
===================================================================
@@ -1130,7 +1130,7 @@ static void report_emulation_failure(str
 {
 	static int reported;
 	u8 opcodes[4];
-	unsigned long rip = vmcs_readl(GUEST_RIP);
+	unsigned long rip = ctxt->vcpu->rip;
 	unsigned long rip_linear;
 
 	rip_linear = rip + get_segment_base(ctxt->vcpu, VCPU_SREG_CS);
@@ -1406,13 +1406,15 @@ static int kvm_dev_ioctl_get_regs(struct
 	if (!vcpu)
 		return -ENOENT;
 
+	kvm_arch_ops->cache_regs(vcpu);
+
 	regs->rax = vcpu->regs[VCPU_REGS_RAX];
 	regs->rbx = vcpu->regs[VCPU_REGS_RBX];
 	regs->rcx = vcpu->regs[VCPU_REGS_RCX];
 	regs->rdx = vcpu->regs[VCPU_REGS_RDX];
 	regs->rsi = vcpu->regs[VCPU_REGS_RSI];
 	regs->rdi = vcpu->regs[VCPU_REGS_RDI];
-	regs->rsp = vmcs_readl(GUEST_RSP);
+	regs->rsp = vcpu->regs[VCPU_REGS_RSP];
 	regs->rbp = vcpu->regs[VCPU_REGS_RBP];
 #ifdef __x86_64__
 	regs->r8 = vcpu->regs[VCPU_REGS_R8];
@@ -1425,7 +1427,7 @@ static int kvm_dev_ioctl_get_regs(struct
 	regs->r15 = vcpu->regs[VCPU_REGS_R15];
 #endif
 
-	regs->rip = vmcs_readl(GUEST_RIP);
+	regs->rip = vcpu->rip;
 	regs->rflags = vmcs_readl(GUEST_RFLAGS);
 
 	/*
@@ -1456,7 +1458,7 @@ static int kvm_dev_ioctl_set_regs(struct
 	vcpu->regs[VCPU_REGS_RDX] = regs->rdx;
 	vcpu->regs[VCPU_REGS_RSI] = regs->rsi;
 	vcpu->regs[VCPU_REGS_RDI] = regs->rdi;
-	vmcs_writel(GUEST_RSP, regs->rsp);
+	vcpu->regs[VCPU_REGS_RSP] = regs->rsp;
 	vcpu->regs[VCPU_REGS_RBP] = regs->rbp;
 #ifdef __x86_64__
 	vcpu->regs[VCPU_REGS_R8] = regs->r8;
@@ -1469,9 +1471,11 @@ static int kvm_dev_ioctl_set_regs(struct
 	vcpu->regs[VCPU_REGS_R15] = regs->r15;
 #endif
 
-	vmcs_writel(GUEST_RIP, regs->rip);
+	vcpu->rip = regs->rip;
 	vmcs_writel(GUEST_RFLAGS, regs->rflags);
 
+	kvm_arch_ops->decache_regs(vcpu);
+
 	vcpu_put(vcpu);
 
 	return 0;

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

author
#35 lore raw

PATCH 25/38 KVM: Move the vmx tsc accessors to vmx.c

In reply to Avi Kivity
drivers/kvm/kvm_main.c +0 -27
Index: linux-2.6/drivers/kvm/kvm_main.c
===================================================================
@@ -490,33 +490,6 @@ static void inject_gp(struct kvm_vcpu *v
 	kvm_arch_ops->inject_gp(vcpu, 0);
 }
 
-/*
- * reads and returns guest's timestamp counter "register"
- * guest_tsc = host_tsc + tsc_offset    -- 21.3
- */
-u64 guest_read_tsc(void)
-{
-	u64 host_tsc, tsc_offset;
-
-	rdtscll(host_tsc);
-	tsc_offset = vmcs_read64(TSC_OFFSET);
-	return host_tsc + tsc_offset;
-}
-EXPORT_SYMBOL_GPL(guest_read_tsc);
-
-/*
- * writes 'guest_tsc' into guest's timestamp counter "register"
- * guest_tsc = host_tsc + tsc_offset ==> tsc_offset = guest_tsc - host_tsc
- */
-void guest_write_tsc(u64 guest_tsc)
-{
-	u64 host_tsc;
-
-	rdtscll(host_tsc);
-	vmcs_write64(TSC_OFFSET, guest_tsc - host_tsc);
-}
-EXPORT_SYMBOL_GPL(guest_write_tsc);
-
 static int pdptrs_have_reserved_bits_set(struct kvm_vcpu *vcpu,
 					 unsigned long cr3)
 {
drivers/kvm/vmx.c +25 -2
Index: linux-2.6/drivers/kvm/vmx.c
===================================================================
@@ -57,8 +57,6 @@ static const u32 vmx_msr_index[] = {
 };
 #define NR_VMX_MSR (sizeof(vmx_msr_index) / sizeof(*vmx_msr_index))
 
-u64 guest_read_tsc(void);
-void guest_write_tsc(u64 guest_tsc);
 struct vmx_msr_entry *find_msr_entry(struct kvm_vcpu *vcpu, u32 msr);
 
 static void skip_emulated_instruction(struct kvm_vcpu *vcpu)
@@ -92,6 +90,31 @@ static void vmx_inject_gp(struct kvm_vcp
 		     INTR_INFO_VALID_MASK);
 }
 
+/*
+ * reads and returns guest's timestamp counter "register"
+ * guest_tsc = host_tsc + tsc_offset    -- 21.3
+ */
+static u64 guest_read_tsc(void)
+{
+	u64 host_tsc, tsc_offset;
+
+	rdtscll(host_tsc);
+	tsc_offset = vmcs_read64(TSC_OFFSET);
+	return host_tsc + tsc_offset;
+}
+
+/*
+ * writes 'guest_tsc' into guest's timestamp counter "register"
+ * guest_tsc = host_tsc + tsc_offset ==> tsc_offset = guest_tsc - host_tsc
+ */
+static void guest_write_tsc(u64 guest_tsc)
+{
+	u64 host_tsc;
+
+	rdtscll(host_tsc);
+	vmcs_write64(TSC_OFFSET, guest_tsc - host_tsc);
+}
+
 static void reload_tss(void)
 {
 #ifndef __x86_64__

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

author
#36 lore raw

PATCH 26/38 KVM: Access rflags through an arch operation

In reply to Avi Kivity
drivers/kvm/kvm.h +2 -0
Index: linux-2.6/drivers/kvm/kvm.h
===================================================================
@@ -279,6 +279,8 @@ struct kvm_arch_ops {
 	void (*set_gdt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
 	void (*cache_regs)(struct kvm_vcpu *vcpu);
 	void (*decache_regs)(struct kvm_vcpu *vcpu);
+	unsigned long (*get_rflags)(struct kvm_vcpu *vcpu);
+	void (*set_rflags)(struct kvm_vcpu *vcpu, unsigned long rflags);
 
 	void (*flush_tlb)(struct kvm_vcpu *vcpu);
 	void (*inject_page_fault)(struct kvm_vcpu *vcpu,
drivers/kvm/kvm_main.c +6 -6
Index: linux-2.6/drivers/kvm/kvm_main.c
===================================================================
@@ -1141,7 +1141,7 @@ int emulate_instruction(struct kvm_vcpu 
 	cs_ar = vmcs_read32(GUEST_CS_AR_BYTES);
 
 	emulate_ctxt.vcpu = vcpu;
-	emulate_ctxt.eflags = vmcs_readl(GUEST_RFLAGS);
+	emulate_ctxt.eflags = kvm_arch_ops->get_rflags(vcpu);
 	emulate_ctxt.cr2 = cr2;
 	emulate_ctxt.mode = (emulate_ctxt.eflags & X86_EFLAGS_VM)
 		? X86EMUL_MODE_REAL : (cs_ar & AR_L_MASK)
@@ -1182,7 +1182,7 @@ int emulate_instruction(struct kvm_vcpu 
 	}
 
 	kvm_arch_ops->decache_regs(vcpu);
-	vmcs_writel(GUEST_RFLAGS, emulate_ctxt.eflags);
+	kvm_arch_ops->set_rflags(vcpu, emulate_ctxt.eflags);
 
 	if (vcpu->mmio_is_write)
 		return EMULATE_DO_MMIO;
@@ -1214,7 +1214,7 @@ void realmode_lmsw(struct kvm_vcpu *vcpu
 		   unsigned long *rflags)
 {
 	lmsw(vcpu, msw);
-	*rflags = vmcs_readl(GUEST_RFLAGS);
+	*rflags = kvm_arch_ops->get_rflags(vcpu);
 }
 
 unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr)
@@ -1240,7 +1240,7 @@ void realmode_set_cr(struct kvm_vcpu *vc
 	switch (cr) {
 	case 0:
 		set_cr0(vcpu, mk_cr_64(vcpu->cr0, val));
-		*rflags = vmcs_readl(GUEST_RFLAGS);
+		*rflags = kvm_arch_ops->get_rflags(vcpu);
 		break;
 	case 2:
 		vcpu->cr2 = val;
@@ -1401,7 +1401,7 @@ static int kvm_dev_ioctl_get_regs(struct
 #endif
 
 	regs->rip = vcpu->rip;
-	regs->rflags = vmcs_readl(GUEST_RFLAGS);
+	regs->rflags = kvm_arch_ops->get_rflags(vcpu);
 
 	/*
 	 * Don't leak debug flags in case they were set for guest debugging
@@ -1445,7 +1445,7 @@ static int kvm_dev_ioctl_set_regs(struct
 #endif
 
 	vcpu->rip = regs->rip;
-	vmcs_writel(GUEST_RFLAGS, regs->rflags);
+	kvm_arch_ops->set_rflags(vcpu, regs->rflags);
 
 	kvm_arch_ops->decache_regs(vcpu);
 
drivers/kvm/vmx.c +12 -0
Index: linux-2.6/drivers/kvm/vmx.c
===================================================================
@@ -59,6 +59,16 @@ static const u32 vmx_msr_index[] = {
 
 struct vmx_msr_entry *find_msr_entry(struct kvm_vcpu *vcpu, u32 msr);
 
+static unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu)
+{
+	return vmcs_readl(GUEST_RFLAGS);
+}
+
+static void vmx_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
+{
+	vmcs_writel(GUEST_RFLAGS, rflags);
+}
+
 static void skip_emulated_instruction(struct kvm_vcpu *vcpu)
 {
 	unsigned long rip;
@@ -1713,6 +1723,8 @@ static struct kvm_arch_ops vmx_arch_ops 
 	.set_gdt = vmx_set_gdt,
 	.cache_regs = vcpu_load_rsp_rip,
 	.decache_regs = vcpu_put_rsp_rip,
+	.get_rflags = vmx_get_rflags,
+	.set_rflags = vmx_set_rflags,
 
 	.flush_tlb = vmx_flush_tlb,
 	.inject_page_fault = vmx_inject_page_fault,

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

author
#37 lore raw

PATCH 27/38 KVM: Move the vmx segment field definitions to vmx.c

In reply to Avi Kivity
drivers/kvm/kvm_main.c +0 -25
Index: linux-2.6/drivers/kvm/kvm_main.c
===================================================================
@@ -65,31 +65,6 @@ static struct kvm_stats_debugfs_item {
 
 static struct dentry *debugfs_dir;
 
-#define VMX_SEGMENT_FIELD(seg)					\
-	[VCPU_SREG_##seg] {                                     \
-		GUEST_##seg##_SELECTOR,				\
-		GUEST_##seg##_BASE,			   	\
-		GUEST_##seg##_LIMIT,			   	\
-		GUEST_##seg##_AR_BYTES,			   	\
-	}
-
-struct kvm_vmx_segment_field {
-	unsigned selector;
-	unsigned base;
-	unsigned limit;
-	unsigned ar_bytes;
-} kvm_vmx_segment_fields[] = {
-	VMX_SEGMENT_FIELD(CS),
-	VMX_SEGMENT_FIELD(DS),
-	VMX_SEGMENT_FIELD(ES),
-	VMX_SEGMENT_FIELD(FS),
-	VMX_SEGMENT_FIELD(GS),
-	VMX_SEGMENT_FIELD(SS),
-	VMX_SEGMENT_FIELD(TR),
-	VMX_SEGMENT_FIELD(LDTR),
-};
-EXPORT_SYMBOL_GPL(kvm_vmx_segment_fields);
-
 #define MAX_IO_MSRS 256
 
 #define CR0_RESEVED_BITS 0xffffffff1ffaffc0ULL
drivers/kvm/vmx.c +19 -2
Index: linux-2.6/drivers/kvm/vmx.c
===================================================================
@@ -42,12 +42,29 @@ extern struct vmcs_descriptor {
 	u32 revision_id;
 } vmcs_descriptor;
 
-extern struct kvm_vmx_segment_field {
+#define VMX_SEGMENT_FIELD(seg)					\
+	[VCPU_SREG_##seg] {                                     \
+		GUEST_##seg##_SELECTOR,				\
+		GUEST_##seg##_BASE,			   	\
+		GUEST_##seg##_LIMIT,			   	\
+		GUEST_##seg##_AR_BYTES,			   	\
+	}
+
+static struct kvm_vmx_segment_field {
 	unsigned selector;
 	unsigned base;
 	unsigned limit;
 	unsigned ar_bytes;
-} kvm_vmx_segment_fields[];
+} kvm_vmx_segment_fields[] = {
+	VMX_SEGMENT_FIELD(CS),
+	VMX_SEGMENT_FIELD(DS),
+	VMX_SEGMENT_FIELD(ES),
+	VMX_SEGMENT_FIELD(FS),
+	VMX_SEGMENT_FIELD(GS),
+	VMX_SEGMENT_FIELD(SS),
+	VMX_SEGMENT_FIELD(TR),
+	VMX_SEGMENT_FIELD(LDTR),
+};
 
 static const u32 vmx_msr_index[] = {
 #ifdef __x86_64__

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

author
#38 lore raw

PATCH 28/38 KVM: Add an arch accessor for cs d/b and l bits

In reply to Avi Kivity

These are used for detecting the current processor mode.

drivers/kvm/kvm.h +1 -0
Index: linux-2.6/drivers/kvm/kvm.h
===================================================================
@@ -269,6 +269,7 @@ struct kvm_arch_ops {
 			    struct kvm_segment *var, int seg);
 	void (*set_segment)(struct kvm_vcpu *vcpu,
 			    struct kvm_segment *var, int seg);
+	void (*get_cs_db_l_bits)(struct kvm_vcpu *vcpu, int *db, int *l);
 	void (*set_cr0)(struct kvm_vcpu *vcpu, unsigned long cr0);
 	void (*set_cr3)(struct kvm_vcpu *vcpu, unsigned long cr3);
 	void (*set_cr4)(struct kvm_vcpu *vcpu, unsigned long cr4);
drivers/kvm/kvm_main.c +8 -7
Index: linux-2.6/drivers/kvm/kvm_main.c
===================================================================
@@ -517,15 +517,16 @@ void set_cr0(struct kvm_vcpu *vcpu, unsi
 	if (!is_paging(vcpu) && (cr0 & CR0_PG_MASK)) {
 #ifdef __x86_64__
 		if ((vcpu->shadow_efer & EFER_LME)) {
-			u32 guest_cs_ar;
+			int cs_db, cs_l;
+
 			if (!is_pae(vcpu)) {
 				printk(KERN_DEBUG "set_cr0: #GP, start paging "
 				       "in long mode while PAE is disabled\n");
 				inject_gp(vcpu);
 				return;
 			}
-			guest_cs_ar = vmcs_read32(GUEST_CS_AR_BYTES);
-			if (guest_cs_ar & SEGMENT_AR_L_MASK) {
+			kvm_arch_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
+			if (cs_l) {
 				printk(KERN_DEBUG "set_cr0: #GP, start paging "
 				       "in long mode while CS.L == 1\n");
 				inject_gp(vcpu);
@@ -1109,18 +1110,18 @@ int emulate_instruction(struct kvm_vcpu 
 {
 	struct x86_emulate_ctxt emulate_ctxt;
 	int r;
-	u32 cs_ar;
+	int cs_db, cs_l;
 
 	kvm_arch_ops->cache_regs(vcpu);
 
-	cs_ar = vmcs_read32(GUEST_CS_AR_BYTES);
+	kvm_arch_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
 
 	emulate_ctxt.vcpu = vcpu;
 	emulate_ctxt.eflags = kvm_arch_ops->get_rflags(vcpu);
 	emulate_ctxt.cr2 = cr2;
 	emulate_ctxt.mode = (emulate_ctxt.eflags & X86_EFLAGS_VM)
-		? X86EMUL_MODE_REAL : (cs_ar & AR_L_MASK)
-		? X86EMUL_MODE_PROT64 :	(cs_ar & AR_DB_MASK)
+		? X86EMUL_MODE_REAL : cs_l
+		? X86EMUL_MODE_PROT64 :	cs_db
 		? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16;
 
 	if (emulate_ctxt.mode == X86EMUL_MODE_PROT64) {
drivers/kvm/vmx.c +9 -0
Index: linux-2.6/drivers/kvm/vmx.c
===================================================================
@@ -698,6 +698,14 @@ static void vmx_set_segment(struct kvm_v
 	vmcs_write32(sf->ar_bytes, ar);
 }
 
+static void vmx_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l)
+{
+	u32 ar = vmcs_read32(GUEST_CS_AR_BYTES);
+
+	*db = (ar >> 14) & 1;
+	*l = (ar >> 13) & 1;
+}
+
 static void vmx_get_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
 {
 	dt->limit = vmcs_read32(GUEST_IDTR_LIMIT);
@@ -1730,6 +1738,7 @@ static struct kvm_arch_ops vmx_arch_ops 
 	.get_segment_base = vmx_get_segment_base,
 	.get_segment = vmx_get_segment,
 	.set_segment = vmx_set_segment,
+	.get_cs_db_l_bits = vmx_get_cs_db_l_bits,
 	.set_cr0 = vmx_set_cr0,
 	.set_cr3 = vmx_set_cr3,
 	.set_cr4 = vmx_set_cr4,

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

author
#39 lore raw

PATCH 29/38 KVM: Add a set_cr0_no_modeswitch() arch accessor

In reply to Avi Kivity

A side effect of using vm86 mode to simulate real mode is that we mangle the segment registers on mode switching. The new set_cr0_no_modeswitch() accessor avoids the mangling when the restore is due to loading the virtual machine from a file.

drivers/kvm/kvm.h +2 -2
Index: linux-2.6/drivers/kvm/kvm.h
===================================================================
@@ -271,6 +271,8 @@ struct kvm_arch_ops {
 			    struct kvm_segment *var, int seg);
 	void (*get_cs_db_l_bits)(struct kvm_vcpu *vcpu, int *db, int *l);
 	void (*set_cr0)(struct kvm_vcpu *vcpu, unsigned long cr0);
+	void (*set_cr0_no_modeswitch)(struct kvm_vcpu *vcpu,
+				      unsigned long cr0);
 	void (*set_cr3)(struct kvm_vcpu *vcpu, unsigned long cr3);
 	void (*set_cr4)(struct kvm_vcpu *vcpu, unsigned long cr4);
 	void (*set_efer)(struct kvm_vcpu *vcpu, u64 efer);
@@ -292,8 +294,6 @@ struct kvm_arch_ops {
 	int (*run)(struct kvm_vcpu *vcpu, struct kvm_run *run);
 	int (*vcpu_setup)(struct kvm_vcpu *vcpu);
 	void (*skip_emulated_instruction)(struct kvm_vcpu *vcpu);
-
-	void (*update_exception_bitmap)(struct kvm_vcpu *vcpu); /* hack */
 };
 
 extern struct kvm_stat kvm_stat;
drivers/kvm/kvm_main.c +1 -6
Index: linux-2.6/drivers/kvm/kvm_main.c
===================================================================
@@ -1529,12 +1529,7 @@ static int kvm_dev_ioctl_set_sregs(struc
 	vcpu->apic_base = sregs->apic_base;
 
 	mmu_reset_needed |= vcpu->cr0 != sregs->cr0;
-	vcpu->rmode.active = ((sregs->cr0 & CR0_PE_MASK) == 0);
-	kvm_arch_ops->update_exception_bitmap(vcpu);
-	vmcs_writel(CR0_READ_SHADOW, sregs->cr0);
-	vmcs_writel(GUEST_CR0,
-		    (sregs->cr0 & ~KVM_GUEST_CR0_MASK) | KVM_VM_CR0_ALWAYS_ON);
-	vcpu->cr0 = sregs->cr0;
+	kvm_arch_ops->set_cr0_no_modeswitch(vcpu, sregs->cr0);
 
 	mmu_reset_needed |= vcpu->cr4 != sregs->cr4;
 	kvm_arch_ops->set_cr4(vcpu, sregs->cr4);
drivers/kvm/vmx.c +14 -2
Index: linux-2.6/drivers/kvm/vmx.c
===================================================================
@@ -607,6 +607,19 @@ static void vmx_set_cr0(struct kvm_vcpu 
 	vcpu->cr0 = cr0;
 }
 
+/*
+ * Used when restoring the VM to avoid corrupting segment registers
+ */
+static void vmx_set_cr0_no_modeswitch(struct kvm_vcpu *vcpu, unsigned long cr0)
+{
+	vcpu->rmode.active = ((cr0 & CR0_PE_MASK) == 0);
+	update_exception_bitmap(vcpu);
+	vmcs_writel(CR0_READ_SHADOW, cr0);
+	vmcs_writel(GUEST_CR0,
+		    (cr0 & ~KVM_GUEST_CR0_MASK) | KVM_VM_CR0_ALWAYS_ON);
+	vcpu->cr0 = cr0;
+}
+
 static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
 {
 	vmcs_writel(GUEST_CR3, cr3);
@@ -1740,6 +1753,7 @@ static struct kvm_arch_ops vmx_arch_ops 
 	.set_segment = vmx_set_segment,
 	.get_cs_db_l_bits = vmx_get_cs_db_l_bits,
 	.set_cr0 = vmx_set_cr0,
+	.set_cr0_no_modeswitch = vmx_set_cr0_no_modeswitch,
 	.set_cr3 = vmx_set_cr3,
 	.set_cr4 = vmx_set_cr4,
 	.set_efer = vmx_set_efer,
@@ -1760,8 +1774,6 @@ static struct kvm_arch_ops vmx_arch_ops 
 	.run = vmx_vcpu_run,
 	.skip_emulated_instruction = skip_emulated_instruction,
 	.vcpu_setup = vmx_vcpu_setup,
-
-	.update_exception_bitmap = update_exception_bitmap,
 };
 
 static int __init vmx_init(void)

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

author
#40 lore raw

PATCH 30/38 KVM: Make vcpu_load() and vcpu_put() arch operations

In reply to Avi Kivity
drivers/kvm/kvm.h +19 -0
Index: linux-2.6/drivers/kvm/kvm.h
===================================================================
@@ -260,6 +260,9 @@ struct kvm_arch_ops {
 	int (*hardware_setup)(void);               /* __init */
 	void (*hardware_unsetup)(void);            /* __exit */
 
+	struct kvm_vcpu *(*vcpu_load)(struct kvm_vcpu *vcpu);
+	void (*vcpu_put)(struct kvm_vcpu *vcpu);
+
 	int (*set_guest_debug)(struct kvm_vcpu *vcpu,
 			       struct kvm_debug_guest *dbg);
 	int (*get_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata);
@@ -296,6 +299,8 @@ struct kvm_arch_ops {
 	void (*skip_emulated_instruction)(struct kvm_vcpu *vcpu);
 };
 
+void __vcpu_clear(void *arg); /* temporary hack */
+
 extern struct kvm_stat kvm_stat;
 extern struct kvm_arch_ops *kvm_arch_ops;
 
@@ -373,6 +378,8 @@ int kvm_write_guest(struct kvm_vcpu *vcp
 void vmcs_writel(unsigned long field, unsigned long value);
 unsigned long vmcs_readl(unsigned long field);
 
+unsigned long segment_base(u16 selector);
+
 static inline struct page *_gfn_to_page(struct kvm *kvm, gfn_t gfn)
 {
 	struct kvm_memory_slot *slot = gfn_to_memslot(kvm, gfn);
@@ -501,6 +508,18 @@ static inline void get_idt(struct descri
 	asm ("sidt %0" : "=m"(*table));
 }
 
+static inline void get_gdt(struct descriptor_table *table)
+{
+	asm ("sgdt %0" : "=m"(*table));
+}
+
+static inline unsigned long read_tr_base(void)
+{
+	u16 tr;
+	asm ("str %0" : "=g"(tr));
+	return segment_base(tr);
+}
+
 #ifdef __x86_64__
 static inline unsigned long read_msr(unsigned long msr)
 {
drivers/kvm/kvm_main.c +9 -64

128 lines not on this page · raw message

drivers/kvm/vmx.c +56 -0

74 lines not on this page · raw message

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

author
#41 lore raw

PATCH 31/38 KVM: Make vcpu creation and destruction arch operations

In reply to Avi Kivity
drivers/kvm/kvm.h +3 -2
Index: linux-2.6/drivers/kvm/kvm.h
===================================================================
@@ -260,6 +260,9 @@ struct kvm_arch_ops {
 	int (*hardware_setup)(void);               /* __init */
 	void (*hardware_unsetup)(void);            /* __exit */
 
+	int (*vcpu_create)(struct kvm_vcpu *vcpu);
+	void (*vcpu_free)(struct kvm_vcpu *vcpu);
+
 	struct kvm_vcpu *(*vcpu_load)(struct kvm_vcpu *vcpu);
 	void (*vcpu_put)(struct kvm_vcpu *vcpu);
 
@@ -299,8 +302,6 @@ struct kvm_arch_ops {
 	void (*skip_emulated_instruction)(struct kvm_vcpu *vcpu);
 };
 
-void __vcpu_clear(void *arg); /* temporary hack */
-
 extern struct kvm_stat kvm_stat;
 extern struct kvm_arch_ops *kvm_arch_ops;
 
drivers/kvm/kvm_main.c +4 -70

113 lines not on this page · raw message

drivers/kvm/vmx.c +78 -1

103 lines not on this page · raw message

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

author
#42 lore raw

PATCH 32/38 KVM: Move vmcs static variables to vmx.c

In reply to Avi Kivity
drivers/kvm/kvm_main.c +0 -12
Index: linux-2.6/drivers/kvm/kvm_main.c
===================================================================
@@ -138,18 +138,6 @@ unsigned long segment_base(u16 selector)
 }
 EXPORT_SYMBOL_GPL(segment_base);
 
-DEFINE_PER_CPU(struct vmcs *, vmxarea);
-EXPORT_SYMBOL_GPL(per_cpu__vmxarea); /* temporary hack */
-DEFINE_PER_CPU(struct vmcs *, current_vmcs);
-EXPORT_SYMBOL_GPL(per_cpu__current_vmcs); /* temporary hack */
-
-struct vmcs_descriptor {
-	int size;
-	int order;
-	u32 revision_id;
-} vmcs_descriptor;
-EXPORT_SYMBOL_GPL(vmcs_descriptor);
-
 int kvm_read_guest(struct kvm_vcpu *vcpu,
 			     gva_t addr,
 			     unsigned long size,
drivers/kvm/vmx.c +3 -3
Index: linux-2.6/drivers/kvm/vmx.c
===================================================================
@@ -28,8 +28,8 @@
 MODULE_AUTHOR("Qumranet");
 MODULE_LICENSE("GPL");
 
-DECLARE_PER_CPU(struct vmcs *, vmxarea);
-DECLARE_PER_CPU(struct vmcs *, current_vmcs);
+static DEFINE_PER_CPU(struct vmcs *, vmxarea);
+static DEFINE_PER_CPU(struct vmcs *, current_vmcs);
 
 #ifdef __x86_64__
 #define HOST_IS_64 1
@@ -37,7 +37,7 @@ DECLARE_PER_CPU(struct vmcs *, current_v
 #define HOST_IS_64 0
 #endif
 
-extern struct vmcs_descriptor {
+static struct vmcs_descriptor {
 	int size;
 	int order;
 	u32 revision_id;

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

author
#43 lore raw

PATCH 33/38 KVM: Make is_long_mode() an arch operation

In reply to Avi Kivity
drivers/kvm/kvm.h +1 -5
Index: linux-2.6/drivers/kvm/kvm.h
===================================================================
@@ -275,6 +275,7 @@ struct kvm_arch_ops {
 			    struct kvm_segment *var, int seg);
 	void (*set_segment)(struct kvm_vcpu *vcpu,
 			    struct kvm_segment *var, int seg);
+	int (*is_long_mode)(struct kvm_vcpu *vcpu);
 	void (*get_cs_db_l_bits)(struct kvm_vcpu *vcpu, int *db, int *l);
 	void (*set_cr0)(struct kvm_vcpu *vcpu, unsigned long cr0);
 	void (*set_cr0_no_modeswitch)(struct kvm_vcpu *vcpu,
@@ -411,11 +412,6 @@ static inline void vmcs_write32(unsigned
 	vmcs_writel(field, value);
 }
 
-static inline int is_long_mode(void)
-{
-	return vmcs_read32(VM_ENTRY_CONTROLS) & VM_ENTRY_CONTROLS_IA32E_MASK;
-}
-
 static inline int is_pae(struct kvm_vcpu *vcpu)
 {
 	return vcpu->cr4 & CR4_PAE_MASK;
drivers/kvm/kvm_main.c +2 -2
Index: linux-2.6/drivers/kvm/kvm_main.c
===================================================================
@@ -441,7 +441,7 @@ void set_cr4(struct kvm_vcpu *vcpu, unsi
 		return;
 	}
 
-	if (is_long_mode()) {
+	if (kvm_arch_ops->is_long_mode(vcpu)) {
 		if (!(cr4 & CR4_PAE_MASK)) {
 			printk(KERN_DEBUG "set_cr4: #GP, clearing PAE while "
 			       "in long mode\n");
@@ -468,7 +468,7 @@ EXPORT_SYMBOL_GPL(set_cr4);
 
 void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
 {
-	if (is_long_mode()) {
+	if (kvm_arch_ops->is_long_mode(vcpu)) {
 		if ( cr3 & CR3_L_MODE_RESEVED_BITS) {
 			printk(KERN_DEBUG "set_cr3: #GP, reserved bits\n");
 			inject_gp(vcpu);
drivers/kvm/mmu.c +1 -1
Index: linux-2.6/drivers/kvm/mmu.c
===================================================================
@@ -589,7 +589,7 @@ static int init_kvm_mmu(struct kvm_vcpu 
 
 	if (!is_paging(vcpu))
 		return nonpaging_init_context(vcpu);
-	else if (is_long_mode())
+	else if (kvm_arch_ops->is_long_mode(vcpu))
 		return paging64_init_context(vcpu);
 	else if (is_pae(vcpu))
 		return paging32E_init_context(vcpu);
drivers/kvm/paging_tmpl.h +3 -3
Index: linux-2.6/drivers/kvm/paging_tmpl.h
===================================================================
@@ -70,7 +70,7 @@ static void FNAME(init_walker)(struct gu
 	hpa = safe_gpa_to_hpa(vcpu, vcpu->cr3 & PT64_BASE_ADDR_MASK);
 	walker->table = kmap_atomic(pfn_to_page(hpa >> PAGE_SHIFT), KM_USER0);
 
-	ASSERT((!is_long_mode() && is_pae(vcpu)) ||
+	ASSERT((!kvm_arch_ops->is_long_mode(vcpu) && is_pae(vcpu)) ||
 	       (vcpu->cr3 & ~(PAGE_MASK | CR3_FLAGS_MASK)) == 0);
 
 	walker->table = (pt_element_t *)( (unsigned long)walker->table |
@@ -135,7 +135,7 @@ static pt_element_t *FNAME(fetch_guest)(
 		     (walker->table[index] & PT_PAGE_SIZE_MASK) &&
 		     (PTTYPE == 64 || is_pse(vcpu))))
 			return &walker->table[index];
-		if (walker->level != 3 || is_long_mode())
+		if (walker->level != 3 || kvm_arch_ops->is_long_mode(vcpu))
 			walker->inherited_ar &= walker->table[index];
 		paddr = safe_gpa_to_hpa(vcpu, walker->table[index] & PT_BASE_ADDR_MASK);
 		kunmap_atomic(walker->table, KM_USER0);
@@ -204,7 +204,7 @@ static u64 *FNAME(fetch)(struct kvm_vcpu
 		shadow_addr = kvm_mmu_alloc_page(vcpu, shadow_ent);
 		if (!VALID_PAGE(shadow_addr))
 			return ERR_PTR(-ENOMEM);
-		if (!is_long_mode() && level == 3)
+		if (!kvm_arch_ops->is_long_mode(vcpu) && level == 3)
 			*shadow_ent = shadow_addr |
 				(*guest_ent & (PT_PRESENT_MASK | PT_PWT_MASK | PT_PCD_MASK));
 		else {
drivers/kvm/vmx.c +6 -0
Index: linux-2.6/drivers/kvm/vmx.c
===================================================================
@@ -811,6 +811,11 @@ static void vmx_set_segment(struct kvm_v
 	vmcs_write32(sf->ar_bytes, ar);
 }
 
+static int vmx_is_long_mode(struct kvm_vcpu *vcpu)
+{
+	return vmcs_read32(VM_ENTRY_CONTROLS) & VM_ENTRY_CONTROLS_IA32E_MASK;
+}
+
 static void vmx_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l)
 {
 	u32 ar = vmcs_read32(GUEST_CS_AR_BYTES);
@@ -1884,6 +1889,7 @@ static struct kvm_arch_ops vmx_arch_ops 
 	.get_segment_base = vmx_get_segment_base,
 	.get_segment = vmx_get_segment,
 	.set_segment = vmx_set_segment,
+	.is_long_mode = vmx_is_long_mode,
 	.get_cs_db_l_bits = vmx_get_cs_db_l_bits,
 	.set_cr0 = vmx_set_cr0,
 	.set_cr0_no_modeswitch = vmx_set_cr0_no_modeswitch,

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

author
#44 lore raw

PATCH 34/38 KVM: Use the tlb flush arch operation instead of an inline

In reply to Avi Kivity
drivers/kvm/kvm.h +0 -5
Index: linux-2.6/drivers/kvm/kvm.h
===================================================================
@@ -445,11 +445,6 @@ static inline int is_external_interrupt(
 		== (INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK);
 }
 
-static inline void flush_guest_tlb(struct kvm_vcpu *vcpu)
-{
-	vmcs_writel(GUEST_CR3, vmcs_readl(GUEST_CR3));
-}
-
 static inline int memslot_id(struct kvm *kvm, struct kvm_memory_slot *slot)
 {
 	return slot - kvm->memslots;
drivers/kvm/kvm_main.c +1 -1
Index: linux-2.6/drivers/kvm/kvm_main.c
===================================================================
@@ -775,7 +775,7 @@ static int kvm_dev_ioctl_get_dirty_log(s
 
 			if (!vcpu)
 				continue;
-			flush_guest_tlb(vcpu);
+			kvm_arch_ops->flush_tlb(vcpu);
 			vcpu_put(vcpu);
 		}
 	}

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

author
#45 lore raw

PATCH 35/38 KVM: Remove guest_cpl()

In reply to Avi Kivity

This was used only in debugging.

drivers/kvm/kvm.h +0 -5
Index: linux-2.6/drivers/kvm/kvm.h
===================================================================
@@ -422,11 +422,6 @@ static inline int is_pse(struct kvm_vcpu
 	return vcpu->cr4 & CR4_PSE_MASK;
 }
 
-static inline unsigned guest_cpl(void)
-{
-	return vmcs_read16(GUEST_CS_SELECTOR) & SELECTOR_RPL_MASK;
-}
-
 static inline int is_paging(struct kvm_vcpu *vcpu)
 {
 	return vcpu->cr0 & CR0_PG_MASK;
drivers/kvm/vmx.c +0 -8
Index: linux-2.6/drivers/kvm/vmx.c
===================================================================
@@ -1391,14 +1391,6 @@ static int handle_cr(struct kvm_vcpu *vc
 	int cr;
 	int reg;
 
-#ifdef KVM_DEBUG
-	if (guest_cpl() != 0) {
-		vcpu_printf(vcpu, "%s: not supervisor\n", __FUNCTION__);
-		inject_gp(vcpu);
-		return 1;
-	}
-#endif
-
 	exit_qualification = vmcs_read64(EXIT_QUALIFICATION);
 	cr = exit_qualification & 15;
 	reg = (exit_qualification >> 8) & 15;

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

author
#46 lore raw

PATCH 36/38 KVM: Move vmcs accessors to vmx.c

In reply to Avi Kivity
drivers/kvm/kvm.h +0 -27
Index: linux-2.6/drivers/kvm/kvm.h
===================================================================
@@ -377,9 +377,6 @@ int kvm_write_guest(struct kvm_vcpu *vcp
 		unsigned long size,
 		void *data);
 
-void vmcs_writel(unsigned long field, unsigned long value);
-unsigned long vmcs_readl(unsigned long field);
-
 unsigned long segment_base(u16 selector);
 
 static inline struct page *_gfn_to_page(struct kvm *kvm, gfn_t gfn)
@@ -388,30 +385,6 @@ static inline struct page *_gfn_to_page(
 	return (slot) ? slot->phys_mem[gfn - slot->base_gfn] : 0;
 }
 
-static inline u16 vmcs_read16(unsigned long field)
-{
-	return vmcs_readl(field);
-}
-
-static inline u32 vmcs_read32(unsigned long field)
-{
-	return vmcs_readl(field);
-}
-
-static inline u64 vmcs_read64(unsigned long field)
-{
-#ifdef __x86_64__
-	return vmcs_readl(field);
-#else
-	return vmcs_readl(field) | ((u64)vmcs_readl(field+1) << 32);
-#endif
-}
-
-static inline void vmcs_write32(unsigned long field, u32 value)
-{
-	vmcs_writel(field, value);
-}
-
 static inline int is_pae(struct kvm_vcpu *vcpu)
 {
 	return vcpu->cr4 & CR4_PAE_MASK;
drivers/kvm/kvm_main.c +0 -22
Index: linux-2.6/drivers/kvm/kvm_main.c
===================================================================
@@ -310,28 +310,6 @@ static int kvm_dev_release(struct inode 
 	return 0;
 }
 
-unsigned long vmcs_readl(unsigned long field)
-{
-	unsigned long value;
-
-	asm volatile (ASM_VMX_VMREAD_RDX_RAX
-		      : "=a"(value) : "d"(field) : "cc");
-	return value;
-}
-EXPORT_SYMBOL_GPL(vmcs_readl);
-
-void vmcs_writel(unsigned long field, unsigned long value)
-{
-	u8 error;
-
-	asm volatile (ASM_VMX_VMWRITE_RAX_RDX "; setna %0"
-		       : "=q"(error) : "a"(value), "d"(field) : "cc" );
-	if (error)
-		printk(KERN_ERR "vmwrite error: reg %lx value %lx (err %d)\n",
-		       field, value, vmcs_read32(VM_INSTRUCTION_ERROR));
-}
-EXPORT_SYMBOL_GPL(vmcs_writel);
-
 static void inject_gp(struct kvm_vcpu *vcpu)
 {
 	kvm_arch_ops->inject_gp(vcpu, 0);
drivers/kvm/kvm_vmx.h +0 -16
Index: linux-2.6/drivers/kvm/kvm_vmx.h
===================================================================
@@ -1,22 +1,6 @@
 #ifndef __KVM_VMX_H
 #define __KVM_VMX_H
 
-static inline void vmcs_write16(unsigned long field, u16 value)
-{
-	vmcs_writel(field, value);
-}
-
-static inline void vmcs_write64(unsigned long field, u64 value)
-{
-#ifdef __x86_64__
-	vmcs_writel(field, value);
-#else
-	vmcs_writel(field, value);
-	asm volatile ("");
-	vmcs_writel(field+1, value >> 32);
-#endif
-}
-
 #ifdef __x86_64__
 /*
  * avoid save/load MSR_SYSCALL_MASK and MSR_LSTAR by std vt
drivers/kvm/vmx.c +60 -0

66 lines not on this page · raw message

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

author
#47 lore raw

PATCH 37/38 KVM: Move vmx helper inlines to vmx.c

In reply to Avi Kivity
drivers/kvm/kvm.h +0 -13
Index: linux-2.6/drivers/kvm/kvm.h
===================================================================
@@ -400,19 +400,6 @@ static inline int is_paging(struct kvm_v
 	return vcpu->cr0 & CR0_PG_MASK;
 }
 
-static inline int is_page_fault(u32 intr_info)
-{
-	return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK |
-			     INTR_INFO_VALID_MASK)) ==
-		(INTR_TYPE_EXCEPTION | PF_VECTOR | INTR_INFO_VALID_MASK);
-}
-
-static inline int is_external_interrupt(u32 intr_info)
-{
-	return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VALID_MASK))
-		== (INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK);
-}
-
 static inline int memslot_id(struct kvm *kvm, struct kvm_memory_slot *slot)
 {
 	return slot - kvm->memslots;
drivers/kvm/vmx.c +13 -0
Index: linux-2.6/drivers/kvm/vmx.c
===================================================================
@@ -77,6 +77,19 @@ static const u32 vmx_msr_index[] = {
 
 struct vmx_msr_entry *find_msr_entry(struct kvm_vcpu *vcpu, u32 msr);
 
+static inline int is_page_fault(u32 intr_info)
+{
+	return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK |
+			     INTR_INFO_VALID_MASK)) ==
+		(INTR_TYPE_EXCEPTION | PF_VECTOR | INTR_INFO_VALID_MASK);
+}
+
+static inline int is_external_interrupt(u32 intr_info)
+{
+	return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VALID_MASK))
+		== (INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK);
+}
+
 static void vmcs_clear(struct vmcs *vmcs)
 {
 	u64 phys_addr = __pa(vmcs);

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

author
#48 lore raw

PATCH 38/38 KVM: Remove vmx includes from arch independent code

In reply to Avi Kivity
drivers/kvm/kvm_main.c +0 -2
Index: linux-2.6/drivers/kvm/kvm_main.c
===================================================================
@@ -35,8 +35,6 @@
 #include <linux/file.h>
 #include <asm/desc.h>
 
-#include "vmx.h"
-#include "kvm_vmx.h"
 #include "x86_emulate.h"
 
 MODULE_AUTHOR("Qumranet");
drivers/kvm/vmx.c +1 -1
Index: linux-2.6/drivers/kvm/vmx.c
===================================================================
@@ -16,9 +16,9 @@
  */
 
 #include "kvm.h"
-#include <linux/module.h>
 #include "vmx.h"
 #include "kvm_vmx.h"
+#include <linux/module.h>
 #include <linux/mm.h>
 #include <linux/highmem.h>
 #include <asm/io.h>

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV