aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Hogan <james.hogan@imgtec.com>2016-11-28 18:19:32 -0500
committerJames Hogan <james.hogan@imgtec.com>2017-02-03 10:21:09 -0500
commitb29e115ae451a67a8c044dffb3aa02b19d4570a0 (patch)
treef6e148c0623c2619d20de875e0a75612338156bd
parent4841e0dd4f53c127b11947bdbe4423b5e9014ebc (diff)
KVM: MIPS/T&E: Handle TLB invalidation requests
Add handling of TLB invalidation requests before entering guest mode. This will allow asynchonous invalidation of the VCPU mappings when physical memory regions are altered. Should the CPU running the VCPU already be in guest mode an IPI will be sent to trigger a guest exit. The reload_asid path will be used in a future patch for when GVA is about to be directly accessed by KVM. In the process, the stale user ASID check in the re-entry path (for lazy user GVA flushing) is generalised to check the ASID for the current guest mode, in case a TLB invalidation request was handled. This has the side effect of making the ASID checks on vcpu_load too conservative, which will be addressed in a later patch. 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/kvm/trap_emul.c71
1 files changed, 63 insertions, 8 deletions
diff --git a/arch/mips/kvm/trap_emul.c b/arch/mips/kvm/trap_emul.c
index ccd56b3ce84b..2b20b7de493e 100644
--- a/arch/mips/kvm/trap_emul.c
+++ b/arch/mips/kvm/trap_emul.c
@@ -773,31 +773,86 @@ static int kvm_trap_emul_vcpu_put(struct kvm_vcpu *vcpu, int cpu)
773 return 0; 773 return 0;
774} 774}
775 775
776static void kvm_trap_emul_check_requests(struct kvm_vcpu *vcpu, int cpu,
777 bool reload_asid)
778{
779 struct mm_struct *kern_mm = &vcpu->arch.guest_kernel_mm;
780 struct mm_struct *user_mm = &vcpu->arch.guest_user_mm;
781 struct mm_struct *mm;
782 int i;
783
784 if (likely(!vcpu->requests))
785 return;
786
787 if (kvm_check_request(KVM_REQ_TLB_FLUSH, vcpu)) {
788 /*
789 * Both kernel & user GVA mappings must be invalidated. The
790 * caller is just about to check whether the ASID is stale
791 * anyway so no need to reload it here.
792 */
793 kvm_mips_flush_gva_pt(kern_mm->pgd, KMF_GPA | KMF_KERN);
794 kvm_mips_flush_gva_pt(user_mm->pgd, KMF_GPA | KMF_USER);
795 for_each_possible_cpu(i) {
796 cpu_context(i, kern_mm) = 0;
797 cpu_context(i, user_mm) = 0;
798 }
799
800 /* Generate new ASID for current mode */
801 if (reload_asid) {
802 mm = KVM_GUEST_KERNEL_MODE(vcpu) ? kern_mm : user_mm;
803 get_new_mmu_context(mm, cpu);
804 htw_stop();
805 write_c0_entryhi(cpu_asid(cpu, mm));
806 TLBMISS_HANDLER_SETUP_PGD(mm->pgd);
807 htw_start();
808 }
809 }
810}
811
776static void kvm_trap_emul_vcpu_reenter(struct kvm_run *run, 812static void kvm_trap_emul_vcpu_reenter(struct kvm_run *run,
777 struct kvm_vcpu *vcpu) 813 struct kvm_vcpu *vcpu)
778{ 814{
815 struct mm_struct *kern_mm = &vcpu->arch.guest_kernel_mm;
779 struct mm_struct *user_mm = &vcpu->arch.guest_user_mm; 816 struct mm_struct *user_mm = &vcpu->arch.guest_user_mm;
817 struct mm_struct *mm;
780 struct mips_coproc *cop0 = vcpu->arch.cop0; 818 struct mips_coproc *cop0 = vcpu->arch.cop0;
781 int i, cpu = smp_processor_id(); 819 int i, cpu = smp_processor_id();
782 unsigned int gasid; 820 unsigned int gasid;
783 821
784 /* 822 /*
785 * Lazy host ASID regeneration / PT flush for guest user mode. 823 * No need to reload ASID, IRQs are disabled already so there's no rush,
786 * If the guest ASID has changed since the last guest usermode 824 * and we'll check if we need to regenerate below anyway before
787 * execution, regenerate the host ASID so as to invalidate stale TLB 825 * re-entering the guest.
788 * entries and flush GVA PT entries too.
789 */ 826 */
790 if (!KVM_GUEST_KERNEL_MODE(vcpu)) { 827 kvm_trap_emul_check_requests(vcpu, cpu, false);
828
829 if (KVM_GUEST_KERNEL_MODE(vcpu)) {
830 mm = kern_mm;
831 } else {
832 mm = user_mm;
833
834 /*
835 * Lazy host ASID regeneration / PT flush for guest user mode.
836 * If the guest ASID has changed since the last guest usermode
837 * execution, invalidate the stale TLB entries and flush GVA PT
838 * entries too.
839 */
791 gasid = kvm_read_c0_guest_entryhi(cop0) & KVM_ENTRYHI_ASID; 840 gasid = kvm_read_c0_guest_entryhi(cop0) & KVM_ENTRYHI_ASID;
792 if (gasid != vcpu->arch.last_user_gasid) { 841 if (gasid != vcpu->arch.last_user_gasid) {
793 kvm_mips_flush_gva_pt(user_mm->pgd, KMF_USER); 842 kvm_mips_flush_gva_pt(user_mm->pgd, KMF_USER);
794 get_new_mmu_context(user_mm, cpu);
795 for_each_possible_cpu(i) 843 for_each_possible_cpu(i)
796 if (i != cpu) 844 cpu_context(i, user_mm) = 0;
797 cpu_context(i, user_mm) = 0;
798 vcpu->arch.last_user_gasid = gasid; 845 vcpu->arch.last_user_gasid = gasid;
799 } 846 }
800 } 847 }
848
849 /*
850 * Check if ASID is stale. This may happen due to a TLB flush request or
851 * a lazy user MM invalidation.
852 */
853 if ((cpu_context(cpu, mm) ^ asid_cache(cpu)) &
854 asid_version_mask(cpu))
855 get_new_mmu_context(mm, cpu);
801} 856}
802 857
803static int kvm_trap_emul_vcpu_run(struct kvm_run *run, struct kvm_vcpu *vcpu) 858static int kvm_trap_emul_vcpu_run(struct kvm_run *run, struct kvm_vcpu *vcpu)