summaryrefslogtreecommitdiffstats
path: root/arch/mips/kvm/tlb.c
diff options
context:
space:
mode:
authorJames Hogan2016-10-08 01:15:52 +0200
committerJames Hogan2017-02-03 16:20:54 +0100
commit57e3869cfaaec712f6ea1855ab7ba868f6f306ed (patch)
tree4a4a5e45953ba95e744c4ca59fe32faee5daaf5d /arch/mips/kvm/tlb.c
parentKVM: MIPS/TLB: Fix off-by-one in TLB invalidate (diff)
downloadkernel-qcow2-linux-57e3869cfaaec712f6ea1855ab7ba868f6f306ed.tar.gz
kernel-qcow2-linux-57e3869cfaaec712f6ea1855ab7ba868f6f306ed.tar.xz
kernel-qcow2-linux-57e3869cfaaec712f6ea1855ab7ba868f6f306ed.zip
KVM: MIPS/TLB: Generalise host TLB invalidate to kernel ASID
Refactor kvm_mips_host_tlb_inv() to also be able to invalidate any matching TLB entry in the kernel ASID rather than assuming only the TLB entries in the user ASID can change. Two new bool user/kernel arguments allow the caller to indicate whether the mapping should affect each of the ASIDs for guest user/kernel mode. - kvm_mips_invalidate_guest_tlb() (used by TLBWI/TLBWR emulation) can now invalidate any corresponding TLB entry in both the kernel ASID (guest kernel may have accessed any guest mapping), and the user ASID if the entry being replaced is in guest USeg (where guest user may also have accessed it). - The tlbmod fault handler (and the KSeg0 / TLB mapped / commpage fault handlers in later patches) can now invalidate the corresponding TLB entry in whichever ASID is currently active, since only a single page table will have been updated anyway. Signed-off-by: James Hogan <james.hogan@imgtec.com> Cc: Paolo Bonzini <pbonzini@redhat.com> Cc: "Radim Krčmář" <rkrcmar@redhat.com> Cc: Ralf Baechle <ralf@linux-mips.org> Cc: linux-mips@linux-mips.org Cc: kvm@vger.kernel.org
Diffstat (limited to 'arch/mips/kvm/tlb.c')
-rw-r--r--arch/mips/kvm/tlb.c40
1 files changed, 30 insertions, 10 deletions
diff --git a/arch/mips/kvm/tlb.c b/arch/mips/kvm/tlb.c
index 4bf82613d440..06ee9a1d78a5 100644
--- a/arch/mips/kvm/tlb.c
+++ b/arch/mips/kvm/tlb.c
@@ -263,16 +263,11 @@ int kvm_mips_host_tlb_lookup(struct kvm_vcpu *vcpu, unsigned long vaddr)
}
EXPORT_SYMBOL_GPL(kvm_mips_host_tlb_lookup);
-int kvm_mips_host_tlb_inv(struct kvm_vcpu *vcpu, unsigned long va)
+static int _kvm_mips_host_tlb_inv(unsigned long entryhi)
{
int idx;
- unsigned long flags, old_entryhi;
-
- local_irq_save(flags);
-
- old_entryhi = read_c0_entryhi();
- write_c0_entryhi((va & VPN2_MASK) | kvm_mips_get_user_asid(vcpu));
+ write_c0_entryhi(entryhi);
mtc0_tlbw_hazard();
tlb_probe();
@@ -292,14 +287,39 @@ int kvm_mips_host_tlb_inv(struct kvm_vcpu *vcpu, unsigned long va)
tlbw_use_hazard();
}
+ return idx;
+}
+
+int kvm_mips_host_tlb_inv(struct kvm_vcpu *vcpu, unsigned long va,
+ bool user, bool kernel)
+{
+ int idx_user, idx_kernel;
+ unsigned long flags, old_entryhi;
+
+ local_irq_save(flags);
+
+ old_entryhi = read_c0_entryhi();
+
+ if (user)
+ idx_user = _kvm_mips_host_tlb_inv((va & VPN2_MASK) |
+ kvm_mips_get_user_asid(vcpu));
+ if (kernel)
+ idx_kernel = _kvm_mips_host_tlb_inv((va & VPN2_MASK) |
+ kvm_mips_get_kernel_asid(vcpu));
+
write_c0_entryhi(old_entryhi);
mtc0_tlbw_hazard();
local_irq_restore(flags);
- if (idx >= 0)
- kvm_debug("%s: Invalidated entryhi %#lx @ idx %d\n", __func__,
- (va & VPN2_MASK) | kvm_mips_get_user_asid(vcpu), idx);
+ if (user && idx_user >= 0)
+ kvm_debug("%s: Invalidated guest user entryhi %#lx @ idx %d\n",
+ __func__, (va & VPN2_MASK) |
+ kvm_mips_get_user_asid(vcpu), idx_user);
+ if (kernel && idx_kernel >= 0)
+ kvm_debug("%s: Invalidated guest kernel entryhi %#lx @ idx %d\n",
+ __func__, (va & VPN2_MASK) |
+ kvm_mips_get_kernel_asid(vcpu), idx_kernel);
return 0;
}