|
@@ -99,7 +99,7 @@ int kvm_mips_handle_kseg0_tlb_fault(unsigned long badvaddr,
|
|
|
}
|
|
|
|
|
|
gfn = (KVM_GUEST_CPHYSADDR(badvaddr) >> PAGE_SHIFT);
|
|
|
- if (gfn >= kvm->arch.guest_pmap_npages) {
|
|
|
+ if ((gfn | 1) >= kvm->arch.guest_pmap_npages) {
|
|
|
kvm_err("%s: Invalid gfn: %#llx, BadVaddr: %#lx\n", __func__,
|
|
|
gfn, badvaddr);
|
|
|
kvm_mips_dump_host_tlbs();
|
|
@@ -138,35 +138,49 @@ int kvm_mips_handle_mapped_seg_tlb_fault(struct kvm_vcpu *vcpu,
|
|
|
unsigned long entryhi = 0, entrylo0 = 0, entrylo1 = 0;
|
|
|
struct kvm *kvm = vcpu->kvm;
|
|
|
kvm_pfn_t pfn0, pfn1;
|
|
|
+ gfn_t gfn0, gfn1;
|
|
|
+ long tlb_lo[2];
|
|
|
int ret;
|
|
|
|
|
|
- if ((tlb->tlb_hi & VPN2_MASK) == 0) {
|
|
|
- pfn0 = 0;
|
|
|
- pfn1 = 0;
|
|
|
- } else {
|
|
|
- if (kvm_mips_map_page(kvm, mips3_tlbpfn_to_paddr(tlb->tlb_lo[0])
|
|
|
- >> PAGE_SHIFT) < 0)
|
|
|
- return -1;
|
|
|
-
|
|
|
- if (kvm_mips_map_page(kvm, mips3_tlbpfn_to_paddr(tlb->tlb_lo[1])
|
|
|
- >> PAGE_SHIFT) < 0)
|
|
|
- return -1;
|
|
|
-
|
|
|
- pfn0 = kvm->arch.guest_pmap[
|
|
|
- mips3_tlbpfn_to_paddr(tlb->tlb_lo[0]) >> PAGE_SHIFT];
|
|
|
- pfn1 = kvm->arch.guest_pmap[
|
|
|
- mips3_tlbpfn_to_paddr(tlb->tlb_lo[1]) >> PAGE_SHIFT];
|
|
|
+ tlb_lo[0] = tlb->tlb_lo[0];
|
|
|
+ tlb_lo[1] = tlb->tlb_lo[1];
|
|
|
+
|
|
|
+ /*
|
|
|
+ * The commpage address must not be mapped to anything else if the guest
|
|
|
+ * TLB contains entries nearby, or commpage accesses will break.
|
|
|
+ */
|
|
|
+ if (!((tlb->tlb_hi ^ KVM_GUEST_COMMPAGE_ADDR) &
|
|
|
+ VPN2_MASK & (PAGE_MASK << 1)))
|
|
|
+ tlb_lo[(KVM_GUEST_COMMPAGE_ADDR >> PAGE_SHIFT) & 1] = 0;
|
|
|
+
|
|
|
+ gfn0 = mips3_tlbpfn_to_paddr(tlb_lo[0]) >> PAGE_SHIFT;
|
|
|
+ gfn1 = mips3_tlbpfn_to_paddr(tlb_lo[1]) >> PAGE_SHIFT;
|
|
|
+ if (gfn0 >= kvm->arch.guest_pmap_npages ||
|
|
|
+ gfn1 >= kvm->arch.guest_pmap_npages) {
|
|
|
+ kvm_err("%s: Invalid gfn: [%#llx, %#llx], EHi: %#lx\n",
|
|
|
+ __func__, gfn0, gfn1, tlb->tlb_hi);
|
|
|
+ kvm_mips_dump_guest_tlbs(vcpu);
|
|
|
+ return -1;
|
|
|
}
|
|
|
|
|
|
+ if (kvm_mips_map_page(kvm, gfn0) < 0)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ if (kvm_mips_map_page(kvm, gfn1) < 0)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ pfn0 = kvm->arch.guest_pmap[gfn0];
|
|
|
+ pfn1 = kvm->arch.guest_pmap[gfn1];
|
|
|
+
|
|
|
/* Get attributes from the Guest TLB */
|
|
|
entrylo0 = mips3_paddr_to_tlbpfn(pfn0 << PAGE_SHIFT) |
|
|
|
((_page_cachable_default >> _CACHE_SHIFT) << ENTRYLO_C_SHIFT) |
|
|
|
- (tlb->tlb_lo[0] & ENTRYLO_D) |
|
|
|
- (tlb->tlb_lo[0] & ENTRYLO_V);
|
|
|
+ (tlb_lo[0] & ENTRYLO_D) |
|
|
|
+ (tlb_lo[0] & ENTRYLO_V);
|
|
|
entrylo1 = mips3_paddr_to_tlbpfn(pfn1 << PAGE_SHIFT) |
|
|
|
((_page_cachable_default >> _CACHE_SHIFT) << ENTRYLO_C_SHIFT) |
|
|
|
- (tlb->tlb_lo[1] & ENTRYLO_D) |
|
|
|
- (tlb->tlb_lo[1] & ENTRYLO_V);
|
|
|
+ (tlb_lo[1] & ENTRYLO_D) |
|
|
|
+ (tlb_lo[1] & ENTRYLO_V);
|
|
|
|
|
|
kvm_debug("@ %#lx tlb_lo0: 0x%08lx tlb_lo1: 0x%08lx\n", vcpu->arch.pc,
|
|
|
tlb->tlb_lo[0], tlb->tlb_lo[1]);
|
|
@@ -354,9 +368,15 @@ u32 kvm_get_inst(u32 *opc, struct kvm_vcpu *vcpu)
|
|
|
local_irq_restore(flags);
|
|
|
return KVM_INVALID_INST;
|
|
|
}
|
|
|
- kvm_mips_handle_mapped_seg_tlb_fault(vcpu,
|
|
|
- &vcpu->arch.
|
|
|
- guest_tlb[index]);
|
|
|
+ if (kvm_mips_handle_mapped_seg_tlb_fault(vcpu,
|
|
|
+ &vcpu->arch.guest_tlb[index])) {
|
|
|
+ kvm_err("%s: handling mapped seg tlb fault failed for %p, index: %u, vcpu: %p, ASID: %#lx\n",
|
|
|
+ __func__, opc, index, vcpu,
|
|
|
+ read_c0_entryhi());
|
|
|
+ kvm_mips_dump_guest_tlbs(vcpu);
|
|
|
+ local_irq_restore(flags);
|
|
|
+ return KVM_INVALID_INST;
|
|
|
+ }
|
|
|
inst = *(opc);
|
|
|
}
|
|
|
local_irq_restore(flags);
|