IOQ is a shared-memory-queue interface for implmenting PV driver
communication.

Signed-off-by: Gregory Haskins <[EMAIL PROTECTED]>
---

 drivers/kvm/Kconfig    |    5 +
 drivers/kvm/Makefile   |    3 
 drivers/kvm/ioq.h      |   12 +-
 drivers/kvm/ioq_host.c |  365 ++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/kvm/kvm.h      |    4 +
 drivers/kvm/kvm_main.c |    3 
 6 files changed, 391 insertions(+), 1 deletions(-)

diff --git a/drivers/kvm/Kconfig b/drivers/kvm/Kconfig
index d17ce96..b81a188 100644
--- a/drivers/kvm/Kconfig
+++ b/drivers/kvm/Kconfig
@@ -41,6 +41,11 @@ config KVM_AMD
          Provides support for KVM on AMD processors equipped with the AMD-V
          (SVM) extensions.
 
+config KVM_PV_HOST
+        boolean "Add paravirtualization backend support to KVM"
+       depends on KVM
+       select IOQ
+        
 config KVM_GUEST
        bool "KVM Guest support"
        depends on X86
diff --git a/drivers/kvm/Makefile b/drivers/kvm/Makefile
index cd621fc..eb32ce5 100644
--- a/drivers/kvm/Makefile
+++ b/drivers/kvm/Makefile
@@ -3,6 +3,9 @@
 #
 
 kvm-objs := kvm_main.o mmu.o x86_emulate.o
+ifeq ($(CONFIG_KVM_PV_HOST),y)
+kvm-objs += ioq_host.o
+endif
 obj-$(CONFIG_KVM) += kvm.o
 kvm-intel-objs = vmx.o
 obj-$(CONFIG_KVM_INTEL) += kvm-intel.o
diff --git a/drivers/kvm/ioq.h b/drivers/kvm/ioq.h
index 7e955f1..347fa0b 100644
--- a/drivers/kvm/ioq.h
+++ b/drivers/kvm/ioq.h
@@ -25,7 +25,17 @@
 
 #include <linux/ioq.h>
 
-#define IOQHC_REGISTER   1
+struct kvm;
+
+#ifdef CONFIG_KVM_PV_HOST
+int kvmhost_ioqmgr_init(struct kvm *kvm);
+int kvmhost_ioqmgr_module_init(void);
+#else
+#define kvmhost_ioqmgr_init(kvm) {}
+#define kvmhost_ioqmgr_module_init() {}
+#endif
+
+#define IOQHC_REGISTER    1
 #define IOQHC_UNREGISTER  2
 #define IOQHC_SIGNAL     3
 
