]> Pileus Git - ~andy/linux/blobdiff - arch/powerpc/kvm/powerpc.c
KVM: PPC: Ignore EXITING_GUEST_MODE mode
[~andy/linux] / arch / powerpc / kvm / powerpc.c
index 87f4dc886076d3ad2d6ecede5dfbe1990cd568e0..dc86371b9953dee0c761d985fca937c7873d4ea2 100644 (file)
@@ -30,6 +30,7 @@
 #include <asm/kvm_ppc.h>
 #include <asm/tlbflush.h>
 #include <asm/cputhreads.h>
+#include <asm/irqflags.h>
 #include "timing.h"
 #include "../mm/mmu_decl.h"
 
@@ -38,8 +39,7 @@
 
 int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)
 {
-       return !(v->arch.shared->msr & MSR_WE) ||
-              !!(v->arch.pending_exceptions) ||
+       return !!(v->arch.pending_exceptions) ||
               v->requests;
 }
 
@@ -48,6 +48,74 @@ int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
        return 1;
 }
 
+#ifndef CONFIG_KVM_BOOK3S_64_HV
+/*
+ * Common checks before entering the guest world.  Call with interrupts
+ * disabled.
+ *
+ * returns !0 if a signal is pending and check_signal is true
+ */
+int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu)
+{
+       int r = 0;
+
+       WARN_ON_ONCE(!irqs_disabled());
+       while (true) {
+               if (need_resched()) {
+                       local_irq_enable();
+                       cond_resched();
+                       local_irq_disable();
+                       continue;
+               }
+
+               if (signal_pending(current)) {
+                       r = 1;
+                       break;
+               }
+
+               smp_mb();
+               if (vcpu->requests) {
+                       /* Make sure we process requests preemptable */
+                       local_irq_enable();
+                       trace_kvm_check_requests(vcpu);
+                       kvmppc_core_check_requests(vcpu);
+                       local_irq_disable();
+                       continue;
+               }
+
+               if (kvmppc_core_prepare_to_enter(vcpu)) {
+                       /* interrupts got enabled in between, so we
+                          are back at square 1 */
+                       continue;
+               }
+
+#ifdef CONFIG_PPC64
+               /* lazy EE magic */
+               hard_irq_disable();
+               if (lazy_irq_pending()) {
+                       /* Got an interrupt in between, try again */
+                       local_irq_enable();
+                       local_irq_disable();
+                       kvm_guest_exit();
+                       continue;
+               }
+
+               trace_hardirqs_on();
+#endif
+
+               kvm_guest_enter();
+
+               /* Going into guest context! Yay! */
+               vcpu->mode = IN_GUEST_MODE;
+               smp_wmb();
+
+               break;
+       }
+
+       return r;
+}
+#endif /* CONFIG_KVM_BOOK3S_64_HV */
+
 int kvmppc_kvm_pv(struct kvm_vcpu *vcpu)
 {
        int nr = kvmppc_get_gpr(vcpu, 11);
@@ -67,18 +135,18 @@ int kvmppc_kvm_pv(struct kvm_vcpu *vcpu)
        }
 
        switch (nr) {
-       case HC_VENDOR_KVM | KVM_HC_PPC_MAP_MAGIC_PAGE:
+       case KVM_HCALL_TOKEN(KVM_HC_PPC_MAP_MAGIC_PAGE):
        {
                vcpu->arch.magic_page_pa = param1;
                vcpu->arch.magic_page_ea = param2;
 
                r2 = KVM_MAGIC_FEAT_SR | KVM_MAGIC_FEAT_MAS0_TO_SPRG7;
 
-               r = HC_EV_SUCCESS;
+               r = EV_SUCCESS;
                break;
        }
-       case HC_VENDOR_KVM | KVM_HC_FEATURES:
-               r = HC_EV_SUCCESS;
+       case KVM_HCALL_TOKEN(KVM_HC_FEATURES):
+               r = EV_SUCCESS;
 #if defined(CONFIG_PPC_BOOK3S) || defined(CONFIG_KVM_E500V2)
                /* XXX Missing magic page on 44x */
                r2 |= (1 << KVM_FEATURE_MAGIC_PAGE);
@@ -86,8 +154,13 @@ int kvmppc_kvm_pv(struct kvm_vcpu *vcpu)
 
                /* Second return value is in r4 */
                break;
+       case EV_HCALL_TOKEN(EV_IDLE):
+               r = EV_SUCCESS;
+               kvm_vcpu_block(vcpu);
+               clear_bit(KVM_REQ_UNHALT, &vcpu->requests);
+               break;
        default:
-               r = HC_EV_UNIMPLEMENTED;
+               r = EV_UNIMPLEMENTED;
                break;
        }
 
