aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Hogan <james.hogan@imgtec.com>2016-09-15 12:20:06 -0400
committerJames Hogan <james.hogan@imgtec.com>2016-09-29 07:39:30 -0400
commit91e4f1b6073dd680d86cdb7e42d7cccca9db39d8 (patch)
tree961b33d04895288d2758c6c384f2b38fe1eca6e3
parentd5888477d31c64dba9264fbb33cfa9b066f071d0 (diff)
KVM: MIPS: Drop other CPU ASIDs on guest MMU changes
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@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 Cc: <stable@vger.kernel.org> # 3.10.x-
-rw-r--r--arch/mips/kvm/emulate.c63
1 files changed, 53 insertions, 10 deletions
diff --git a/arch/mips/kvm/emulate.c b/arch/mips/kvm/emulate.c
index e788515f766b..43853ec6e160 100644
--- a/arch/mips/kvm/emulate.c
+++ b/arch/mips/kvm/emulate.c
@@ -846,6 +846,47 @@ enum emulation_result kvm_mips_emul_tlbr(struct kvm_vcpu *vcpu)
846 return EMULATE_FAIL; 846 return EMULATE_FAIL;
847} 847}
848 848
849/**
850 * kvm_mips_invalidate_guest_tlb() - Indicates a change in guest MMU map.
851 * @vcpu: VCPU with changed mappings.
852 * @tlb: TLB entry being removed.
853 *
854 * This is called to indicate a single change in guest MMU mappings, so that we
855 * can arrange TLB flushes on this and other CPUs.
856 */
857static void kvm_mips_invalidate_guest_tlb(struct kvm_vcpu *vcpu,
858 struct kvm_mips_tlb *tlb)
859{
860 int cpu, i;
861 bool user;
862
863 /* No need to flush for entries which are already invalid */
864 if (!((tlb->tlb_lo[0] | tlb->tlb_lo[1]) & ENTRYLO_V))
865 return;
866 /* User address space doesn't need flushing for KSeg2/3 changes */
867 user = tlb->tlb_hi < KVM_GUEST_KSEG0;
868
869 preempt_disable();
870
871 /*
872 * Probe the shadow host TLB for the entry being overwritten, if one
873 * matches, invalidate it
874 */
875 kvm_mips_host_tlb_inv(vcpu, tlb->tlb_hi);
876
877 /* Invalidate the whole ASID on other CPUs */
878 cpu = smp_processor_id();
879 for_each_possible_cpu(i) {
880 if (i == cpu)
881 continue;
882 if (user)
883 vcpu->arch.guest_user_asid[i] = 0;
884 vcpu->arch.guest_kernel_asid[i] = 0;
885 }
886
887 preempt_enable();
888}
889
849/* Write Guest TLB Entry @ Index */ 890/* Write Guest TLB Entry @ Index */
850enum emulation_result kvm_mips_emul_tlbwi(struct kvm_vcpu *vcpu) 891enum emulation_result kvm_mips_emul_tlbwi(struct kvm_vcpu *vcpu)
851{ 892{
@@ -865,11 +906,8 @@ enum emulation_result kvm_mips_emul_tlbwi(struct kvm_vcpu *vcpu)
865 } 906 }
866 907
867 tlb = &vcpu->arch.guest_tlb[index]; 908 tlb = &vcpu->arch.guest_tlb[index];
868 /* 909
869 * Probe the shadow host TLB for the entry being overwritten, if one 910 kvm_mips_invalidate_guest_tlb(vcpu, tlb);
870 * matches, invalidate it
871 */
872 kvm_mips_host_tlb_inv(vcpu, tlb->tlb_hi);
873 911
874 tlb->tlb_mask = kvm_read_c0_guest_pagemask(cop0); 912 tlb->tlb_mask = kvm_read_c0_guest_pagemask(cop0);
875 tlb->tlb_hi = kvm_read_c0_guest_entryhi(cop0); 913 tlb->tlb_hi = kvm_read_c0_guest_entryhi(cop0);
@@ -898,11 +936,7 @@ enum emulation_result kvm_mips_emul_tlbwr(struct kvm_vcpu *vcpu)
898 936
899 tlb = &vcpu->arch.guest_tlb[index]; 937 tlb = &vcpu->arch.guest_tlb[index];
900 938
901 /* 939 kvm_mips_invalidate_guest_tlb(vcpu, tlb);
902 * Probe the shadow host TLB for the entry being overwritten, if one
903 * matches, invalidate it
904 */
905 kvm_mips_host_tlb_inv(vcpu, tlb->tlb_hi);
906 940
907 tlb->tlb_mask = kvm_read_c0_guest_pagemask(cop0); 941 tlb->tlb_mask = kvm_read_c0_guest_pagemask(cop0);
908 tlb->tlb_hi = kvm_read_c0_guest_entryhi(cop0); 942 tlb->tlb_hi = kvm_read_c0_guest_entryhi(cop0);
@@ -1026,6 +1060,7 @@ enum emulation_result kvm_mips_emulate_CP0(union mips_instruction inst,
1026 enum emulation_result er = EMULATE_DONE; 1060 enum emulation_result er = EMULATE_DONE;
1027 u32 rt, rd, sel; 1061 u32 rt, rd, sel;
1028 unsigned long curr_pc; 1062 unsigned long curr_pc;
1063 int cpu, i;
1029 1064
1030 /* 1065 /*
1031 * Update PC and hold onto current PC in case there is 1066 * Update PC and hold onto current PC in case there is
@@ -1135,8 +1170,16 @@ enum emulation_result kvm_mips_emulate_CP0(union mips_instruction inst,
1135 & KVM_ENTRYHI_ASID, 1170 & KVM_ENTRYHI_ASID,
1136 nasid); 1171 nasid);
1137 1172
1173 preempt_disable();
1138 /* Blow away the shadow host TLBs */ 1174 /* Blow away the shadow host TLBs */
1139 kvm_mips_flush_host_tlb(1); 1175 kvm_mips_flush_host_tlb(1);
1176 cpu = smp_processor_id();
1177 for_each_possible_cpu(i)
1178 if (i != cpu) {
1179 vcpu->arch.guest_user_asid[i] = 0;
1180 vcpu->arch.guest_kernel_asid[i] = 0;
1181 }
1182 preempt_enable();
1140 } 1183 }
1141 kvm_write_c0_guest_entryhi(cop0, 1184 kvm_write_c0_guest_entryhi(cop0,
1142 vcpu->arch.gprs[rt]); 1185 vcpu->arch.gprs[rt]);