aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAvi Kivity <avi@qumranet.com>2007-01-05 19:36:38 -0500
committerLinus Torvalds <torvalds@woody.osdl.org>2007-01-06 02:55:23 -0500
commit399badf315bd4dd571b4b3b7cf666d9a2af40229 (patch)
tree5c84e0392454df650cb4ce25d6bfcb3bac843bc3
parentcb26b572dc39467ba0969d1a76c2f723d2d6a2a6 (diff)
[PATCH] KVM: Prevent stale bits in cr0 and cr4
Hardware virtualization implementations allow the guests to freely change some of the bits in cr0 and cr4, but trap when changing the other bits. This is useful to avoid excessive exits due to changing, for example, the ts flag. It also means the kvm's copy of cr0 and cr4 may be stale with respect to these bits. most of the time this doesn't matter as these bits are not very interesting. Other times, however (for example when returning cr0 to userspace), they are, so get the fresh contents of these bits from the guest by means of a new arch operation. Signed-off-by: Avi Kivity <avi@qumranet.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--drivers/kvm/kvm.h1
-rw-r--r--drivers/kvm/kvm_main.c10
-rw-r--r--drivers/kvm/svm.c5
-rw-r--r--drivers/kvm/vmx.c10
4 files changed, 24 insertions, 2 deletions
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
index 32023d1ac24b..e8fe1039e3b5 100644
--- a/drivers/kvm/kvm.h
+++ b/drivers/kvm/kvm.h
@@ -283,6 +283,7 @@ struct kvm_arch_ops {
283 void (*set_segment)(struct kvm_vcpu *vcpu, 283 void (*set_segment)(struct kvm_vcpu *vcpu,
284 struct kvm_segment *var, int seg); 284 struct kvm_segment *var, int seg);
285 void (*get_cs_db_l_bits)(struct kvm_vcpu *vcpu, int *db, int *l); 285 void (*get_cs_db_l_bits)(struct kvm_vcpu *vcpu, int *db, int *l);
286 void (*decache_cr0_cr4_guest_bits)(struct kvm_vcpu *vcpu);
286 void (*set_cr0)(struct kvm_vcpu *vcpu, unsigned long cr0); 287 void (*set_cr0)(struct kvm_vcpu *vcpu, unsigned long cr0);
287 void (*set_cr0_no_modeswitch)(struct kvm_vcpu *vcpu, 288 void (*set_cr0_no_modeswitch)(struct kvm_vcpu *vcpu,
288 unsigned long cr0); 289 unsigned long cr0);
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index aca14139a680..bc88c334664b 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -390,6 +390,7 @@ EXPORT_SYMBOL_GPL(set_cr0);
390 390
391void lmsw(struct kvm_vcpu *vcpu, unsigned long msw) 391void lmsw(struct kvm_vcpu *vcpu, unsigned long msw)
392{ 392{
393 kvm_arch_ops->decache_cr0_cr4_guest_bits(vcpu);
393 set_cr0(vcpu, (vcpu->cr0 & ~0x0ful) | (msw & 0x0f)); 394 set_cr0(vcpu, (vcpu->cr0 & ~0x0ful) | (msw & 0x0f));
394} 395}
395EXPORT_SYMBOL_GPL(lmsw); 396EXPORT_SYMBOL_GPL(lmsw);
@@ -917,9 +918,10 @@ int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address)
917 918
918int emulate_clts(struct kvm_vcpu *vcpu) 919int emulate_clts(struct kvm_vcpu *vcpu)
919{ 920{
920 unsigned long cr0 = vcpu->cr0; 921 unsigned long cr0;
921 922
922 cr0 &= ~CR0_TS_MASK; 923 kvm_arch_ops->decache_cr0_cr4_guest_bits(vcpu);
924 cr0 = vcpu->cr0 & ~CR0_TS_MASK;
923 kvm_arch_ops->set_cr0(vcpu, cr0); 925 kvm_arch_ops->set_cr0(vcpu, cr0);
924 return X86EMUL_CONTINUE; 926 return X86EMUL_CONTINUE;
925} 927}
@@ -1072,6 +1074,7 @@ void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,
1072 1074
1073unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr) 1075unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr)
1074{ 1076{
1077 kvm_arch_ops->decache_cr0_cr4_guest_bits(vcpu);
1075 switch (cr) { 1078 switch (cr) {
1076 case 0: 1079 case 0:
1077 return vcpu->cr0; 1080 return vcpu->cr0;
@@ -1406,6 +1409,7 @@ static int kvm_dev_ioctl_get_sregs(struct kvm *kvm, struct kvm_sregs *sregs)
1406 sregs->gdt.limit = dt.limit; 1409 sregs->gdt.limit = dt.limit;
1407 sregs->gdt.base = dt.base; 1410 sregs->gdt.base = dt.base;
1408 1411
1412 kvm_arch_ops->decache_cr0_cr4_guest_bits(vcpu);
1409 sregs->cr0 = vcpu->cr0; 1413 sregs->cr0 = vcpu->cr0;
1410 sregs->cr2 = vcpu->cr2; 1414 sregs->cr2 = vcpu->cr2;
1411 sregs->cr3 = vcpu->cr3; 1415 sregs->cr3 = vcpu->cr3;
@@ -1470,6 +1474,8 @@ static int kvm_dev_ioctl_set_sregs(struct kvm *kvm, struct kvm_sregs *sregs)
1470#endif 1474#endif
1471 vcpu->apic_base = sregs->apic_base; 1475 vcpu->apic_base = sregs->apic_base;
1472 1476
1477 kvm_arch_ops->decache_cr0_cr4_guest_bits(vcpu);
1478
1473 mmu_reset_needed |= vcpu->cr0 != sregs->cr0; 1479 mmu_reset_needed |= vcpu->cr0 != sregs->cr0;
1474 kvm_arch_ops->set_cr0_no_modeswitch(vcpu, sregs->cr0); 1480 kvm_arch_ops->set_cr0_no_modeswitch(vcpu, sregs->cr0);
1475 1481
diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c
index 855207a9b396..91c7f60ffd42 100644
--- a/drivers/kvm/svm.c
+++ b/drivers/kvm/svm.c
@@ -702,6 +702,10 @@ static void svm_set_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
702 vcpu->svm->vmcb->save.gdtr.base = dt->base ; 702 vcpu->svm->vmcb->save.gdtr.base = dt->base ;
703} 703}
704 704
705static void svm_decache_cr0_cr4_guest_bits(struct kvm_vcpu *vcpu)
706{
707}
708
705static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) 709static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
706{ 710{
707#ifdef CONFIG_X86_64 711#ifdef CONFIG_X86_64
@@ -1645,6 +1649,7 @@ static struct kvm_arch_ops svm_arch_ops = {
1645 .get_segment = svm_get_segment, 1649 .get_segment = svm_get_segment,
1646 .set_segment = svm_set_segment, 1650 .set_segment = svm_set_segment,
1647 .get_cs_db_l_bits = svm_get_cs_db_l_bits, 1651 .get_cs_db_l_bits = svm_get_cs_db_l_bits,
1652 .decache_cr0_cr4_guest_bits = svm_decache_cr0_cr4_guest_bits,
1648 .set_cr0 = svm_set_cr0, 1653 .set_cr0 = svm_set_cr0,
1649 .set_cr0_no_modeswitch = svm_set_cr0, 1654 .set_cr0_no_modeswitch = svm_set_cr0,
1650 .set_cr3 = svm_set_cr3, 1655 .set_cr3 = svm_set_cr3,
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c
index c55635ddf426..aaa98e3e9caf 100644
--- a/drivers/kvm/vmx.c
+++ b/drivers/kvm/vmx.c
@@ -737,6 +737,15 @@ static void exit_lmode(struct kvm_vcpu *vcpu)
737 737
738#endif 738#endif
739 739
740static void vmx_decache_cr0_cr4_guest_bits(struct kvm_vcpu *vcpu)
741{
742 vcpu->cr0 &= KVM_GUEST_CR0_MASK;
743 vcpu->cr0 |= vmcs_readl(GUEST_CR0) & ~KVM_GUEST_CR0_MASK;
744
745 vcpu->cr4 &= KVM_GUEST_CR4_MASK;
746 vcpu->cr4 |= vmcs_readl(GUEST_CR4) & ~KVM_GUEST_CR4_MASK;
747}
748
740static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) 749static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
741{ 750{
742 if (vcpu->rmode.active && (cr0 & CR0_PE_MASK)) 751 if (vcpu->rmode.active && (cr0 & CR0_PE_MASK))
@@ -2002,6 +2011,7 @@ static struct kvm_arch_ops vmx_arch_ops = {
2002 .get_segment = vmx_get_segment, 2011 .get_segment = vmx_get_segment,
2003 .set_segment = vmx_set_segment, 2012 .set_segment = vmx_set_segment,
2004 .get_cs_db_l_bits = vmx_get_cs_db_l_bits, 2013 .get_cs_db_l_bits = vmx_get_cs_db_l_bits,
2014 .decache_cr0_cr4_guest_bits = vmx_decache_cr0_cr4_guest_bits,
2005 .set_cr0 = vmx_set_cr0, 2015 .set_cr0 = vmx_set_cr0,
2006 .set_cr0_no_modeswitch = vmx_set_cr0_no_modeswitch, 2016 .set_cr0_no_modeswitch = vmx_set_cr0_no_modeswitch,
2007 .set_cr3 = vmx_set_cr3, 2017 .set_cr3 = vmx_set_cr3,