Avi Kivity wrote:
> Thomas Glanzmann wrote:
>   
>> Hello Pelle,
>>
>>   
>>     
>>> Hey, I recognize that problem, although my display isn't corrupted, just 
>>> the mouse. It was resistant to X restarts. It first surfaced with kvm-21 
>>> and debian edgy on my machine. I don't believe there was an opera update 
>>> recently.
>>>     
>>>       
>> for me the same thing. Debian ETCH. And the display is only corrupted
>> for a short time, as soon as I switch applications or do a X redraw
>> everything is fine again expect for the mouse. And it popped always up
>> when I was using opera. But that just could be coincedence. I don't
>> believe in coincedence.
>>   
>>     
>
> I've just reproduced this, it's fe7dc1f2c0c3d0c21abf9dfa4387f0b748080688
> (vmx lazy fpu).
>
> I'm looking into it.
>
>
>   

The attached patch (against HEAD) fixes this issue.  It's still not
committed as I have to rework it into smaller patches (and to backport
it to the 2.6.22 patchqueue... sigh).

Please test.

-- 
Do not meddle in the internals of kernels, for they are subtle and quick to 
panic.

diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
index 9c20d5d..4d7f7c4 100644
--- a/drivers/kvm/kvm.h
+++ b/drivers/kvm/kvm.h
@@ -39,9 +39,9 @@
 
 #define KVM_GUEST_CR0_MASK \
 	(CR0_PG_MASK | CR0_PE_MASK | CR0_WP_MASK | CR0_NE_MASK \
-	 | CR0_NW_MASK | CR0_CD_MASK)
+	 | CR0_NW_MASK | CR0_CD_MASK | CR0_TS_MASK)
 #define KVM_VM_CR0_ALWAYS_ON \
-	(CR0_PG_MASK | CR0_PE_MASK | CR0_WP_MASK | CR0_NE_MASK)
+	(CR0_PG_MASK | CR0_PE_MASK | CR0_WP_MASK | CR0_NE_MASK | CR0_TS_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)
@@ -60,7 +60,7 @@
 
 #define FX_IMAGE_SIZE 512
 #define FX_IMAGE_ALIGN 16
-#define FX_BUF_SIZE (2 * FX_IMAGE_SIZE + FX_IMAGE_ALIGN)
+#define FX_BUF_SIZE (FX_IMAGE_SIZE + FX_IMAGE_ALIGN)
 
 #define DE_VECTOR 0
 #define NM_VECTOR 7
@@ -301,7 +301,6 @@ struct kvm_vcpu {
 	struct kvm_guest_debug guest_debug;
 
 	char fx_buf[FX_BUF_SIZE];
-	char *host_fx_image;
 	char *guest_fx_image;
 	int fpu_active;
 
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index a3723dd..7c5dede 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -40,6 +40,7 @@
 #include <linux/file.h>
 #include <linux/fs.h>
 #include <linux/mount.h>
+#include <asm/i387.h>
 
 #include "x86_emulate.h"
 #include "segment_descriptor.h"
@@ -615,10 +616,10 @@ void fx_init(struct kvm_vcpu *vcpu)
 
 	} *fx_image;
 
-	fx_save(vcpu->host_fx_image);
+	kernel_fpu_begin();
 	fpu_init();
 	fx_save(vcpu->guest_fx_image);
-	fx_restore(vcpu->host_fx_image);
+	kernel_fpu_end();
 
 	fx_image = (struct fx_image_s *)vcpu->guest_fx_image;
 	fx_image->mxcsr = 0x1f80;
@@ -2315,9 +2316,8 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, int n)
 		goto out_free_run;
 	vcpu->pio_data = page_address(page);
 
-	vcpu->host_fx_image = (char*)ALIGN((hva_t)vcpu->fx_buf,
+	vcpu->guest_fx_image = (char*)ALIGN((hva_t)vcpu->fx_buf,
 					   FX_IMAGE_ALIGN);
-	vcpu->guest_fx_image = vcpu->host_fx_image + FX_IMAGE_SIZE;
 	vcpu->cr0 = 0x10;
 
 	r = kvm_arch_ops->vcpu_create(vcpu);
diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c
index b621403..99ab4ce 100644
--- a/drivers/kvm/svm.c
+++ b/drivers/kvm/svm.c
@@ -20,6 +20,7 @@
 #include <linux/highmem.h>
 #include <linux/profile.h>
 #include <asm/desc.h>
+#include <asm/i387.h>
 
 #include "kvm_svm.h"
 #include "x86_emulate.h"
@@ -1505,7 +1506,7 @@ again:
 	}
 
 	if (vcpu->fpu_active) {
-		fx_save(vcpu->host_fx_image);
+		kernel_fpu_begin();
 		fx_restore(vcpu->guest_fx_image);
 	}
 
