diff options
-rw-r--r-- | arch/mips/kvm/emulate.c | 63 |
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 | */ | ||
857 | static 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 */ |
850 | enum emulation_result kvm_mips_emul_tlbwi(struct kvm_vcpu *vcpu) | 891 | enum 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]); |