aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAvi Kivity <avi@qumranet.com>2007-11-20 19:57:59 -0500
committerAvi Kivity <avi@qumranet.com>2008-01-30 10:53:10 -0500
commitd835dfecd00fd770288dcd9a46c0e0966d526fdf (patch)
tree9e80c69f9024e45b39cf0d1eeda56ba4a57567a6
parent79539cec0c3c38d35a1e3e5310d2c562ae6e82b8 (diff)
KVM: Don't bother the mmu if cr3 load doesn't change cr3
If the guest requests just a tlb flush, don't take the vm lock and drop the mmu context pointlessly. Signed-off-by: Avi Kivity <avi@qumranet.com>
-rw-r--r--drivers/kvm/mmu.c2
-rw-r--r--drivers/kvm/x86.c25
-rw-r--r--drivers/kvm/x86.h1
3 files changed, 27 insertions, 1 deletions
diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c
index 281dd5f9310c..346aa65a08d5 100644
--- a/drivers/kvm/mmu.c
+++ b/drivers/kvm/mmu.c
@@ -1086,7 +1086,7 @@ static int nonpaging_init_context(struct kvm_vcpu *vcpu)
1086 return 0; 1086 return 0;
1087} 1087}
1088 1088
1089static void kvm_mmu_flush_tlb(struct kvm_vcpu *vcpu) 1089void kvm_mmu_flush_tlb(struct kvm_vcpu *vcpu)
1090{ 1090{
1091 ++vcpu->stat.tlb_flush; 1091 ++vcpu->stat.tlb_flush;
1092 kvm_x86_ops->tlb_flush(vcpu); 1092 kvm_x86_ops->tlb_flush(vcpu);
diff --git a/drivers/kvm/x86.c b/drivers/kvm/x86.c
index ac09f381f47f..15e1203faef0 100644
--- a/drivers/kvm/x86.c
+++ b/drivers/kvm/x86.c
@@ -166,6 +166,26 @@ out:
166 return ret; 166 return ret;
167} 167}
168 168
169static bool pdptrs_changed(struct kvm_vcpu *vcpu)
170{
171 u64 pdpte[ARRAY_SIZE(vcpu->pdptrs)];
172 bool changed = true;
173 int r;
174
175 if (is_long_mode(vcpu) || !is_pae(vcpu))
176 return false;
177
178 mutex_lock(&vcpu->kvm->lock);
179 r = kvm_read_guest(vcpu->kvm, vcpu->cr3 & ~31u, pdpte, sizeof(pdpte));
180 if (r < 0)
181 goto out;
182 changed = memcmp(pdpte, vcpu->pdptrs, sizeof(pdpte)) != 0;
183out:
184 mutex_unlock(&vcpu->kvm->lock);
185
186 return changed;
187}
188
169void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) 189void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
170{ 190{
171 if (cr0 & CR0_RESERVED_BITS) { 191 if (cr0 & CR0_RESERVED_BITS) {
@@ -271,6 +291,11 @@ EXPORT_SYMBOL_GPL(set_cr4);
271 291
272void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) 292void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
273{ 293{
294 if (cr3 == vcpu->cr3 && !pdptrs_changed(vcpu)) {
295 kvm_mmu_flush_tlb(vcpu);
296 return;
297 }
298
274 if (is_long_mode(vcpu)) { 299 if (is_long_mode(vcpu)) {
275 if (cr3 & CR3_L_MODE_RESERVED_BITS) { 300 if (cr3 & CR3_L_MODE_RESERVED_BITS) {
276 printk(KERN_DEBUG "set_cr3: #GP, reserved bits\n"); 301 printk(KERN_DEBUG "set_cr3: #GP, reserved bits\n");
diff --git a/drivers/kvm/x86.h b/drivers/kvm/x86.h
index 71f2477d03fd..b1528c9f566f 100644
--- a/drivers/kvm/x86.h
+++ b/drivers/kvm/x86.h
@@ -299,6 +299,7 @@ int emulator_write_emulated(unsigned long addr,
299 299
300unsigned long segment_base(u16 selector); 300unsigned long segment_base(u16 selector);
301 301
302void kvm_mmu_flush_tlb(struct kvm_vcpu *vcpu);
302void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, 303void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
303 const u8 *new, int bytes); 304 const u8 *new, int bytes);
304int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva); 305int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva);