KVM: PPC: Handle magic page in kvmppc_ld/st
[firefly-linux-kernel-4.4.55.git] / arch / powerpc / kvm / powerpc.c
index bab20f4104430489674b5c05e4a1223036e2eac3..544d1d30c8cc69cc5d84e4ed7d01f0e75af876c6 100644 (file)
@@ -190,6 +190,25 @@ int kvmppc_kvm_pv(struct kvm_vcpu *vcpu)
                vcpu->arch.magic_page_pa = param1 & ~0xfffULL;
                vcpu->arch.magic_page_ea = param2 & ~0xfffULL;
 
+#ifdef CONFIG_PPC_64K_PAGES
+               /*
+                * Make sure our 4k magic page is in the same window of a 64k
+                * page within the guest and within the host's page.
+                */
+               if ((vcpu->arch.magic_page_pa & 0xf000) !=
+                   ((ulong)vcpu->arch.shared & 0xf000)) {
+                       void *old_shared = vcpu->arch.shared;
+                       ulong shared = (ulong)vcpu->arch.shared;
+                       void *new_shared;
+
+                       shared &= PAGE_MASK;
+                       shared |= vcpu->arch.magic_page_pa & 0xf000;
+                       new_shared = (void*)shared;
+                       memcpy(new_shared, old_shared, 0x1000);
+                       vcpu->arch.shared = new_shared;
+               }
+#endif
+
                r2 = KVM_MAGIC_FEAT_SR | KVM_MAGIC_FEAT_MAS0_TO_SPRG7;
 
                r = EV_SUCCESS;
@@ -198,7 +217,6 @@ int kvmppc_kvm_pv(struct kvm_vcpu *vcpu)
        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);
 #endif
 
@@ -261,6 +279,9 @@ int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu)
                 * actually modified. */
                r = RESUME_GUEST_NV;
                break;
+       case EMULATE_AGAIN:
+               r = RESUME_GUEST;
+               break;
        case EMULATE_DO_MMIO:
                run->exit_reason = KVM_EXIT_MMIO;
                /* We must reload nonvolatiles because "update" load/store
@@ -270,11 +291,15 @@ int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu)
                r = RESUME_HOST_NV;
                break;
        case EMULATE_FAIL:
+       {
+               u32 last_inst;
+
+               kvmppc_get_last_inst(vcpu, false, &last_inst);
                /* XXX Deliver Program interrupt to guest. */
-               printk(KERN_EMERG "%s: emulation failed (%08x)\n", __func__,
-                      kvmppc_get_last_inst(vcpu));
+               pr_emerg("%s: emulation failed (%08x)\n", __func__, last_inst);
                r = RESUME_HOST;
                break;
+       }
        default:
                WARN_ON(1);
                r = RESUME_GUEST;
@@ -284,6 +309,81 @@ int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu)
 }
 EXPORT_SYMBOL_GPL(kvmppc_emulate_mmio);
 