@@ -1620,7 +1621,7 @@ again:
 
 	if (vcpu->fpu_active) {
 		fx_save(vcpu->guest_fx_image);
-		fx_restore(vcpu->host_fx_image);
+		kernel_fpu_end();
 	}
 
 	if ((vcpu->svm->vmcb->save.dr7 & 0xff))
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c
index 19edb34..95c5262 100644
--- a/drivers/kvm/vmx.c
+++ b/drivers/kvm/vmx.c
@@ -24,6 +24,7 @@
 #include <linux/profile.h>
 #include <asm/io.h>
 #include <asm/desc.h>
+#include <asm/i387.h>
 
 #include "segment_descriptor.h"
 
@@ -332,6 +333,40 @@ static void vmx_inject_gp(struct kvm_vcpu *vcpu, unsigned error_code)
 		     INTR_INFO_VALID_MASK);
 }
 
+static void update_exception_bitmap(struct kvm_vcpu *vcpu)
+{
+	u32 eb = 0;
+
+	if (vcpu->rmode.active)
+		eb |= ~0u;
+	else
+		eb |= (1u << PF_VECTOR) | (1 << NM_VECTOR);
+	if (vcpu->fpu_active)
+		eb &= ~(1u << NM_VECTOR);
+	vmcs_write32(EXCEPTION_BITMAP, eb);
+}
+
+static void vmx_activate_fpu(struct kvm_vcpu *vcpu)
+{
+	if (vcpu->fpu_active)
+		return;
+	vcpu->fpu_active = 1;
+	vmcs_clear_bits(GUEST_CR0, CR0_TS_MASK);
+	if (vcpu->cr0 & CR0_TS_MASK)
+		vmcs_set_bits(GUEST_CR0, CR0_TS_MASK);
+	update_exception_bitmap(vcpu);
+}
+
+static void vmx_deactivate_fpu(struct kvm_vcpu *vcpu)
+{
+	if (!vcpu->fpu_active || !(vcpu->cr0 & CR0_PE_MASK))
+		return;
+	vcpu->fpu_active = 0;
+	vmcs_set_bits(GUEST_CR0, CR0_TS_MASK);
+	vmcs_set_bits(EXCEPTION_BITMAP, 1 << NM_VECTOR);
+	update_exception_bitmap(vcpu);
+}
+
 /*
  * Set up the vmcs to automatically save and restore system
  * msrs.  Don't touch the 64-bit msrs if the guest is in legacy
@@ -538,10 +573,8 @@ static void vcpu_put_rsp_rip(struct kvm_vcpu *vcpu)
 static int set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg)
 {
 	unsigned long dr7 = 0x400;
-	u32 exception_bitmap;
 	int old_singlestep;
 
-	exception_bitmap = vmcs_read32(EXCEPTION_BITMAP);
 	old_singlestep = vcpu->guest_debug.singlestep;
 
 	vcpu->guest_debug.enabled = dbg->enabled;
@@ -557,11 +590,13 @@ static int set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg)
 			dr7 |= 0 << (i*4+16); /* execution breakpoint */
 		}
 
-		exception_bitmap |= (1u << 1);  /* Trap debug exceptions */
+		/* Trap debug exceptions */
+		vmcs_set_bits(EXCEPTION_BITMAP, 1u << 1);
 
 		vcpu->guest_debug.singlestep = dbg->singlestep;
 	} else {
-		exception_bitmap &= ~(1u << 1); /* Ignore debug exceptions */
+		/* Ignore debug exceptions */
+		vmcs_clear_bits(EXCEPTION_BITMAP, 1u << 1);
 		vcpu->guest_debug.singlestep = 0;
 	}
 
@@ -573,7 +608,6 @@ static int set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg)
 		vmcs_writel(GUEST_RFLAGS, flags);
 	}
 
-	vmcs_write32(EXCEPTION_BITMAP, exception_bitmap);
 	vmcs_writel(GUEST_DR7, dr7);
 
 	return 0;
@@ -687,14 +721,6 @@ static __exit void hardware_unsetup(void)
 	free_kvm_area();
 }
 
-static void update_exception_bitmap(struct kvm_vcpu *vcpu)
-{
-	if (vcpu->rmode.active)
-		vmcs_write32(EXCEPTION_BITMAP, ~0);
-	else
-		vmcs_write32(EXCEPTION_BITMAP, 1 << PF_VECTOR);
-}
-
 static void fix_pmode_dataseg(int seg, struct kvm_save_segment *save)
 {
 	struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
@@ -860,26 +886,21 @@ static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
 	}
 #endif
 
