lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Message-ID: <20101029145126.26039.16101.stgit@s20.home>
Date:	Fri, 29 Oct 2010 08:52:21 -0600
From:	Alex Williamson <alex.williamson@...hat.com>
To:	linux-kernel@...r.kernel.org, avi@...hat.com
Cc:	kvm@...r.kernel.org, alex.williamson@...hat.com, mst@...hat.com,
	chrisw@...hat.com
Subject: [PATCH] kvm: Create an eventfd mechanism for EOIs to get to userspace

To support VFIO based device assignment, we need to be able to get
an EOI out of the KVM irqchip.  This introduces a mechanism to do
that by registering an eventfd to be signaled when the IRQ is ACKed.

Signed-off-by: Alex Williamson <alex.williamson@...hat.com>
---

 include/linux/kvm.h      |   13 ++++++
 include/linux/kvm_host.h |    6 +++
 virt/kvm/eventfd.c       |   95 ++++++++++++++++++++++++++++++++++++++++++++++
 virt/kvm/kvm_main.c      |    8 ++++
 4 files changed, 122 insertions(+), 0 deletions(-)

diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index ea2dc1a..92d5b27 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -541,6 +541,7 @@ struct kvm_ppc_pvinfo {
 #define KVM_CAP_PPC_GET_PVINFO 57
 #define KVM_CAP_PPC_IRQ_LEVEL 58
 #define KVM_CAP_ASYNC_PF 59
+#define KVM_CAP_EOI_EVENTFD 60
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -620,6 +621,16 @@ struct kvm_clock_data {
 	__u32 pad[9];
 };
 
+#define KVM_EOI_EVENTFD_FLAG_DEASSIGN (1 << 0)
+#define KVM_EOI_EVENTFD_FLAG_DEASSERT (1 << 1)
+
+struct kvm_eoi {
+	__u32 fd;
+	__u32 gsi;
+	__u32 flags;
+	__u8  pad[20];
+};
+
 /*
  * ioctls for VM fds
  */
@@ -677,6 +688,8 @@ struct kvm_clock_data {
 #define KVM_SET_PIT2              _IOW(KVMIO,  0xa0, struct kvm_pit_state2)
 /* Available with KVM_CAP_PPC_GET_PVINFO */
 #define KVM_PPC_GET_PVINFO	  _IOW(KVMIO,  0xa1, struct kvm_ppc_pvinfo)
+/* Available with KVM_CAP_EOI_EVENTFD */
+#define KVM_EOI_EVENTFD           _IOW(KVMIO,  0xa2, struct kvm_eoi)
 
 /*
  * ioctls for vcpu fds
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index ee4314e..5d50a7e 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -227,6 +227,7 @@ struct kvm {
 		struct list_head  items;
 	} irqfds;
 	struct list_head ioeventfds;
+	struct list_head eoi_eventfds;
 #endif
 	struct kvm_vm_stat stat;
 	struct kvm_arch arch;
@@ -643,6 +644,7 @@ void kvm_eventfd_init(struct kvm *kvm);
 int kvm_irqfd(struct kvm *kvm, int fd, int gsi, int flags);
 void kvm_irqfd_release(struct kvm *kvm);
 int kvm_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args);
+int kvm_eoi_eventfd(struct kvm *kvm, struct kvm_eoi *eoi);
 
 #else
 
@@ -658,6 +660,10 @@ static inline int kvm_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args)
 	return -ENOSYS;
 }
 
+static inline int kvm_eoi_eventfd(struct kvm *kvm, struct kvm_eoi *eoi)
+{
+	return -ENOSYS;
+}
 #endif /* CONFIG_HAVE_KVM_EVENTFD */
 
 #ifdef CONFIG_KVM_APIC_ARCHITECTURE
diff --git a/virt/kvm/eventfd.c b/virt/kvm/eventfd.c
index c1f1e3c..3dbfb21 100644
--- a/virt/kvm/eventfd.c
+++ b/virt/kvm/eventfd.c
@@ -253,6 +253,7 @@ kvm_eventfd_init(struct kvm *kvm)
 	spin_lock_init(&kvm->irqfds.lock);
 	INIT_LIST_HEAD(&kvm->irqfds.items);
 	INIT_LIST_HEAD(&kvm->ioeventfds);
+	INIT_LIST_HEAD(&kvm->eoi_eventfds);
 }
 
 /*
@@ -586,3 +587,97 @@ kvm_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args)
 
 	return kvm_assign_ioeventfd(kvm, args);
 }
+
+/*
+ * --------------------------------------------------------------------
+ *  eoi_eventfd: Translate KVM APIC/IOAPIC EOI into eventfd signal.
+ *
+ *  userspace can register GSIs with an eventfd for receiving notification
+ *  when an EOI occurs.
+ * --------------------------------------------------------------------
+ */
+
+struct _eoi_eventfd {
+	struct list_head            list;
+	struct kvm                  *kvm;
+	struct eventfd_ctx          *eventfd;
+	bool                        deassert;
+	struct kvm_irq_ack_notifier notifier;
+};
+
+static void kvm_eoi_eventfd_acked(struct kvm_irq_ack_notifier *notifier)
+{
+	struct _eoi_eventfd *p;
+
+	p = container_of(notifier, struct _eoi_eventfd, notifier);
+
+	if (p->deassert)
+		kvm_set_irq(p->kvm, KVM_USERSPACE_IRQ_SOURCE_ID,
+			    notifier->gsi, 0);
+
+	eventfd_signal(p->eventfd, 1);
+}
+
+static int kvm_assign_eoi_eventfd(struct kvm *kvm, struct kvm_eoi *eoi)
+{
+	struct eventfd_ctx *eventfd;
+	struct _eoi_eventfd *p;
+
+	eventfd = eventfd_ctx_fdget(eoi->fd);
+	if (IS_ERR(eventfd))
+		return PTR_ERR(eventfd);
+
+	p = kzalloc(sizeof(*p), GFP_KERNEL);
+	if (!p) {
+		eventfd_ctx_put(eventfd);
+		return -ENOMEM;
+	}
+
+	INIT_LIST_HEAD(&p->list);
+	p->kvm = kvm;
+	p->eventfd = eventfd;
+	p->deassert = !!(eoi->flags & KVM_EOI_EVENTFD_FLAG_DEASSERT);
+
+	p->notifier.gsi = eoi->gsi;
+	p->notifier.irq_acked = kvm_eoi_eventfd_acked;
+
+	list_add_tail(&p->list, &kvm->eoi_eventfds);
+	kvm_register_irq_ack_notifier(kvm, &p->notifier);
+
+	return 0;
+}
+
+static int kvm_deassign_eoi_eventfd(struct kvm *kvm, struct kvm_eoi *eoi)
+{
+	struct eventfd_ctx *eventfd;
+	struct _eoi_eventfd *p, *tmp;
+	int ret = -ENOENT;
+
+	eventfd = eventfd_ctx_fdget(eoi->fd);
+	if (IS_ERR(eventfd))
+		return PTR_ERR(eventfd);
+
+	list_for_each_entry_safe(p, tmp, &kvm->eoi_eventfds, list) {
+		if (p->eventfd != eventfd || p->notifier.gsi != eoi->gsi)
+			continue;
+
+		kvm_unregister_irq_ack_notifier(kvm, &p->notifier);
+		eventfd_ctx_put(p->eventfd);
+		list_del(&p->list);
+		kfree(p);
+		ret = 0;
+		break;
+	}
+
+	eventfd_ctx_put(eventfd);
+
+	return ret;
+}
+
+int kvm_eoi_eventfd(struct kvm *kvm, struct kvm_eoi *eoi)
+{
+	if (eoi->flags & KVM_EOI_EVENTFD_FLAG_DEASSIGN)
+		return kvm_deassign_eoi_eventfd(kvm, eoi);
+
+	return kvm_assign_eoi_eventfd(kvm, eoi);
+}
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 88d869e..7ca6f13 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -1807,6 +1807,14 @@ static long kvm_vm_ioctl(struct file *filp,
 		mutex_unlock(&kvm->lock);
 		break;
 #endif
+	case KVM_EOI_EVENTFD: {
+		struct kvm_eoi eoi;
+		r = -EFAULT;
+		if (copy_from_user(&eoi, argp, sizeof eoi))
+			goto out;
+		r = kvm_eoi_eventfd(kvm, &eoi);
+		break;
+	}
 	default:
 		r = kvm_arch_vm_ioctl(filp, ioctl, arg);
 		if (r == -ENOTTY)

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