diff options
author | Paul Mackerras <paulus@samba.org> | 2012-09-20 15:39:21 -0400 |
---|---|---|
committer | Alexander Graf <agraf@suse.de> | 2012-10-05 17:38:53 -0400 |
commit | 70bddfefbdcdbfdebd81d8b59ff8a7fa5d450ccc (patch) | |
tree | 64196d1bffa4379dfcf6ed6c4e809ba138ae44cc /arch | |
parent | 964ee98ccde0534548565a201827cf06d813180f (diff) |
KVM: PPC: Book3S HV: Fix calculation of guest phys address for MMIO emulation
In the case where the host kernel is using a 64kB base page size and
the guest uses a 4k HPTE (hashed page table entry) to map an emulated
MMIO device, we were calculating the guest physical address wrongly.
We were calculating a gfn as the guest physical address shifted right
16 bits (PAGE_SHIFT) but then only adding back in 12 bits from the
effective address, since the HPTE had a 4k page size. Thus the gpa
reported to userspace was missing 4 bits.
Instead, we now compute the guest physical address from the HPTE
without reference to the host page size, and then compute the gfn
by shifting the gpa right PAGE_SHIFT bits.
Reported-by: Alexey Kardashevskiy <aik@ozlabs.ru>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/kvm/book3s_64_mmu_hv.c | 9 |
1 files changed, 4 insertions, 5 deletions
diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c index f598366e51c6..7a4aae99ac5b 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_hv.c +++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c | |||
@@ -571,7 +571,7 @@ int kvmppc_book3s_hv_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu, | |||
571 | struct kvm *kvm = vcpu->kvm; | 571 | struct kvm *kvm = vcpu->kvm; |
572 | unsigned long *hptep, hpte[3], r; | 572 | unsigned long *hptep, hpte[3], r; |
573 | unsigned long mmu_seq, psize, pte_size; | 573 | unsigned long mmu_seq, psize, pte_size; |
574 | unsigned long gfn, hva, pfn; | 574 | unsigned long gpa, gfn, hva, pfn; |
575 | struct kvm_memory_slot *memslot; | 575 | struct kvm_memory_slot *memslot; |
576 | unsigned long *rmap; | 576 | unsigned long *rmap; |
577 | struct revmap_entry *rev; | 577 | struct revmap_entry *rev; |
@@ -609,15 +609,14 @@ int kvmppc_book3s_hv_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu, | |||
609 | 609 | ||
610 | /* Translate the logical address and get the page */ | 610 | /* Translate the logical address and get the page */ |
611 | psize = hpte_page_size(hpte[0], r); | 611 | psize = hpte_page_size(hpte[0], r); |
612 | gfn = hpte_rpn(r, psize); | 612 | gpa = (r & HPTE_R_RPN & ~(psize - 1)) | (ea & (psize - 1)); |
613 | gfn = gpa >> PAGE_SHIFT; | ||
613 | memslot = gfn_to_memslot(kvm, gfn); | 614 | memslot = gfn_to_memslot(kvm, gfn); |
614 | 615 | ||
615 | /* No memslot means it's an emulated MMIO region */ | 616 | /* No memslot means it's an emulated MMIO region */ |
616 | if (!memslot || (memslot->flags & KVM_MEMSLOT_INVALID)) { | 617 | if (!memslot || (memslot->flags & KVM_MEMSLOT_INVALID)) |
617 | unsigned long gpa = (gfn << PAGE_SHIFT) | (ea & (psize - 1)); | ||
618 | return kvmppc_hv_emulate_mmio(run, vcpu, gpa, ea, | 618 | return kvmppc_hv_emulate_mmio(run, vcpu, gpa, ea, |
619 | dsisr & DSISR_ISSTORE); | 619 | dsisr & DSISR_ISSTORE); |
620 | } | ||
621 | 620 | ||
622 | if (!kvm->arch.using_mmu_notifiers) | 621 | if (!kvm->arch.using_mmu_notifiers) |
623 | return -EFAULT; /* should never get here */ | 622 | return -EFAULT; /* should never get here */ |