-	if (!(cr0 & CR0_TS_MASK)) {
-		vcpu->fpu_active = 1;
-		vmcs_clear_bits(EXCEPTION_BITMAP, CR0_TS_MASK);
-	}
+	vmx_deactivate_fpu(vcpu);
 
 	vmcs_writel(CR0_READ_SHADOW, cr0);
 	vmcs_writel(GUEST_CR0,
 		    (cr0 & ~KVM_GUEST_CR0_MASK) | KVM_VM_CR0_ALWAYS_ON);
 	vcpu->cr0 = cr0;
+
+	if (!(cr0 & CR0_TS_MASK))
+		vmx_activate_fpu(vcpu);
 }
 
 static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
 {
 	vmcs_writel(GUEST_CR3, cr3);
-
-	if (!(vcpu->cr0 & CR0_TS_MASK)) {
-		vcpu->fpu_active = 0;
-		vmcs_set_bits(GUEST_CR0, CR0_TS_MASK);
-		vmcs_set_bits(EXCEPTION_BITMAP, 1 << NM_VECTOR);
-	}
+	vmx_deactivate_fpu(vcpu);
 }
 
 static void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
@@ -1249,6 +1270,7 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu)
 #ifdef CONFIG_X86_64
 	vmx_set_efer(vcpu, 0);
 #endif
+	vmx_activate_fpu(vcpu);
 
 	return 0;
 
@@ -1408,10 +1430,7 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 	}
 
 	if (is_no_device(intr_info)) {
-		vcpu->fpu_active = 1;
-		vmcs_clear_bits(EXCEPTION_BITMAP, 1 << NM_VECTOR);
-		if (!(vcpu->cr0 & CR0_TS_MASK))
-			vmcs_clear_bits(GUEST_CR0, CR0_TS_MASK);
+		vmx_activate_fpu(vcpu);
 		return 1;
 	}
 
@@ -1603,12 +1622,10 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 		break;
 	case 2: /* clts */
 		vcpu_load_rsp_rip(vcpu);
-		vcpu->fpu_active = 1;
-		vmcs_clear_bits(EXCEPTION_BITMAP, 1 << NM_VECTOR);
-		vmcs_clear_bits(GUEST_CR0, CR0_TS_MASK);
 		vcpu->cr0 &= ~CR0_TS_MASK;
 		vmcs_writel(CR0_READ_SHADOW, vcpu->cr0);
 		skip_emulated_instruction(vcpu);
+		vmx_activate_fpu(vcpu);
 		return 1;
 	case 1: /*mov from cr*/
 		switch (cr) {
@@ -1824,8 +1841,10 @@ static int vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 	u16 fs_sel, gs_sel, ldt_sel;
 	int fs_gs_ldt_reload_needed;
 	int r;
+	int guest_fpu_loaded;
 
 preempted:
+	guest_fpu_loaded = 0;
 	/*
 	 * Set host fs and gs selectors.  Unfortunately, 22.2.3 does not
 	 * allow segment selectors with cpl > 0 or ti == 1.
@@ -1861,11 +1880,6 @@ preempted:
 	if (vcpu->guest_debug.enabled)
 		kvm_guest_debug_pre(vcpu);
 
-	if (vcpu->fpu_active) {
-		fx_save(vcpu->host_fx_image);
-		fx_restore(vcpu->guest_fx_image);
-	}
-
 #ifdef CONFIG_X86_64
 	if (is_long_mode(vcpu)) {
 		save_msrs(vcpu->host_msrs + msr_offset_kernel_gs_base, 1);
@@ -1874,6 +1888,12 @@ preempted:
 #endif
 
 again:
+	if (vcpu->fpu_active && !guest_fpu_loaded) {
+		kernel_fpu_begin();
+		fx_restore(vcpu->guest_fx_image);
+		guest_fpu_loaded = 1;
+	}
+
 	asm (
 		/* Store host registers */
 		"pushf \n\t"
@@ -2059,9 +2079,10 @@ out:
 	}
 #endif
 
-	if (vcpu->fpu_active) {
+	if (guest_fpu_loaded) {
 		fx_save(vcpu->guest_fx_image);
-		fx_restore(vcpu->host_fx_image);
+		kernel_fpu_end();
+		guest_fpu_loaded = 0;
 	}
 
 	if (r > 0) {
@@ -2141,7 +2162,6 @@ static int vmx_create_vcpu(struct kvm_vcpu *vcpu)
 	vmcs_clear(vmcs);
 	vcpu->vmcs = vmcs;
 	vcpu->launched = 0;
-	vcpu->fpu_active = 1;
 
 	return 0;
 
-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
kvm-devel mailing list
kvm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/kvm-devel

Reply via email to