diff --git a/drivers/kvm/ioq_host.c b/drivers/kvm/ioq_host.c
new file mode 100644
index 0000000..413f103
--- /dev/null
+++ b/drivers/kvm/ioq_host.c
@@ -0,0 +1,365 @@
+/*
+ * Copyright 2007 Novell.  All Rights Reserved.
+ *
+ * See include/linux/ioq.h for documentation
+ *
+ * Author:
+ *     Gregory Haskins <[EMAIL PROTECTED]>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/ioq.h>
+#include <linux/rbtree.h>
+#include <linux/spinlock.h>
+#include <linux/highmem.h>
+
+#include <asm/atomic.h>
+
+#include "ioq.h"
+#include "kvm.h"
+
+struct kvmhost_ioq {
+       struct ioq            ioq;
+       struct rb_node        node;
+       atomic_t              refcnt;
+       struct kvm_vcpu      *vcpu;
+       int                   irq;
+};
+
+struct kvmhost_map {
+       spinlock_t     lock;
+       struct rb_root root;
+};
+
+struct kvmhost_ioq_mgr {
+       struct ioq_mgr      mgr;
+       struct kvm         *kvm;
+       struct kvmhost_map  map;
+};
+
+struct kvmhost_ioq* to_ioq(struct ioq *ioq)
+{
+       return container_of(ioq, struct kvmhost_ioq, ioq);
+}
+
+struct kvmhost_ioq_mgr* to_mgr(struct ioq_mgr *mgr)
+{
+       return container_of(mgr, struct kvmhost_ioq_mgr, mgr);
+}
+
+/*
+ * ------------------
+ * rb map management
+ * ------------------
+ */
+
+static void kvmhost_map_init(struct kvmhost_map *map)
+{
+       spin_lock_init(&map->lock);
+       map->root = RB_ROOT;
+}
+
+static int kvmhost_map_register(struct kvmhost_map *map,
+                               struct kvmhost_ioq *ioq)
+{
+       int             ret = 0;
+       struct rb_root *root;
+       struct rb_node **new, *parent = NULL;
+
+       spin_lock(&map->lock);
+
+       root = &map->root;
+       new  = &(root->rb_node);
+
+       /* Figure out where to put new node */
+       while (*new) {
+               struct kvmhost_ioq *this;
+
+               this   = container_of(*new, struct kvmhost_ioq, node);
+               parent = *new;
+
+               if (ioq->ioq.id < this->ioq.id)
+                       new = &((*new)->rb_left);
+               else if (ioq->ioq.id > this->ioq.id)
+                       new = &((*new)->rb_right);
+               else {
+                       ret = -EEXIST;
+                       break;
+               }
+       }
+
+       if (!ret) {
+               /* Add new node and rebalance tree. */
+               rb_link_node(&ioq->node, parent, new);
+               rb_insert_color(&ioq->node, root);
+       }
+
+       spin_unlock(&map->lock);
+
+       return ret;
+}
+
+static struct kvmhost_ioq* kvmhost_map_find(struct kvmhost_map *map,
+                                           ioq_id_t id)
+{
+       struct rb_node *node;
+       struct kvmhost_ioq *ioq = NULL;
+
+       spin_lock(&map->lock);
+
+       node = map->root.rb_node;
+
+       while (node) {
+               struct kvmhost_ioq *_ioq;
+
+               _ioq = container_of(node, struct kvmhost_ioq, node);
+
+               if (ioq->ioq.id < id)
+                       node = node->rb_left;
+               else if (_ioq->ioq.id > id)
+                       node = node->rb_right;
+               else {
+                       ioq = _ioq;
+                       break;
+               }
+       }
+
+       spin_unlock(&map->lock);
+
+       return ioq;
+}
+
+static void kvmhost_map_erase(struct kvmhost_map *map,
+                             struct kvmhost_ioq *ioq)
+{
+       spin_lock(&map->lock);
+       rb_erase(&ioq->node, &map->root);
+       spin_unlock(&map->lock);
+}
+
+/*
+ * ------------------
+ * ioq implementation
+ * ------------------
+ */
+
+static int kvmhost_ioq_signal(struct ioq *ioq)
+{
+       struct kvmhost_ioq *_ioq = to_ioq(ioq);
+       BUG_ON(!_ioq);
+
+       /*
+        * FIXME: Inject an interrupt to the guest for "id"
+        *
+        *  We will have to decide if we will have 1:1 IOQ:IRQ, or if we
+        * will aggregate all IOQs through a single IRQ.  For purposes of
+        * example, we will assume 1:1.
+        */
+
+       /* kvm_vcpu_send_interrupt(_ioq->vcpu, _ioq->irq); */
+
+       return 0;
+}
+
+static void kvmhost_ioq_destroy(struct ioq *ioq)
+{
+       struct kvmhost_ioq *_ioq = to_ioq(ioq);
+
+       if (atomic_dec_and_test(&_ioq->refcnt))
+               kfree(_ioq);
+}
+
+static struct kvmhost_ioq* kvmhost_ioq_alloc(struct ioq_mgr *t,
+                                            struct kvm_vcpu *vcpu,
+                                            ioq_id_t id, int irq, gpa_t ring)
+{
+       struct kvmhost_ioq *_ioq;
+       struct ioq         *ioq;
+
+       _ioq = kzalloc(sizeof(*_ioq), GFP_KERNEL);
+       if (!_ioq)
+               return NULL;
+
+       ioq = &_ioq->ioq;
+
+       atomic_set(&_ioq->refcnt, 1);
+       _ioq->vcpu    = vcpu;
+       _ioq->irq     = irq;
+
+       ioq_init(&_ioq->ioq);
+
+       ioq->signal     = kvmhost_ioq_signal;
+       ioq->destroy    = kvmhost_ioq_destroy;
+
+       ioq->id         = id;
+       ioq->locale     = ioq_locality_south;
+       ioq->mgr        = t;
+       ioq->head_desc  = (struct ioq_ring_head*)gpa_to_hva(vcpu->kvm, ring);
+       ioq->ring       = (struct ioq_ring_desc*)gpa_to_hva(vcpu->kvm,
+                                                           
ioq->head_desc->ptr);
+
+       return _ioq;
+}
+
+/*
+ * ------------------
+ * hypercall implementation
+ * ------------------
+ */
+
+static int kvmhost_ioq_hc_register(struct ioq_mgr *t, struct kvm_vcpu *vcpu,
+                                  ioq_id_t id, int irq, gpa_t ring)
+{
+       struct kvmhost_ioq *_ioq = kvmhost_ioq_alloc(t, vcpu, id, irq, ring);
+       int ret;
+
+       if (!_ioq)
+               return -ENOMEM;
+
+       ret = kvmhost_map_register(&to_mgr(t)->map, _ioq);
+       if (ret < 0)
+               kvmhost_ioq_destroy(&_ioq->ioq);
+
+       return 0;
+}
+
+static int kvmhost_ioq_hc_unregister(struct ioq_mgr *t, ioq_id_t id)
+{
+       struct kvmhost_ioq_mgr *_mgr = to_mgr(t);
+       struct kvmhost_ioq     *_ioq = kvmhost_map_find(&_mgr->map, id);
+
+       if (!_ioq)
+               return -ENOENT;
+
+       kvmhost_map_erase(&_mgr->map, _ioq);
+       kvmhost_ioq_destroy(&_ioq->ioq);
+
+       return 0;
+}
+
+static int kvmhost_ioq_hc_signal(struct ioq_mgr *t, ioq_id_t id)
+{
+       struct kvmhost_ioq *_ioq = kvmhost_map_find(&to_mgr(t)->map, id);
+
+       if (!_ioq)
+               return -1;
+
+       ioq_wakeup(&_ioq->ioq);
+
+       return 0;
+}
+
+/*
+ * Our hypercall format will always follow with the call-id in arg[0] and
+ * a pointer to the arguments in arg[1]
+ */
+static unsigned long kvmhost_hc(struct kvm_vcpu *vcpu, unsigned long args[])
+{
+       struct ioq_mgr *t = vcpu->kvm->ioqmgr;
+       void *vdata = gpa_to_hva(vcpu->kvm, args[1]);
+       int ret = -EINVAL;
+
+       if (!vdata)
+               return -EINVAL;
+
+       /*
+        * FIXME: we need to make sure that the pointer is sane
+        * so a malicious guest cannot crash the host.
+        */
+
+       switch (args[0])
+       {
+       case IOQHC_REGISTER: {
+               struct ioq_register *data = (struct ioq_register*)vdata;
+               ret = kvmhost_ioq_hc_register(t, vcpu,
+                                             data->id,
+                                             data->irq,
+                                             data->ring);
+       }
+       case IOQHC_UNREGISTER: {
+               ioq_id_t *id = (ioq_id_t*)vdata;
+               ret = kvmhost_ioq_hc_unregister(t, *id);
+       }
+       case IOQHC_SIGNAL: {
+               ioq_id_t *id = (ioq_id_t*)vdata;
+               ret = kvmhost_ioq_hc_signal(t, *id);
+       }
+       }
+
+       /* FIXME: unmap the vdata? */
+
+       return ret;
+}
+
+/*
+ * ------------------
+ * ioqmgr implementation
+ * ------------------
+ */
+
+static int kvmhost_ioq_create(struct ioq_mgr *t, struct ioq **ioq,
+                             size_t ringsize, int flags)
+{
+       /* You cannot create queues on the host */
+       return -EINVAL;
+}
+
+static int kvmhost_ioq_connect(struct ioq_mgr *t, ioq_id_t id,
+                              struct ioq **ioq, int flags)
+{
+       struct kvmhost_ioq *_ioq = kvmhost_map_find(&to_mgr(t)->map, id);
+
+       if (!_ioq)
+               return -1;
+
+       atomic_inc(&_ioq->refcnt);
+       *ioq = &_ioq->ioq;
+
+       return 0;
+
+}
+
+int kvmhost_ioqmgr_init(struct kvm *kvm)
+{
+       struct kvmhost_ioq_mgr *_mgr = kzalloc(sizeof(*_mgr), GFP_KERNEL);
+       if (!_mgr)
+               return -ENOMEM;
+
+       _mgr->kvm = kvm;
+       kvmhost_map_init(&_mgr->map);
+
+       _mgr->mgr.create  = kvmhost_ioq_create;
+       _mgr->mgr.connect = kvmhost_ioq_connect;
+
+       kvm->ioqmgr = &_mgr->mgr;
+
+       return 0;
+}
+
+__init int kvmhost_ioqmgr_module_init(void)
+{
+       struct kvm_hypercall hc;
+
+       hc.hypercall      = kvmhost_hc;
+       hc.idx            = __NR_hypercall_ioq;
+
+       kvm_register_hypercall(THIS_MODULE, &hc);
+
+       return 0;
+}
+
+
+
+
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
index 2987edc..aaa6d12 100644
--- a/drivers/kvm/kvm.h
+++ b/drivers/kvm/kvm.h
@@ -16,6 +16,7 @@
 #include <linux/preempt.h>
 #include <asm/signal.h>
 
+#include "ioq.h"
 #include <linux/kvm.h>
 #include <linux/kvm_para.h>
 
@@ -411,6 +412,9 @@ struct kvm {
        struct file *filp;
        struct kvm_io_bus mmio_bus;
        struct kvm_io_bus pio_bus;
+#ifdef CONFIG_KVM_PV_HOST
+       struct ioq_mgr *ioqmgr;
+#endif
 };
 
 struct descriptor_table {
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index 6428746..03d0d67 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -301,6 +301,7 @@ static struct kvm *kvm_create_vm(void)
        spin_lock(&kvm_lock);
        list_add(&kvm->vm_list, &vm_list);
        spin_unlock(&kvm_lock);
+       kvmhost_ioqmgr_init(kvm);
        return kvm;
 }
 
@@ -3303,6 +3304,8 @@ static __init int kvm_init(void)
        bad_page_address = page_to_pfn(bad_page) << PAGE_SHIFT;
        memset(__va(bad_page_address), 0, PAGE_SIZE);
 
+       kvmhost_ioqmgr_module_init();
+
        return 0;
 
 out:


-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/
_______________________________________________
kvm-devel mailing list
kvm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/kvm-devel

Reply via email to