diff options
author | Avi Kivity <avi@qumranet.com> | 2007-01-05 19:36:38 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.osdl.org> | 2007-01-06 02:55:23 -0500 |
commit | 399badf315bd4dd571b4b3b7cf666d9a2af40229 (patch) | |
tree | 5c84e0392454df650cb4ce25d6bfcb3bac843bc3 /drivers/kvm/kvm_main.c | |
parent | cb26b572dc39467ba0969d1a76c2f723d2d6a2a6 (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>
Diffstat (limited to 'drivers/kvm/kvm_main.c')
-rw-r--r-- | drivers/kvm/kvm_main.c | 10 |
1 files changed, 8 insertions, 2 deletions
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 | ||
391 | void lmsw(struct kvm_vcpu *vcpu, unsigned long msw) | 391 | void 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 | } |
395 | EXPORT_SYMBOL_GPL(lmsw); | 396 | EXPORT_SYMBOL_GPL(lmsw); |
@@ -917,9 +918,10 @@ int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address) | |||
917 | 918 | ||
918 | int emulate_clts(struct kvm_vcpu *vcpu) | 919 | int 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 | ||
1073 | unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr) | 1075 | unsigned 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 | ||