KVM: MIPS: Add vcpu_run() & vcpu_reenter() callbacks
authorJames Hogan <james.hogan@imgtec.com>
Fri, 18 Nov 2016 13:14:37 +0000 (13:14 +0000)
committerJames Hogan <james.hogan@imgtec.com>
Fri, 3 Feb 2017 15:20:46 +0000 (15:20 +0000)
Add implementation callbacks for entering the guest (vcpu_run()) and
reentering the guest (vcpu_reenter()), allowing implementation specific
operations to be performed before entering the guest or after returning
to the host without cluttering kvm_arch_vcpu_ioctl_run().

This allows the T&E specific lazy user GVA flush to be moved into
trap_emul.c, along with disabling of the HTW. We also move
kvm_mips_deliver_interrupts() as VZ will need to restore the guest timer
state prior to delivering interrupts.

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

index 923f81dc61158e31c56f811771c87ee04d70f6e4..9f319375835af51ed901a8d8b8197fb3da4a17ab 100644 (file)
@@ -539,6 +539,8 @@ struct kvm_mips_callbacks {
                           const struct kvm_one_reg *reg, s64 v);
        int (*vcpu_load)(struct kvm_vcpu *vcpu, int cpu);
        int (*vcpu_put)(struct kvm_vcpu *vcpu, int cpu);
+       int (*vcpu_run)(struct kvm_run *run, struct kvm_vcpu *vcpu);
+       void (*vcpu_reenter)(struct kvm_run *run, struct kvm_vcpu *vcpu);
 };
 extern struct kvm_mips_callbacks *kvm_mips_callbacks;
 int kvm_mips_emulation_init(struct kvm_mips_callbacks **install_callbacks);
index 85bc54f35695ec1a3cf99e018ec252a35498275d..1733877d8a53718cad5791fd03e0141b6c9bedfa 100644 (file)
@@ -410,32 +410,6 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
        return -ENOIOCTLCMD;
 }
 
-/* Must be called with preemption disabled, just before entering guest */
-static void kvm_mips_check_asids(struct kvm_vcpu *vcpu)
-{
-       struct mm_struct *user_mm = &vcpu->arch.guest_user_mm;
-       struct mips_coproc *cop0 = vcpu->arch.cop0;
-       int i, cpu = smp_processor_id();
-       unsigned int gasid;
-
-       /*
-        * Lazy host ASID regeneration for guest user mode.
-        * If the guest ASID has changed since the last guest usermode
-        * execution, regenerate the host ASID so as to invalidate stale TLB
-        * entries.
-        */
-       if (!KVM_GUEST_KERNEL_MODE(vcpu)) {
-               gasid = kvm_read_c0_guest_entryhi(cop0) & KVM_ENTRYHI_ASID;
-               if (gasid != vcpu->arch.last_user_gasid) {
-                       kvm_get_new_mmu_context(user_mm, cpu, vcpu);
-                       for_each_possible_cpu(i)
-                               if (i != cpu)
-                                       cpu_context(i, user_mm) = 0;
-                       vcpu->arch.last_user_gasid = gasid;
-               }
-       }
-}
-
 int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
        int r = 0;
@@ -453,25 +427,12 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
        lose_fpu(1);
 
        local_irq_disable();
-       /* Check if we have any exceptions/interrupts pending */
-       kvm_mips_deliver_interrupts(vcpu,
-                                   kvm_read_c0_guest_cause(vcpu->arch.cop0));
-
        guest_enter_irqoff();
-
-       /* Disable hardware page table walking while in guest */
-       htw_stop();
-
        trace_kvm_enter(vcpu);
 
-       kvm_mips_check_asids(vcpu);
+       r = kvm_mips_callbacks->vcpu_run(run, vcpu);
 
-       r = vcpu->arch.vcpu_run(run, vcpu);
        trace_kvm_out(vcpu);
-
-       /* Re-enable HTW before enabling interrupts */
-       htw_start();
-
        guest_exit_irqoff();
        local_irq_enable();
 
@@ -1570,7 +1531,7 @@ skip_emul:
        if (ret == RESUME_GUEST) {
                trace_kvm_reenter(vcpu);
 
-               kvm_mips_check_asids(vcpu);
+               kvm_mips_callbacks->vcpu_reenter(run, vcpu);
 
                /*
                 * If FPU / MSA are enabled (i.e. the guest's FPU / MSA context
index c7854d32fd64e02c0225b682d6d84ca9055e4879..92734d095c9419d090b41c6b5b1f09278d3e53bc 100644 (file)
@@ -692,6 +692,52 @@ static int kvm_trap_emul_vcpu_put(struct kvm_vcpu *vcpu, int cpu)
        return 0;
 }
 
+static void kvm_trap_emul_vcpu_reenter(struct kvm_run *run,
+                                      struct kvm_vcpu *vcpu)
+{
+       struct mm_struct *user_mm = &vcpu->arch.guest_user_mm;
+       struct mips_coproc *cop0 = vcpu->arch.cop0;
+       int i, cpu = smp_processor_id();
+       unsigned int gasid;
+
+       /*
+        * Lazy host ASID regeneration for guest user mode.
+        * If the guest ASID has changed since the last guest usermode
+        * execution, regenerate the host ASID so as to invalidate stale TLB
+        * entries.
+        */
+       if (!KVM_GUEST_KERNEL_MODE(vcpu)) {
+               gasid = kvm_read_c0_guest_entryhi(cop0) & KVM_ENTRYHI_ASID;
+               if (gasid != vcpu->arch.last_user_gasid) {
+                       kvm_get_new_mmu_context(user_mm, cpu, vcpu);
+                       for_each_possible_cpu(i)
+                               if (i != cpu)
+                                       cpu_context(i, user_mm) = 0;
+                       vcpu->arch.last_user_gasid = gasid;
+               }
+       }
+}
+
+static int kvm_trap_emul_vcpu_run(struct kvm_run *run, struct kvm_vcpu *vcpu)
+{
+       int r;
+
+       /* Check if we have any exceptions/interrupts pending */
+       kvm_mips_deliver_interrupts(vcpu,
+                                   kvm_read_c0_guest_cause(vcpu->arch.cop0));
+
+       kvm_trap_emul_vcpu_reenter(run, vcpu);
+
+       /* Disable hardware page table walking while in guest */
+       htw_stop();
+
+       r = vcpu->arch.vcpu_run(run, vcpu);
+
+       htw_start();
+
+       return r;
+}
+
 static struct kvm_mips_callbacks kvm_trap_emul_callbacks = {
        /* exit handlers */
        .handle_cop_unusable = kvm_trap_emul_handle_cop_unusable,
@@ -724,6 +770,8 @@ static struct kvm_mips_callbacks kvm_trap_emul_callbacks = {
        .set_one_reg = kvm_trap_emul_set_one_reg,
        .vcpu_load = kvm_trap_emul_vcpu_load,
        .vcpu_put = kvm_trap_emul_vcpu_put,
+       .vcpu_run = kvm_trap_emul_vcpu_run,
+       .vcpu_reenter = kvm_trap_emul_vcpu_reenter,
 };
 
 int kvm_mips_emulation_init(struct kvm_mips_callbacks **install_callbacks)