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

 drivers/kvm/Kconfig       |   27 +++++-
 drivers/kvm/Makefile      |    3 -
 drivers/kvm/ioq.h         |   39 +++++++++
 drivers/kvm/ioq_guest.c   |  190 +++++++++++++++++++++++++++++++++++++++++++++
 drivers/kvm/pvbus.h       |   41 ++++++++++
 drivers/kvm/pvbus_guest.c |  189 +++++++++++++++++++++++++++++++++++++++++++++
 include/linux/kvm.h       |    4 +
 7 files changed, 485 insertions(+), 8 deletions(-)

diff --git a/drivers/kvm/Kconfig b/drivers/kvm/Kconfig
index 22d0eb4..cba03d2 100644
--- a/drivers/kvm/Kconfig
+++ b/drivers/kvm/Kconfig
@@ -47,16 +47,31 @@ config KVM_BALLOON
          The driver inflate/deflate guest physical memory on demand.
          This ability provides memory over commit for the host
 
-config KVM_NET
-       tristate "Para virtual network device"
-       depends on KVM
-       ---help---
-         Provides support for guest paravirtualization networking
-
 config KVM_NET_HOST
        tristate "Para virtual network host device"
        depends on KVM
        ---help---
          Provides support for host paravirtualization networking
 
+config KVM_GUEST
+       bool "KVM Guest support"
+       depends on X86
+       default y
+
+config KVM_PVBUS_GUEST
+       tristate "Paravirtualized Bus (PVBUS) support"
+       depends on KVM_GUEST
+       select IOQ
+       ---help---
+        PVBUS is an infrastructure for generic PV drivers to take advantage
+        of an underlying hypervisor without having to understand the details
+       of the hypervisor itself.  You only need this option if you plan to
+       run this kernel as a KVM guest.
+
+config KVM_NET
+       tristate "Para virtual network device"
+       depends on KVM && KVM_GUEST
+       ---help---
+         Provides support for guest paravirtualization networking
+
 endif # VIRTUALIZATION
diff --git a/drivers/kvm/Makefile b/drivers/kvm/Makefile
index 92600d8..c6a59bb 100644
--- a/drivers/kvm/Makefile
+++ b/drivers/kvm/Makefile
@@ -14,4 +14,5 @@ kvm-net-objs = kvm_net.o
 obj-$(CONFIG_KVM_NET) += kvm-net.o
 kvm-net-host-objs = kvm_net_host.o
 obj-$(CONFIG_KVM_NET_HOST) += kvm_net_host.o
