aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/kvm/kvm.h1
-rw-r--r--drivers/kvm/kvm_main.c29
2 files changed, 20 insertions, 10 deletions
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
index b65511ed4388..8323f4009362 100644
--- a/drivers/kvm/kvm.h
+++ b/drivers/kvm/kvm.h
@@ -185,6 +185,7 @@ struct kvm_vcpu {
185 unsigned long cr3; 185 unsigned long cr3;
186 unsigned long cr4; 186 unsigned long cr4;
187 unsigned long cr8; 187 unsigned long cr8;
188 u64 pdptrs[4]; /* pae */
188 u64 shadow_efer; 189 u64 shadow_efer;
189 u64 apic_base; 190 u64 apic_base;
190 int nmsrs; 191 int nmsrs;
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index f2a6b6f0e929..4512d8c39c84 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -298,14 +298,17 @@ static void inject_gp(struct kvm_vcpu *vcpu)
298 kvm_arch_ops->inject_gp(vcpu, 0); 298 kvm_arch_ops->inject_gp(vcpu, 0);
299} 299}
300 300
301static int pdptrs_have_reserved_bits_set(struct kvm_vcpu *vcpu, 301/*
302 unsigned long cr3) 302 * Load the pae pdptrs. Return true is they are all valid.
303 */
304static int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3)
303{ 305{
304 gfn_t pdpt_gfn = cr3 >> PAGE_SHIFT; 306 gfn_t pdpt_gfn = cr3 >> PAGE_SHIFT;
305 unsigned offset = (cr3 & (PAGE_SIZE-1)) >> 5; 307 unsigned offset = ((cr3 & (PAGE_SIZE-1)) >> 5) << 2;
306 int i; 308 int i;
307 u64 pdpte; 309 u64 pdpte;
308 u64 *pdpt; 310 u64 *pdpt;
311 int ret;
309 struct kvm_memory_slot *memslot; 312 struct kvm_memory_slot *memslot;
310 313
311 spin_lock(&vcpu->kvm->lock); 314 spin_lock(&vcpu->kvm->lock);
@@ -313,16 +316,23 @@ static int pdptrs_have_reserved_bits_set(struct kvm_vcpu *vcpu,
313 /* FIXME: !memslot - emulate? 0xff? */ 316 /* FIXME: !memslot - emulate? 0xff? */
314 pdpt = kmap_atomic(gfn_to_page(memslot, pdpt_gfn), KM_USER0); 317 pdpt = kmap_atomic(gfn_to_page(memslot, pdpt_gfn), KM_USER0);
315 318
319 ret = 1;
316 for (i = 0; i < 4; ++i) { 320 for (i = 0; i < 4; ++i) {
317 pdpte = pdpt[offset + i]; 321 pdpte = pdpt[offset + i];
318 if ((pdpte & 1) && (pdpte & 0xfffffff0000001e6ull)) 322 if ((pdpte & 1) && (pdpte & 0xfffffff0000001e6ull)) {
319 break; 323 ret = 0;
324 goto out;
325 }
320 } 326 }
321 327
328 for (i = 0; i < 4; ++i)
329 vcpu->pdptrs[i] = pdpt[offset + i];
330
331out:
322 kunmap_atomic(pdpt, KM_USER0); 332 kunmap_atomic(pdpt, KM_USER0);
323 spin_unlock(&vcpu->kvm->lock); 333 spin_unlock(&vcpu->kvm->lock);
324 334
325 return i != 4; 335 return ret;
326} 336}
327 337
328void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) 338void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
@@ -368,8 +378,7 @@ void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
368 } 378 }
369 } else 379 } else
370#endif 380#endif
371 if (is_pae(vcpu) && 381 if (is_pae(vcpu) && !load_pdptrs(vcpu, vcpu->cr3)) {
372 pdptrs_have_reserved_bits_set(vcpu, vcpu->cr3)) {
373 printk(KERN_DEBUG "set_cr0: #GP, pdptrs " 382 printk(KERN_DEBUG "set_cr0: #GP, pdptrs "
374 "reserved bits\n"); 383 "reserved bits\n");
375 inject_gp(vcpu); 384 inject_gp(vcpu);
@@ -411,7 +420,7 @@ void set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
411 return; 420 return;
412 } 421 }
413 } else if (is_paging(vcpu) && !is_pae(vcpu) && (cr4 & CR4_PAE_MASK) 422 } else if (is_paging(vcpu) && !is_pae(vcpu) && (cr4 & CR4_PAE_MASK)
414 && pdptrs_have_reserved_bits_set(vcpu, vcpu->cr3)) { 423 && !load_pdptrs(vcpu, vcpu->cr3)) {
415 printk(KERN_DEBUG "set_cr4: #GP, pdptrs reserved bits\n"); 424 printk(KERN_DEBUG "set_cr4: #GP, pdptrs reserved bits\n");
416 inject_gp(vcpu); 425 inject_gp(vcpu);
417 } 426 }
@@ -443,7 +452,7 @@ void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
443 return; 452 return;
444 } 453 }
445 if (is_paging(vcpu) && is_pae(vcpu) && 454 if (is_paging(vcpu) && is_pae(vcpu) &&
446 pdptrs_have_reserved_bits_set(vcpu, cr3)) { 455 !load_pdptrs(vcpu, cr3)) {
447 printk(KERN_DEBUG "set_cr3: #GP, pdptrs " 456 printk(KERN_DEBUG "set_cr3: #GP, pdptrs "
448 "reserved bits\n"); 457 "reserved bits\n");
449 inject_gp(vcpu); 458 inject_gp(vcpu);