]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
KVM: MIPS/T&E: Allocate GVA -> HPA page tables
authorJames Hogan <james.hogan@imgtec.com>
Thu, 8 Sep 2016 21:57:03 +0000 (22:57 +0100)
committerJames Hogan <james.hogan@imgtec.com>
Fri, 3 Feb 2017 15:20:50 +0000 (15:20 +0000)
Allocate GVA -> HPA page tables for guest kernel and guest user mode on
each VCPU, to allow for fast path TLB refill handling to be added later.

In the process kvm_arch_vcpu_init() needs updating to pass on any error
from the vcpu_init() callback.

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/kvm/mips.c
arch/mips/kvm/trap_emul.c

index 011710a68c6b3120645d1294e26e88aa15b38e9c..7cf85fa1f6588d9c3529ca1785fd62302793d28f 100644 (file)
@@ -1338,7 +1338,12 @@ static enum hrtimer_restart kvm_mips_comparecount_wakeup(struct hrtimer *timer)
 
 int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
 {
-       kvm_mips_callbacks->vcpu_init(vcpu);
+       int err;
+
+       err = kvm_mips_callbacks->vcpu_init(vcpu);
+       if (err)
+               return err;
+
        hrtimer_init(&vcpu->arch.comparecount_timer, CLOCK_MONOTONIC,
                     HRTIMER_MODE_REL);
        vcpu->arch.comparecount_timer.function = kvm_mips_comparecount_wakeup;
index 07540cf2b557aaa0e4cb0c5f3c20faa528b2b09f..183150a963ec0edabcb8c74d42c4c7179f085d3a 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/kvm_host.h>
 #include <linux/vmalloc.h>
 #include <asm/mmu_context.h>
+#include <asm/pgalloc.h>
 
 #include "interrupt.h"
 
@@ -435,13 +436,75 @@ static int kvm_trap_emul_vm_init(struct kvm *kvm)
 
 static int kvm_trap_emul_vcpu_init(struct kvm_vcpu *vcpu)
 {
+       struct mm_struct *kern_mm = &vcpu->arch.guest_kernel_mm;
+       struct mm_struct *user_mm = &vcpu->arch.guest_user_mm;
+
        vcpu->arch.kscratch_enabled = 0xfc;
 
+       /*
+        * Allocate GVA -> HPA page tables.
+        * MIPS doesn't use the mm_struct pointer argument.
+        */
+       kern_mm->pgd = pgd_alloc(kern_mm);
+       if (!kern_mm->pgd)
+               return -ENOMEM;
+
+       user_mm->pgd = pgd_alloc(user_mm);
+       if (!user_mm->pgd) {
+               pgd_free(kern_mm, kern_mm->pgd);
+               return -ENOMEM;
+       }
+
        return 0;
 }
 
+static void kvm_mips_emul_free_gva_pt(pgd_t *pgd)
+{
+       /* Don't free host kernel page tables copied from init_mm.pgd */
+       const unsigned long end = 0x80000000;
+       unsigned long pgd_va, pud_va, pmd_va;
+       pud_t *pud;
+       pmd_t *pmd;
+       pte_t *pte;
+       int i, j, k;
+
+       for (i = 0; i < USER_PTRS_PER_PGD; i++) {
+               if (pgd_none(pgd[i]))
+                       continue;
+
+               pgd_va = (unsigned long)i << PGDIR_SHIFT;
+               if (pgd_va >= end)
+                       break;
+               pud = pud_offset(pgd + i, 0);
+               for (j = 0; j < PTRS_PER_PUD; j++) {
+                       if (pud_none(pud[j]))
+                               continue;
+
+                       pud_va = pgd_va | ((unsigned long)j << PUD_SHIFT);
+                       if (pud_va >= end)
+                               break;
+                       pmd = pmd_offset(pud + j, 0);
+                       for (k = 0; k < PTRS_PER_PMD; k++) {
+                               if (pmd_none(pmd[k]))
+                                       continue;
+
+                               pmd_va = pud_va | (k << PMD_SHIFT);
+                               if (pmd_va >= end)
+                                       break;
+                               pte = pte_offset(pmd + k, 0);
+                               pte_free_kernel(NULL, pte);
+                       }
+                       pmd_free(NULL, pmd);
+               }
+               pud_free(NULL, pud);
+       }
+       pgd_free(NULL, pgd);
+}
+
 static void kvm_trap_emul_vcpu_uninit(struct kvm_vcpu *vcpu)
 {
+       kvm_mips_emul_free_gva_pt(vcpu->arch.guest_kernel_mm.pgd);
+       kvm_mips_emul_free_gva_pt(vcpu->arch.guest_user_mm.pgd);
 }
 
 static int kvm_trap_emul_vcpu_setup(struct kvm_vcpu *vcpu)