[RFC,16/16] KVM: PPC: Book3S HV: disconnect vCPU from IRQ device

Message ID 20180423164341.15767-17-clg@kaod.org
State New
Headers show
Series
  • KVM: PPC: Book3S HV: add XIVE native exploitation mode
Related show

Commit Message

Cédric Le Goater April 23, 2018, 4:43 p.m.
Before destroying a KVM device for IRQs, we need to disconnect the
VCPUs. Do that using a 'disable=1' as last argument of the
KVM_ENABLE_CAP ioctl. This is a bit hacky, we should introduce a
KVM_DISABLE_CAP ioctl most certainly.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 arch/powerpc/include/asm/kvm_ppc.h |  4 ++--
 arch/powerpc/kvm/book3s_xics.c     |  5 +++--
 arch/powerpc/kvm/book3s_xive.c     | 10 +++++++++-
 arch/powerpc/kvm/powerpc.c         | 28 +++++++++++++++++++++-------
 4 files changed, 35 insertions(+), 12 deletions(-)

Patch

diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
index 748518c7bf70..5c0af1cabe34 100644
--- a/arch/powerpc/include/asm/kvm_ppc.h
+++ b/arch/powerpc/include/asm/kvm_ppc.h
@@ -518,7 +518,7 @@  extern void kvmppc_alloc_host_rm_ops(void);
 extern void kvmppc_free_host_rm_ops(void);
 extern void kvmppc_free_pimap(struct kvm *kvm);
 extern int kvmppc_xics_rm_complete(struct kvm_vcpu *vcpu, u32 hcall);
-extern void kvmppc_xics_free_icp(struct kvm_vcpu *vcpu);
+extern int kvmppc_xics_free_icp(struct kvm_vcpu *vcpu);
 extern int kvmppc_xics_hcall(struct kvm_vcpu *vcpu, u32 cmd);
 extern u64 kvmppc_xics_get_icp(struct kvm_vcpu *vcpu);
 extern int kvmppc_xics_set_icp(struct kvm_vcpu *vcpu, u64 icpval);
@@ -574,7 +574,7 @@  extern void kvmppc_xive_exit_module(void);
 
 extern int kvmppc_xive_connect_vcpu(struct kvm_device *dev,
 				    struct kvm_vcpu *vcpu, u32 cpu);
-extern void kvmppc_xive_cleanup_vcpu(struct kvm_vcpu *vcpu);
+extern int kvmppc_xive_cleanup_vcpu(struct kvm_vcpu *vcpu);
 extern int kvmppc_xive_set_mapped(struct kvm *kvm, unsigned long guest_irq,
 				  struct irq_desc *host_desc);
 extern int kvmppc_xive_clr_mapped(struct kvm *kvm, unsigned long guest_irq,
diff --git a/arch/powerpc/kvm/book3s_xics.c b/arch/powerpc/kvm/book3s_xics.c
index b8356cdc0c04..b0c85525944d 100644
--- a/arch/powerpc/kvm/book3s_xics.c
+++ b/arch/powerpc/kvm/book3s_xics.c
@@ -1440,13 +1440,14 @@  int kvmppc_xics_connect_vcpu(struct kvm_device *dev, struct kvm_vcpu *vcpu,
 	return r;
 }
 
-void kvmppc_xics_free_icp(struct kvm_vcpu *vcpu)
+int kvmppc_xics_free_icp(struct kvm_vcpu *vcpu)
 {
 	if (!vcpu->arch.icp)
-		return;
+		return -ENOENT;
 	kfree(vcpu->arch.icp);
 	vcpu->arch.icp = NULL;
 	vcpu->arch.irq_type = KVMPPC_IRQ_DEFAULT;
+	return 0;
 }
 
 void kvmppc_xics_set_mapped(struct kvm *kvm, unsigned long irq,
diff --git a/arch/powerpc/kvm/book3s_xive.c b/arch/powerpc/kvm/book3s_xive.c
index abb4ae5c5b91..3c66480d3304 100644
--- a/arch/powerpc/kvm/book3s_xive.c
+++ b/arch/powerpc/kvm/book3s_xive.c
@@ -1023,12 +1023,15 @@  void kvmppc_xive_disable_vcpu_interrupts(struct kvm_vcpu *vcpu)
 	}
 }
 
-void kvmppc_xive_cleanup_vcpu(struct kvm_vcpu *vcpu)
+int kvmppc_xive_cleanup_vcpu(struct kvm_vcpu *vcpu)
 {
 	struct kvmppc_xive_vcpu *xc = vcpu->arch.xive_vcpu;
 	struct kvmppc_xive *xive = xc->xive;
 	int i;
 
+	if (!vcpu->arch.xive_vcpu)
+		return -ENOENT;
+
 	pr_devel("cleanup_vcpu(cpu=%d)\n", xc->server_num);
 
 	/* Ensure no interrupt is still routed to that VP */
@@ -1067,6 +1070,11 @@  void kvmppc_xive_cleanup_vcpu(struct kvm_vcpu *vcpu)
 	}
 	/* Free the VP */
 	kfree(xc);
+
+	/* Cleanup the vcpu */
+	vcpu->arch.irq_type = KVMPPC_IRQ_DEFAULT;
+	vcpu->arch.xive_vcpu = NULL;
+	return 0;
 }
 
 int kvmppc_xive_connect_vcpu(struct kvm_device *dev,
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index 42eb75e43d6e..e0ff5e9610ee 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -1710,10 +1710,19 @@  static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
 		r = -EPERM;
 		dev = kvm_device_from_filp(f.file);
 		if (dev) {
-			if (xive_enabled())
-				r = kvmppc_xive_connect_vcpu(dev, vcpu, cap->args[1]);
-			else
-				r = kvmppc_xics_connect_vcpu(dev, vcpu, cap->args[1]);
+			if (cap->args[2]) {
+				if (xive_enabled())
+					r = kvmppc_xive_cleanup_vcpu(vcpu);
+				else
+					r = kvmppc_xics_free_icp(vcpu);
+			} else {
+				if (xive_enabled())
+					r = kvmppc_xive_connect_vcpu(dev, vcpu,
+							     cap->args[1]);
+				else
+					r = kvmppc_xics_connect_vcpu(dev, vcpu,
+							     cap->args[1]);
+			}
 		}
 
 		fdput(f);
@@ -1736,9 +1745,14 @@  static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
 
 		r = -EPERM;
 		dev = kvm_device_from_filp(f.file);
-		if (dev)
-			r = kvmppc_xive_native_connect_vcpu(dev, vcpu,
-							    cap->args[1]);
+		if (dev) {
+			if (cap->args[2]) {
+				r = kvmppc_xive_native_cleanup_vcpu(vcpu);
+			} else {
+				r = kvmppc_xive_native_connect_vcpu(dev, vcpu,
+							     cap->args[1]);
+			}
+		}
 
 		fdput(f);
 		break;