On Wed, 2016-11-09 at 14:46 +0000, James Hogan wrote: > commit 91e4f1b6073dd680d86cdb7e42d7cccca9db39d8 upstream. > > When a guest TLB entry is replaced by TLBWI or TLBWR, we only invalidate > TLB entries on the local CPU. This doesn't work correctly on an SMP host > when the guest is migrated to a different physical CPU, as it could pick > up stale TLB mappings from the last time the vCPU ran on that physical > CPU. > > Therefore invalidate both user and kernel host ASIDs on other CPUs, > which will cause new ASIDs to be generated when it next runs on those > CPUs. > > We're careful only to do this if the TLB entry was already valid, and > only for the kernel ASID where the virtual address it mapped is outside > of the guest user address range. > > Signed-off-by: James Hogan <james.hogan@xxxxxxxxxx> > Cc: Paolo Bonzini <pbonzini@xxxxxxxxxx> > Cc: "Radim Krčmář" <rkrcmar@xxxxxxxxxx> > Cc: Ralf Baechle <ralf@xxxxxxxxxxxxxx> > Cc: linux-mips@xxxxxxxxxxxxxx > Cc: kvm@xxxxxxxxxxxxxxx > Cc: <stable@xxxxxxxxxxxxxxx> # 3.10.x- > Cc: Jiri Slaby <jslaby@xxxxxxx> > [james.hogan@xxxxxxxxxx: Backport to 3.10..3.16] > Signed-off-by: James Hogan <james.hogan@xxxxxxxxxx> Queued up for 3.16, thanks. Ben. > --- > Unfortunately the original commit went in to v3.12.65 as commit > 168e5ebbd63e, without fixing up the references to tlb_lo[0/1] to > tlb_lo0/1 which broke the MIPS KVM build, and I didn't twig that I > already had a correct backport outstanding (sorry!). That commit should > be reverted before applying this backport to 3.12. > --- > arch/mips/kvm/kvm_mips_emul.c | 61 +++++++++++++++++++++++++++++++++++++------ > 1 file changed, 53 insertions(+), 8 deletions(-) > > diff --git a/arch/mips/kvm/kvm_mips_emul.c b/arch/mips/kvm/kvm_mips_emul.c > index 1983678883c9..d0eb34279955 100644 > --- a/arch/mips/kvm/kvm_mips_emul.c > +++ b/arch/mips/kvm/kvm_mips_emul.c > @@ -817,6 +817,47 @@ enum emulation_result kvm_mips_emul_tlbr(struct kvm_vcpu *vcpu) > > return er; > } > > +/** > + * kvm_mips_invalidate_guest_tlb() - Indicates a change in guest MMU map. > > + * @vcpu: VCPU with changed mappings. > > + * @tlb: TLB entry being removed. > + * > + * This is called to indicate a single change in guest MMU mappings, so that we > + * can arrange TLB flushes on this and other CPUs. > + */ > +static void kvm_mips_invalidate_guest_tlb(struct kvm_vcpu *vcpu, > > + struct kvm_mips_tlb *tlb) > +{ > > + int cpu, i; > > + bool user; > + > > + /* No need to flush for entries which are already invalid */ > > + if (!((tlb->tlb_lo0 | tlb->tlb_lo1) & MIPS3_PG_V)) > > + return; > > + /* User address space doesn't need flushing for KSeg2/3 changes */ > > + user = tlb->tlb_hi < KVM_GUEST_KSEG0; > + > > + preempt_disable(); > + > > + /* > > + * Probe the shadow host TLB for the entry being overwritten, if one > > + * matches, invalidate it > > + */ > > + kvm_mips_host_tlb_inv(vcpu, tlb->tlb_hi); > + > > + /* Invalidate the whole ASID on other CPUs */ > > + cpu = smp_processor_id(); > > + for_each_possible_cpu(i) { > > + if (i == cpu) > > + continue; > > + if (user) > > + vcpu->arch.guest_user_asid[i] = 0; > > + vcpu->arch.guest_kernel_asid[i] = 0; > > + } > + > > + preempt_enable(); > +} > + > /* Write Guest TLB Entry @ Index */ > enum emulation_result kvm_mips_emul_tlbwi(struct kvm_vcpu *vcpu) > { > @@ -838,10 +879,8 @@ enum emulation_result kvm_mips_emul_tlbwi(struct kvm_vcpu *vcpu) > > } > > > tlb = &vcpu->arch.guest_tlb[index]; > -#if 1 > > - /* Probe the shadow host TLB for the entry being overwritten, if one matches, invalidate it */ > > - kvm_mips_host_tlb_inv(vcpu, tlb->tlb_hi); > -#endif > + > > + kvm_mips_invalidate_guest_tlb(vcpu, tlb); > > > tlb->tlb_mask = kvm_read_c0_guest_pagemask(cop0); > > tlb->tlb_hi = kvm_read_c0_guest_entryhi(cop0); > @@ -880,10 +919,7 @@ enum emulation_result kvm_mips_emul_tlbwr(struct kvm_vcpu *vcpu) > > > tlb = &vcpu->arch.guest_tlb[index]; > > -#if 1 > > - /* Probe the shadow host TLB for the entry being overwritten, if one matches, invalidate it */ > > - kvm_mips_host_tlb_inv(vcpu, tlb->tlb_hi); > -#endif > > + kvm_mips_invalidate_guest_tlb(vcpu, tlb); > > > tlb->tlb_mask = kvm_read_c0_guest_pagemask(cop0); > > tlb->tlb_hi = kvm_read_c0_guest_entryhi(cop0); > @@ -926,6 +962,7 @@ kvm_mips_emulate_CP0(uint32_t inst, uint32_t *opc, uint32_t cause, > > int32_t rt, rd, copz, sel, co_bit, op; > > uint32_t pc = vcpu->arch.pc; > > unsigned long curr_pc; > > + int cpu, i; > > > /* > > * Update PC and hold onto current PC in case there is > @@ -1037,8 +1074,16 @@ kvm_mips_emulate_CP0(uint32_t inst, uint32_t *opc, uint32_t cause, > > ASID_MASK, > > vcpu->arch.gprs[rt] & ASID_MASK); > > > + preempt_disable(); > > /* Blow away the shadow host TLBs */ > > kvm_mips_flush_host_tlb(1); > > + cpu = smp_processor_id(); > > + for_each_possible_cpu(i) > > + if (i != cpu) { > > + vcpu->arch.guest_user_asid[i] = 0; > > + vcpu->arch.guest_kernel_asid[i] = 0; > > + } > > + preempt_enable(); > > } > > kvm_write_c0_guest_entryhi(cop0, > vcpu->arch.gprs[rt]); -- Ben Hutchings If you seem to know what you are doing, you'll be given more to do.
Attachment:
signature.asc
Description: This is a digitally signed message part