+int kvmppc_st(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr,
+             bool data)
+{
+       ulong mp_pa = vcpu->arch.magic_page_pa & KVM_PAM & PAGE_MASK;
+       struct kvmppc_pte pte;
+       int r;
+
+       vcpu->stat.st++;
+
+       r = kvmppc_xlate(vcpu, *eaddr, data ? XLATE_DATA : XLATE_INST,
+                        XLATE_WRITE, &pte);
+       if (r < 0)
+               return r;
+
+       *eaddr = pte.raddr;
+
+       if (!pte.may_write)
+               return -EPERM;
+
+       /* Magic page override */
+       if (kvmppc_supports_magic_page(vcpu) && mp_pa &&
+           ((pte.raddr & KVM_PAM & PAGE_MASK) == mp_pa) &&
+           !(kvmppc_get_msr(vcpu) & MSR_PR)) {
+               void *magic = vcpu->arch.shared;
+               magic += pte.eaddr & 0xfff;
+               memcpy(magic, ptr, size);
+               return EMULATE_DONE;
+       }
+
+       if (kvm_write_guest(vcpu->kvm, pte.raddr, ptr, size))
+               return EMULATE_DO_MMIO;
+
+       return EMULATE_DONE;
+}
+EXPORT_SYMBOL_GPL(kvmppc_st);
+
+int kvmppc_ld(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr,
+                     bool data)
+{
+       ulong mp_pa = vcpu->arch.magic_page_pa & KVM_PAM & PAGE_MASK;
+       struct kvmppc_pte pte;
+       int rc;
+
+       vcpu->stat.ld++;
+
+       rc = kvmppc_xlate(vcpu, *eaddr, data ? XLATE_DATA : XLATE_INST,
+                         XLATE_READ, &pte);
+       if (rc)
+               return rc;
+
+       *eaddr = pte.raddr;
+
+       if (!pte.may_read)
+               return -EPERM;
+
+       if (!data && !pte.may_execute)
+               return -ENOEXEC;
+
+       /* Magic page override */
+       if (kvmppc_supports_magic_page(vcpu) && mp_pa &&
+           ((pte.raddr & KVM_PAM & PAGE_MASK) == mp_pa) &&
+           !(kvmppc_get_msr(vcpu) & MSR_PR)) {
+               void *magic = vcpu->arch.shared;
+               magic += pte.eaddr & 0xfff;
+               memcpy(ptr, magic, size);
+               return EMULATE_DONE;
+       }
+
+       if (kvm_read_guest(vcpu->kvm, pte.raddr, ptr, size))
+               return EMULATE_DO_MMIO;
+
+       return EMULATE_DONE;
+}
+EXPORT_SYMBOL_GPL(kvmppc_ld);
+
 int kvm_arch_hardware_enable(void *garbage)
 {
        return 0;
@@ -366,14 +466,20 @@ void kvm_arch_sync_events(struct kvm *kvm)
 {
 }
 
-int kvm_dev_ioctl_check_extension(long ext)
+int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 {
        int r;
-       /* FIXME!!
-        * Should some of this be vm ioctl ? is it possible now ?
-        */
+       /* Assume we're using HV mode when the HV module is loaded */
        int hv_enabled = kvmppc_hv_ops ? 1 : 0;
 
+       if (kvm) {
+               /*
+                * Hooray - we know which VM type we're running on. Depend on
+                * that rather than the guess above.
+                */
+               hv_enabled = is_kvmppc_hv_enabled(kvm);
+       }
+
        switch (ext) {
 #ifdef CONFIG_BOOKE
        case KVM_CAP_PPC_BOOKE_SREGS:
@@ -387,6 +493,7 @@ int kvm_dev_ioctl_check_extension(long ext)
        case KVM_CAP_PPC_UNSET_IRQ:
        case KVM_CAP_PPC_IRQ_LEVEL:
        case KVM_CAP_ENABLE_CAP:
+       case KVM_CAP_ENABLE_CAP_VM:
        case KVM_CAP_ONE_REG:
        case KVM_CAP_IOEVENTFD:
        case KVM_CAP_DEVICE_CTRL:
@@ -417,6 +524,7 @@ int kvm_dev_ioctl_check_extension(long ext)
        case KVM_CAP_PPC_ALLOC_HTAB:
        case KVM_CAP_PPC_RTAS:
        case KVM_CAP_PPC_FIXUP_HCALL:
+       case KVM_CAP_PPC_ENABLE_HCALL:
 #ifdef CONFIG_KVM_XICS
        case KVM_CAP_IRQ_XICS:
 #endif
@@ -426,7 +534,7 @@ int kvm_dev_ioctl_check_extension(long ext)
 #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
        case KVM_CAP_PPC_SMT:
                if (hv_enabled)
-                       r = threads_per_core;
+                       r = threads_per_subcore;
                else
                        r = 0;
                break;
@@ -1099,6 +1207,42 @@ int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_event,
        return 0;
 }
 
+
+static int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
+                                  struct kvm_enable_cap *cap)
+{
+       int r;
+
+       if (cap->flags)
+               return -EINVAL;
+
+       switch (cap->cap) {
+#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
+       case KVM_CAP_PPC_ENABLE_HCALL: {
+               unsigned long hcall = cap->args[0];
+
+               r = -EINVAL;
+               if (hcall > MAX_HCALL_OPCODE || (hcall & 3) ||
+                   cap->args[1] > 1)
+                       break;
+               if (!kvmppc_book3s_hcall_implemented(kvm, hcall))
+                       break;
+               if (cap->args[1])
+                       set_bit(hcall / 4, kvm->arch.enabled_hcalls);
+               else
+                       clear_bit(hcall / 4, kvm->arch.enabled_hcalls);
+               r = 0;
+               break;
+       }
+#endif
+       default:
+               r = -EINVAL;
+               break;
+       }
+
+       return r;
+}
+
 long kvm_arch_vm_ioctl(struct file *filp,
                        unsigned int ioctl, unsigned long arg)
 {
@@ -1118,6 +1262,15 @@ long kvm_arch_vm_ioctl(struct file *filp,
 
                break;
        }
+       case KVM_ENABLE_CAP:
+       {
+               struct kvm_enable_cap cap;
+               r = -EFAULT;
+               if (copy_from_user(&cap, argp, sizeof(cap)))
+                       goto out;
+               r = kvm_vm_ioctl_enable_cap(kvm, &cap);
+               break;
+       }
 #ifdef CONFIG_PPC_BOOK3S_64
        case KVM_CREATE_SPAPR_TCE: {
                struct kvm_create_spapr_tce create_tce;