KVM: MIPS/T&E: Activate GVA page tables in guest context
authorJames Hogan <james.hogan@imgtec.com>
Fri, 7 Oct 2016 22:58:53 +0000 (23:58 +0100)
committerJames Hogan <james.hogan@imgtec.com>
Fri, 3 Feb 2017 15:20:51 +0000 (15:20 +0000)
Activate the GVA page tables when in guest context. This will allow the
normal Linux TLB refill handler to fill from it when guest memory is
read, as well as preventing accidental reading from user memory.

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
arch/mips/include/asm/mmu_context.h
arch/mips/kvm/entry.c
arch/mips/kvm/trap_emul.c

index ddd57ade1aa845c0f770c8321905c4914630f10d..16eb8521398e1a8d43674988ef581504d8a29f47 100644 (file)
@@ -29,9 +29,11 @@ do {                                                                 \
        }                                                               \
 } while (0)
 
+extern void tlbmiss_handler_setup_pgd(unsigned long);
+
+/* Note: This is also implemented with uasm in arch/mips/kvm/entry.c */
 #define TLBMISS_HANDLER_SETUP_PGD(pgd)                                 \
 do {                                                                   \
-       extern void tlbmiss_handler_setup_pgd(unsigned long);           \
        tlbmiss_handler_setup_pgd((unsigned long)(pgd));                \
        htw_set_pwbase((unsigned long)pgd);                             \
 } while (0)
index f81888704caa0546cc4d158b6ef8d769fe22c052..f683d123172cf8eab4b1a2c55dc05d316b2405a8 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/kvm_host.h>
 #include <linux/log2.h>
+#include <asm/mmu_context.h>
 #include <asm/msa.h>
 #include <asm/setup.h>
 #include <asm/uasm.h>
@@ -316,7 +317,20 @@ static void *kvm_mips_build_enter_guest(void *addr)
 #else
        uasm_i_andi(&p, K0, K0, MIPS_ENTRYHI_ASID);
 #endif
-       uasm_i_mtc0(&p, K0, C0_ENTRYHI);
+
+       /*
+        * Set up KVM T&E GVA pgd.
+        * This does roughly the same as TLBMISS_HANDLER_SETUP_PGD():
+        * - call tlbmiss_handler_setup_pgd(mm->pgd)
+        * - but skips write into CP0_PWBase for now
+        */
+       UASM_i_LW(&p, A0, (int)offsetof(struct mm_struct, pgd) -
+                         (int)offsetof(struct mm_struct, context.asid), T1);
+
+       UASM_i_LA(&p, T9, (unsigned long)tlbmiss_handler_setup_pgd);
+       uasm_i_jalr(&p, RA, T9);
+        uasm_i_mtc0(&p, K0, C0_ENTRYHI);
+
        uasm_i_ehb(&p);
 
        /* Disable RDHWR access */
index 183150a963ec0edabcb8c74d42c4c7179f085d3a..f39d427649dc54be889ff30840fd7a5af489e77b 100644 (file)
@@ -704,6 +704,7 @@ static int kvm_trap_emul_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 {
        struct mm_struct *kern_mm = &vcpu->arch.guest_kernel_mm;
        struct mm_struct *user_mm = &vcpu->arch.guest_user_mm;
+       struct mm_struct *mm;
 
        /* Allocate new kernel and user ASIDs if needed */
 
@@ -733,10 +734,9 @@ static int kvm_trap_emul_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
         * on the mode of the Guest (Kernel/User)
         */
        if (current->flags & PF_VCPU) {
-               if (KVM_GUEST_KERNEL_MODE(vcpu))
-                       write_c0_entryhi(cpu_asid(cpu, kern_mm));
-               else
-                       write_c0_entryhi(cpu_asid(cpu, user_mm));
+               mm = KVM_GUEST_KERNEL_MODE(vcpu) ? kern_mm : user_mm;
+               write_c0_entryhi(cpu_asid(cpu, mm));
+               TLBMISS_HANDLER_SETUP_PGD(mm->pgd);
                kvm_mips_suspend_mm(cpu);
                ehb();
        }
@@ -757,6 +757,7 @@ static int kvm_trap_emul_vcpu_put(struct kvm_vcpu *vcpu, int cpu)
                        get_new_mmu_context(current->mm, cpu);
                }
                write_c0_entryhi(cpu_asid(cpu, current->mm));
+               TLBMISS_HANDLER_SETUP_PGD(current->mm->pgd);
                kvm_mips_resume_mm(cpu);
                ehb();
        }
@@ -821,6 +822,7 @@ static int kvm_trap_emul_vcpu_run(struct kvm_run *run, struct kvm_vcpu *vcpu)
             asid_version_mask(cpu)))
                get_new_mmu_context(current->mm, cpu);
        write_c0_entryhi(cpu_asid(cpu, current->mm));
+       TLBMISS_HANDLER_SETUP_PGD(current->mm->pgd);
        kvm_mips_resume_mm(cpu);
 
        htw_start();