aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Hogan <james.hogan@imgtec.com>2016-10-07 19:15:52 -0400
committerJames Hogan <james.hogan@imgtec.com>2017-02-03 10:20:54 -0500
commit57e3869cfaaec712f6ea1855ab7ba868f6f306ed (patch)
tree4a4a5e45953ba95e744c4ca59fe32faee5daaf5d
parentf3a8603f098fd2c68311d945a6531d1e3b62271c (diff)
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
-rw-r--r--arch/mips/include/asm/kvm_host.h3
-rw-r--r--arch/mips/kvm/emulate.c6
-rw-r--r--arch/mips/kvm/tlb.c40
3 files changed, 36 insertions, 13 deletions
diff --git a/arch/mips/include/asm/kvm_host.h b/arch/mips/include/asm/kvm_host.h
index 80928ffa0150..fb2ea578c193 100644
--- a/arch/mips/include/asm/kvm_host.h
+++ b/arch/mips/include/asm/kvm_host.h
@@ -604,7 +604,8 @@ extern int kvm_mips_host_tlb_write(struct kvm_vcpu *vcpu, unsigned long entryhi,
604 unsigned long entrylo1, 604 unsigned long entrylo1,
605 int flush_dcache_mask); 605 int flush_dcache_mask);
606extern void kvm_mips_flush_host_tlb(int skip_kseg0); 606extern void kvm_mips_flush_host_tlb(int skip_kseg0);
607extern int kvm_mips_host_tlb_inv(struct kvm_vcpu *vcpu, unsigned long entryhi); 607extern int kvm_mips_host_tlb_inv(struct kvm_vcpu *vcpu, unsigned long entryhi,
608 bool user, bool kernel);
608 609
609extern int kvm_mips_guest_tlb_lookup(struct kvm_vcpu *vcpu, 610extern int kvm_mips_guest_tlb_lookup(struct kvm_vcpu *vcpu,
610 unsigned long entryhi); 611 unsigned long entryhi);
diff --git a/arch/mips/kvm/emulate.c b/arch/mips/kvm/emulate.c
index 060acc5b3378..611b8996ca0c 100644
--- a/arch/mips/kvm/emulate.c
+++ b/arch/mips/kvm/emulate.c
@@ -873,7 +873,7 @@ static void kvm_mips_invalidate_guest_tlb(struct kvm_vcpu *vcpu,
873 * Probe the shadow host TLB for the entry being overwritten, if one 873 * Probe the shadow host TLB for the entry being overwritten, if one
874 * matches, invalidate it 874 * matches, invalidate it
875 */ 875 */
876 kvm_mips_host_tlb_inv(vcpu, tlb->tlb_hi); 876 kvm_mips_host_tlb_inv(vcpu, tlb->tlb_hi, user, true);
877 877
878 /* Invalidate the whole ASID on other CPUs */ 878 /* Invalidate the whole ASID on other CPUs */
879 cpu = smp_processor_id(); 879 cpu = smp_processor_id();
@@ -2100,13 +2100,15 @@ enum emulation_result kvm_mips_handle_tlbmod(u32 cause, u32 *opc,
2100 struct mips_coproc *cop0 = vcpu->arch.cop0; 2100 struct mips_coproc *cop0 = vcpu->arch.cop0;
2101 unsigned long entryhi = (vcpu->arch.host_cp0_badvaddr & VPN2_MASK) | 2101 unsigned long entryhi = (vcpu->arch.host_cp0_badvaddr & VPN2_MASK) |
2102 (kvm_read_c0_guest_entryhi(cop0) & KVM_ENTRYHI_ASID); 2102 (kvm_read_c0_guest_entryhi(cop0) & KVM_ENTRYHI_ASID);
2103 bool kernel = KVM_GUEST_KERNEL_MODE(vcpu);
2103 int index; 2104 int index;
2104 2105
2105 /* If address not in the guest TLB, then we are in trouble */ 2106 /* If address not in the guest TLB, then we are in trouble */
2106 index = kvm_mips_guest_tlb_lookup(vcpu, entryhi); 2107 index = kvm_mips_guest_tlb_lookup(vcpu, entryhi);
2107 if (index < 0) { 2108 if (index < 0) {
2108 /* XXXKYMA Invalidate and retry */ 2109 /* XXXKYMA Invalidate and retry */
2109 kvm_mips_host_tlb_inv(vcpu, vcpu->arch.host_cp0_badvaddr); 2110 kvm_mips_host_tlb_inv(vcpu, vcpu->arch.host_cp0_badvaddr,
2111 !kernel, kernel);
2110 kvm_err("%s: host got TLBMOD for %#lx but entry not present in Guest TLB\n", 2112 kvm_err("%s: host got TLBMOD for %#lx but entry not present in Guest TLB\n",
2111 __func__, entryhi); 2113 __func__, entryhi);
2112 kvm_mips_dump_guest_tlbs(vcpu); 2114 kvm_mips_dump_guest_tlbs(vcpu);
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)
263} 263}
264EXPORT_SYMBOL_GPL(kvm_mips_host_tlb_lookup); 264EXPORT_SYMBOL_GPL(kvm_mips_host_tlb_lookup);
265 265
266int kvm_mips_host_tlb_inv(struct kvm_vcpu *vcpu, unsigned long va) 266static int _kvm_mips_host_tlb_inv(unsigned long entryhi)
267{ 267{
268 int idx; 268 int idx;
269 unsigned long flags, old_entryhi;
270
271 local_irq_save(flags);
272
273 old_entryhi = read_c0_entryhi();
274 269
275 write_c0_entryhi((va & VPN2_MASK) | kvm_mips_get_user_asid(vcpu)); 270 write_c0_entryhi(entryhi);
276 mtc0_tlbw_hazard(); 271 mtc0_tlbw_hazard();
277 272
278 tlb_probe(); 273 tlb_probe();
@@ -292,14 +287,39 @@ int kvm_mips_host_tlb_inv(struct kvm_vcpu *vcpu, unsigned long va)
292 tlbw_use_hazard(); 287 tlbw_use_hazard();
293 } 288 }
294 289
290 return idx;
291}
292
293int kvm_mips_host_tlb_inv(struct kvm_vcpu *vcpu, unsigned long va,
294 bool user, bool kernel)
295{
296 int idx_user, idx_kernel;
297 unsigned long flags, old_entryhi;
298
299 local_irq_save(flags);
300
301 old_entryhi = read_c0_entryhi();
302
303 if (user)
304 idx_user = _kvm_mips_host_tlb_inv((va & VPN2_MASK) |
305 kvm_mips_get_user_asid(vcpu));
306 if (kernel)
307 idx_kernel = _kvm_mips_host_tlb_inv((va & VPN2_MASK) |
308 kvm_mips_get_kernel_asid(vcpu));
309
295 write_c0_entryhi(old_entryhi); 310 write_c0_entryhi(old_entryhi);
296 mtc0_tlbw_hazard(); 311 mtc0_tlbw_hazard();
297 312
298 local_irq_restore(flags); 313 local_irq_restore(flags);
299 314
300 if (idx >= 0) 315 if (user && idx_user >= 0)
301 kvm_debug("%s: Invalidated entryhi %#lx @ idx %d\n", __func__, 316 kvm_debug("%s: Invalidated guest user entryhi %#lx @ idx %d\n",
302 (va & VPN2_MASK) | kvm_mips_get_user_asid(vcpu), idx); 317 __func__, (va & VPN2_MASK) |
318 kvm_mips_get_user_asid(vcpu), idx_user);
319 if (kernel && idx_kernel >= 0)
320 kvm_debug("%s: Invalidated guest kernel entryhi %#lx @ idx %d\n",
321 __func__, (va & VPN2_MASK) |
322 kvm_mips_get_kernel_asid(vcpu), idx_kernel);
303 323
304 return 0; 324 return 0;
305} 325}