Skip to content

Commit 399badf

Browse files
avikivityLinus Torvalds
authored andcommitted
[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>
1 parent cb26b57 commit 399badf

File tree

4 files changed

+24
-2
lines changed

4 files changed

+24
-2
lines changed

drivers/kvm/kvm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,7 @@ struct kvm_arch_ops {
283283
void (*set_segment)(struct kvm_vcpu *vcpu,
284284
struct kvm_segment *var, int seg);
285285
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);
286287
void (*set_cr0)(struct kvm_vcpu *vcpu, unsigned long cr0);
287288
void (*set_cr0_no_modeswitch)(struct kvm_vcpu *vcpu,
288289
unsigned long cr0);

drivers/kvm/kvm_main.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,7 @@ EXPORT_SYMBOL_GPL(set_cr0);
390390

391391
void lmsw(struct kvm_vcpu *vcpu, unsigned long msw)
392392
{
393+
kvm_arch_ops->decache_cr0_cr4_guest_bits(vcpu);
393394
set_cr0(vcpu, (vcpu->cr0 & ~0x0ful) | (msw & 0x0f));
394395
}
395396
EXPORT_SYMBOL_GPL(lmsw);
@@ -917,9 +918,10 @@ int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address)
917918

918919
int emulate_clts(struct kvm_vcpu *vcpu)
919920
{
920-
unsigned long cr0 = vcpu->cr0;
921+
unsigned long cr0;
921922

922-
cr0 &= ~CR0_TS_MASK;
923+
kvm_arch_ops->decache_cr0_cr4_guest_bits(vcpu);
924+
cr0 = vcpu->cr0 & ~CR0_TS_MASK;
923925
kvm_arch_ops->set_cr0(vcpu, cr0);
924926
return X86EMUL_CONTINUE;
925927
}
@@ -1072,6 +1074,7 @@ void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,
10721074

10731075
unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr)
10741076
{
1077+
kvm_arch_ops->decache_cr0_cr4_guest_bits(vcpu);
10751078
switch (cr) {
10761079
case 0:
10771080
return vcpu->cr0;
@@ -1406,6 +1409,7 @@ static int kvm_dev_ioctl_get_sregs(struct kvm *kvm, struct kvm_sregs *sregs)
14061409
sregs->gdt.limit = dt.limit;
14071410
sregs->gdt.base = dt.base;
14081411

1412+
kvm_arch_ops->decache_cr0_cr4_guest_bits(vcpu);
14091413
sregs->cr0 = vcpu->cr0;
14101414
sregs->cr2 = vcpu->cr2;
14111415
sregs->cr3 = vcpu->cr3;
@@ -1470,6 +1474,8 @@ static int kvm_dev_ioctl_set_sregs(struct kvm *kvm, struct kvm_sregs *sregs)
14701474
#endif
14711475
vcpu->apic_base = sregs->apic_base;
14721476

1477+
kvm_arch_ops->decache_cr0_cr4_guest_bits(vcpu);
1478+
14731479
mmu_reset_needed |= vcpu->cr0 != sregs->cr0;
14741480
kvm_arch_ops->set_cr0_no_modeswitch(vcpu, sregs->cr0);
14751481

drivers/kvm/svm.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,10 @@ static void svm_set_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
702702
vcpu->svm->vmcb->save.gdtr.base = dt->base ;
703703
}
704704

705+
static void svm_decache_cr0_cr4_guest_bits(struct kvm_vcpu *vcpu)
706+
{
707+
}
708+
705709
static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
706710
{
707711
#ifdef CONFIG_X86_64
@@ -1645,6 +1649,7 @@ static struct kvm_arch_ops svm_arch_ops = {
16451649
.get_segment = svm_get_segment,
16461650
.set_segment = svm_set_segment,
16471651
.get_cs_db_l_bits = svm_get_cs_db_l_bits,
1652+
.decache_cr0_cr4_guest_bits = svm_decache_cr0_cr4_guest_bits,
16481653
.set_cr0 = svm_set_cr0,
16491654
.set_cr0_no_modeswitch = svm_set_cr0,
16501655
.set_cr3 = svm_set_cr3,

drivers/kvm/vmx.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,15 @@ static void exit_lmode(struct kvm_vcpu *vcpu)
737737

738738
#endif
739739

740+
static 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+
740749
static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
741750
{
742751
if (vcpu->rmode.active && (cr0 & CR0_PE_MASK))
@@ -2002,6 +2011,7 @@ static struct kvm_arch_ops vmx_arch_ops = {
20022011
.get_segment = vmx_get_segment,
20032012
.set_segment = vmx_set_segment,
20042013
.get_cs_db_l_bits = vmx_get_cs_db_l_bits,
2014+
.decache_cr0_cr4_guest_bits = vmx_decache_cr0_cr4_guest_bits,
20052015
.set_cr0 = vmx_set_cr0,
20062016
.set_cr0_no_modeswitch = vmx_set_cr0_no_modeswitch,
20072017
.set_cr3 = vmx_set_cr3,

0 commit comments

Comments
 (0)