@@ -260,10 +333,16 @@ int kvm_dev_ioctl_check_extension(long ext)
                if (cpu_has_feature(CPU_FTR_ARCH_201))
                        r = 2;
                break;
+#endif
        case KVM_CAP_SYNC_MMU:
+#ifdef CONFIG_KVM_BOOK3S_64_HV
                r = cpu_has_feature(CPU_FTR_ARCH_206) ? 1 : 0;
-               break;
+#elif defined(KVM_ARCH_WANT_MMU_NOTIFIER)
+               r = 1;
+#else
+               r = 0;
 #endif
+               break;
        case KVM_CAP_NR_VCPUS:
                /*
                 * Recommending a number of CPUs is somewhat arbitrary; we
@@ -302,10 +381,18 @@ long kvm_arch_dev_ioctl(struct file *filp,
 void kvm_arch_free_memslot(struct kvm_memory_slot *free,
                           struct kvm_memory_slot *dont)
 {
+       if (!dont || free->arch.rmap != dont->arch.rmap) {
+               vfree(free->arch.rmap);
+               free->arch.rmap = NULL;
+       }
 }
 
 int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages)
 {
+       slot->arch.rmap = vzalloc(npages * sizeof(*slot->arch.rmap));
+       if (!slot->arch.rmap)
+               return -ENOMEM;
+
        return 0;
 }
 
@@ -326,8 +413,12 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
        kvmppc_core_commit_memory_region(kvm, mem);
 }
 
+void kvm_arch_flush_shadow_all(struct kvm *kvm)
+{
+}
 
-void kvm_arch_flush_shadow(struct kvm *kvm)
+void kvm_arch_flush_shadow_memslot(struct kvm *kvm,
+                                  struct kvm_memory_slot *slot)
 {
 }
 
@@ -739,9 +830,16 @@ int kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf)
 
 static int kvm_vm_ioctl_get_pvinfo(struct kvm_ppc_pvinfo *pvinfo)
 {
+       u32 inst_nop = 0x60000000;
+#ifdef CONFIG_KVM_BOOKE_HV
+       u32 inst_sc1 = 0x44000022;
+       pvinfo->hcall[0] = inst_sc1;
+       pvinfo->hcall[1] = inst_nop;
+       pvinfo->hcall[2] = inst_nop;
+       pvinfo->hcall[3] = inst_nop;
+#else
        u32 inst_lis = 0x3c000000;
        u32 inst_ori = 0x60000000;
-       u32 inst_nop = 0x60000000;
        u32 inst_sc = 0x44000002;
        u32 inst_imm_mask = 0xffff;
 
@@ -758,6 +856,9 @@ static int kvm_vm_ioctl_get_pvinfo(struct kvm_ppc_pvinfo *pvinfo)
        pvinfo->hcall[1] = inst_ori | (KVM_SC_MAGIC_R0 & inst_imm_mask);
        pvinfo->hcall[2] = inst_sc;
        pvinfo->hcall[3] = inst_nop;
+#endif
+
+       pvinfo->flags = KVM_PPC_PVINFO_FLAGS_EV_IDLE;
 
        return 0;
 }