aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/kvm/kvm_main.c
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2007-07-24 23:29:51 -0400
committerAvi Kivity <avi@qumranet.com>2007-10-13 04:18:20 -0400
commitc820c2aa27bb5b6069aa708b0a0b44b59a16bfa7 (patch)
tree4fbf8adca97cafb1f52968fed36963fb36c4254d /drivers/kvm/kvm_main.c
parent3ccb8827fb3bd389ed15320da83543d016a94822 (diff)
KVM: load_pdptrs() cleanups
load_pdptrs can be handed an invalid cr3, and it should not oops. This can happen because we injected #gp in set_cr3() after we set vcpu->cr3 to the invalid value, or from kvm_vcpu_ioctl_set_sregs(), or memory configuration changes after the guest did set_cr3(). We should also copy the pdpte array once, before checking and assigning, otherwise an SMP guest can potentially alter the values between the check and the set. Finally one nitpick: ret = 1 should be done as late as possible: this allows GCC to check for unset "ret" should the function change in future. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers/kvm/kvm_main.c')
-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;