-
+kvm-pvbus-objs := ioq_guest.o pvbus_guest.o
+obj-$(CONFIG_KVM_PVBUS_GUEST) += kvm-pvbus.o
diff --git a/drivers/kvm/ioq.h b/drivers/kvm/ioq.h
new file mode 100644
index 0000000..7e955f1
--- /dev/null
+++ b/drivers/kvm/ioq.h
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+#ifndef _KVM_IOQ_H_
+#define _KVM_IOQ_H_
+
+#include <linux/ioq.h>
+
+#define IOQHC_REGISTER   1
+#define IOQHC_UNREGISTER  2
+#define IOQHC_SIGNAL     3
+
+struct ioq_register {
+       ioq_id_t id;
+       u32      irq;
+       u64      ring;
+};
+
+
+#endif /* _KVM_IOQ_H_ */
diff --git a/drivers/kvm/ioq_guest.c b/drivers/kvm/ioq_guest.c
new file mode 100644
index 0000000..d608407
--- /dev/null
+++ b/drivers/kvm/ioq_guest.c
@@ -0,0 +1,190 @@
+/*
+ * 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 <asm/hypercall.h>
+
+#include "ioq.h"
+#include "kvm.h"
+
+struct kvmguest_ioq {
+       struct ioq            ioq;
+       int                   irq;
+};
+
+struct kvmguest_ioq* to_ioq(struct ioq *ioq)
+{
+       return container_of(ioq, struct kvmguest_ioq, ioq);
+}
+
+static int ioq_hypercall(unsigned long nr, void *data)
+{
+       return hypercall(2, __NR_hypercall_ioq, nr, __pa(data));
+}
+
+/*
+ * ------------------
+ * interrupt handler
+ * ------------------
+ */
+irqreturn_t kvmguest_ioq_intr(int irq, void *dev)
+{
+       struct kvmguest_ioq *_ioq = to_ioq(dev);
+
+       ioq_wakeup(&_ioq->ioq);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * ------------------
+ * ioq implementation
+ * ------------------
+ */
+
+static int kvmguest_ioq_signal(struct ioq *ioq)
+{
+       return ioq_hypercall(IOQHC_SIGNAL, &ioq->id);
+}
+
+static void kvmguest_ioq_destroy(struct ioq *ioq)
+{
+       struct kvmguest_ioq *_ioq = to_ioq(ioq);
+       int ret;
+
+       ret = ioq_hypercall(IOQHC_UNREGISTER, &ioq->id);
+       BUG_ON (ret < 0);
+
+       free_irq(_ioq->irq, NULL);
+
+       kfree(_ioq->ioq.ring);
+       kfree(_ioq->ioq.head_desc);
+       kfree(_ioq);
+}
+
+/*
+ * ------------------
+ * ioqmgr implementation
+ * ------------------
+ */
+static int kvmguest_ioq_register(struct kvmguest_ioq *ioq, ioq_id_t id,
+                                int irq, void *ring)
+{
+       struct ioq_register data = {
+               .id   = id,
+               .irq  = irq,
+               .ring = (u64)__pa(ring),
+       };
+
+       return ioq_hypercall(IOQHC_REGISTER, &data);
+}
+
+static int kvmguest_ioq_create(struct ioq_mgr *t, struct ioq **ioq,
+                               size_t ringsize, int flags)
+{
+       struct kvmguest_ioq  *_ioq      = NULL;
+       struct ioq_ring_head *head_desc = NULL;
+       void                 *ring      = NULL;
+       size_t ringlen = sizeof(struct ioq_ring_desc) * ringsize;
+       int ret = -ENOMEM;
+
+       _ioq = kzalloc(sizeof(*_ioq), GFP_KERNEL);
+       if (!_ioq)
+               goto error;
+
+       head_desc = kzalloc(sizeof(*head_desc), GFP_KERNEL | GFP_DMA);
+       if (!head_desc)
+               goto error;
+
+       ring = kzalloc(ringlen, GFP_KERNEL | GFP_DMA);
+       if (!ring)
+               goto error;
+
+       head_desc->magic         = IOQ_RING_MAGIC;
+       head_desc->ver           = IOQ_RING_VER;
+       head_desc->id            = (ioq_id_t)_ioq;
+       head_desc->count         = ringsize;
+       head_desc->ptr           = (u64)__pa(ring);
+
+       _ioq->irq            = 0; /* FIXME: Get a free IRQ */
+
+       ioq_init(&_ioq->ioq);
+
+       _ioq->ioq.signal     = kvmguest_ioq_signal;
+       _ioq->ioq.destroy    = kvmguest_ioq_destroy;
+
+       _ioq->ioq.id         = head_desc->id;
+       _ioq->ioq.locale     = ioq_locality_north;
+       _ioq->ioq.mgr        = t;
+       _ioq->ioq.head_desc  = head_desc;
+       _ioq->ioq.ring       = ring;
+
+       ret = request_irq(_ioq->irq, kvmguest_ioq_intr, 0, "KVM-IOQ", _ioq);
+       if (ret < 0)
+               goto error;
+
+       ret = kvmguest_ioq_register(_ioq, _ioq->ioq.id, _ioq->irq, ring);
+       if (ret < 0)
+               goto error;
+
+       *ioq = &_ioq->ioq;
+
+       return 0;
+
+ error:
+       if (_ioq)
+               kfree(_ioq);
+       if (head_desc)
+               kfree(head_desc);
+       if (ring)
+               kfree(ring);
+
+       return ret;
+}
+
+static int kvmguest_ioq_connect(struct ioq_mgr *t, ioq_id_t id,
+                                struct ioq **ioq, int flags)
+{
+       /* You cannot connect to queues on the guest */
+       return -EINVAL;
+
+}
+
+int kvmguest_ioqmgr_alloc(struct ioq_mgr **mgr)
+{
+       struct ioq_mgr *_mgr = kzalloc(sizeof(*_mgr), GFP_KERNEL);
+       if (!_mgr)
+               return -ENOMEM;
+
+       _mgr->create  = kvmguest_ioq_create;
+       _mgr->connect = kvmguest_ioq_connect;
+
+       *mgr = _mgr;
+
+       return 0;
+}
+
+
+
+
+
+
diff --git a/drivers/kvm/pvbus.h b/drivers/kvm/pvbus.h
new file mode 100644
index 0000000..97b5dce
--- /dev/null
+++ b/drivers/kvm/pvbus.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2007 Novell.  All Rights Reserved.
+ *
+ * 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.
+ */
+
+#ifndef _KVM_PVBUS_H
+#define _KVM_PVBUS_H
+
+#define KVM_PVBUS_OP_ENUM 1
+#define KVM_PVBUS_OP_CALL 2
+
+struct enumerate_params {
+       u32 name_offset;
+       u32 inst_offset;
+       u32 count;
+       u8  data[1];
+};
+
+struct call_params {
+       u64 inst;
+       u32 func;
+       u64 data;
+       u64 len;
+};
+
+#endif /* _KVM_PVBUS_H */
diff --git a/drivers/kvm/pvbus_guest.c b/drivers/kvm/pvbus_guest.c
new file mode 100644
index 0000000..3003745
--- /dev/null
+++ b/drivers/kvm/pvbus_guest.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright 2007 Novell.  All Rights Reserved.
+ *
+ * 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/module.h>
+#include <linux/pvbus.h>
+#include <linux/kvm_para.h>
+#include <linux/kvm.h>
+#include <linux/mm.h>
+#include <linux/ioq.h>
+
+#include <asm/hypercall.h>
+
+#include "pvbus.h"
+
+MODULE_AUTHOR ("Gregory Haskins");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1");
+
+static int kvm_pvbus_hypercall(unsigned long nr, void *data, unsigned long len)
+{
+       return hypercall(3, __NR_hypercall_pvbus, nr, __pa(data), len);
+}
+
+static int kvm_pvbus_enumerate(const char *dev, struct pvbus_dev inst[],
+                              size_t *cnt, int flags)
+{
+       int ret;
+       size_t namelen = strlen(dev);
+       size_t total = sizeof(struct enumerate_params)
+               + namelen /* dont add one...extra is already in data[1] */
+               + (sizeof(struct pvbus_dev) * (*cnt));
+
+       struct enumerate_params *e = kzalloc(total, GFP_KERNEL | GFP_DMA);
+       if (!e)
+               return -ENOMEM;
+
+       e->name_offset = 0;
+       memcpy(&e->data[e->name_offset], dev, namelen);
+       e->inst_offset = namelen + 1;
+       e->count       = *cnt;
+
+       ret = kvm_pvbus_hypercall(KVM_PVBUS_OP_ENUM, e, total);
+       if (ret < 0)
+               goto out;
+
+       *cnt = e->count;
+
+       if (e->count)
+               memcpy(inst, &e->data[e->inst_offset],
+                      (sizeof(struct pvbus_dev) * e->count));
+
+ out:
+       kfree(e);
+
+       return ret;
+}
+
+static int kvm_pvbus_call(u64 inst, u32 func, void *data,
+                         size_t len, int flags)
+{
+       struct call_params params = {
+               .inst = inst,
+               .func = func,
+               .data = (u64)__pa(data),
+               .len  = len,
+       };
+
+       return kvm_pvbus_hypercall(KVM_PVBUS_OP_CALL, &params, sizeof(params));
+}
+
+/*
+ * This is the vm-syscall address - to be patched by the host to
+ * VMCALL (Intel) or VMMCALL (AMD), depending on the CPU model:
+ */
+asm (
+       "       .globl hypercall_addr                   \n"
+       "       .align 4                                \n"
+       "       hypercall_addr:                         \n"
+       "               movl $-38, %eax                 \n"
+       "               ret                             \n"
+);
+
+extern unsigned char hypercall_addr[6];
+
+#ifndef CONFIG_X86_64
+static DEFINE_PER_CPU(struct kvm_vcpu_para_state, para_state);
+#endif
+
+static int __init kvm_pvbus_probe(void)
+{
+       struct page *hypercall_addr_page;
+       struct kvm_vcpu_para_state *para_state;
+
+#ifdef CONFIG_X86_64
+       struct page *pstate_page;
+       if ((pstate_page = alloc_page(GFP_KERNEL)) == NULL)
+               return -ENOMEM;
+       para_state = (struct kvm_vcpu_para_state*)page_address(pstate_page);
+#else
+       para_state =  &per_cpu(para_state, cpu);
+#endif
+       /*
+        * Try to write to a magic MSR (which is invalid on any real CPU),
+        * and thus signal to KVM that we wish to entering para-virtualized
+        * mode:
+        */
+       para_state->guest_version = KVM_PARA_API_VERSION;
+       para_state->host_version = -1;
+       para_state->size = sizeof(*para_state);
+       para_state->ret = -1;
+
+       hypercall_addr_page = vmalloc_to_page(hypercall_addr);
+       para_state->hypercall_gpa = page_to_pfn(hypercall_addr_page)
+               << PAGE_SHIFT | offset_in_page(hypercall_addr);
+       printk(KERN_DEBUG "kvm guest: hypercall gpa is 0x%lx\n",
+              (long)para_state->hypercall_gpa);
+
+       if (wrmsr_safe(MSR_KVM_API_MAGIC, __pa(para_state), 0)) {
+               printk(KERN_INFO "KVM guest: WRMSR probe failed.\n");
+               return -1;
+       }
+
+       printk(KERN_DEBUG "kvm guest: host returned %d\n",
+              para_state->ret);
+       printk(KERN_DEBUG "kvm guest: host version: %d\n",
+              para_state->host_version);
+       printk(KERN_DEBUG "kvm guest: syscall entry: %02x %02x %02x %02x\n",
+                       hypercall_addr[0], hypercall_addr[1],
+                       hypercall_addr[2], hypercall_addr[3]);
+
+       if (para_state->ret) {
+               printk(KERN_ERR "kvm guest: host refused registration.\n");
+               return -1;
+       }
+
+       return 0;
+
+}
+
+static struct pvbus_ops kvm_pvbus_ops = {
+       .enumerate = kvm_pvbus_enumerate,
+       .call      = kvm_pvbus_call,
+       .ioqmgr    = NULL,
+};
+
+int kvmguest_ioqmgr_alloc(struct ioq_mgr **mgr);
+
+int __init kvm_pvbus_init(void)
+{
+       int ret = kvm_pvbus_probe();
+       if (ret < 0)
+               return ret;
+
+       ret = kvmguest_ioqmgr_alloc(&kvm_pvbus_ops.ioqmgr);
+       if (ret < 0)
+               return ret;
+
+       pvbus_ops = &kvm_pvbus_ops;
+
+       return 0;
+
+}
+
+static void __exit kvm_pvbus_exit(void)
+{
+
+}
+
+module_init(kvm_pvbus_init);
+module_exit(kvm_pvbus_exit);
+
+
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index 992aeec..bc2b51e 100755
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -377,13 +377,15 @@ struct kvm_pvnet_config {
  * No registers are clobbered by the hypercall, except that the
  * return value is in RAX.
  */
-#define KVM_NR_HYPERCALLS              5
+#define KVM_NR_HYPERCALLS              7
 
 #define __NR_hypercall_test            0
 #define __NR_hypercall_register_eth    1
 #define __NR_hypercall_send_eth                2
 #define __NR_hypercall_set_multicast_eth 3
 #define __NR_hypercall_start_stop_eth   4
+#define __NR_hypercall_ioq              5
+#define __NR_hypercall_pvbus            6
 
 #define __NR_hypercall_balloon         (KVM_NR_HYPERCALLS + 0)
 


-------------------------------------------------------------------------
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