aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/kvm/kvm_main.c22
1 files changed, 12 insertions, 10 deletions
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index 80ee427754d2..65c9a31f1d91 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -442,30 +442,32 @@ static int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3)
442 gfn_t pdpt_gfn = cr3 >> PAGE_SHIFT; 442 gfn_t pdpt_gfn = cr3 >> PAGE_SHIFT;
443 unsigned offset = ((cr3 & (PAGE_SIZE-1)) >> 5) << 2; 443 unsigned offset = ((cr3 & (PAGE_SIZE-1)) >> 5) << 2;
444 int i; 444 int i;
445 u64 pdpte;
446 u64 *pdpt; 445 u64 *pdpt;
447 int ret; 446 int ret;
448 struct page *page; 447 struct page *page;
448 u64 pdpte[ARRAY_SIZE(vcpu->pdptrs)];
449 449
450 spin_lock(&vcpu->kvm->lock); 450 spin_lock(&vcpu->kvm->lock);
451 page = gfn_to_page(vcpu->kvm, pdpt_gfn); 451 page = gfn_to_page(vcpu->kvm, pdpt_gfn);
452 /* FIXME: !page - emulate? 0xff? */ 452 if (!page) {
453 ret = 0;
454 goto out;
455 }
456
453 pdpt = kmap_atomic(page, KM_USER0); 457 pdpt = kmap_atomic(page, KM_USER0);
458 memcpy(pdpte, pdpt+offset, sizeof(pdpte));
459 kunmap_atomic(pdpt, KM_USER0);
454 460
455 ret = 1; 461 for (i = 0; i < ARRAY_SIZE(pdpte); ++i) {
456 for (i = 0; i < 4; ++i) { 462 if ((pdpte[i] & 1) && (pdpte[i] & 0xfffffff0000001e6ull)) {
457 pdpte = pdpt[offset + i];
458 if ((pdpte & 1) && (pdpte & 0xfffffff0000001e6ull)) {
459 ret = 0; 463 ret = 0;
460 goto out; 464 goto out;
461 } 465 }
462 } 466 }
467 ret = 1;
463 468
464 for (i = 0; i < 4; ++i) 469 memcpy(vcpu->pdptrs, pdpte, sizeof(vcpu->pdptrs));
465 vcpu->pdptrs[i] = pdpt[offset + i];
466
467out: 470out:
468 kunmap_atomic(pdpt, KM_USER0);
469 spin_unlock(&vcpu->kvm->lock); 471 spin_unlock(&vcpu->kvm->lock);
470 472
471 return ret; 473 return ret;