qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu
@ 2008-07-28 13:17 Gerd Hoffmann
  2008-07-28 13:17 ` [Qemu-devel] [PATCH 1/7] xen: groundwork for xen support Gerd Hoffmann
                   ` (6 more replies)
  0 siblings, 7 replies; 64+ messages in thread
From: Gerd Hoffmann @ 2008-07-28 13:17 UTC (permalink / raw)
  To: qemu-devel, xen-devel; +Cc: Gerd Hoffmann

  Hi folks,

Here are a bunch of patches which start adding xen support to qemu.
Overview (individual patches have longer descriptions):

  #1 -- groundwork: build system, cmd line options, ...
  #2 -- xen backend driver infrastructrure
  #3 -- xen console backend driver
  #4 -- xen framebuffer backend driver
  #5 -- xen block backend driver
  #6 -- xen nic backend driver
  #7 -- allow xen disks and nics being configured via qemu command
        line options.

With the first four patches in place upstream qemu can replace xen's
qemu-dm for paravirtual domains.  The block and nic backend drivers are
full userspace implementations using the grant table device (gntdev).

xen support is implemented using another machine type.  xen's qemu-dm
already uses the machine type to switch between paravirtualized and
fully virtualized machines, so this was the natural choice.  qemu has
gets a new "xenpv" machine type additionally to the "pc" and "isapc"
ones.

I've placed the new files into the hw/ directory.  With all my xen bits
(partly not submitted yet with these patches) those add up to 18 new
files, all prefixed with xen.  Hmm, maybe I should better place them
somewhere else, so the already quite crowded hw/ directory doesn't
become even more cluttered?  If so, any suggestions?  New toplevel
directory?  New subdirectory below hw/?  Something else?

Comments?

cheers,
  Gerd

^ permalink raw reply	[flat|nested] 64+ messages in thread

* [Qemu-devel] [PATCH 1/7] xen: groundwork for xen support
  2008-07-28 13:17 [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu Gerd Hoffmann
@ 2008-07-28 13:17 ` Gerd Hoffmann
  2008-07-28 14:04   ` Anthony Liguori
  2008-07-28 13:17 ` [Qemu-devel] [PATCH 2/7] xen: backend driver core Gerd Hoffmann
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 64+ messages in thread
From: Gerd Hoffmann @ 2008-07-28 13:17 UTC (permalink / raw)
  To: qemu-devel, xen-devel; +Cc: Gerd Hoffmann

- configure script and build system changes.
- wind up new machine type.
- add -domid command line option.
- allow xenpv machines run without disk and kernel specified.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 Makefile.target       |    8 +++++
 configure             |   27 ++++++++++++++++
 hw/boards.h           |    4 ++
 hw/xen-machine.c      |   83 +++++++++++++++++++++++++++++++++++++++++++++++++
 hw/xen.h              |   12 +++++++
 target-i386/machine.c |    3 ++
 vl.c                  |   25 +++++++++++++--
 7 files changed, 159 insertions(+), 3 deletions(-)
 create mode 100644 hw/xen-machine.c
 create mode 100644 hw/xen.h

diff --git a/Makefile.target b/Makefile.target
index ff105c1..4f42582 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -515,6 +515,14 @@ CPPFLAGS += $(CONFIG_VNC_TLS_CFLAGS)
 LIBS += $(CONFIG_VNC_TLS_LIBS)
 endif
 
+# xen backend driver support
+XEN_OBJS := xen-machine.o
+ifeq ($(CONFIG_XEN), yes)
+  OBJS += $(XEN_OBJS)
+  LIBS += $(XEN_LIBS)
+  $(XEN_OBJS) : CFLAGS += -Wall -Wmissing-prototypes -Wstrict-prototypes
+endif
+
 # SCSI layer
 OBJS+= lsi53c895a.o esp.o
 
diff --git a/configure b/configure
index fd04766..34516b9 100755
--- a/configure
+++ b/configure
@@ -108,6 +108,7 @@ uname_release=""
 curses="yes"
 nptl="yes"
 mixemu="no"
+xen="no"
 
 # OS specific
 targetos=`uname -s`
@@ -202,6 +203,7 @@ linux="yes"
 linux_user="yes"
 if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
     kqemu="yes"
+    xen="yes"
     audio_possible_drivers="$audio_possible_drivers fmod"
 fi
 ;;
@@ -285,6 +287,8 @@ for opt do
   ;;
   --disable-kqemu) kqemu="no"
   ;;
+  --disable-xen) xen="no"
+  ;;
   --disable-brlapi) brlapi="no"
   ;;
   --enable-profiler) profiler="yes"
@@ -421,6 +425,7 @@ echo "                           Available drivers: $audio_possible_drivers"
 echo "  --audio-card-list=LIST   set list of additional emulated audio cards"
 echo "                           Available cards: ac97 adlib cs4231a gus"
 echo "  --enable-mixemu          enable mixer emulation"
+echo "  --disable-xen            disable xen backend driver support"
 echo "  --disable-brlapi         disable BrlAPI"
 echo "  --disable-vnc-tls        disable TLS encryption for VNC server"
 echo "  --disable-curses         disable curses output"
@@ -681,6 +686,22 @@ else
 fi
 
 ##########################################
+# xen probe
+
+if test "$xen" = "yes" ; then
+cat > $TMPC <<EOF
+#include <xs.h>
+#include <xenctrl.h>
+int main(void) { xs_daemon_open; xc_interface_open; }
+EOF
+   if $cc $ARCH_CFLAGS -c -o $TMPO $TMPC -lxenstore -lxenctrl 2> /dev/null ; then
+      :
+   else
+      xen="no"
+   fi
+fi
+
+##########################################
 # SDL probe
 
 sdl_too_old=no
@@ -916,6 +937,7 @@ if test -n "$sparc_cpu"; then
     echo "Target Sparc Arch $sparc_cpu"
 fi
 echo "kqemu support     $kqemu"
+echo "xen support       $xen"
 echo "brlapi support    $brlapi"
 echo "Documentation     $build_docs"
 [ ! -z "$uname_release" ] && \
@@ -1167,6 +1189,11 @@ if test "$brlapi" = "yes" ; then
   echo "#define CONFIG_BRLAPI 1" >> $config_h
   echo "BRLAPI_LIBS=-lbrlapi" >> $config_mak
 fi
+if test "$xen" = "yes" ; then
+  echo "CONFIG_XEN=yes" >> $config_mak
+  echo "#define CONFIG_XEN 1" >> $config_h
+  echo "XEN_LIBS=-lxenstore -lxenctrl" >> $config_mak
+fi
 
 # XXX: suppress that
 if [ "$bsd" = "yes" ] ; then
diff --git a/hw/boards.h b/hw/boards.h
index 22ac332..5931720 100644
--- a/hw/boards.h
+++ b/hw/boards.h
@@ -29,6 +29,10 @@ extern QEMUMachine bareetraxfs_machine;
 extern QEMUMachine pc_machine;
 extern QEMUMachine isapc_machine;
 
+/* xen_machine.c */
+extern QEMUMachine xenpv_machine;
+extern QEMUMachine xenfv_machine;
+
 /* ppc.c */
 extern QEMUMachine prep_machine;
 extern QEMUMachine core99_machine;
diff --git a/hw/xen-machine.c b/hw/xen-machine.c
new file mode 100644
index 0000000..88f0f6e
--- /dev/null
+++ b/hw/xen-machine.c
@@ -0,0 +1,83 @@
+/*
+ * QEMU Xen PV Machine
+ *
+ * Copyright (c) 2007,08 Red Hat
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw.h"
+#include "boards.h"
+
+#include "xen.h"
+
+/* -------------------------------------------------------------------- */
+/* variables                                                            */
+
+int xen_domid;
+
+/* -------------------------------------------------------------------- */
+/* paravirtualized xen guests                                           */
+
+static void xenpv_init(ram_addr_t ram_size, int vga_ram_size,
+		       const char *boot_device, DisplayState *ds,
+		       const char *kernel_filename,
+		       const char *kernel_cmdline,
+		       const char *initrd_filename,
+		       const char *cpu_model)
+{
+    CPUState *env;
+
+    /* create dummy cpu, halted */
+    if (cpu_model == NULL) {
+#ifdef TARGET_X86_64
+        cpu_model = "qemu64";
+#else
+        cpu_model = "qemu32";
+#endif
+    }
+    env = cpu_init(cpu_model);
+    env->halted = 1;
+}
+
+QEMUMachine xenpv_machine = {
+    "xenpv",
+    "paravirtualized Xen machine",
+    xenpv_init,
+};
+
+/* -------------------------------------------------------------------- */
+/* fully virtualized xen guests                                         */
+
+static void xenfv_init(ram_addr_t ram_size, int vga_ram_size,
+		       const char *boot_device, DisplayState *ds,
+		       const char *kernel_filename,
+		       const char *kernel_cmdline,
+		       const char *initrd_filename,
+		       const char *cpu_model)
+{
+    /* to be done */
+    fprintf(stderr, "%s: not implemented yet\n", __FUNCTION__);
+}
+
+QEMUMachine xenfv_machine = {
+    "xenfv",
+    "fully virtualized Xen machine",
+    xenfv_init,
+};
diff --git a/hw/xen.h b/hw/xen.h
new file mode 100644
index 0000000..19349b5
--- /dev/null
+++ b/hw/xen.h
@@ -0,0 +1,12 @@
+/*
+ * public xen header
+ *   stuff needed outside xen-*.c, i.e. interfaces to qemu.
+ *   should not depend on any xen headers being present in
+ *   /usr/include/xen, so it can be included unconditionally.
+ *
+ * internal bits for the xen backend drivers are in xen-backend.h
+ */
+
+/* xen-machine.c */
+extern int xen_domid;
+
diff --git a/target-i386/machine.c b/target-i386/machine.c
index 91dbd55..98ece17 100644
--- a/target-i386/machine.c
+++ b/target-i386/machine.c
@@ -9,6 +9,9 @@ void register_machines(void)
 {
     qemu_register_machine(&pc_machine);
     qemu_register_machine(&isapc_machine);
+#ifdef CONFIG_XEN
+    qemu_register_machine(&xenpv_machine);
+#endif
 }
 
 static void cpu_put_seg(QEMUFile *f, SegmentCache *dt)
diff --git a/vl.c b/vl.c
index 8801615..8aef3bd 100644
--- a/vl.c
+++ b/vl.c
@@ -29,6 +29,7 @@
 #include "hw/audiodev.h"
 #include "hw/isa.h"
 #include "hw/baum.h"
+#include "hw/xen.h"
 #include "net.h"
 #include "console.h"
 #include "sysemu.h"
@@ -7737,6 +7738,9 @@ static void help(int exitcode)
            "-startdate      select initial date of the clock\n"
            "-icount [N|auto]\n"
            "                Enable virtual instruction counter with 2^N clock ticks per instruction\n"
+#ifdef CONFIG_XEN
+	   "-domid          specify xen guest domain id\n"
+#endif
            "\n"
            "During emulation, the following keys are useful:\n"
            "ctrl-alt-f      toggle full screen\n"
@@ -7842,6 +7846,9 @@ enum {
     QEMU_OPTION_startdate,
     QEMU_OPTION_tb_size,
     QEMU_OPTION_icount,
+#ifdef CONFIG_XEN
+    QEMU_OPTION_domid,
+#endif
 };
 
 typedef struct QEMUOption {
@@ -7930,6 +7937,9 @@ const QEMUOption qemu_options[] = {
 #ifdef CONFIG_CURSES
     { "curses", 0, QEMU_OPTION_curses },
 #endif
+#ifdef CONFIG_XEN
+    { "domid", HAS_ARG, QEMU_OPTION_domid },
+#endif
 
     /* temporary options */
     { "usb", 0, QEMU_OPTION_usb },
@@ -8150,7 +8160,7 @@ int main(int argc, char **argv)
 #endif
     uint32_t boot_devices_bitmap = 0;
     int i;
-    int snapshot, linux_boot, net_boot;
+    int snapshot, linux_boot, net_boot, nodisk_ok;
     const char *initrd_filename;
     const char *kernel_filename, *kernel_cmdline;
     const char *boot_devices = "";
@@ -8787,6 +8797,11 @@ int main(int argc, char **argv)
                     icount_time_shift = strtol(optarg, NULL, 0);
                 }
                 break;
+#ifdef CONFIG_XEN
+            case QEMU_OPTION_domid:
+                xen_domid = atoi(optarg);
+                break;
+#endif
             }
         }
     }
@@ -8852,9 +8867,13 @@ int main(int argc, char **argv)
     linux_boot = (kernel_filename != NULL);
     net_boot = (boot_devices_bitmap >> ('n' - 'a')) & 0xF;
 
-    /* XXX: this should not be: some embedded targets just have flash */
+    /* need a disk for this machine to boot ? */
+    /* XXX: add embedded targets which just have flash */
+    nodisk_ok = 0;
+    if (0 == strcmp(machine->name, "xenpv"))
+	nodisk_ok = 1;
     if (!linux_boot && net_boot == 0 &&
-        nb_drives_opt == 0)
+        !nodisk_ok && nb_drives_opt == 0)
         help(1);
 
     if (!linux_boot && *kernel_cmdline != '\0') {
-- 
1.5.4.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [Qemu-devel] [PATCH 2/7] xen: backend driver core
  2008-07-28 13:17 [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu Gerd Hoffmann
  2008-07-28 13:17 ` [Qemu-devel] [PATCH 1/7] xen: groundwork for xen support Gerd Hoffmann
@ 2008-07-28 13:17 ` Gerd Hoffmann
  2008-07-28 14:13   ` Anthony Liguori
  2008-07-28 13:17 ` [Qemu-devel] [PATCH 3/7] xen: add console backend driver Gerd Hoffmann
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 64+ messages in thread
From: Gerd Hoffmann @ 2008-07-28 13:17 UTC (permalink / raw)
  To: qemu-devel, xen-devel; +Cc: Gerd Hoffmann

This patch adds infrastructure for xen backend drivers living in qemu,
so drivers don't need to implement common stuff on their own.  It's
mostly xenbus management stuff: some functions to access xentore,
setting up xenstore watches, callbacks on device discovery and state
changes, handle event channel, ...

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 Makefile.target  |    2 +-
 hw/list.h        |  169 ++++++++++++++
 hw/xen-backend.c |  663 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/xen-backend.h |  116 ++++++++++
 hw/xen-machine.c |    5 +-
 5 files changed, 953 insertions(+), 2 deletions(-)
 create mode 100644 hw/list.h
 create mode 100644 hw/xen-backend.c
 create mode 100644 hw/xen-backend.h

diff --git a/Makefile.target b/Makefile.target
index 4f42582..0451048 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -516,7 +516,7 @@ LIBS += $(CONFIG_VNC_TLS_LIBS)
 endif
 
 # xen backend driver support
-XEN_OBJS := xen-machine.o
+XEN_OBJS := xen-machine.o xen-backend.o
 ifeq ($(CONFIG_XEN), yes)
   OBJS += $(XEN_OBJS)
   LIBS += $(XEN_LIBS)
diff --git a/hw/list.h b/hw/list.h
new file mode 100644
index 0000000..fa9f790
--- /dev/null
+++ b/hw/list.h
@@ -0,0 +1,169 @@
+#ifndef _LIST_H
+#define _LIST_H 1
+
+/*
+ * Simple doubly linked list implementation.
+ *	-- shamelessly stolen from the linux kernel sources
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+	struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+	struct list_head name = LIST_HEAD_INIT(name)
+
+#define INIT_LIST_HEAD(ptr) do { \
+	(ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+/*
+ * Insert a item entry between two known consecutive entries. 
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static __inline__ void __list_add(struct list_head * item,
+	struct list_head * prev,
+	struct list_head * next)
+{
+	next->prev = item;
+	item->next = next;
+	item->prev = prev;
+	prev->next = item;
+}
+
+/**
+ * list_add - add a item entry
+ * @item: item entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a item entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static __inline__ void list_add(struct list_head *item, struct list_head *head)
+{
+	__list_add(item, head, head->next);
+}
+
+/**
+ * list_add_tail - add a item entry
+ * @item: item entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a item entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static __inline__ void list_add_tail(struct list_head *item, struct list_head *head)
+{
+	__list_add(item, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static __inline__ void __list_del(struct list_head * prev,
+				  struct list_head * next)
+{
+	next->prev = prev;
+	prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty on entry does not return true after this, the entry is in an undefined state.
+ */
+static __inline__ void list_del(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static __inline__ void list_del_init(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+	INIT_LIST_HEAD(entry); 
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static __inline__ int list_empty(struct list_head *head)
+{
+	return head->next == head;
+}
+
+/**
+ * list_splice - join two lists
+ * @list: the item list to add.
+ * @head: the place to add it in the first list.
+ */
+static __inline__ void list_splice(struct list_head *list, struct list_head *head)
+{
+	struct list_head *first = list->next;
+
+	if (first != list) {
+		struct list_head *last = list->prev;
+		struct list_head *at = head->next;
+
+		first->prev = head;
+		head->next = first;
+
+		last->next = at;
+		at->prev = last;
+	}
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr:	the &struct list_head pointer.
+ * @type:	the type of the struct this is embedded in.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+	((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+
+/**
+ * list_for_each	-	iterate over a list
+ * @pos:	the &struct list_head to use as a loop counter.
+ * @head:	the head for your list.
+ */
+#define list_for_each(pos, head) \
+	for (pos = (head)->next; pos != (head); pos = pos->next)
+        	
+/**
+ * list_for_each_safe	-	iterate over a list safe against removal of list entry
+ * @pos:	the &struct list_head to use as a loop counter.
+ * @n:		another &struct list_head to use as temporary storage
+ * @head:	the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+	for (pos = (head)->next, n = pos->next; pos != (head); \
+		pos = n, n = pos->next)
+
+/**
+ * list_for_each_prev	-	iterate over a list in reverse order
+ * @pos:	the &struct list_head to use as a loop counter.
+ * @head:	the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+	for (pos = (head)->prev; pos != (head); pos = pos->prev)
+
+#endif /* _LIST_H */
diff --git a/hw/xen-backend.c b/hw/xen-backend.c
new file mode 100644
index 0000000..4819624
--- /dev/null
+++ b/hw/xen-backend.c
@@ -0,0 +1,663 @@
+/*
+ *  xen backend driver infrastructure
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; under version 2 of the License.
+ *
+ *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/signal.h>
+
+#include <xs.h>
+#include <xenctrl.h>
+#include <xen/grant_table.h>
+
+#include "hw.h"
+#include "qemu-char.h"
+#include "xen-backend.h"
+
+/* ------------------------------------------------------------- */
+
+/* public */
+int xen_xc;
+struct xs_handle *xenstore = NULL;
+
+/* private */
+static LIST_HEAD(xendevs);
+static const char *root = "/local/domain/0/backend";
+static int debug = 0;
+
+/* ------------------------------------------------------------- */
+
+int xenstore_write_str(const char *base, const char *node, const char *val)
+{
+    char abspath[BUFSIZE];
+
+    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
+    if (!xs_write(xenstore, 0, abspath, val, strlen(val)))
+	return -1;
+    return 0;
+}
+
+char *xenstore_read_str(const char *base, const char *node)
+{
+    char abspath[BUFSIZE];
+    unsigned int len;
+
+    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
+    return xs_read(xenstore, 0, abspath, &len);
+}
+
+int xenstore_write_int(const char *base, const char *node, int ival)
+{
+    char val[32];
+
+    snprintf(val, sizeof(val), "%d", ival);
+    return xenstore_write_str(base, node, val);
+}
+
+int xenstore_read_int(const char *base, const char *node, int *ival)
+{
+    char *val;
+    int rc = -1;
+
+    val = xenstore_read_str(base, node);
+    if (val && 1 == sscanf(val, "%d", ival))
+	rc = 0;
+    free(val);
+    return rc;
+}
+
+int xenstore_write_be_str(struct xendev *xendev, const char *node, const char *val)
+{
+    return xenstore_write_str(xendev->be, node, val);
+}
+
+int xenstore_write_be_int(struct xendev *xendev, const char *node, int ival)
+{
+    return xenstore_write_int(xendev->be, node, ival);
+}
+
+char *xenstore_read_be_str(struct xendev *xendev, const char *node)
+{
+    return xenstore_read_str(xendev->be, node);
+}
+
+int xenstore_read_be_int(struct xendev *xendev, const char *node, int *ival)
+{
+    return xenstore_read_int(xendev->be, node, ival);
+}
+
+char *xenstore_read_fe_str(struct xendev *xendev, const char *node)
+{
+    return xenstore_read_str(xendev->fe, node);
+}
+
+int xenstore_read_fe_int(struct xendev *xendev, const char *node, int *ival)
+{
+    return xenstore_read_int(xendev->fe, node, ival);
+}
+
+/* ------------------------------------------------------------- */
+
+const char *xenbus_strstate(enum xenbus_state state)
+{
+	static const char *const name[] = {
+		[ XenbusStateUnknown      ] = "Unknown",
+		[ XenbusStateInitialising ] = "Initialising",
+		[ XenbusStateInitWait     ] = "InitWait",
+		[ XenbusStateInitialised  ] = "Initialised",
+		[ XenbusStateConnected    ] = "Connected",
+		[ XenbusStateClosing      ] = "Closing",
+		[ XenbusStateClosed	  ] = "Closed",
+	};
+	return (state < ARRAY_SIZE(name)) ? name[state] : "INVALID";
+}
+
+int xen_be_set_state(struct xendev *xendev, enum xenbus_state state)
+{
+    int rc;
+
+    rc = xenstore_write_be_int(xendev, "state", state);
+    if (0 != rc)
+	return rc;
+    xen_be_printf(xendev, 1, "backend state: %s -> %s\n",
+		  xenbus_strstate(xendev->be_state), xenbus_strstate(state));
+    xendev->be_state = state;
+    return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+struct xendev *xen_be_find_xendev(char *type, int dom, int dev)
+{
+    struct xendev *xendev;
+    struct list_head *item;
+
+    list_for_each(item, &xendevs) {
+	xendev = list_entry(item, struct xendev, next);
+	if (xendev->dom != dom)
+	    continue;
+	if (xendev->dev != dev)
+	    continue;
+	if (0 != strcmp(xendev->type, type))
+	    continue;
+	return xendev;
+    }
+    return NULL;
+}
+
+/*
+ * get xen backend device, allocate a new one if it doesn't exist.
+ */
+static struct xendev *xen_be_get_xendev(char *type, int dom, int dev,
+					struct devops *ops)
+{
+    struct xendev *xendev;
+
+    xendev = xen_be_find_xendev(type, dom, dev);
+    if (xendev)
+	return xendev;
+
+    /* init new xendev */
+    xendev = malloc(ops->size);
+    memset(xendev,0,ops->size);
+    xendev->type  = type;
+    xendev->dom   = dom;
+    xendev->dev   = dev;
+    xendev->ops   = ops;
+    snprintf(xendev->be, sizeof(xendev->be), "%s/%s/%d/%d",
+	     root, xendev->type, xendev->dom, xendev->dev);
+    snprintf(xendev->name, sizeof(xendev->name), "%s-%d",
+	     xendev->type, xendev->dev);
+
+    xendev->debug      = debug;
+    xendev->local_port = -1;
+
+    xendev->evtchndev = xc_evtchn_open();
+    if (xendev->evtchndev < 0) {
+	fprintf(stderr, "can't open evtchn device\n");
+	free(xendev);
+	return NULL;
+    }
+    fcntl(xc_evtchn_fd(xendev->evtchndev), F_SETFD, FD_CLOEXEC);
+
+    if (ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
+	xendev->gnttabdev = xc_gnttab_open();
+	if (xendev->gnttabdev < 0) {
+	    fprintf(stderr, "can't open gnttab device\n");
+	    xc_evtchn_close(xendev->evtchndev);
+	    free(xendev);
+	    return NULL;
+	}
+    } else {
+	xendev->gnttabdev = -1;
+    }
+
+    list_add_tail(&xendev->next, &xendevs);
+
+    if (xendev->ops->alloc)
+	xendev->ops->alloc(xendev);
+
+    return xendev;
+}
+
+/*
+ * release xen backend device.
+ */
+static struct xendev *xen_be_del_xendev(int dom, int dev)
+{
+    struct xendev *xendev;
+    struct list_head *item, *tmp;
+
+    list_for_each_safe(item, tmp, &xendevs) {
+	xendev = list_entry(item, struct xendev, next);
+	if (xendev->dom != dom)
+	    continue;
+	if (xendev->dev != dev && dev != -1)
+	    continue;
+
+	if (xendev->ops->free)
+	    xendev->ops->free(xendev);
+
+	if (xendev->fe) {
+	    char token[BUFSIZE];
+	    snprintf(token, sizeof(token), "fe:%p", xendev);
+	    xs_unwatch(xenstore, xendev->fe, token);
+	    free(xendev->fe);
+	}
+
+	if (xendev->evtchndev >= 0)
+	    xc_evtchn_close(xendev->evtchndev);
+	if (xendev->gnttabdev >= 0)
+	    xc_gnttab_close(xendev->gnttabdev);
+
+	list_del(&xendev->next);
+	free(xendev);
+    }
+    return NULL;
+}
+
+/*
+ * Sync internal data structures on xenstore updates.
+ * Node specifies the changed field.  node = NULL means
+ * update all fields (used for initialization).
+ */
+static void xen_be_backend_changed(struct xendev *xendev, const char *node)
+{
+    if (NULL == node  ||  0 == strcmp(node, "online")) {
+	if (-1 == xenstore_read_be_int(xendev, "online", &xendev->online))
+	    xendev->online = 0;
+    }
+
+    if (node) {
+	xen_be_printf(xendev, 2, "backend update: %s\n", node);
+	if (xendev->ops->backend_changed)
+	    xendev->ops->backend_changed(xendev, node);
+    }
+}
+
+static void xen_be_frontend_changed(struct xendev *xendev, const char *node)
+{
+    int fe_state;
+
+    if (NULL == node  ||  0 == strcmp(node, "state")) {
+	if (-1 == xenstore_read_fe_int(xendev, "state", &fe_state))
+	    fe_state = XenbusStateUnknown;
+	if (xendev->fe_state != fe_state)
+	    xen_be_printf(xendev, 1, "frontend state: %s -> %s\n",
+			  xenbus_strstate(xendev->fe_state),
+			  xenbus_strstate(fe_state));
+	xendev->fe_state = fe_state;
+    }
+    if (NULL == node  ||  0 == strcmp(node, "protocol")) {
+	free(xendev->protocol);
+	xendev->protocol = xenstore_read_fe_str(xendev, "protocol");
+	if (xendev->protocol)
+	    xen_be_printf(xendev, 1, "frontend protocol: %s\n", xendev->protocol);
+    }
+
+    if (node) {
+	xen_be_printf(xendev, 2, "frontend update: %s\n", node);
+	if (xendev->ops->frontend_changed)
+	    xendev->ops->frontend_changed(xendev, node);
+    }
+}
+
+/* ------------------------------------------------------------- */
+/* Check for possible state transitions and perform them.        */
+
+/*
+ * Initial xendev setup.  Read frontend path, register watch for it.
+ * Should succeed once xend finished setting up the backend device.
+ *
+ * Also sets initial state (-> Initializing) when done.  Which
+ * only affects the xendev->be_state variable as xenbus should
+ * already be put into that state by xend.
+ */
+static int xen_be_try_setup(struct xendev *xendev)
+{
+    char token[BUFSIZE];
+    int be_state;
+
+    if (-1 == xenstore_read_be_int(xendev, "state", &be_state)) {
+	xen_be_printf(xendev, 0, "reading backend state failed\n");
+	return -1;
+    }
+
+    if (be_state != XenbusStateInitialising) {
+	xen_be_printf(xendev, 0, "initial backend state is wrong (%s)\n",
+		      xenbus_strstate(be_state));
+	return -1;
+    }
+
+    xendev->fe = xenstore_read_be_str(xendev, "frontend");
+    if (NULL == xendev->fe) {
+	xen_be_printf(xendev, 0, "reading frontend path failed\n");
+	return -1;
+    }
+
+    /* setup frontend watch */
+    snprintf(token, sizeof(token), "fe:%p", xendev);
+    if (!xs_watch(xenstore, xendev->fe, token)) {
+	xen_be_printf(xendev, 0, "watching frontend path (%s) failed\n",
+		      xendev->fe);
+	return -1;
+    }
+    xen_be_set_state(xendev, XenbusStateInitialising);
+
+    xen_be_backend_changed(xendev, NULL);
+    xen_be_frontend_changed(xendev, NULL);
+    return 0;
+}
+
+/*
+ * Try initialize xendev.  Prepare everything the backend can do
+ * without synchronizing with the frontend.  Fakes hotplug-status.  No
+ * hotplug involved here because this is about userspace drivers, thus
+ * there are kernel backend devices which could invoke hotplug.
+ *
+ * Goes to InitWait on success.
+ */
+static int xen_be_try_init(struct xendev *xendev)
+{
+    int rc = 0;
+
+    if (!xendev->online) {
+	xen_be_printf(xendev, 1, "not online\n");
+	return -1;
+    }
+
+    if (xendev->ops->init)
+	rc = xendev->ops->init(xendev);
+    if (0 != rc) {
+	xen_be_printf(xendev, 1, "init() failed\n");
+	return rc;
+    }
+
+    xenstore_write_be_str(xendev, "hotplug-status", "connected");
+    xen_be_set_state(xendev, XenbusStateInitWait);
+    return 0;
+}
+
+/*
+ * Try to connect xendev.  Depends on the frontend being ready
+ * for it (shared ring and evtchn info in xenstore, state being
+ * Initialised or Connected).
+ *
+ * Goes to Connected on success.
+ */
+static int xen_be_try_connect(struct xendev *xendev)
+{
+    int rc = 0;
+
+    if (xendev->fe_state != XenbusStateInitialised  &&
+	xendev->fe_state != XenbusStateConnected) {
+	if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) {
+	    xen_be_printf(xendev, 2, "frontend not ready, ignoring\n");
+	} else {
+	    xen_be_printf(xendev, 2, "frontend not ready (yet)\n");
+	    return -1;
+	}
+    }
+
+    if (xendev->ops->connect)
+	rc = xendev->ops->connect(xendev);
+    if (0 != rc) {
+	xen_be_printf(xendev, 0, "connect() failed\n");
+	return rc;
+    }
+
+    xen_be_set_state(xendev, XenbusStateConnected);
+
+#if 0
+    if (xendev->ops->event)
+	xendev->ops->event(xendev);
+#endif
+    return 0;
+}
+
+/*
+ * Teardown connection.
+ *
+ * Goes to Closed when done.
+ */
+static void xen_be_disconnect(struct xendev *xendev)
+{
+    if (xendev->be_state == XenbusStateClosed)
+	return;
+    if (xendev->ops->disconnect)
+	xendev->ops->disconnect(xendev);
+    xen_be_set_state(xendev, XenbusStateClosed);
+}
+
+/*
+ * state change dispatcher function
+ */
+void xen_be_check_state(struct xendev *xendev)
+{
+    int rc = 0;
+
+    /* frontend may request shutdown from almost anywhere */
+    if (xendev->fe_state == XenbusStateClosing ||
+	xendev->fe_state == XenbusStateClosed) {
+	xen_be_disconnect(xendev);
+	return;
+    }
+
+    /* check for possible backend state transitions */
+    for (;;) {
+	switch (xendev->be_state) {
+	case XenbusStateUnknown:
+	    rc = xen_be_try_setup(xendev);
+	    break;
+	case XenbusStateInitialising:
+	    rc = xen_be_try_init(xendev);
+	    break;
+	case XenbusStateInitWait:
+	    rc = xen_be_try_connect(xendev);
+	    break;
+	default:
+	    rc = -1;
+	}
+	if (0 != rc)
+	    break;
+    }
+}
+
+/* ------------------------------------------------------------- */
+
+static int xenstore_scan(char *type, int dom, struct devops *ops)
+{
+    struct xendev *xendev;
+    char path[BUFSIZE], token[BUFSIZE];
+    char **dev = NULL;
+    unsigned int cdev, j;
+
+    /* setup watch */
+    snprintf(token, sizeof(token), "be:%p:%d:%p", type, dom, ops);
+    snprintf(path, sizeof(path), "%s/%s/%d", root, type, dom);
+    if (!xs_watch(xenstore, path, token)) {
+	fprintf(stderr, "xen be: watching backend path (%s) failed\n", path);
+	return -1;
+    }
+
+    /* look for backends */
+    dev = xs_directory(xenstore, 0, path, &cdev);
+    if (!dev)
+	return 0;
+    for (j = 0; j < cdev; j++) {
+	xendev = xen_be_get_xendev(type, dom, atoi(dev[j]), ops);
+	if (NULL == xendev)
+	    continue;
+	xen_be_check_state(xendev);
+    }
+    free(dev);
+    return 0;
+}
+
+static void xenstore_update_be(char *watch, char *type, int dom,
+			       struct devops *ops)
+{
+    struct xendev *xendev;
+    char path[BUFSIZE];
+    unsigned int len, dev;
+
+    len = snprintf(path, sizeof(path), "%s/%s/%d", root, type, dom);
+    if (0 != strncmp(path, watch, len))
+	return;
+    if (2 != sscanf(watch+len, "/%u/%255s", &dev, path)) {
+	strcpy(path, "");
+	if (1 != sscanf(watch+len, "/%u", &dev))
+	    dev = -1;
+    }
+    if (-1 == dev)
+	return;
+
+    if (0) {
+	/* FIXME: detect devices being deleted from xenstore ... */
+	xen_be_del_xendev(dom, dev);
+    }
+
+    xendev = xen_be_get_xendev(type, dom, dev, ops);
+    if (NULL != xendev) {
+	xen_be_backend_changed(xendev, path);
+	xen_be_check_state(xendev);
+    }
+}
+
+static void xenstore_update_fe(char *watch, struct xendev *xendev)
+{
+    char *node;
+    unsigned int len;
+
+    len = strlen(xendev->fe);
+    if (0 != strncmp(xendev->fe, watch, len))
+	return;
+    if (watch[len] != '/')
+	return;
+    node = watch + len + 1;
+
+    xen_be_frontend_changed(xendev, node);
+    xen_be_check_state(xendev);
+}
+
+static void xenstore_update(void *unused)
+{
+    char **vec = NULL;
+    intptr_t type, ops, ptr;
+    unsigned int dom, count;
+
+    vec = xs_read_watch(xenstore, &count);
+    if (NULL == vec)
+	goto cleanup;
+
+    if (3 == sscanf(vec[XS_WATCH_TOKEN], "be:%" PRIxPTR ":%d:%" PRIxPTR,
+		    &type, &dom, &ops))
+	xenstore_update_be(vec[XS_WATCH_PATH], (void*)type, dom, (void*)ops);
+    if (1 == sscanf(vec[XS_WATCH_TOKEN], "fe:%" PRIxPTR, &ptr))
+	xenstore_update_fe(vec[XS_WATCH_PATH], (void*)ptr);
+
+cleanup:
+    free(vec);
+}
+
+static void xen_be_evtchn_event(void *opaque)
+{
+    struct xendev *xendev = opaque;
+    evtchn_port_t port;
+
+    port = xc_evtchn_pending(xendev->evtchndev);
+    if (port != xendev->local_port) {
+	xen_be_printf(xendev, 0, "xc_evtchn_pending returned %d (expected %d)\n",
+		      port, xendev->local_port);
+	return;
+    }
+    xc_evtchn_unmask(xendev->evtchndev, port);
+
+    if (xendev->ops->event)
+	xendev->ops->event(xendev);
+}
+
+/* -------------------------------------------------------------------- */
+
+int xen_be_init(void)
+{
+    xenstore = xs_daemon_open();
+    if (!xenstore) {
+	fprintf(stderr, "can't connect to xenstored\n");
+	return -1;
+    }
+
+    if (qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update, NULL, NULL) < 0)
+	goto err;
+
+    xen_xc = xc_interface_open();
+    if (-1 == xen_xc) {
+	fprintf(stderr, "can't open xen interface\n");
+	goto err;
+    }
+    return 0;
+
+err:
+    qemu_set_fd_handler(xs_fileno(xenstore), NULL, NULL, NULL);
+    xs_daemon_close(xenstore);
+    xenstore = NULL;
+    
+    return -1;
+}
+
+int xen_be_register(char *type, struct devops *ops)
+{
+    return xenstore_scan(type, xen_domid, ops);
+}
+
+int xen_be_bind_evtchn(struct xendev *xendev)
+{
+    if (xendev->local_port != -1)
+	return 0;
+    xendev->local_port = xc_evtchn_bind_interdomain
+	(xendev->evtchndev, xendev->dom, xendev->remote_port);
+    if (-1 == xendev->local_port) {
+	xendev->local_port = 0;
+	return -1;
+    }
+    qemu_set_fd_handler(xc_evtchn_fd(xendev->evtchndev),
+			xen_be_evtchn_event, NULL, xendev);
+#if 0
+    xc_evtchn_unmask(xendev->evtchndev, xendev->local_port);
+#endif
+    return 0;
+}
+
+void xen_be_unbind_evtchn(struct xendev *xendev)
+{
+    if (xendev->local_port == -1)
+	return;
+    qemu_set_fd_handler(xc_evtchn_fd(xendev->evtchndev), NULL, NULL, NULL);
+    xc_evtchn_unbind(xendev->evtchndev, xendev->local_port);
+    xendev->local_port = -1;
+}
+
+int xen_be_send_notify(struct xendev *xendev)
+{
+    return xc_evtchn_notify(xendev->evtchndev, xendev->local_port);
+}
+
+/*
+ * msg_level:
+ *  0 == errors.
+ *  1 == informative debug messages.
+ *  2 == noisy debug messages.
+ *  3 == will flood your log.
+ */
+void xen_be_printf(struct xendev *xendev, int msg_level, const char *fmt, ...)
+{
+    va_list args;
+
+    if (msg_level > xendev->debug)
+	return;
+    fprintf(stderr, "xen be: %s: ", xendev->name);
+    va_start(args, fmt);
+    vfprintf(stderr, fmt, args);
+    va_end(args);
+}
diff --git a/hw/xen-backend.h b/hw/xen-backend.h
new file mode 100644
index 0000000..db36ae7
--- /dev/null
+++ b/hw/xen-backend.h
@@ -0,0 +1,116 @@
+#include <stddef.h>
+#include <xs.h>
+#include <xenctrl.h>
+#include <xen/elfnote.h>
+#include <xen/elfstructs.h>
+
+#include <xen/io/xenbus.h>
+
+#include "list.h"
+
+#include "hw.h"
+#include "xen.h"
+
+/*
+ * tweaks needed to build with different xen versions
+ *  0x00030205 -> 3.1.0
+ *  0x00030207 -> 3.2.0
+ *  0x00030208 -> unstable
+ */
+#include <xen/xen-compat.h>
+#if __XEN_LATEST_INTERFACE_VERSION__ < 0x00030207
+# define xc_map_foreign_pages xc_map_foreign_batch
+#endif
+#if __XEN_LATEST_INTERFACE_VERSION__ < 0x00030208
+# define xen_mb()  mb()
+# define xen_rmb() rmb()
+# define xen_wmb() wmb()
+#endif
+
+/* ------------------------------------------------------------- */
+
+#define container_of(ptr, type, member) ({                      \
+        const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
+        (type *)( (char *)__mptr - offsetof(type,member) );})
+
+/* ------------------------------------------------------------- */
+
+#define BUFSIZE 1024
+
+struct xendev;
+
+/* driver uses grant tables  ->  open gntdev device (xendev->gnttabdev) */
+#define DEVOPS_FLAG_NEED_GNTDEV   1
+/* don't expect frontend doing correct state transitions (aka console quirk) */
+#define DEVOPS_FLAG_IGNORE_STATE  2  
+
+struct devops {
+    size_t    size;
+    uint32_t  flags;
+    void      (*alloc)(struct xendev *xendev);
+    int       (*init)(struct xendev *xendev);
+    int       (*connect)(struct xendev *xendev);
+    void      (*event)(struct xendev *xendev);
+    void      (*disconnect)(struct xendev *xendev);
+    int       (*free)(struct xendev *xendev);
+    void      (*backend_changed)(struct xendev *xendev, const char *node);
+    void      (*frontend_changed)(struct xendev *xendev, const char *node);
+};
+
+struct xendev {
+    char               *type;
+    int                dom;
+    int                dev;
+    char               name[64];
+    int                debug;
+
+    enum xenbus_state  be_state;
+    enum xenbus_state  fe_state;
+    int                online;
+    char               be[BUFSIZE];
+    char               *fe;
+    char               *protocol;
+    int                remote_port;
+    int                local_port;
+
+    int                evtchndev;
+    int                gnttabdev;
+
+    struct devops      *ops;
+    struct list_head   next;
+};
+
+/* ------------------------------------------------------------- */
+
+/* variables */
+extern int xen_domid; /* set by cmd line option, in vl.c */
+extern int xen_xc;
+extern struct xs_handle *xenstore;
+
+/* xenstore helper functions */
+int xenstore_write_str(const char *base, const char *node, const char *val);
+int xenstore_write_int(const char *base, const char *node, int ival);
+char *xenstore_read_str(const char *base, const char *node);
+int xenstore_read_int(const char *base, const char *node, int *ival);
+
+int xenstore_write_be_str(struct xendev *xendev, const char *node, const char *val);
+int xenstore_write_be_int(struct xendev *xendev, const char *node, int ival);
+char *xenstore_read_be_str(struct xendev *xendev, const char *node);
+int xenstore_read_be_int(struct xendev *xendev, const char *node, int *ival);
+char *xenstore_read_fe_str(struct xendev *xendev, const char *node);
+int xenstore_read_fe_int(struct xendev *xendev, const char *node, int *ival);
+
+const char *xenbus_strstate(enum xenbus_state state);
+struct xendev *xen_be_find_xendev(char *type, int dom, int dev);
+void xen_be_check_state(struct xendev *xendev);
+
+/* xen backend driver bits */
+int xen_be_init(void);
+int xen_be_register(char *type, struct devops *ops);
+int xen_be_set_state(struct xendev *xendev, enum xenbus_state state);
+int xen_be_bind_evtchn(struct xendev *xendev);
+void xen_be_unbind_evtchn(struct xendev *xendev);
+int xen_be_send_notify(struct xendev *xendev);
+void xen_be_printf(struct xendev *xendev, int msg_level, const char *fmt, ...)
+    __attribute__ ((format(printf, 3, 4)));
+
diff --git a/hw/xen-machine.c b/hw/xen-machine.c
index 88f0f6e..798c0a7 100644
--- a/hw/xen-machine.c
+++ b/hw/xen-machine.c
@@ -25,7 +25,7 @@
 #include "hw.h"
 #include "boards.h"
 
-#include "xen.h"
+#include "xen-backend.h"
 
 /* -------------------------------------------------------------------- */
 /* variables                                                            */
@@ -54,6 +54,9 @@ static void xenpv_init(ram_addr_t ram_size, int vga_ram_size,
     }
     env = cpu_init(cpu_model);
     env->halted = 1;
+
+    /* setup xen backend handlers */
+    xen_be_init();
 }
 
 QEMUMachine xenpv_machine = {
-- 
1.5.4.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [Qemu-devel] [PATCH 3/7] xen: add console backend driver.
  2008-07-28 13:17 [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu Gerd Hoffmann
  2008-07-28 13:17 ` [Qemu-devel] [PATCH 1/7] xen: groundwork for xen support Gerd Hoffmann
  2008-07-28 13:17 ` [Qemu-devel] [PATCH 2/7] xen: backend driver core Gerd Hoffmann
@ 2008-07-28 13:17 ` Gerd Hoffmann
  2008-07-28 14:17   ` Anthony Liguori
  2008-07-28 13:17 ` [Qemu-devel] [PATCH 4/7] xen: add framebuffer " Gerd Hoffmann
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 64+ messages in thread
From: Gerd Hoffmann @ 2008-07-28 13:17 UTC (permalink / raw)
  To: qemu-devel, xen-devel; +Cc: Gerd Hoffmann

This patch adds a xenconsole backend driver.  It it based on current
xen-unstable code.  It has been changed to make use of the common
backend driver code.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 Makefile.target  |    1 +
 hw/xen-backend.h |    3 +
 hw/xen-console.c |  271 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/xen-machine.c |    2 +
 4 files changed, 277 insertions(+), 0 deletions(-)
 create mode 100644 hw/xen-console.c

diff --git a/Makefile.target b/Makefile.target
index 0451048..05619fa 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -517,6 +517,7 @@ endif
 
 # xen backend driver support
 XEN_OBJS := xen-machine.o xen-backend.o
+XEN_OBJS += xen-console.o
 ifeq ($(CONFIG_XEN), yes)
   OBJS += $(XEN_OBJS)
   LIBS += $(XEN_LIBS)
diff --git a/hw/xen-backend.h b/hw/xen-backend.h
index db36ae7..55ffd31 100644
--- a/hw/xen-backend.h
+++ b/hw/xen-backend.h
@@ -114,3 +114,6 @@ int xen_be_send_notify(struct xendev *xendev);
 void xen_be_printf(struct xendev *xendev, int msg_level, const char *fmt, ...)
     __attribute__ ((format(printf, 3, 4)));
 
+/* actual backend drivers */
+struct devops xen_console_ops;      /* xen_console.c     */
+
diff --git a/hw/xen-console.c b/hw/xen-console.c
new file mode 100644
index 0000000..9c67f1b
--- /dev/null
+++ b/hw/xen-console.c
@@ -0,0 +1,271 @@
+/*
+ *  Copyright (C) International Business Machines  Corp., 2005
+ *  Author(s): Anthony Liguori <aliguori@us.ibm.com>
+ *
+ *  Copyright (C) Red Hat 2007
+ *
+ *  Xen Console
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; under version 2 of the License.
+ *
+ *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <malloc.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/select.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <termios.h>
+#include <stdarg.h>
+#include <sys/mman.h>
+#include <xs.h>
+#include <xen/io/console.h>
+#include <xenctrl.h>
+
+#include "hw.h"
+#include "sysemu.h"
+#include "qemu-char.h"
+#include "xen-backend.h"
+
+#define dolog(val, fmt, ...) fprintf(stderr, fmt "\n", ## __VA_ARGS__)
+
+struct buffer {
+    uint8_t *data;
+    size_t consumed;
+    size_t size;
+    size_t capacity;
+    size_t max_capacity;
+};
+
+struct xen_console {
+    struct xendev     xendev;  /* must be first */
+    struct buffer     buffer;
+    char              console[BUFSIZE];
+    int               ring_ref;
+    void              *sring;
+    CharDriverState   *chr;
+    int               backlog;
+};
+
+static void buffer_append(struct xen_console *con)
+{
+    struct buffer *buffer = &con->buffer;
+    XENCONS_RING_IDX cons, prod, size;
+    struct xencons_interface *intf = con->sring;
+
+    cons = intf->out_cons;
+    prod = intf->out_prod;
+    xen_mb();
+
+    size = prod - cons;
+    if ((size == 0) || (size > sizeof(intf->out)))
+	return;
+
+    if ((buffer->capacity - buffer->size) < size) {
+	buffer->capacity += (size + 1024);
+	buffer->data = realloc(buffer->data, buffer->capacity);
+	if (buffer->data == NULL) {
+	    dolog(LOG_ERR, "Memory allocation failed");
+	    exit(ENOMEM);
+	}
+    }
+
+    while (cons != prod)
+	buffer->data[buffer->size++] = intf->out[
+	    MASK_XENCONS_IDX(cons++, intf->out)];
+
+    xen_mb();
+    intf->out_cons = cons;
+    xen_be_send_notify(&con->xendev);
+
+    if (buffer->max_capacity &&
+	buffer->size > buffer->max_capacity) {
+	/* Discard the middle of the data. */
+
+	size_t over = buffer->size - buffer->max_capacity;
+	uint8_t *maxpos = buffer->data + buffer->max_capacity;
+
+	memmove(maxpos - over, maxpos, over);
+	buffer->data = realloc(buffer->data, buffer->max_capacity);
+	buffer->size = buffer->capacity = buffer->max_capacity;
+
+	if (buffer->consumed > buffer->max_capacity - over)
+	    buffer->consumed = buffer->max_capacity - over;
+    }
+}
+
+static void buffer_advance(struct buffer *buffer, size_t len)
+{
+    buffer->consumed += len;
+    if (buffer->consumed == buffer->size) {
+	buffer->consumed = 0;
+	buffer->size = 0;
+    }
+}
+
+static int ring_free_bytes(struct xen_console *con)
+{
+    struct xencons_interface *intf = con->sring;
+    XENCONS_RING_IDX cons, prod, space;
+
+    cons = intf->in_cons;
+    prod = intf->in_prod;
+    xen_mb();
+
+    space = prod - cons;
+    if (space > sizeof(intf->in))
+	return 0; /* ring is screwed: ignore it */
+
+    return (sizeof(intf->in) - space);
+}
+
+static int xencons_can_receive(void *opaque)
+{
+    struct xen_console *con = opaque;
+    return ring_free_bytes(con);
+}
+
+static void xencons_receive(void *opaque, const uint8_t *buf, int len)
+{
+    struct xen_console *con = opaque;
+    struct xencons_interface *intf = con->sring;
+    XENCONS_RING_IDX prod;
+    int i, max;
+
+    max = ring_free_bytes(con);
+    /* The can_receive() func limits this, but check again anyway */
+    if (max < len)
+	len = max;
+
+    prod = intf->in_prod;
+    for (i = 0; i < len; i++) {
+	intf->in[MASK_XENCONS_IDX(prod++, intf->in)] =
+	    buf[i];
+    }
+    xen_wmb();
+    intf->in_prod = prod;
+    xen_be_send_notify(&con->xendev);
+}
+
+static void xencons_send(struct xen_console *con)
+{
+    ssize_t len, size;
+
+    size = con->buffer.size - con->buffer.consumed;
+    len = qemu_chr_write(con->chr, con->buffer.data + con->buffer.consumed,
+			 size);
+    if (len < 1) {
+	if (!con->backlog) {
+	    con->backlog = 1;
+	    xen_be_printf(&con->xendev, 1, "backlog piling up, nobody listening?\n");
+	}
+    } else {
+	buffer_advance(&con->buffer, len);
+	if (con->backlog && len == size) {
+	    con->backlog = 0;
+	    xen_be_printf(&con->xendev, 1, "backlog is gone\n");
+	}
+    }
+}
+
+/* -------------------------------------------------------------------- */
+
+static int con_init(struct xendev *xendev)
+{
+    struct xen_console *con = container_of(xendev, struct xen_console, xendev);
+    char *type;
+
+    if (!serial_hds[con->xendev.dev]) {
+	xen_be_printf(xendev, 1, "serial line %d not configured\n", con->xendev.dev);
+	return -1;
+    }
+
+    /* setup */
+    snprintf(con->console, sizeof(con->console),
+	     "/local/domain/%d/console", con->xendev.dom);
+    con->chr = serial_hds[con->xendev.dev];
+
+    type = xenstore_read_str(con->console, "type");
+    if (!type || 0 != strcmp(type, "ioemu")) {
+	xen_be_printf(xendev, 1, "not for me (type=%s)\n", type);
+	return -1;
+    }
+
+    return 0;
+}
+
+static int con_connect(struct xendev *xendev)
+{
+    struct xen_console *con = container_of(xendev, struct xen_console, xendev);
+    int limit;
+
+    if (-1 == xenstore_read_int(con->console, "ring-ref", &con->ring_ref))
+	return -1;
+    if (-1 == xenstore_read_int(con->console, "port", &con->xendev.remote_port))
+	return -1;
+    if (0 == xenstore_read_int(con->console, "limit", &limit))
+	con->buffer.max_capacity = limit;
+
+    con->sring = xc_map_foreign_range(xen_xc, con->xendev.dom,
+				      XC_PAGE_SIZE,
+				      PROT_READ|PROT_WRITE,
+				      con->ring_ref);
+    if (!con->sring)
+	return -1;
+
+    xen_be_bind_evtchn(&con->xendev);
+    qemu_chr_add_handlers(con->chr, xencons_can_receive, xencons_receive,
+			  NULL, con);
+
+    xen_be_printf(xendev, 1, "ring mfn %d, remote port %d, local port %d, limit %zd\n",
+		  con->ring_ref,
+		  con->xendev.remote_port,
+		  con->xendev.local_port,
+		  con->buffer.max_capacity);
+    return 0;
+}
+
+static void con_disconnect(struct xendev *xendev)
+{
+    struct xen_console *con = container_of(xendev, struct xen_console, xendev);
+
+    qemu_chr_add_handlers(con->chr, NULL, NULL, NULL, NULL);
+    xen_be_unbind_evtchn(&con->xendev);
+
+    if (con->sring) {
+	munmap(con->sring, XC_PAGE_SIZE);
+	con->sring = NULL;
+    }
+}
+
+static void con_event(struct xendev *xendev)
+{
+    struct xen_console *con = container_of(xendev, struct xen_console, xendev);
+
+    buffer_append(con);
+    if (con->buffer.size - con->buffer.consumed)
+	xencons_send(con);
+}
+
+/* -------------------------------------------------------------------- */
+
+struct devops xen_console_ops = {
+    .size       = sizeof(struct xen_console),
+    .flags      = DEVOPS_FLAG_IGNORE_STATE,
+    .init       = con_init,
+    .connect    = con_connect,
+    .event      = con_event,
+    .disconnect = con_disconnect,
+};
diff --git a/hw/xen-machine.c b/hw/xen-machine.c
index 798c0a7..da10982 100644
--- a/hw/xen-machine.c
+++ b/hw/xen-machine.c
@@ -57,6 +57,8 @@ static void xenpv_init(ram_addr_t ram_size, int vga_ram_size,
 
     /* setup xen backend handlers */
     xen_be_init();
+
+    xen_be_register("console", &xen_console_ops);
 }
 
 QEMUMachine xenpv_machine = {
-- 
1.5.4.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [Qemu-devel] [PATCH 4/7] xen: add framebuffer backend driver
  2008-07-28 13:17 [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu Gerd Hoffmann
                   ` (2 preceding siblings ...)
  2008-07-28 13:17 ` [Qemu-devel] [PATCH 3/7] xen: add console backend driver Gerd Hoffmann
@ 2008-07-28 13:17 ` Gerd Hoffmann
  2008-07-28 14:22   ` Anthony Liguori
  2008-07-28 13:17 ` [Qemu-devel] [PATCH 5/7] xen: add block device " Gerd Hoffmann
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 64+ messages in thread
From: Gerd Hoffmann @ 2008-07-28 13:17 UTC (permalink / raw)
  To: qemu-devel, xen-devel; +Cc: Gerd Hoffmann

This patch adds a frsamebuffer (and kbd+mouse) backend driver.  It
it based on current xen-unstable code.  It has been changed to make
use of the common backend driver code.  It also has been changed to
compile with xen headers older than unstable (aka son-to-be 3.3).

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 Makefile.target      |    2 +-
 hw/xen-backend.h     |    4 +
 hw/xen-framebuffer.c |  925 ++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/xen-machine.c     |    5 +
 4 files changed, 935 insertions(+), 1 deletions(-)
 create mode 100644 hw/xen-framebuffer.c

diff --git a/Makefile.target b/Makefile.target
index 05619fa..66d41ee 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -517,7 +517,7 @@ endif
 
 # xen backend driver support
 XEN_OBJS := xen-machine.o xen-backend.o
-XEN_OBJS += xen-console.o
+XEN_OBJS += xen-console.o xen-framebuffer.o
 ifeq ($(CONFIG_XEN), yes)
   OBJS += $(XEN_OBJS)
   LIBS += $(XEN_LIBS)
diff --git a/hw/xen-backend.h b/hw/xen-backend.h
index 55ffd31..3facf90 100644
--- a/hw/xen-backend.h
+++ b/hw/xen-backend.h
@@ -116,4 +116,8 @@ void xen_be_printf(struct xendev *xendev, int msg_level, const char *fmt, ...)
 
 /* actual backend drivers */
 struct devops xen_console_ops;      /* xen_console.c     */
+struct devops xen_kbdmouse_ops;     /* xen_framebuffer.c */
+struct devops xen_framebuffer_ops;  /* xen_framebuffer.c */
+
+void xen_set_display(int domid, DisplayState *ds);
 
diff --git a/hw/xen-framebuffer.c b/hw/xen-framebuffer.c
new file mode 100644
index 0000000..716eafd
--- /dev/null
+++ b/hw/xen-framebuffer.c
@@ -0,0 +1,925 @@
+/*
+ *  xen paravirt framebuffer backend
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; under version 2 of the License.
+ *
+ *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include <xs.h>
+#include <xenctrl.h>
+#include <xen/event_channel.h>
+#include <xen/io/xenbus.h>
+#include <xen/io/fbif.h>
+#include <xen/io/kbdif.h>
+#include <xen/io/protocols.h>
+
+#include "hw.h"
+#include "sysemu.h"
+#include "console.h"
+#include "qemu-char.h"
+#include "xen-backend.h"
+
+#ifndef BTN_LEFT
+#define BTN_LEFT 0x110 /* from <linux/input.h> */
+#endif
+
+/* -------------------------------------------------------------------- */
+
+struct xen_common {
+    struct xendev     xendev;  /* must be first */
+    void              *page;
+    DisplayState      *ds;
+};
+
+struct xen_input {
+    struct xen_common c;
+    int abs_pointer_wanted; /* Whether guest supports absolute pointer */
+    int button_state;       /* Last seen pointer button state */
+    int extended;
+    QEMUPutMouseEntry *qmouse;
+};
+
+#define UP_QUEUE 8
+
+struct xen_fb {
+    struct xen_common c;
+    size_t            fb_len;
+    int               row_stride;
+    int               depth;
+    int               width;
+    int               height;
+    int               offset;
+    void              *pixels;
+    int               feature_update;
+    int               refresh_period;
+    int               bug_trigger;
+
+    struct {
+	int x,y,w,h;
+    } up_rects[UP_QUEUE];
+    int               up_count;
+    int               up_fullscreen;
+};
+
+/* -------------------------------------------------------------------- */
+
+static int common_bind(struct xen_common *c)
+{
+    int mfn;
+
+    if (-1 == xenstore_read_fe_int(&c->xendev, "page-ref", &mfn))
+	return -1;
+    if (-1 == xenstore_read_fe_int(&c->xendev, "event-channel", &c->xendev.remote_port))
+	return -1;
+
+    xen_be_bind_evtchn(&c->xendev);
+    xen_be_printf(&c->xendev, 1, "ring mfn %d, remote-port %d, local-port %d\n",
+		  mfn, c->xendev.remote_port, c->xendev.local_port);
+
+    c->page = xc_map_foreign_range(xen_xc, c->xendev.dom,
+				   XC_PAGE_SIZE,
+				   PROT_READ | PROT_WRITE, mfn);
+    if (NULL == c->page)
+	return -1;
+    return 0;
+}
+
+static void common_unbind(struct xen_common *c)
+{
+    if (c->page) {
+	munmap(c->page, XC_PAGE_SIZE);
+	c->page = NULL;
+    }
+    xen_be_unbind_evtchn(&c->xendev);
+}
+
+/* -------------------------------------------------------------------- */
+
+/*
+ * Tables to map from scancode to Linux input layer keycode.
+ * Scancodes are hardware-specific.  These maps assumes a
+ * standard AT or PS/2 keyboard which is what QEMU feeds us.
+ */
+const unsigned char atkbd_set2_keycode[512] = {
+
+     0, 67, 65, 63, 61, 59, 60, 88,  0, 68, 66, 64, 62, 15, 41,117,
+     0, 56, 42, 93, 29, 16,  2,  0,  0,  0, 44, 31, 30, 17,  3,  0,
+     0, 46, 45, 32, 18,  5,  4, 95,  0, 57, 47, 33, 20, 19,  6,183,
+     0, 49, 48, 35, 34, 21,  7,184,  0,  0, 50, 36, 22,  8,  9,185,
+     0, 51, 37, 23, 24, 11, 10,  0,  0, 52, 53, 38, 39, 25, 12,  0,
+     0, 89, 40,  0, 26, 13,  0,  0, 58, 54, 28, 27,  0, 43,  0, 85,
+     0, 86, 91, 90, 92,  0, 14, 94,  0, 79,124, 75, 71,121,  0,  0,
+    82, 83, 80, 76, 77, 72,  1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
+
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    217,100,255,  0, 97,165,  0,  0,156,  0,  0,  0,  0,  0,  0,125,
+    173,114,  0,113,  0,  0,  0,126,128,  0,  0,140,  0,  0,  0,127,
+    159,  0,115,  0,164,  0,  0,116,158,  0,150,166,  0,  0,  0,142,
+    157,  0,  0,  0,  0,  0,  0,  0,155,  0, 98,  0,  0,163,  0,  0,
+    226,  0,  0,  0,  0,  0,  0,  0,  0,255, 96,  0,  0,  0,143,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,107,  0,105,102,  0,  0,112,
+    110,111,108,112,106,103,  0,119,  0,118,109,  0, 99,104,119,  0,
+
+};
+
+const unsigned char atkbd_unxlate_table[128] = {
+
+      0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
+     21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
+     35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
+     50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88,  5,  6,  4, 12,  3,
+     11,  2, 10,  1,  9,119,126,108,117,125,123,107,115,116,121,105,
+    114,122,112,113,127, 96, 97,120,  7, 15, 23, 31, 39, 47, 55, 63,
+     71, 79, 86, 94,  8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
+     19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
+
+};
+
+static unsigned char scancode2linux[512];
+
+/* Send an event to the keyboard frontend driver */
+static int xenfb_kbd_event(struct xen_input *xenfb,
+			   union xenkbd_in_event *event)
+{
+    struct xenkbd_page *page = xenfb->c.page;
+    uint32_t prod;
+
+    if (xenfb->c.xendev.be_state != XenbusStateConnected)
+	return 0;
+
+    prod = page->in_prod;
+    if (prod - page->in_cons == XENKBD_IN_RING_LEN) {
+	errno = EAGAIN;
+	return -1;
+    }
+
+    xen_mb();		/* ensure ring space available */
+    XENKBD_IN_RING_REF(page, prod) = *event;
+    xen_wmb();		/* ensure ring contents visible */
+    page->in_prod = prod + 1;
+    return xen_be_send_notify(&xenfb->c.xendev);
+}
+
+/* Send a keyboard (or mouse button) event */
+static int xenfb_send_key(struct xen_input *xenfb, bool down, int keycode)
+{
+    union xenkbd_in_event event;
+
+    memset(&event, 0, XENKBD_IN_EVENT_SIZE);
+    event.type = XENKBD_TYPE_KEY;
+    event.key.pressed = down ? 1 : 0;
+    event.key.keycode = keycode;
+
+    return xenfb_kbd_event(xenfb, &event);
+}
+
+/* Send a relative mouse movement event */
+static int xenfb_send_motion(struct xen_input *xenfb,
+			     int rel_x, int rel_y, int rel_z)
+{
+    union xenkbd_in_event event;
+
+    memset(&event, 0, XENKBD_IN_EVENT_SIZE);
+    event.type = XENKBD_TYPE_MOTION;
+    event.motion.rel_x = rel_x;
+    event.motion.rel_y = rel_y;
+#if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030207
+    event.motion.rel_z = rel_z;
+#endif
+
+    return xenfb_kbd_event(xenfb, &event);
+}
+
+/* Send an absolute mouse movement event */
+static int xenfb_send_position(struct xen_input *xenfb,
+			       int abs_x, int abs_y, int rel_z)
+{
+    union xenkbd_in_event event;
+
+    memset(&event, 0, XENKBD_IN_EVENT_SIZE);
+    event.type = XENKBD_TYPE_POS;
+    event.pos.abs_x = abs_x;
+    event.pos.abs_y = abs_y;
+#if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030207
+    event.pos.rel_z = rel_z;
+#endif
+
+    return xenfb_kbd_event(xenfb, &event);
+}
+
+/*
+ * Send a key event from the client to the guest OS
+ * QEMU gives us a raw scancode from an AT / PS/2 style keyboard.
+ * We have to turn this into a Linux Input layer keycode.
+ *
+ * Extra complexity from the fact that with extended scancodes
+ * (like those produced by arrow keys) this method gets called
+ * twice, but we only want to send a single event. So we have to
+ * track the '0xe0' scancode state & collapse the extended keys
+ * as needed.
+ *
+ * Wish we could just send scancodes straight to the guest which
+ * already has code for dealing with this...
+ */
+static void xenfb_key_event(void *opaque, int scancode)
+{
+    struct xen_input *xenfb = opaque;
+    int down = 1;
+
+    if (scancode == 0xe0) {
+	xenfb->extended = 1;
+	return;
+    } else if (scancode & 0x80) {
+	scancode &= 0x7f;
+	down = 0;
+    }
+    if (xenfb->extended) {
+	scancode |= 0x80;
+	xenfb->extended = 0;
+    }
+    xenfb_send_key(xenfb, down, scancode2linux[scancode]);
+}
+
+/*
+ * Send a mouse event from the client to the guest OS
+ *
+ * The QEMU mouse can be in either relative, or absolute mode.
+ * Movement is sent separately from button state, which has to
+ * be encoded as virtual key events. We also don't actually get
+ * given any button up/down events, so have to track changes in
+ * the button state.
+ */
+static void xenfb_mouse_event(void *opaque,
+			      int dx, int dy, int dz, int button_state)
+{
+    struct xen_input *xenfb = opaque;
+    int i;
+
+    if (xenfb->abs_pointer_wanted)
+	xenfb_send_position(xenfb,
+			    dx * (xenfb->c.ds->width - 1) / 0x7fff,
+			    dy * (xenfb->c.ds->height - 1) / 0x7fff,
+			    dz);
+    else
+	xenfb_send_motion(xenfb, dx, dy, dz);
+
+    for (i = 0 ; i < 8 ; i++) {
+	int lastDown = xenfb->button_state & (1 << i);
+	int down = button_state & (1 << i);
+	if (down == lastDown)
+	    continue;
+
+	if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0)
+	    return;
+    }
+    xenfb->button_state = button_state;
+}
+
+static int input_init(struct xendev *xendev)
+{
+    struct xen_input *in = container_of(xendev, struct xen_input, c.xendev);
+    static int first = 1;
+    int i;
+
+    if (first) {
+	/* Prepare scancode mapping table */
+	for (i = 0; i < 128; i++) {
+	    scancode2linux[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
+	    scancode2linux[i | 0x80] =
+		atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
+	}
+	first = 0;
+    }
+
+    if (!in->c.ds) {
+        /* xen_set_display() below will set that and trigger us again */
+        xen_be_printf(xendev, 1, "ds not set (yet)\n");
+	return -1;
+    }
+
+    xenstore_write_be_int(xendev, "feature-abs-pointer", 1);
+    return 0;
+}
+
+static int input_connect(struct xendev *xendev)
+{
+    struct xen_input *in = container_of(xendev, struct xen_input, c.xendev);
+    int rc;
+
+    if (-1 == xenstore_read_fe_int(xendev, "request-abs-pointer", &in->abs_pointer_wanted))
+	in->abs_pointer_wanted = 0;
+
+    rc = common_bind(&in->c);
+    if (0 != rc)
+	return rc;
+
+    qemu_add_kbd_event_handler(xenfb_key_event, in);
+    in->qmouse = qemu_add_mouse_event_handler(xenfb_mouse_event, in,
+					      in->abs_pointer_wanted,
+					      "Xen PVFB Mouse");
+    return 0;
+}
+
+static void input_disconnect(struct xendev *xendev)
+{
+    struct xen_input *in = container_of(xendev, struct xen_input, c.xendev);
+
+    if (in->qmouse) {
+	qemu_remove_mouse_event_handler(in->qmouse);
+	in->qmouse = NULL;
+    }
+    qemu_add_kbd_event_handler(NULL, NULL);
+    common_unbind(&in->c);
+}
+
+static void input_event(struct xendev *xendev)
+{
+    struct xen_input *xenfb = container_of(xendev, struct xen_input, c.xendev);
+    struct xenkbd_page *page = xenfb->c.page;
+
+    /* We don't understand any keyboard events, so just ignore them. */
+    if (page->out_prod == page->out_cons)
+	return;
+    page->out_cons = page->out_prod;
+    xen_be_send_notify(&xenfb->c.xendev);
+}
+
+/* -------------------------------------------------------------------- */
+
+static void xenfb_copy_mfns(int mode, int count, unsigned long *dst, void *src)
+{
+    uint32_t *src32 = src;
+    uint64_t *src64 = src;
+    int i;
+
+    for (i = 0; i < count; i++)
+	dst[i] = (mode == 32) ? src32[i] : src64[i];
+}
+
+static int xenfb_map_fb(struct xen_fb *xenfb)
+{
+    struct xenfb_page *page = xenfb->c.page;
+    char *protocol = xenfb->c.xendev.protocol;
+    int n_fbmfns;
+    int n_fbdirs;
+    unsigned long *pgmfns = NULL;
+    unsigned long *fbmfns = NULL;
+    void *map, *pd;
+    int mode, ret = -1;
+
+    /* default to native */
+    pd = page->pd;
+    mode = sizeof(unsigned long) * 8;
+
+    if (!protocol) {
+	/*
+	 * Undefined protocol, some guesswork needed.
+	 *
+	 * Old frontends which don't set the protocol use
+	 * one page directory only, thus pd[1] must be zero.
+	 * pd[1] of the 32bit struct layout and the lower
+	 * 32 bits of pd[0] of the 64bit struct layout have
+	 * the same location, so we can check that ...
+	 */
+	uint32_t *ptr32 = NULL;
+	uint32_t *ptr64 = NULL;
+#if defined(__i386__)
+	ptr32 = (void*)page->pd;
+	ptr64 = ((void*)page->pd) + 4;
+#elif defined(__x86_64__)
+	ptr32 = ((void*)page->pd) - 4;
+	ptr64 = (void*)page->pd;
+#endif
+	if (ptr32) {
+	    if (0 == ptr32[1]) {
+		mode = 32;
+		pd   = ptr32;
+	    } else {
+		mode = 64;
+		pd   = ptr64;
+	    }
+	}
+#if defined(__x86_64__)
+    } else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_32)) {
+	/* 64bit dom0, 32bit domU */
+	mode = 32;
+	pd   = ((void*)page->pd) - 4;
+#elif defined(__i386__)
+    } else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_64)) {
+	/* 32bit dom0, 64bit domU */
+	mode = 64;
+	pd   = ((void*)page->pd) + 4;
+#endif
+    }
+
+    n_fbmfns = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
+    n_fbdirs = n_fbmfns * mode / 8;
+    n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
+
+    pgmfns = malloc(sizeof(unsigned long) * n_fbdirs);
+    fbmfns = malloc(sizeof(unsigned long) * n_fbmfns);
+    if (!pgmfns || !fbmfns)
+	goto out;
+
+    xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd);
+    map = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
+			       PROT_READ, pgmfns, n_fbdirs);
+    if (map == NULL)
+	goto out;
+    xenfb_copy_mfns(mode, n_fbmfns, fbmfns, map);
+    munmap(map, n_fbdirs * XC_PAGE_SIZE);
+
+    xenfb->pixels = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
+					 PROT_READ | PROT_WRITE, fbmfns, n_fbmfns);
+    if (xenfb->pixels == NULL)
+	goto out;
+
+    ret = 0; /* all is fine */
+
+out:
+    if (pgmfns)
+	free(pgmfns);
+    if (fbmfns)
+	free(fbmfns);
+    return ret;
+}
+
+static int xenfb_configure_fb(struct xen_fb *xenfb, size_t fb_len_lim,
+			      int width, int height, int depth,
+			      size_t fb_len, int offset, int row_stride)
+{
+    size_t mfn_sz = sizeof(*((struct xenfb_page *)0)->pd);
+    size_t pd_len = sizeof(((struct xenfb_page *)0)->pd) / mfn_sz;
+    size_t fb_pages = pd_len * XC_PAGE_SIZE / mfn_sz;
+    size_t fb_len_max = fb_pages * XC_PAGE_SIZE;
+    int max_width, max_height;
+
+    if (fb_len_lim > fb_len_max) {
+	xen_be_printf(&xenfb->c.xendev, 0, "fb size limit %zu exceeds %zu, corrected\n",
+		      fb_len_lim, fb_len_max);
+	fb_len_lim = fb_len_max;
+    }
+    if (fb_len_lim && fb_len > fb_len_lim) {
+	xen_be_printf(&xenfb->c.xendev, 0, "frontend fb size %zu limited to %zu\n",
+		      fb_len, fb_len_lim);
+	fb_len = fb_len_lim;
+    }
+    if (depth != 8 && depth != 16 && depth != 24 && depth != 32) {
+	xen_be_printf(&xenfb->c.xendev, 0, "can't handle frontend fb depth %d\n",
+		      depth);
+	return -1;
+    }
+    if (row_stride < 0 || row_stride > fb_len) {
+	xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend stride %d\n", row_stride);
+	return -1;
+    }
+    max_width = row_stride / (depth / 8);
+    if (width < 0 || width > max_width) {
+	xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend width %d limited to %d\n",
+		      width, max_width);
+	width = max_width;
+    }
+    if (offset < 0 || offset >= fb_len) {
+	xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend offset %d (max %zu)\n",
+		      offset, fb_len - 1);
+	return -1;
+    }
+    max_height = (fb_len - offset) / row_stride;
+    if (height < 0 || height > max_height) {
+	xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend height %d limited to %d\n",
+		      height, max_height);
+	height = max_height;
+    }
+    xenfb->fb_len = fb_len;
+    xenfb->row_stride = row_stride;
+    xenfb->depth = depth;
+    xenfb->width = width;
+    xenfb->height = height;
+    xenfb->offset = offset;
+    xen_be_printf(&xenfb->c.xendev, 1, "framebuffer %dx%dx%d offset %d stride %d\n",
+		  width, height, depth, offset, row_stride);
+    return 0;
+}
+
+/* A convenient function for munging pixels between different depths */
+#define BLT(SRC_T,DST_T,RSB,GSB,BSB,RDB,GDB,BDB)                        \
+    for (line = y ; line < (y+h) ; line++) {				\
+	SRC_T *src = (SRC_T *)(xenfb->pixels				\
+			       + xenfb->offset				\
+			       + (line * xenfb->row_stride)		\
+			       + (x * xenfb->depth / 8));		\
+	DST_T *dst = (DST_T *)(xenfb->c.ds->data				\
+			       + (line * xenfb->c.ds->linesize)		\
+			       + (x * xenfb->c.ds->depth / 8));		\
+	int col;							\
+	const int RSS = 32 - (RSB + GSB + BSB);				\
+	const int GSS = 32 - (GSB + BSB);				\
+	const int BSS = 32 - (BSB);					\
+	const uint32_t RSM = (~0U) << (32 - RSB);			\
+	const uint32_t GSM = (~0U) << (32 - GSB);			\
+	const uint32_t BSM = (~0U) << (32 - BSB);			\
+	const int RDS = 32 - (RDB + GDB + BDB);				\
+	const int GDS = 32 - (GDB + BDB);				\
+	const int BDS = 32 - (BDB);					\
+	const uint32_t RDM = (~0U) << (32 - RDB);			\
+	const uint32_t GDM = (~0U) << (32 - GDB);			\
+	const uint32_t BDM = (~0U) << (32 - BDB);			\
+	for (col = x ; col < (x+w) ; col++) {				\
+	    uint32_t spix = *src;					\
+	    *dst = (((spix << RSS) & RSM & RDM) >> RDS) |		\
+		(((spix << GSS) & GSM & GDM) >> GDS) |			\
+		(((spix << BSS) & BSM & BDM) >> BDS);			\
+	    src = (SRC_T *) ((unsigned long) src + xenfb->depth / 8);	\
+	    dst = (DST_T *) ((unsigned long) dst + xenfb->c.ds->depth / 8); \
+	}								\
+    }
+
+
+/* This copies data from the guest framebuffer region, into QEMU's copy
+ * NB. QEMU's copy is stored in the pixel format of a) the local X
+ * server (SDL case) or b) the current VNC client pixel format.
+ * When shifting between colour depths we preserve the MSB.
+ */
+static void xenfb_guest_copy(struct xen_fb *xenfb, int x, int y, int w, int h)
+{
+    int line;
+
+    if (1 /* !xenfb->c.ds->shared_buf */) {
+	if (xenfb->depth == xenfb->c.ds->depth) { /* Perfect match can use fast path */
+	    for (line = y ; line < (y+h) ; line++) {
+		memcpy(xenfb->c.ds->data + (line * xenfb->c.ds->linesize) + (x * xenfb->c.ds->depth / 8),
+		       xenfb->pixels + xenfb->offset + (line * xenfb->row_stride) + (x * xenfb->depth / 8),
+		       w * xenfb->depth / 8);
+	    }
+	} else { /* Mismatch requires slow pixel munging */
+	    /* 8 bit == r:3 g:3 b:2 */
+	    /* 16 bit == r:5 g:6 b:5 */
+	    /* 24 bit == r:8 g:8 b:8 */
+	    /* 32 bit == r:8 g:8 b:8 (padding:8) */
+	    if (xenfb->depth == 8) {
+		if (xenfb->c.ds->depth == 16) {
+		    BLT(uint8_t, uint16_t,   3, 3, 2,   5, 6, 5);
+		} else if (xenfb->c.ds->depth == 32) {
+		    BLT(uint8_t, uint32_t,   3, 3, 2,   8, 8, 8);
+		}
+	    } else if (xenfb->depth == 16) {
+		if (xenfb->c.ds->depth == 8) {
+		    BLT(uint16_t, uint8_t,   5, 6, 5,   3, 3, 2);
+		} else if (xenfb->c.ds->depth == 32) {
+		    BLT(uint16_t, uint32_t,  5, 6, 5,   8, 8, 8);
+		}
+	    } else if (xenfb->depth == 24 || xenfb->depth == 32) {
+		if (xenfb->c.ds->depth == 8) {
+		    BLT(uint32_t, uint8_t,   8, 8, 8,   3, 3, 2);
+		} else if (xenfb->c.ds->depth == 16) {
+		    BLT(uint32_t, uint16_t,  8, 8, 8,   5, 6, 5);
+		} else if (xenfb->c.ds->depth == 32) {
+		    BLT(uint32_t, uint32_t,  8, 8, 8,   8, 8, 8);
+		}
+	    }
+	}
+    }
+    dpy_update(xenfb->c.ds, x, y, w, h);
+}
+
+#ifdef XENFB_TYPE_REFRESH_PERIOD
+static int xenfb_queue_full(struct xen_fb *xenfb)
+{
+    struct xenfb_page *page = xenfb->c.page;
+    uint32_t cons, prod;
+
+    prod = page->in_prod;
+    cons = page->in_cons;
+    return prod - cons == XENFB_IN_RING_LEN;
+}
+
+static void xenfb_send_event(struct xen_fb *xenfb, union xenfb_in_event *event)
+{
+    uint32_t prod;
+    struct xenfb_page *page = xenfb->c.page;
+
+    prod = page->in_prod;
+    /* caller ensures !xenfb_queue_full() */
+    xen_mb();                   /* ensure ring space available */
+    XENFB_IN_RING_REF(page, prod) = *event;
+    xen_wmb();                  /* ensure ring contents visible */
+    page->in_prod = prod + 1;
+
+    xen_be_send_notify(&xenfb->c.xendev);
+}
+
+static void xenfb_send_refresh_period(struct xen_fb *xenfb, int period)
+{
+    union xenfb_in_event event;
+
+    memset(&event, 0, sizeof(event));
+    event.type = XENFB_TYPE_REFRESH_PERIOD;
+    event.refresh_period.period = period;
+    xenfb_send_event(xenfb, &event);
+}
+#endif
+
+/*
+ * Periodic update of display.
+ * Also transmit the refresh interval to the frontend.
+ * 
+ * Never ever do any qemu display operations
+ * (resize, screen update) outside this function.
+ * Our screen might be inactive.  When asked for
+ * an update we know it is active.
+ */
+static void xenfb_update(void *opaque)
+{
+    struct xen_fb *xenfb = opaque;
+    int i;
+
+    if (xenfb->feature_update) {
+#ifdef XENFB_TYPE_REFRESH_PERIOD
+	int period;
+
+	if (xenfb_queue_full(xenfb))
+	    return;
+
+        /*
+         * TODO: xen's qemu-dm seems to have some patches to
+         *       make the qemu display code avoid unneeded
+         *       work.
+         *        - Port them over.
+         *        - Put ds->idle back into use then.
+         *        - Same goes for ds->shared_buf btw.
+         */
+	if (0 /* xenfb->c.ds->idle */)
+	    period =  XENFB_NO_REFRESH;
+	else {
+	    period = xenfb->c.ds->gui_timer_interval;
+	    if (!period)
+		period = 30; // GUI_REFRESH_INTERVAL (see vl.c)
+	}
+
+	if (xenfb->refresh_period != period) {
+	    dprintf("%s: %d\n", __FUNCTION__, period);
+	    xenfb_send_refresh_period(xenfb, period);
+	    xenfb->refresh_period = period;
+	}
+#else
+	; /* nothing */
+#endif
+    } else {
+	/* we don't get update notifications, thus use the
+	 * sledge hammer approach ... */
+	xenfb->up_fullscreen = 1;
+    }
+
+    /* resize if needed */
+    if (xenfb->width != xenfb->c.ds->width || xenfb->height != xenfb->c.ds->height) {
+	xen_be_printf(&xenfb->c.xendev, 1, "update: resizing\n");
+	dpy_resize(xenfb->c.ds, xenfb->width, xenfb->height);
+	xenfb->up_fullscreen = 1;
+    }
+
+    /* run queued updates */
+    if (xenfb->up_fullscreen) {
+	xen_be_printf(&xenfb->c.xendev, 3, "update: fullscreen\n");
+	xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height);
+    } else if (xenfb->up_count) {
+	xen_be_printf(&xenfb->c.xendev, 3, "update: %d rects\n", xenfb->up_count);
+	for (i = 0; i < xenfb->up_count; i++)
+	    xenfb_guest_copy(xenfb,
+			     xenfb->up_rects[i].x,
+			     xenfb->up_rects[i].y,
+			     xenfb->up_rects[i].w,
+			     xenfb->up_rects[i].h);
+    } else {
+	xen_be_printf(&xenfb->c.xendev, 3, "update: nothing\n");
+    }
+    xenfb->up_count = 0;
+    xenfb->up_fullscreen = 0;
+}
+
+static void xenfb_handle_events(struct xen_fb *xenfb)
+{
+    uint32_t prod, cons;
+    struct xenfb_page *page = xenfb->c.page;
+
+    prod = page->out_prod;
+    if (prod == page->out_cons)
+	return;
+    xen_rmb();		/* ensure we see ring contents up to prod */
+    for (cons = page->out_cons; cons != prod; cons++) {
+	union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons);
+	int x, y, w, h;
+
+	switch (event->type) {
+	case XENFB_TYPE_UPDATE:
+	    if (xenfb->up_count == UP_QUEUE)
+		xenfb->up_fullscreen = 1;
+	    if (xenfb->up_fullscreen)
+		break;
+	    x = MAX(event->update.x, 0);
+	    y = MAX(event->update.y, 0);
+	    w = MIN(event->update.width, xenfb->width - x);
+	    h = MIN(event->update.height, xenfb->height - y);
+	    if (w < 0 || h < 0) {
+		fprintf(stderr, "xen be: %s: bogus update ignored\n",
+			xenfb->c.xendev.name);
+		break;
+	    }
+	    if (x != event->update.x || y != event->update.y
+		|| w != event->update.width
+		|| h != event->update.height) {
+		fprintf(stderr, "xen be: %s: bogus update clipped\n",
+			xenfb->c.xendev.name);
+	    }
+	    if (w == xenfb->width && h > xenfb->height / 2) {
+		/* scroll detector: updated more than 50% of the lines,
+		 * don't bother keeping track of the rectangles then */
+		xenfb->up_fullscreen = 1;
+	    } else {
+		xenfb->up_rects[xenfb->up_count].x = x;
+		xenfb->up_rects[xenfb->up_count].y = y;
+		xenfb->up_rects[xenfb->up_count].w = w;
+		xenfb->up_rects[xenfb->up_count].h = h;
+		xenfb->up_count++;
+	    }
+	    break;
+#ifdef XENFB_TYPE_RESIZE
+	case XENFB_TYPE_RESIZE:
+	    if (xenfb_configure_fb(xenfb, xenfb->fb_len,
+				   event->resize.width,
+				   event->resize.height,
+				   event->resize.depth,
+				   xenfb->fb_len,
+				   event->resize.offset,
+				   event->resize.stride) < 0)
+		break;
+	    xenfb_invalidate(xenfb);
+	    break;
+#endif
+	}
+    }
+    xen_mb();		/* ensure we're done with ring contents */
+    page->out_cons = cons;
+}
+
+/* QEMU display state changed, so refresh the framebuffer copy */
+static void xenfb_invalidate(void *opaque)
+{
+    struct xen_fb *xenfb = opaque;
+    xenfb->up_fullscreen = 1;
+}
+
+static int fb_init(struct xendev *xendev)
+{
+    struct xen_fb *fb = container_of(xendev, struct xen_fb, c.xendev);
+
+    if (!fb->c.ds) {
+        /* xen_set_display() below will set that and trigger us again */
+	xen_be_printf(xendev, 1, "ds not set (yet)\n");
+	return -1;
+    }
+
+    fb->refresh_period = -1;
+
+#ifdef XENFB_TYPE_RESIZE
+    xenstore_write_be_int(xendev, "feature-resize", 1);
+#endif
+    return 0;
+}
+
+static int fb_connect(struct xendev *xendev)
+{
+    struct xen_fb *fb = container_of(xendev, struct xen_fb, c.xendev);
+    struct xenfb_page *fb_page;
+    int videoram;
+    int rc;
+
+    if (-1 == xenstore_read_fe_int(xendev, "feature-update", &fb->feature_update))
+	fb->feature_update = 0;
+    if (fb->feature_update)
+	xenstore_write_be_int(xendev, "request-update", 1);
+
+    if (-1 == xenstore_read_fe_int(xendev, "videoram", &videoram))
+	videoram = 0;
+
+    rc = common_bind(&fb->c);
+    if (0 != rc)
+	return rc;
+
+    fb_page = fb->c.page;
+    rc = xenfb_configure_fb(fb, videoram * 1024 * 1024U,
+			    fb_page->width, fb_page->height, fb_page->depth,
+			    fb_page->mem_length, 0, fb_page->line_length);
+    if (0 != rc)
+	return rc;
+
+    rc = xenfb_map_fb(fb);
+    if (0 != rc)
+	return rc;
+
+    graphic_console_init(fb->c.ds,
+			 xenfb_update,
+			 xenfb_invalidate,
+			 NULL,
+			 NULL,
+			 fb);
+
+    xen_be_printf(xendev, 1, "feature-update=%d, videoram=%d\n",
+		  fb->feature_update, videoram);
+
+    return 0;
+}
+
+static void fb_disconnect(struct xendev *xendev)
+{
+    struct xen_fb *fb = container_of(xendev, struct xen_fb, c.xendev);
+
+    /* FIXME: Hmm, un-init gfx display? can qemu handle that? */
+    common_unbind(&fb->c);
+}
+
+static void fb_frontend_changed(struct xendev *xendev, const char *node)
+{
+    struct xen_fb *fb = container_of(xendev, struct xen_fb, c.xendev);
+
+    /*
+     * Set state to Connected *again* once the frontend switched
+     * to connected.  We must trigger the watch a second time to
+     * workaround a frontend bug.
+     */
+    if (0 == fb->bug_trigger && 0 == strcmp(node, "state") &&
+	xendev->fe_state == XenbusStateConnected &&
+	xendev->be_state == XenbusStateConnected) {
+	xen_be_set_state(xendev, XenbusStateConnected);
+	fb->bug_trigger = 1; /* only once */
+    }
+}
+
+static void fb_event(struct xendev *xendev)
+{
+    struct xen_fb *xenfb = container_of(xendev, struct xen_fb, c.xendev);
+
+    xenfb_handle_events(xenfb);
+    xen_be_send_notify(&xenfb->c.xendev);
+}
+
+/* -------------------------------------------------------------------- */
+
+struct devops xen_kbdmouse_ops = {
+    .size       = sizeof(struct xen_input),
+    .init       = input_init,
+    .connect    = input_connect,
+    .disconnect = input_disconnect,
+    .event      = input_event,
+};
+
+struct devops xen_framebuffer_ops = {
+    .size       = sizeof(struct xen_fb),
+    .init       = fb_init,
+    .connect    = fb_connect,
+    .disconnect = fb_disconnect,
+    .event      = fb_event,
+    .frontend_changed = fb_frontend_changed,
+};
+
+static void xen_set_display_type(int domid, char *type, DisplayState *ds)
+{
+    struct xendev *xendev;
+    struct xen_common *c;
+
+    xendev = xen_be_find_xendev(type, domid, 0);
+    if (!xendev)
+	return;
+    c = container_of(xendev, struct xen_common, xendev);
+    c->ds = ds;
+    xen_be_printf(xendev, 1, "ds is %p\n", ds);
+    /* retry ->init() */
+    xen_be_check_state(xendev);
+}
+
+void xen_set_display(int domid, DisplayState *ds)
+{
+    xen_set_display_type(domid, "vkbd", ds);
+    xen_set_display_type(domid, "vfb", ds);
+}
diff --git a/hw/xen-machine.c b/hw/xen-machine.c
index da10982..c03cb53 100644
--- a/hw/xen-machine.c
+++ b/hw/xen-machine.c
@@ -59,6 +59,11 @@ static void xenpv_init(ram_addr_t ram_size, int vga_ram_size,
     xen_be_init();
 
     xen_be_register("console", &xen_console_ops);
+    xen_be_register("vkbd", &xen_kbdmouse_ops);
+    xen_be_register("vfb", &xen_framebuffer_ops);
+
+    /* setup framebuffer */
+    xen_set_display(xen_domid, ds);
 }
 
 QEMUMachine xenpv_machine = {
-- 
1.5.4.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [Qemu-devel] [PATCH 5/7] xen: add block device backend driver.
  2008-07-28 13:17 [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu Gerd Hoffmann
                   ` (3 preceding siblings ...)
  2008-07-28 13:17 ` [Qemu-devel] [PATCH 4/7] xen: add framebuffer " Gerd Hoffmann
@ 2008-07-28 13:17 ` Gerd Hoffmann
  2008-07-28 14:25   ` Anthony Liguori
  2008-07-28 13:17 ` [Qemu-devel] [PATCH 6/7] xen: add net " Gerd Hoffmann
  2008-07-28 13:17 ` [Qemu-devel] [PATCH 7/7] xen: blk & nic configuration via cmd line Gerd Hoffmann
  6 siblings, 1 reply; 64+ messages in thread
From: Gerd Hoffmann @ 2008-07-28 13:17 UTC (permalink / raw)
  To: qemu-devel, xen-devel; +Cc: Gerd Hoffmann

This patch adds a block device backend driver to qemu.  It is a pure
userspace implemention using the gntdev interface.  It uses "qdisk" as
backend name in xenstore so it doesn't interfere with the other existing
backends (blkback aka "vbd" and tapdisk aka "tap").

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 Makefile.target  |    2 +-
 hw/xen-backend.h |    2 +
 hw/xen-blkif.h   |  103 ++++++++
 hw/xen-disk.c    |  681 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/xen-machine.c |    1 +
 sysemu.h         |    2 +-
 vl.c             |    4 +
 7 files changed, 793 insertions(+), 2 deletions(-)
 create mode 100644 hw/xen-blkif.h
 create mode 100644 hw/xen-disk.c

diff --git a/Makefile.target b/Makefile.target
index 66d41ee..2d599d2 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -517,7 +517,7 @@ endif
 
 # xen backend driver support
 XEN_OBJS := xen-machine.o xen-backend.o
-XEN_OBJS += xen-console.o xen-framebuffer.o
+XEN_OBJS += xen-console.o xen-framebuffer.o xen-disk.o
 ifeq ($(CONFIG_XEN), yes)
   OBJS += $(XEN_OBJS)
   LIBS += $(XEN_LIBS)
diff --git a/hw/xen-backend.h b/hw/xen-backend.h
index 3facf90..941b0a6 100644
--- a/hw/xen-backend.h
+++ b/hw/xen-backend.h
@@ -10,6 +10,7 @@
 
 #include "hw.h"
 #include "xen.h"
+#include "sysemu.h"
 
 /*
  * tweaks needed to build with different xen versions
@@ -118,6 +119,7 @@ void xen_be_printf(struct xendev *xendev, int msg_level, const char *fmt, ...)
 struct devops xen_console_ops;      /* xen_console.c     */
 struct devops xen_kbdmouse_ops;     /* xen_framebuffer.c */
 struct devops xen_framebuffer_ops;  /* xen_framebuffer.c */
+struct devops xen_blkdev_ops;       /* xen_disk.c        */
 
 void xen_set_display(int domid, DisplayState *ds);
 
diff --git a/hw/xen-blkif.h b/hw/xen-blkif.h
new file mode 100644
index 0000000..254a5fd
--- /dev/null
+++ b/hw/xen-blkif.h
@@ -0,0 +1,103 @@
+#ifndef __XEN_BLKIF_H__
+#define __XEN_BLKIF_H__
+
+#include <xen/io/ring.h>
+#include <xen/io/blkif.h>
+#include <xen/io/protocols.h>
+
+/* Not a real protocol.  Used to generate ring structs which contain
+ * the elements common to all protocols only.  This way we get a
+ * compiler-checkable way to use common struct elements, so we can
+ * avoid using switch(protocol) in a number of places.  */
+struct blkif_common_request {
+	char dummy;
+};
+struct blkif_common_response {
+	char dummy;
+};
+
+/* i386 protocol version */
+#pragma pack(push, 4)
+struct blkif_x86_32_request {
+	uint8_t        operation;    /* BLKIF_OP_???                         */
+	uint8_t        nr_segments;  /* number of segments                   */
+	blkif_vdev_t   handle;       /* only for read/write requests         */
+	uint64_t       id;           /* private guest value, echoed in resp  */
+	blkif_sector_t sector_number;/* start sector idx on disk (r/w only)  */
+	struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+};
+struct blkif_x86_32_response {
+	uint64_t        id;              /* copied from request */
+	uint8_t         operation;       /* copied from request */
+	int16_t         status;          /* BLKIF_RSP_???       */
+};
+typedef struct blkif_x86_32_request blkif_x86_32_request_t;
+typedef struct blkif_x86_32_response blkif_x86_32_response_t;
+#pragma pack(pop)
+
+/* x86_64 protocol version */
+struct blkif_x86_64_request {
+	uint8_t        operation;    /* BLKIF_OP_???                         */
+	uint8_t        nr_segments;  /* number of segments                   */
+	blkif_vdev_t   handle;       /* only for read/write requests         */
+	uint64_t       __attribute__((__aligned__(8))) id;
+	blkif_sector_t sector_number;/* start sector idx on disk (r/w only)  */
+	struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+};
+struct blkif_x86_64_response {
+	uint64_t       __attribute__((__aligned__(8))) id;
+	uint8_t         operation;       /* copied from request */
+	int16_t         status;          /* BLKIF_RSP_???       */
+};
+typedef struct blkif_x86_64_request blkif_x86_64_request_t;
+typedef struct blkif_x86_64_response blkif_x86_64_response_t;
+
+DEFINE_RING_TYPES(blkif_common, struct blkif_common_request, struct blkif_common_response);
+DEFINE_RING_TYPES(blkif_x86_32, struct blkif_x86_32_request, struct blkif_x86_32_response);
+DEFINE_RING_TYPES(blkif_x86_64, struct blkif_x86_64_request, struct blkif_x86_64_response);
+
+union blkif_back_rings {
+	blkif_back_ring_t        native;
+	blkif_common_back_ring_t common;
+	blkif_x86_32_back_ring_t x86_32;
+	blkif_x86_64_back_ring_t x86_64;
+};
+typedef union blkif_back_rings blkif_back_rings_t;
+
+enum blkif_protocol {
+	BLKIF_PROTOCOL_NATIVE = 1,
+	BLKIF_PROTOCOL_X86_32 = 2,
+	BLKIF_PROTOCOL_X86_64 = 3,
+};
+
+static void inline blkif_get_x86_32_req(blkif_request_t *dst, blkif_x86_32_request_t *src)
+{
+	int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST;
+
+	dst->operation = src->operation;
+	dst->nr_segments = src->nr_segments;
+	dst->handle = src->handle;
+	dst->id = src->id;
+	dst->sector_number = src->sector_number;
+	if (n > src->nr_segments)
+		n = src->nr_segments;
+	for (i = 0; i < n; i++)
+		dst->seg[i] = src->seg[i];
+}
+
+static void inline blkif_get_x86_64_req(blkif_request_t *dst, blkif_x86_64_request_t *src)
+{
+	int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST;
+
+	dst->operation = src->operation;
+	dst->nr_segments = src->nr_segments;
+	dst->handle = src->handle;
+	dst->id = src->id;
+	dst->sector_number = src->sector_number;
+	if (n > src->nr_segments)
+		n = src->nr_segments;
+	for (i = 0; i < n; i++)
+		dst->seg[i] = src->seg[i];
+}
+
+#endif /* __XEN_BLKIF_H__ */
diff --git a/hw/xen-disk.c b/hw/xen-disk.c
new file mode 100644
index 0000000..6947363
--- /dev/null
+++ b/hw/xen-disk.c
@@ -0,0 +1,681 @@
+/*
+ *  xen paravirt block device backend
+ *
+ *  FIXME: the code is designed to handle multiple outstanding
+ *  requests (using aio or using threads), which isn't used right
+ *  now due to limitations of the qemu block driver interface.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; under version 2 of the License.
+ *
+ *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <inttypes.h>
+#include <time.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <pthread.h>
+#include <sys/utsname.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/uio.h>
+
+#include <xs.h>
+#include <xenctrl.h>
+#include <xen/io/xenbus.h>
+
+#include "list.h"
+
+#include "hw.h"
+#include "block_int.h"
+#include "qemu-char.h"
+#include "xen-blkif.h"
+#include "xen-backend.h"
+
+/* ------------------------------------------------------------- */
+
+#define BLOCK_SIZE  512
+#define IOCB_COUNT  (BLKIF_MAX_SEGMENTS_PER_REQUEST + 2)
+
+struct ioreq {
+    blkif_request_t     req;
+    int16_t             status;
+
+    /* parsed request */
+    off_t               start, end;
+    struct iovec        vec[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+    int                 vecs;
+    int                 presync;
+    int                 postsync;
+
+    /* grant mapping */
+    uint32_t            domids[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+    uint32_t            refs[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+    int                 prot;
+    void                *page[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+    void                *pages;
+
+    struct blkdev       *blkdev;
+    struct list_head    list;
+};
+
+struct blkdev {
+    struct xendev       xendev;  /* must be first */
+    char                *params;
+    char                *mode;
+    char                *type;
+    char                *dev;
+    char                *fileproto;
+    char                *filename;
+    int                 ring_ref;
+    void                *sring;
+    int                 file;
+    int64_t             file_blk;
+    int64_t             file_size;
+    int                 protocol;
+    blkif_back_rings_t  rings;
+    int                 more_work;
+    int                 cnt_map;
+
+    /* request lists */
+    struct list_head    inflight;
+    struct list_head    finished;
+    struct list_head    freelist;
+    int                 requests;
+
+    /* qemu block driver */
+    BlockDriverState    *bs;
+};
+
+static int syncwrite    = 0;
+static int batch_maps   = 0;
+static int max_requests = 32;
+
+/* ------------------------------------------------------------- */
+
+static struct ioreq *ioreq_start(struct blkdev *blkdev)
+{
+    struct ioreq *ioreq = NULL;
+
+    if (list_empty(&blkdev->freelist)) {
+	if (blkdev->requests >= max_requests)
+	    goto out;
+	/* allocate new struct */
+	ioreq = malloc(sizeof(*ioreq));
+	if (NULL == ioreq)
+	    goto out;
+	memset(ioreq, 0, sizeof(*ioreq));
+	ioreq->blkdev = blkdev;
+	blkdev->requests++;
+    } else {
+	/* get one from freelist */
+	ioreq = list_entry(blkdev->freelist.next, struct ioreq, list);
+	list_del(&ioreq->list);
+    }
+    list_add_tail(&ioreq->list, &blkdev->inflight);
+
+out:
+    return ioreq;
+}
+
+static void ioreq_finish(struct ioreq *ioreq)
+{
+    struct blkdev *blkdev = ioreq->blkdev;
+
+    list_del(&ioreq->list);
+    list_add_tail(&ioreq->list, &blkdev->finished);
+}
+
+static void ioreq_release(struct ioreq *ioreq)
+{
+    struct blkdev *blkdev = ioreq->blkdev;
+
+    list_del(&ioreq->list);
+    memset(ioreq, 0, sizeof(*ioreq));
+    ioreq->blkdev = blkdev;
+    list_add_tail(&ioreq->list, &blkdev->freelist);
+}
+
+/*
+ * translate request into iovec + start offset + end offset
+ * do sanity checks along the way
+ */
+static int ioreq_parse(struct ioreq *ioreq)
+{
+    struct blkdev *blkdev = ioreq->blkdev;
+    uintptr_t mem;
+    size_t len;
+    int i;
+
+    xen_be_printf(&blkdev->xendev, 3,
+		  "op %d, nr %d, handle %d, id %" PRId64 ", sector %" PRId64 "\n",
+		  ioreq->req.operation, ioreq->req.nr_segments,
+		  ioreq->req.handle, ioreq->req.id, ioreq->req.sector_number);
+    switch (ioreq->req.operation) {
+    case BLKIF_OP_READ:
+	ioreq->prot = PROT_WRITE; /* to memory */
+	if (BLKIF_OP_READ != ioreq->req.operation && blkdev->mode[0] != 'w') {
+	    xen_be_printf(&blkdev->xendev, 0, "error: write req for ro device\n");
+	    goto err;
+	}
+	break;
+    case BLKIF_OP_WRITE_BARRIER:
+	if (!syncwrite)
+	    ioreq->presync = ioreq->postsync = 1;
+	/* fall through */
+    case BLKIF_OP_WRITE:
+	ioreq->prot = PROT_READ; /* from memory */
+	if (syncwrite)
+	    ioreq->postsync = 1;
+	break;
+    default:
+	xen_be_printf(&blkdev->xendev, 0, "error: unknown operation (%d)\n",
+		      ioreq->req.operation);
+	goto err;
+    };
+
+    ioreq->start = ioreq->end = ioreq->req.sector_number * blkdev->file_blk;
+    for (i = 0; i < ioreq->req.nr_segments; i++) {
+	if (i == BLKIF_MAX_SEGMENTS_PER_REQUEST) {
+	    xen_be_printf(&blkdev->xendev, 0, "error: nr_segments too big\n");
+	    goto err;
+	}
+	if (ioreq->req.seg[i].first_sect > ioreq->req.seg[i].last_sect) {
+	    xen_be_printf(&blkdev->xendev, 0, "error: first > last sector\n");
+	    goto err;
+	}
+	if (ioreq->req.seg[i].last_sect * BLOCK_SIZE >= XC_PAGE_SIZE) {
+	    xen_be_printf(&blkdev->xendev, 0, "error: page crossing\n");
+	    goto err;
+	}
+	len = (ioreq->req.seg[i].last_sect - ioreq->req.seg[i].first_sect + 1) * blkdev->file_blk;
+
+	ioreq->domids[i] = blkdev->xendev.dom;
+	ioreq->refs[i]   = ioreq->req.seg[i].gref;
+	mem = ioreq->req.seg[i].first_sect * blkdev->file_blk;
+
+	ioreq->vec[i].iov_base = (void*)mem;
+	ioreq->vec[i].iov_len  = len;
+	ioreq->end += len;
+    }
+    if (ioreq->end > blkdev->file_size) {
+	xen_be_printf(&blkdev->xendev, 0, "error: access beyond end of file\n");
+	goto err;
+    }
+    ioreq->vecs = i;
+    return 0;
+
+err:
+    ioreq->status = BLKIF_RSP_ERROR;
+    return -1;
+}
+
+static void ioreq_unmap(struct ioreq *ioreq)
+{
+    int gnt = ioreq->blkdev->xendev.gnttabdev;
+    int i;
+
+    if (batch_maps) {
+	if (!ioreq->pages)
+	    return;
+	if (0 != xc_gnttab_munmap(gnt, ioreq->pages, ioreq->vecs))
+	    xen_be_printf(&ioreq->blkdev->xendev, 0, "xc_gnttab_munmap failed: %s\n",
+			  strerror(errno));
+	ioreq->blkdev->cnt_map -= ioreq->vecs;
+	ioreq->pages = NULL;
+    } else {
+	for (i = 0; i < ioreq->vecs; i++) {
+	    if (!ioreq->page[i])
+		continue;
+	    if (0 != xc_gnttab_munmap(gnt, ioreq->page[i], 1))
+		xen_be_printf(&ioreq->blkdev->xendev, 0, "xc_gnttab_munmap failed: %s\n",
+			      strerror(errno));
+	    ioreq->blkdev->cnt_map--;
+	    ioreq->page[i] = NULL;
+	}
+    }
+}
+
+static int ioreq_map(struct ioreq *ioreq)
+{
+    int gnt = ioreq->blkdev->xendev.gnttabdev;
+    int i;
+
+    if (batch_maps) {
+	ioreq->pages = xc_gnttab_map_grant_refs
+	    (gnt, ioreq->vecs, ioreq->domids, ioreq->refs, ioreq->prot);
+	if (NULL == ioreq->pages) {
+	    xen_be_printf(&ioreq->blkdev->xendev, 0,
+			  "can't map %d grant refs (%s, %d maps)\n",
+			  ioreq->vecs, strerror(errno), ioreq->blkdev->cnt_map);
+	    return -1;
+	}
+	for (i = 0; i < ioreq->vecs; i++)
+	    ioreq->vec[i].iov_base = ioreq->pages + i * XC_PAGE_SIZE +
+		(uintptr_t)ioreq->vec[i].iov_base;
+	ioreq->blkdev->cnt_map += ioreq->vecs;
+    } else  {
+	for (i = 0; i < ioreq->vecs; i++) {
+	    ioreq->page[i] = xc_gnttab_map_grant_ref
+		(gnt, ioreq->domids[i], ioreq->refs[i], ioreq->prot);
+	    if (NULL == ioreq->page[i]) {
+		xen_be_printf(&ioreq->blkdev->xendev, 0,
+			      "can't map grant ref %d (%s, %d maps)\n",
+			      ioreq->refs[i], strerror(errno), ioreq->blkdev->cnt_map);
+		ioreq_unmap(ioreq);
+		return -1;
+	    }
+	    ioreq->vec[i].iov_base = ioreq->page[i] + (uintptr_t)ioreq->vec[i].iov_base;
+	    ioreq->blkdev->cnt_map++;
+	}
+    }
+    return 0;
+}
+
+static int ioreq_runio_qemu(struct ioreq *ioreq)
+{
+    struct blkdev *blkdev = ioreq->blkdev;
+    int i, rc, len = 0;
+    off_t pos;
+
+    if (-1 == ioreq_map(ioreq))
+	goto err;
+    if (ioreq->presync)
+	bdrv_flush(blkdev->bs);
+
+    switch (ioreq->req.operation) {
+    case BLKIF_OP_READ:
+	pos = ioreq->start;
+	for (i = 0; i < ioreq->vecs; i++) {
+	    rc = bdrv_read(blkdev->bs, pos / BLOCK_SIZE,
+			   ioreq->vec[i].iov_base,
+			   ioreq->vec[i].iov_len / BLOCK_SIZE);
+	    if (rc != 0) {
+		xen_be_printf(&blkdev->xendev, 0, "rd I/O error (%p, len %zd)\n",
+			      ioreq->vec[i].iov_base,
+			      ioreq->vec[i].iov_len);
+		goto err;
+	    }
+	    len += ioreq->vec[i].iov_len;
+	    pos += ioreq->vec[i].iov_len;
+	}
+	break;
+    case BLKIF_OP_WRITE:
+    case BLKIF_OP_WRITE_BARRIER:
+	pos = ioreq->start;
+	for (i = 0; i < ioreq->vecs; i++) {
+	    rc = bdrv_write(blkdev->bs, pos / BLOCK_SIZE,
+			    ioreq->vec[i].iov_base,
+			    ioreq->vec[i].iov_len / BLOCK_SIZE);
+	    if (rc != 0) {
+		xen_be_printf(&blkdev->xendev, 0, "wr I/O error (%p, len %zd)\n",
+			      ioreq->vec[i].iov_base,
+			      ioreq->vec[i].iov_len);
+		goto err;
+	    }
+	    len += ioreq->vec[i].iov_len;
+	    pos += ioreq->vec[i].iov_len;
+	}
+	break;
+    default:
+	/* unknown operation (shouldn't happen -- parse catches this) */
+	goto err;
+    }
+
+    if (ioreq->postsync)
+	bdrv_flush(blkdev->bs);
+    ioreq->status = BLKIF_RSP_OKAY;
+
+    ioreq_unmap(ioreq);
+    return 0;
+
+err:
+    ioreq->status = BLKIF_RSP_ERROR;
+    return -1;
+}
+
+static int blk_send_response_one(struct ioreq *ioreq)
+{
+    struct blkdev     *blkdev = ioreq->blkdev;
+    int               send_notify   = 0;
+    int               have_requests = 0;
+    blkif_response_t  resp;
+    void              *dst;
+
+    resp.id        = ioreq->req.id;
+    resp.operation = ioreq->req.operation;
+    resp.status    = ioreq->status;
+
+    /* Place on the response ring for the relevant domain. */
+    switch (blkdev->protocol) {
+    case BLKIF_PROTOCOL_NATIVE:
+	dst = RING_GET_RESPONSE(&blkdev->rings.native, blkdev->rings.native.rsp_prod_pvt);
+	break;
+    case BLKIF_PROTOCOL_X86_32:
+	dst = RING_GET_RESPONSE(&blkdev->rings.x86_32, blkdev->rings.x86_32.rsp_prod_pvt);
+	break;
+    case BLKIF_PROTOCOL_X86_64:
+	dst = RING_GET_RESPONSE(&blkdev->rings.x86_64, blkdev->rings.x86_64.rsp_prod_pvt);
+	break;
+    default:
+	dst = NULL;
+    }
+    memcpy(dst, &resp, sizeof(resp));
+    blkdev->rings.common.rsp_prod_pvt++;
+
+    RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&blkdev->rings.common, send_notify);
+    if (blkdev->rings.common.rsp_prod_pvt == blkdev->rings.common.req_cons) {
+	/*
+	 * Tail check for pending requests. Allows frontend to avoid
+	 * notifications if requests are already in flight (lower
+	 * overheads and promotes batching).
+	 */
+	RING_FINAL_CHECK_FOR_REQUESTS(&blkdev->rings.common, have_requests);
+    } else if (RING_HAS_UNCONSUMED_REQUESTS(&blkdev->rings.common)) {
+	have_requests = 1;
+    }
+
+    if (have_requests)
+	blkdev->more_work++;
+    return send_notify;
+}
+
+/* walk finished list, send outstanding responses, free requests */
+static void blk_send_response_all(struct blkdev *blkdev)
+{
+    struct list_head *item, *safe;
+    struct ioreq *ioreq;
+    int send_notify = 0;
+
+    list_for_each_safe(item, safe, &blkdev->finished) {
+	ioreq = list_entry(item, struct ioreq, list);
+	send_notify += blk_send_response_one(ioreq);
+	ioreq_release(ioreq);
+    }
+    if (send_notify)
+	xen_be_send_notify(&blkdev->xendev);
+}
+
+static int blk_get_request(struct blkdev *blkdev, struct ioreq *ioreq, RING_IDX rc)
+{
+    switch (blkdev->protocol) {
+    case BLKIF_PROTOCOL_NATIVE:
+	memcpy(&ioreq->req, RING_GET_REQUEST(&blkdev->rings.native, rc),
+	       sizeof(ioreq->req));
+	break;
+    case BLKIF_PROTOCOL_X86_32:
+	blkif_get_x86_32_req(&ioreq->req, RING_GET_REQUEST(&blkdev->rings.x86_32, rc));
+	break;
+    case BLKIF_PROTOCOL_X86_64:
+	blkif_get_x86_64_req(&ioreq->req, RING_GET_REQUEST(&blkdev->rings.x86_64, rc));
+	break;
+    }
+    return 0;
+}
+
+static void blk_handle_requests(struct blkdev *blkdev)
+{
+    RING_IDX rc, rp;
+    struct ioreq *ioreq;
+
+    do {
+	blkdev->more_work = 0;
+
+	rc = blkdev->rings.common.req_cons;
+	rp = blkdev->rings.common.sring->req_prod;
+	xen_rmb(); /* Ensure we see queued requests up to 'rp'. */
+
+	/* Limit #of requests we queue up for I/O so we ack requests
+	 * faster if busy.  Improves backend/frontend parallelism and
+	 * reduces evchn signaling. */
+	if (rp > rc + (max_requests >> 2)) {
+	    rp = rc + (max_requests >> 2);
+	    blkdev->more_work++;
+	}
+
+	while ((rc != rp)) {
+	    /* pull request from ring */
+	    if (RING_REQUEST_CONS_OVERFLOW(&blkdev->rings.common, rc))
+		break;
+	    ioreq = ioreq_start(blkdev);
+	    if (NULL == ioreq) {
+		blkdev->more_work++;
+		break;
+	    }
+	    blk_get_request(blkdev, ioreq, rc);
+	    blkdev->rings.common.req_cons = ++rc;
+
+	    /* parse them */
+	    if (0 != ioreq_parse(ioreq)) {
+		if (blk_send_response_one(ioreq))
+		    xen_be_send_notify(&blkdev->xendev);
+		ioreq_release(ioreq);
+		continue;
+	    }
+
+	    /* run i/o in qemu mode */
+	    ioreq_runio_qemu(ioreq);
+	    ioreq_finish(ioreq);
+	}
+	blk_send_response_all(blkdev);
+
+    } while (blkdev->more_work);
+}
+
+/* ------------------------------------------------------------- */
+
+static void blk_alloc(struct xendev *xendev)
+{
+    struct blkdev *blkdev = container_of(xendev, struct blkdev, xendev);
+
+    INIT_LIST_HEAD(&blkdev->inflight);
+    INIT_LIST_HEAD(&blkdev->finished);
+    INIT_LIST_HEAD(&blkdev->freelist);
+}
+
+static int blk_init(struct xendev *xendev)
+{
+    struct blkdev *blkdev = container_of(xendev, struct blkdev, xendev);
+    int mode, qflags, have_barriers, index, info = 0;
+    char *h;
+
+    /* read xenstore entries */
+    if (NULL == blkdev->params) {
+	blkdev->params = xenstore_read_be_str(&blkdev->xendev, "params");
+	if (NULL != (h = strchr(blkdev->params, ':'))) {
+	    blkdev->fileproto = blkdev->params;
+	    blkdev->filename  = h+1;
+	    *h = 0;
+	} else {
+	    blkdev->fileproto = "<unset>";
+	    blkdev->filename  = blkdev->params;
+	}
+    }
+    if (NULL == blkdev->mode)
+	blkdev->mode = xenstore_read_be_str(&blkdev->xendev, "mode");
+    if (NULL == blkdev->type)
+	blkdev->type = xenstore_read_be_str(&blkdev->xendev, "type");
+    if (NULL == blkdev->dev)
+	blkdev->dev  = xenstore_read_be_str(&blkdev->xendev, "dev");
+
+    /* do we have all we need? */
+    if (NULL == blkdev->params ||
+	NULL == blkdev->mode   ||
+	NULL == blkdev->type   ||
+	NULL == blkdev->dev)
+	return -1;
+
+    /* read-only ? */
+    if (0 == strcmp(blkdev->mode, "w")) {
+	mode   = O_RDWR;
+	qflags = BDRV_O_RDWR;
+    } else {
+	mode   = O_RDONLY;
+	qflags = BDRV_O_RDONLY;
+	info  |= VDISK_READONLY | VDISK_REMOVABLE | VDISK_CDROM;
+    }
+
+    /* init qemu block driver */
+    index = (blkdev->xendev.dev - 202 * 256) / 16;
+    index = drive_get_index(IF_XEN, 0, index);
+    if (-1 == index) {
+	blkdev->bs = bdrv_new(blkdev->dev);
+	if (blkdev->bs) {
+	    if (0 != bdrv_open2(blkdev->bs, blkdev->filename, qflags,
+				bdrv_find_format(blkdev->fileproto))) {
+		bdrv_delete(blkdev->bs);
+		blkdev->bs = NULL;
+	    }
+	}
+	if (!blkdev->bs)
+	    return -1;
+    } else {
+	blkdev->bs = drives_table[index].bdrv;
+    }
+    blkdev->file_blk  = BLOCK_SIZE;
+    blkdev->file_size = bdrv_getlength(blkdev->bs);
+    if (blkdev->file_size < 0)
+	blkdev->file_size = 0;
+    have_barriers = blkdev->bs->drv && blkdev->bs->drv->bdrv_flush ? 1 : 0;
+
+    xen_be_printf(xendev, 1, "type \"%s\", fileproto \"%s\", filename \"%s\","
+		  " size %" PRId64 " (%" PRId64 " MB)\n",
+		  blkdev->type, blkdev->fileproto, blkdev->filename,
+		  blkdev->file_size, blkdev->file_size >> 20);
+
+    /* fill info */
+    xenstore_write_be_int(&blkdev->xendev, "feature-barrier", have_barriers);
+    xenstore_write_be_int(&blkdev->xendev, "info",            info);
+    xenstore_write_be_int(&blkdev->xendev, "sector-size",     blkdev->file_blk);
+    xenstore_write_be_int(&blkdev->xendev, "sectors",
+			  blkdev->file_size / blkdev->file_blk);
+    return 0;
+}
+
+static int blk_connect(struct xendev *xendev)
+{
+    struct blkdev *blkdev = container_of(xendev, struct blkdev, xendev);
+
+    if (-1 == xenstore_read_fe_int(&blkdev->xendev, "ring-ref", &blkdev->ring_ref))
+	return -1;
+    if (-1 == xenstore_read_fe_int(&blkdev->xendev, "event-channel",
+				   &blkdev->xendev.remote_port))
+	return -1;
+
+    blkdev->protocol = BLKIF_PROTOCOL_NATIVE;
+    if (0 == strcmp(blkdev->xendev.protocol, XEN_IO_PROTO_ABI_X86_32))
+	blkdev->protocol = BLKIF_PROTOCOL_X86_32;
+    if (0 == strcmp(blkdev->xendev.protocol, XEN_IO_PROTO_ABI_X86_64))
+	blkdev->protocol = BLKIF_PROTOCOL_X86_64;
+
+    blkdev->sring = xc_gnttab_map_grant_ref(blkdev->xendev.gnttabdev,
+					    blkdev->xendev.dom,
+					    blkdev->ring_ref,
+					    PROT_READ | PROT_WRITE);
+    if (!blkdev->sring)
+	return -1;
+    blkdev->cnt_map++;
+
+    switch (blkdev->protocol) {
+    case BLKIF_PROTOCOL_NATIVE:
+    {
+	blkif_sring_t *sring_native = blkdev->sring;
+	BACK_RING_INIT(&blkdev->rings.native, sring_native, XC_PAGE_SIZE);
+	break;
+    }
+    case BLKIF_PROTOCOL_X86_32:
+    {
+	blkif_x86_32_sring_t *sring_x86_32 = blkdev->sring;
+	BACK_RING_INIT(&blkdev->rings.x86_32, sring_x86_32, XC_PAGE_SIZE);
+	break;
+    }
+    case BLKIF_PROTOCOL_X86_64:
+    {
+	blkif_x86_64_sring_t *sring_x86_64 = blkdev->sring;
+	BACK_RING_INIT(&blkdev->rings.x86_64, sring_x86_64, XC_PAGE_SIZE);
+	break;
+    }
+    }
+
+    xen_be_bind_evtchn(&blkdev->xendev);
+
+    xen_be_printf(&blkdev->xendev, 1, "ok: proto %s, ring-ref %d, "
+		  "remote port %d, local port %d\n",
+		  blkdev->xendev.protocol, blkdev->ring_ref,
+		  blkdev->xendev.remote_port, blkdev->xendev.local_port);
+    return 0;
+}
+
+static void blk_disconnect(struct xendev *xendev)
+{
+    struct blkdev *blkdev = container_of(xendev, struct blkdev, xendev);
+
+    if (-1 != blkdev->file) {
+	close(blkdev->file);
+	blkdev->file = -1;
+    }
+    if (blkdev->bs) {
+	bdrv_close(blkdev->bs);
+	bdrv_delete(blkdev->bs);
+	blkdev->bs = NULL;
+    }
+    xen_be_unbind_evtchn(&blkdev->xendev);
+
+    if (blkdev->sring) {
+	xc_gnttab_munmap(blkdev->xendev.gnttabdev, blkdev->sring, 1);
+	blkdev->cnt_map--;
+	blkdev->sring = NULL;
+    }
+}
+
+static int blk_free(struct xendev *xendev)
+{
+    struct blkdev *blkdev = container_of(xendev, struct blkdev, xendev);
+    struct list_head *item, *safe;
+    struct ioreq *ioreq;
+
+    list_for_each_safe(item, safe, &blkdev->freelist) {
+	ioreq = list_entry(item, struct ioreq, list);
+	list_del(&ioreq->list);
+	free(ioreq);
+    }
+
+    free(blkdev->params);
+    free(blkdev->mode);
+    return 0;
+}
+
+static void blk_event(struct xendev *xendev)
+{
+    struct blkdev *blkdev = container_of(xendev, struct blkdev, xendev);
+    blk_handle_requests(blkdev);
+}
+
+struct devops xen_blkdev_ops = {
+    .size       = sizeof(struct blkdev),
+    .flags      = DEVOPS_FLAG_NEED_GNTDEV,
+    .alloc      = blk_alloc,
+    .init       = blk_init,
+    .connect    = blk_connect,
+    .disconnect = blk_disconnect,
+    .event      = blk_event,
+    .free       = blk_free,
+};
diff --git a/hw/xen-machine.c b/hw/xen-machine.c
index c03cb53..1b647a2 100644
--- a/hw/xen-machine.c
+++ b/hw/xen-machine.c
@@ -61,6 +61,7 @@ static void xenpv_init(ram_addr_t ram_size, int vga_ram_size,
     xen_be_register("console", &xen_console_ops);
     xen_be_register("vkbd", &xen_kbdmouse_ops);
     xen_be_register("vfb", &xen_framebuffer_ops);
+    xen_be_register("qdisk", &xen_blkdev_ops);
 
     /* setup framebuffer */
     xen_set_display(xen_domid, ds);
diff --git a/sysemu.h b/sysemu.h
index b12fae0..49e75b1 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -113,7 +113,7 @@ extern unsigned int nb_prom_envs;
 #endif
 
 typedef enum {
-    IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD
+    IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD, IF_XEN
 } BlockInterfaceType;
 
 typedef struct DriveInfo {
diff --git a/vl.c b/vl.c
index 8aef3bd..7187545 100644
--- a/vl.c
+++ b/vl.c
@@ -5478,6 +5478,9 @@ static int drive_init(struct drive_opt *arg, int snapshot,
 	} else if (!strcmp(buf, "sd")) {
 	    type = IF_SD;
             max_devs = 0;
+	} else if (!strcmp(buf, "xen")) {
+	    type = IF_XEN;
+            max_devs = 0;
 	} else {
             fprintf(stderr, "qemu: '%s' unsupported bus type '%s'\n", str, buf);
             return -1;
@@ -5663,6 +5666,7 @@ static int drive_init(struct drive_opt *arg, int snapshot,
     switch(type) {
     case IF_IDE:
     case IF_SCSI:
+    case IF_XEN:
         switch(media) {
 	case MEDIA_DISK:
             if (cyls != 0) {
-- 
1.5.4.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [Qemu-devel] [PATCH 6/7] xen: add net backend driver.
  2008-07-28 13:17 [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu Gerd Hoffmann
                   ` (4 preceding siblings ...)
  2008-07-28 13:17 ` [Qemu-devel] [PATCH 5/7] xen: add block device " Gerd Hoffmann
@ 2008-07-28 13:17 ` Gerd Hoffmann
  2008-07-28 14:27   ` Anthony Liguori
  2008-07-28 13:17 ` [Qemu-devel] [PATCH 7/7] xen: blk & nic configuration via cmd line Gerd Hoffmann
  6 siblings, 1 reply; 64+ messages in thread
From: Gerd Hoffmann @ 2008-07-28 13:17 UTC (permalink / raw)
  To: qemu-devel, xen-devel; +Cc: Gerd Hoffmann

This patch adds a network interface backend driver to qemu.  It is a pure
userspace implemention using the gntdev interface.  It uses "qnet" as
backend name in xenstore so it doesn't interfere with the netback
backend (aka "vnif").

The network backend is hooked into the corrosponding qemu vlan, i.e.
vif 0 is hooked into vlan 0.  To make the packages actually arrive
somewhere you additionally have to link the vlan to the outside world
using the usual qemu command line options such as "-net tap,...".

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 Makefile.target  |    2 +-
 hw/xen-backend.h |    1 +
 hw/xen-machine.c |    1 +
 hw/xen-nic.c     |  448 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 451 insertions(+), 1 deletions(-)
 create mode 100644 hw/xen-nic.c

diff --git a/Makefile.target b/Makefile.target
index 2d599d2..281d7fa 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -517,7 +517,7 @@ endif
 
 # xen backend driver support
 XEN_OBJS := xen-machine.o xen-backend.o
-XEN_OBJS += xen-console.o xen-framebuffer.o xen-disk.o
+XEN_OBJS += xen-console.o xen-framebuffer.o xen-disk.o xen-nic.o
 ifeq ($(CONFIG_XEN), yes)
   OBJS += $(XEN_OBJS)
   LIBS += $(XEN_LIBS)
diff --git a/hw/xen-backend.h b/hw/xen-backend.h
index 941b0a6..2db2c3c 100644
--- a/hw/xen-backend.h
+++ b/hw/xen-backend.h
@@ -120,6 +120,7 @@ struct devops xen_console_ops;      /* xen_console.c     */
 struct devops xen_kbdmouse_ops;     /* xen_framebuffer.c */
 struct devops xen_framebuffer_ops;  /* xen_framebuffer.c */
 struct devops xen_blkdev_ops;       /* xen_disk.c        */
+struct devops xen_netdev_ops;       /* xen_nic.c         */
 
 void xen_set_display(int domid, DisplayState *ds);
 
diff --git a/hw/xen-machine.c b/hw/xen-machine.c
index 1b647a2..3fa4079 100644
--- a/hw/xen-machine.c
+++ b/hw/xen-machine.c
@@ -62,6 +62,7 @@ static void xenpv_init(ram_addr_t ram_size, int vga_ram_size,
     xen_be_register("vkbd", &xen_kbdmouse_ops);
     xen_be_register("vfb", &xen_framebuffer_ops);
     xen_be_register("qdisk", &xen_blkdev_ops);
+    xen_be_register("qnic", &xen_netdev_ops);
 
     /* setup framebuffer */
     xen_set_display(xen_domid, ds);
diff --git a/hw/xen-nic.c b/hw/xen-nic.c
new file mode 100644
index 0000000..56d1474
--- /dev/null
+++ b/hw/xen-nic.c
@@ -0,0 +1,448 @@
+/*
+ *  xen paravirt network card backend
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; under version 2 of the License.
+ *
+ *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <inttypes.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <pthread.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <linux/if.h>
+#include <linux/if_tun.h>
+
+#include <xs.h>
+#include <xenctrl.h>
+#include <xen/io/xenbus.h>
+#include <xen/io/netif.h>
+
+#include "hw.h"
+#include "net.h"
+#include "qemu-char.h"
+#include "xen-backend.h"
+
+/* ------------------------------------------------------------- */
+
+struct netdev {
+    struct xendev         xendev;  /* must be first */
+    char                  *mac;
+    int                   tx_work;
+    int                   tx_ring_ref;
+    int                   rx_ring_ref;
+    struct netif_tx_sring *txs;
+    struct netif_rx_sring *rxs;
+    netif_tx_back_ring_t  tx_ring;
+    netif_rx_back_ring_t  rx_ring;
+    VLANClientState       *vs;
+};
+
+/* ------------------------------------------------------------- */
+
+#define PROTO_TCP  6
+#define PROTO_UDP 17
+
+static uint32_t checksum_add(int len, uint8_t *buf)
+{
+    uint32_t sum = 0;
+    int i;
+
+    for (i = 0; i < len; i++) {
+	if (i & 1)
+	    sum += (uint32_t)buf[i];
+	else
+	    sum += (uint32_t)buf[i] << 8;
+    }
+    return sum;
+}
+
+static uint16_t checksum_finish(uint32_t sum)
+{
+    while (sum>>16)
+	sum = (sum & 0xFFFF)+(sum >> 16);
+    return ~sum;
+}
+
+static uint16_t checksum_tcpudp(uint16_t length, uint16_t proto,
+				uint8_t *addrs, uint8_t *buf)
+{
+    uint32_t sum = 0;
+
+    sum += checksum_add(length, buf);         // payload
+    sum += checksum_add(8, addrs);            // src + dst address
+    sum += proto + length;                    // protocol & length
+    return checksum_finish(sum);
+}
+
+static void checksum_calculate(uint8_t *data, int length)
+{
+    int hlen, plen, proto, csum_offset;
+    uint16_t csum;
+
+    if ((data[14] & 0xf0) != 0x40)
+	return; /* not IPv4 */
+    hlen  = (data[14] & 0x0f) * 4;
+    plen  = (data[16] << 8 | data[17]) - hlen;
+    proto = data[23];
+
+    switch (proto) {
+    case PROTO_TCP:
+	csum_offset = 16;
+	break;
+    case PROTO_UDP:
+	csum_offset = 6;
+	break;
+    default:
+	return;
+    }
+
+    if (plen < csum_offset+2)
+	return;
+
+    data[14+hlen+csum_offset]   = 0;
+    data[14+hlen+csum_offset+1] = 0;
+    csum = checksum_tcpudp(plen, proto, data+14+12, data+14+hlen);
+    data[14+hlen+csum_offset]   = csum >> 8;
+    data[14+hlen+csum_offset+1] = csum & 0xff;
+}
+
+
+/* ------------------------------------------------------------- */
+
+static void net_tx_response(struct netdev *netdev, netif_tx_request_t *txp, int8_t st)
+{
+    RING_IDX i = netdev->tx_ring.rsp_prod_pvt;
+    netif_tx_response_t *resp;
+    int notify;
+
+    resp = RING_GET_RESPONSE(&netdev->tx_ring, i);
+    resp->id     = txp->id;
+    resp->status = st;
+
+#if 0
+    if (txp->flags & NETTXF_extra_info)
+	RING_GET_RESPONSE(&netdev->tx_ring, ++i)->status = NETIF_RSP_NULL;
+#endif
+
+    netdev->tx_ring.rsp_prod_pvt = ++i;
+    RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netdev->tx_ring, notify);
+    if (notify)
+	xen_be_send_notify(&netdev->xendev);
+
+    if (i == netdev->tx_ring.req_cons) {
+	int more_to_do;
+	RING_FINAL_CHECK_FOR_REQUESTS(&netdev->tx_ring, more_to_do);
+	if (more_to_do)
+	    netdev->tx_work++;
+    }
+}
+
+static void net_tx_error(struct netdev *netdev, netif_tx_request_t *txp, RING_IDX end)
+{
+#if 0
+    /*
+     * Hmm, why netback fails everything in the ring?
+     * Should we do that even when not supporting SG and TSO?
+     */
+    RING_IDX cons = netdev->tx_ring.req_cons;
+
+    do {
+	make_tx_response(netif, txp, NETIF_RSP_ERROR);
+	if (cons >= end)
+	    break;
+	txp = RING_GET_REQUEST(&netdev->tx_ring, cons++);
+    } while (1);
+    netdev->tx_ring.req_cons = cons;
+    netif_schedule_work(netif);
+    netif_put(netif);
+#else
+    net_tx_response(netdev, txp, NETIF_RSP_ERROR);
+#endif
+}
+
+static void net_tx_packets(struct netdev *netdev)
+{
+    netif_tx_request_t txreq;
+    RING_IDX rc, rp;
+    void *page;
+
+    for (;;) {
+	rc = netdev->tx_ring.req_cons;
+	rp = netdev->tx_ring.sring->req_prod;
+	xen_rmb(); /* Ensure we see queued requests up to 'rp'. */
+
+	while ((rc != rp)) {
+	    if (RING_REQUEST_CONS_OVERFLOW(&netdev->tx_ring, rc))
+		break;
+	    memcpy(&txreq, RING_GET_REQUEST(&netdev->tx_ring, rc), sizeof(txreq));
+	    netdev->tx_ring.req_cons = ++rc;
+
+#if 1
+	    /* should not happen in theory, we don't announce the *
+	     * feature-{sg,gso,whatelse} flags in xenstore (yet?) */
+	    if (txreq.flags & NETTXF_extra_info) {
+		xen_be_printf(&netdev->xendev, 0, "FIXME: extra info flag\n");
+		net_tx_error(netdev, &txreq, rc);
+		continue;
+	    }
+	    if (txreq.flags & NETTXF_more_data) {
+		xen_be_printf(&netdev->xendev, 0, "FIXME: more data flag\n");
+		net_tx_error(netdev, &txreq, rc);
+		continue;
+	    }
+#endif
+
+	    if (txreq.size < 14) {
+		xen_be_printf(&netdev->xendev, 0, "bad packet size: %d\n", txreq.size);
+		net_tx_error(netdev, &txreq, rc);
+		continue;
+	    }
+
+	    if ((txreq.offset + txreq.size) > XC_PAGE_SIZE) {
+		xen_be_printf(&netdev->xendev, 0, "error: page crossing\n");
+		net_tx_error(netdev, &txreq, rc);
+		continue;
+	    }
+
+	    xen_be_printf(&netdev->xendev, 3, "tx packet ref %d, off %d, len %d, flags 0x%x%s%s%s%s\n",
+			  txreq.gref, txreq.offset, txreq.size, txreq.flags,
+			  (txreq.flags & NETTXF_csum_blank)     ? " csum_blank"     : "",
+			  (txreq.flags & NETTXF_data_validated) ? " data_validated" : "",
+			  (txreq.flags & NETTXF_more_data)      ? " more_data"      : "",
+			  (txreq.flags & NETTXF_extra_info)     ? " extra_info"     : "");
+
+	    page = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
+					   netdev->xendev.dom,
+					   txreq.gref, PROT_READ);
+	    if (NULL == page) {
+		xen_be_printf(&netdev->xendev, 0, "error: gref dereference failed\n");
+		net_tx_error(netdev, &txreq, rc);
+		continue;
+	    }
+	    if (txreq.flags & NETTXF_csum_blank)
+		checksum_calculate(page + txreq.offset, txreq.size);
+	    qemu_send_packet(netdev->vs, page + txreq.offset, txreq.size);
+	    xc_gnttab_munmap(netdev->xendev.gnttabdev, page, 1);
+	    net_tx_response(netdev, &txreq, NETIF_RSP_OKAY);
+	}
+	if (!netdev->tx_work)
+	    break;
+	netdev->tx_work = 0;
+    }
+}
+
+/* ------------------------------------------------------------- */
+
+static void net_rx_response(struct netdev *netdev,
+			    netif_rx_request_t *req, int8_t st,
+			    uint16_t offset, uint16_t size,
+			    uint16_t flags)
+{
+    RING_IDX i = netdev->rx_ring.rsp_prod_pvt;
+    netif_rx_response_t *resp;
+    int notify;
+
+    resp = RING_GET_RESPONSE(&netdev->rx_ring, i);
+    resp->offset     = offset;
+    resp->flags      = flags;
+    resp->id         = req->id;
+    resp->status     = (int16_t)size;
+    if (st < 0)
+	resp->status = (int16_t)st;
+
+    xen_be_printf(&netdev->xendev, 3, "rx response: idx %d, status %d, flags 0x%x\n",
+		  i, resp->status, resp->flags);
+
+    netdev->rx_ring.rsp_prod_pvt = ++i;
+    RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netdev->rx_ring, notify);
+    if (notify)
+	xen_be_send_notify(&netdev->xendev);
+}
+
+#define NET_IP_ALIGN 2
+
+static int net_rx_ok(void *opaque)
+{
+    struct netdev *netdev = opaque;
+    RING_IDX rc, rp;
+
+    if (netdev->xendev.be_state != XenbusStateConnected)
+	return 0;
+
+    rc = netdev->rx_ring.req_cons;
+    rp = netdev->rx_ring.sring->req_prod;
+    xen_rmb();
+
+    if (rc == rp || RING_REQUEST_CONS_OVERFLOW(&netdev->rx_ring, rc)) {
+	xen_be_printf(&netdev->xendev, 2, "%s: no rx buffers (%d/%d)\n",
+		      __FUNCTION__, rc, rp);
+	return 0;
+    }
+    return 1;
+}
+
+static void net_rx_packet(void *opaque, const uint8_t *buf, int size)
+{
+    struct netdev *netdev = opaque;
+    netif_rx_request_t rxreq;
+    RING_IDX rc, rp;
+    void *page;
+
+    if (netdev->xendev.be_state != XenbusStateConnected)
+	return;
+
+    rc = netdev->rx_ring.req_cons;
+    rp = netdev->rx_ring.sring->req_prod;
+    xen_rmb(); /* Ensure we see queued requests up to 'rp'. */
+
+    if (rc == rp || RING_REQUEST_CONS_OVERFLOW(&netdev->rx_ring, rc)) {
+	xen_be_printf(&netdev->xendev, 2, "no buffer, drop packet\n");
+	return;
+    }
+    if (size > XC_PAGE_SIZE - NET_IP_ALIGN) {
+	xen_be_printf(&netdev->xendev, 0, "packet too big (%d > %ld)",
+		      size, XC_PAGE_SIZE - NET_IP_ALIGN);
+	return;
+    }
+
+    memcpy(&rxreq, RING_GET_REQUEST(&netdev->rx_ring, rc), sizeof(rxreq));
+    netdev->rx_ring.req_cons = ++rc;
+
+    page = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
+				   netdev->xendev.dom,
+				   rxreq.gref, PROT_WRITE);
+    if (NULL == page) {
+	xen_be_printf(&netdev->xendev, 0, "error: gref dereference failed\n");
+	net_rx_response(netdev, &rxreq, NETIF_RSP_ERROR, 0, 0, 0);
+	return;
+    }
+    memcpy(page + NET_IP_ALIGN, buf, size);
+    xc_gnttab_munmap(netdev->xendev.gnttabdev, page, 1);
+    net_rx_response(netdev, &rxreq, NETIF_RSP_OKAY, NET_IP_ALIGN, size, 0);
+}
+
+/* ------------------------------------------------------------- */
+
+static int net_init(struct xendev *xendev)
+{
+    struct netdev *netdev = container_of(xendev, struct netdev, xendev);
+    VLANState *vlan;
+
+    /* read xenstore entries */
+    if (NULL == netdev->mac)
+	netdev->mac = xenstore_read_be_str(&netdev->xendev, "mac");
+
+    /* do we have all we need? */
+    if (NULL == netdev->mac)
+	return -1;
+
+    vlan = qemu_find_vlan(netdev->xendev.dev);
+    netdev->vs = qemu_new_vlan_client(vlan, net_rx_packet, net_rx_ok, netdev);
+    snprintf(netdev->vs->info_str, sizeof(netdev->vs->info_str),
+             "nic: xenbus vif macaddr=%s", netdev->mac);
+
+    /* fill info */
+    xenstore_write_be_int(&netdev->xendev, "feature-rx-copy", 1);
+    xenstore_write_be_int(&netdev->xendev, "feature-rx-flip", 0);
+
+    return 0;
+}
+
+static int net_connect(struct xendev *xendev)
+{
+    struct netdev *netdev = container_of(xendev, struct netdev, xendev);
+    int rx_copy;
+
+    if (-1 == xenstore_read_fe_int(&netdev->xendev, "tx-ring-ref",
+				   &netdev->tx_ring_ref))
+	return -1;
+    if (-1 == xenstore_read_fe_int(&netdev->xendev, "rx-ring-ref",
+				   &netdev->rx_ring_ref))
+	return 1;
+    if (-1 == xenstore_read_fe_int(&netdev->xendev, "event-channel",
+				   &netdev->xendev.remote_port))
+	return -1;
+
+    if (-1 == xenstore_read_fe_int(&netdev->xendev, "request-rx-copy", &rx_copy))
+	rx_copy = 0;
+    if (0 == rx_copy) {
+	xen_be_printf(&netdev->xendev, 0, "frontend doesn't support rx-copy.\n");
+	return -1;
+    }
+
+    netdev->txs = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
+					  netdev->xendev.dom,
+					  netdev->tx_ring_ref,
+					  PROT_READ | PROT_WRITE);
+    netdev->rxs = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
+					  netdev->xendev.dom,
+					  netdev->rx_ring_ref,
+					  PROT_READ | PROT_WRITE);
+    if (!netdev->txs || !netdev->rxs)
+	return -1;
+    BACK_RING_INIT(&netdev->tx_ring, netdev->txs, XC_PAGE_SIZE);
+    BACK_RING_INIT(&netdev->rx_ring, netdev->rxs, XC_PAGE_SIZE);
+
+    xen_be_bind_evtchn(&netdev->xendev);
+
+    xen_be_printf(&netdev->xendev, 1, "ok: tx-ring-ref %d, rx-ring-ref %d, "
+		  "remote port %d, local port %d\n",
+		  netdev->tx_ring_ref, netdev->rx_ring_ref,
+		  netdev->xendev.remote_port, netdev->xendev.local_port);
+    return 0;
+}
+
+static void net_disconnect(struct xendev *xendev)
+{
+    struct netdev *netdev = container_of(xendev, struct netdev, xendev);
+
+    xen_be_unbind_evtchn(&netdev->xendev);
+
+    if (netdev->txs) {
+	xc_gnttab_munmap(netdev->xendev.gnttabdev, netdev->txs, 1);
+	netdev->txs = NULL;
+    }
+    if (netdev->rxs) {
+	xc_gnttab_munmap(netdev->xendev.gnttabdev, netdev->rxs, 1);
+	netdev->rxs = NULL;
+    }
+}
+
+static void net_event(struct xendev *xendev)
+{
+    struct netdev *netdev = container_of(xendev, struct netdev, xendev);
+    net_tx_packets(netdev);
+}
+
+/* ------------------------------------------------------------- */
+
+struct devops xen_netdev_ops = {
+    .size       = sizeof(struct netdev),
+    .flags      = DEVOPS_FLAG_NEED_GNTDEV,
+    .init       = net_init,
+    .connect    = net_connect,
+    .event      = net_event,
+    .disconnect = net_disconnect,
+};
-- 
1.5.4.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [Qemu-devel] [PATCH 7/7] xen: blk & nic configuration via cmd line.
  2008-07-28 13:17 [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu Gerd Hoffmann
                   ` (5 preceding siblings ...)
  2008-07-28 13:17 ` [Qemu-devel] [PATCH 6/7] xen: add net " Gerd Hoffmann
@ 2008-07-28 13:17 ` Gerd Hoffmann
  6 siblings, 0 replies; 64+ messages in thread
From: Gerd Hoffmann @ 2008-07-28 13:17 UTC (permalink / raw)
  To: qemu-devel, xen-devel; +Cc: Gerd Hoffmann

This patch makes qemu create backend and frontend device entries in
xenstore for devices configured on the command line.  It will use
qdisk and qnic backend names, so the qemu internal backends will
be used.

Disks can be created using -drive if=xen,file=...
Nics can be created using -net nic,macaddr=...

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 Makefile.target  |    2 +-
 hw/xen-backend.h |    7 +++
 hw/xen-config.c  |  140 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/xen-machine.c |   22 ++++++++-
 4 files changed, 169 insertions(+), 2 deletions(-)
 create mode 100644 hw/xen-config.c

diff --git a/Makefile.target b/Makefile.target
index 281d7fa..acb679d 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -516,7 +516,7 @@ LIBS += $(CONFIG_VNC_TLS_LIBS)
 endif
 
 # xen backend driver support
-XEN_OBJS := xen-machine.o xen-backend.o
+XEN_OBJS := xen-machine.o xen-backend.o xen-config.o
 XEN_OBJS += xen-console.o xen-framebuffer.o xen-disk.o xen-nic.o
 ifeq ($(CONFIG_XEN), yes)
   OBJS += $(XEN_OBJS)
diff --git a/hw/xen-backend.h b/hw/xen-backend.h
index 2db2c3c..2f21f84 100644
--- a/hw/xen-backend.h
+++ b/hw/xen-backend.h
@@ -11,6 +11,8 @@
 #include "hw.h"
 #include "xen.h"
 #include "sysemu.h"
+#include "net.h"
+#include "block_int.h"
 
 /*
  * tweaks needed to build with different xen versions
@@ -124,3 +126,8 @@ struct devops xen_netdev_ops;       /* xen_nic.c         */
 
 void xen_set_display(int domid, DisplayState *ds);
 
+/* configuration (aka xenbus setup) */
+void xen_config_cleanup(void);
+int xen_config_dev_blk(DriveInfo *disk);
+int xen_config_dev_nic(NICInfo *nic);
+
diff --git a/hw/xen-config.c b/hw/xen-config.c
new file mode 100644
index 0000000..112cfcf
--- /dev/null
+++ b/hw/xen-config.c
@@ -0,0 +1,140 @@
+#include "xen-backend.h"
+
+/* ------------------------------------------------------------- */
+
+struct xs_dirs {
+    char *xs_dir;
+    struct list_head list;
+};
+static LIST_HEAD (xs_cleanup);
+
+static int xen_config_cleanup_dir(char *dir)
+{
+    struct xs_dirs *d;
+
+    d = malloc(sizeof(*d));
+    d->xs_dir = dir;
+    list_add_tail(&d->list, &xs_cleanup);
+    return 0;
+}
+
+void xen_config_cleanup(void)
+{
+    struct list_head *item;
+    struct xs_dirs *d;
+
+    fprintf(stderr, "xen be: %s\n", __FUNCTION__);
+    list_for_each(item, &xs_cleanup) {
+	d = list_entry(item, struct xs_dirs, list);
+	xs_rm(xenstore, 0, d->xs_dir);
+    }
+}
+
+/* ------------------------------------------------------------- */
+
+static int xen_config_dev_mkdir(char *dev, int p)
+{
+    struct xs_permissions perms = {
+	.id    = xen_domid,
+	.perms = p,
+    };
+
+    if (!xs_mkdir(xenstore, 0, dev)) {
+	fprintf(stderr, "xs_mkdir %s: failed\n", dev);
+	return -1;
+    }
+    xen_config_cleanup_dir(strdup(dev));
+
+    if (!xs_set_permissions(xenstore, 0, dev, &perms, 1)) {
+	fprintf(stderr, "%s: xs_set_permissions failed\n", __FUNCTION__);
+	return -1;
+    }
+    return 0;
+}
+
+static int xen_config_dev_dirs(char *ftype, char *btype, int vdev,
+			       char *fe, char *be, int len)
+{
+    snprintf(fe, len, "/local/domain/%d/device/%s/%d",
+	     xen_domid, ftype, vdev);
+    snprintf(be, len, "/local/domain/0/backend/%s/%d/%d",
+	     btype, xen_domid, vdev);
+
+    xen_config_dev_mkdir(fe, XS_PERM_WRITE);
+    xen_config_dev_mkdir(be, XS_PERM_READ);
+    return 0;
+}
+
+static int xen_config_dev_all(char *fe, char *be)
+{
+    /* frontend */
+#if 0
+    xenstore_write_str(fe, "protocol",
+			    xen_config_dev_protocol(xen));
+#endif
+    xenstore_write_int(fe, "state",           XenbusStateInitialising);
+    xenstore_write_int(fe, "backend-id",      0);
+    xenstore_write_str(fe, "backend",         be);
+
+    /* backend */
+    xenstore_write_str(be, "domain",          qemu_name ? qemu_name : "no-name");
+    xenstore_write_int(be, "online",          1);
+    xenstore_write_int(be, "state",           XenbusStateInitialising);
+    xenstore_write_int(be, "frontend-id",     xen_domid);
+    xenstore_write_str(be, "frontend",        fe);
+
+    return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+int xen_config_dev_blk(DriveInfo *disk)
+{
+    char fe[256], be[256];
+    int vdev = 202 * 256 + 16 * disk->unit;
+    int cdrom = disk->bdrv->type == BDRV_TYPE_CDROM;
+    char *devtype = cdrom ? "cdrom" : "disk";
+    char *mode    = cdrom ? "r"     : "w";
+
+    snprintf(disk->bdrv->device_name, sizeof(disk->bdrv->device_name),
+	     "xvd%c", 'a' + disk->unit);
+    fprintf(stderr, "xen be: config disk %d [%s]: %s\n",
+	    disk->unit, disk->bdrv->device_name, disk->bdrv->filename);
+    xen_config_dev_dirs("vbd", "qdisk", vdev, fe, be, sizeof(fe));
+
+    /* frontend */
+    xenstore_write_int(fe, "virtual-device",  vdev);
+    xenstore_write_str(fe, "device-type",     devtype);
+
+    /* backend */
+    xenstore_write_str(be, "dev",             disk->bdrv->device_name);
+    xenstore_write_str(be, "type",            "file");
+    xenstore_write_str(be, "params",          disk->bdrv->filename);
+    xenstore_write_str(be, "mode",            mode);
+
+    /* common stuff */
+    return xen_config_dev_all(fe, be);
+}
+
+int xen_config_dev_nic(NICInfo *nic)
+{
+    char fe[256], be[256];
+    char mac[20];
+
+    snprintf(mac, sizeof(mac), "%02x:%02x:%02x:%02x:%02x:%02x",
+	     nic->macaddr[0], nic->macaddr[1], nic->macaddr[2],
+	     nic->macaddr[3], nic->macaddr[4], nic->macaddr[5]);
+    fprintf(stderr, "xen be: config nic %d: mac=\"%s\"\n", nic->vlan->id, mac);
+    xen_config_dev_dirs("vif", "qnic", nic->vlan->id, fe, be, sizeof(fe));
+
+    /* frontend */
+    xenstore_write_int(fe, "handle",     nic->vlan->id);
+    xenstore_write_str(fe, "mac",        mac);
+
+    /* backend */
+    xenstore_write_int(be, "handle",     nic->vlan->id);
+    xenstore_write_str(be, "mac",        mac);
+
+    /* common stuff */
+    return xen_config_dev_all(fe, be);
+}
diff --git a/hw/xen-machine.c b/hw/xen-machine.c
index 3fa4079..380a61b 100644
--- a/hw/xen-machine.c
+++ b/hw/xen-machine.c
@@ -43,6 +43,7 @@ static void xenpv_init(ram_addr_t ram_size, int vga_ram_size,
 		       const char *cpu_model)
 {
     CPUState *env;
+    int i, index;
 
     /* create dummy cpu, halted */
     if (cpu_model == NULL) {
@@ -55,9 +56,28 @@ static void xenpv_init(ram_addr_t ram_size, int vga_ram_size,
     env = cpu_init(cpu_model);
     env->halted = 1;
 
-    /* setup xen backend handlers */
+    /* backend core init */
     xen_be_init();
 
+    /* configure disks */
+    for (i = 0; i < 16; i++) {
+        index = drive_get_index(IF_XEN, 0, i);
+	if (index == -1)
+	    continue;
+	xen_config_dev_blk(drives_table + index);
+    }
+
+    /* configure nics */
+    for (i = 0; i < nb_nics; i++) {
+	if (nd_table[i].model && 0 != strcmp(nd_table[i].model, "xen"))
+	    continue;
+        xen_config_dev_nic(nd_table + i);
+    }
+
+    /* config cleanup hook */
+    atexit(xen_config_cleanup);
+
+    /* backend driver init */
     xen_be_register("console", &xen_console_ops);
     xen_be_register("vkbd", &xen_kbdmouse_ops);
     xen_be_register("vfb", &xen_framebuffer_ops);
-- 
1.5.4.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu
       [not found] <m2n.s.1KNSd3-002QXI@chiark.greenend.org.uk>
@ 2008-07-28 13:31 ` Ian Jackson
  2008-07-28 14:33   ` Anthony Liguori
  2008-07-28 14:43   ` Gerd Hoffmann
  0 siblings, 2 replies; 64+ messages in thread
From: Ian Jackson @ 2008-07-28 13:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: xen-devel

Gerd Hoffmann writes ("[Qemu-devel] [PATCH 0/7] merge some xen bits into qemu"):
> Here are a bunch of patches which start adding xen support to qemu.
> Overview (individual patches have longer descriptions):

Just to clarify: as far as I can tell from the description,
this code has scant relationship with Xen upstream.

I'm generally in favour of pushing functionality out of the Xen branch
of qemu into upstream.  But going by Gerd Hoffman's description I
don't think that's what his branch is.  His code doesn't appear to be
related to the Xen branch of qemu that we are using.

For example,

> With the first four patches in place upstream qemu can replace xen's
> qemu-dm for paravirtual domains.  The block and nic backend drivers are
> full userspace implementations using the grant table device (gntdev).

we only use qemu-dm in paravirtualised domains for certain marginal
functions - in many cases it is not used at all.  Certainly the
functionality Gerd describes, such as xen backend block and network
drivers, are not in our qemu tree and we do not intend for them to be
there.

In a Xen installation this functionality is in the dom0 (host) kernel.


As far as I can see much of Gerd Hoffman's intended submission is
effectively an _emulator_ for Xen guests.  That is, it emulates a Xen
host without being one, so that a Xen domU can be run without the Xen
hypervisor.  Am I right, Gerd ?

I don't think there's anything wrong with that from a qemu point of
view.  Obviously we think that the genuine Xen hypervisor is much
better :-) but it is right for people to have a choice, and having
qemu emulate more environments is generally good.

But if this functionality is to go into qemu upstream perhaps it
should be distinguished from `real Xen' functions, because otherwise
users are going to become very very confused.

Ian.

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 1/7] xen: groundwork for xen support
  2008-07-28 13:17 ` [Qemu-devel] [PATCH 1/7] xen: groundwork for xen support Gerd Hoffmann
@ 2008-07-28 14:04   ` Anthony Liguori
  2008-07-28 14:52     ` Gerd Hoffmann
  2008-07-28 23:14     ` Samuel Thibault
  0 siblings, 2 replies; 64+ messages in thread
From: Anthony Liguori @ 2008-07-28 14:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: xen-devel, Gerd Hoffmann

Gerd Hoffmann wrote:
> - configure script and build system changes.
> - wind up new machine type.
> - add -domid command line option.
> - allow xenpv machines run without disk and kernel specified.
>
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  Makefile.target       |    8 +++++
>  configure             |   27 ++++++++++++++++
>  hw/boards.h           |    4 ++
>  hw/xen-machine.c      |   83 +++++++++++++++++++++++++++++++++++++++++++++++++
>  hw/xen.h              |   12 +++++++
>  target-i386/machine.c |    3 ++
>  vl.c                  |   25 +++++++++++++--
>  7 files changed, 159 insertions(+), 3 deletions(-)
>  create mode 100644 hw/xen-machine.c
>  create mode 100644 hw/xen.h
>
> diff --git a/Makefile.target b/Makefile.target
> index ff105c1..4f42582 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -515,6 +515,14 @@ CPPFLAGS += $(CONFIG_VNC_TLS_CFLAGS)
>  LIBS += $(CONFIG_VNC_TLS_LIBS)
>  endif
>  
> +# xen backend driver support
> +XEN_OBJS := xen-machine.o
> +ifeq ($(CONFIG_XEN), yes)
> +  OBJS += $(XEN_OBJS)
> +  LIBS += $(XEN_LIBS)
> +  $(XEN_OBJS) : CFLAGS += -Wall -Wmissing-prototypes -Wstrict-prototypes
> +endif
> +
>  # SCSI layer
>  OBJS+= lsi53c895a.o esp.o
>  
> diff --git a/configure b/configure
> index fd04766..34516b9 100755
> --- a/configure
> +++ b/configure
> @@ -108,6 +108,7 @@ uname_release=""
>  curses="yes"
>  nptl="yes"
>  mixemu="no"
> +xen="no"
>  
>  # OS specific
>  targetos=`uname -s`
> @@ -202,6 +203,7 @@ linux="yes"
>  linux_user="yes"
>  if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
>      kqemu="yes"
> +    xen="yes"
>      audio_possible_drivers="$audio_possible_drivers fmod"
>  fi
>  ;;
> @@ -285,6 +287,8 @@ for opt do
>    ;;
>    --disable-kqemu) kqemu="no"
>    ;;
> +  --disable-xen) xen="no"
> +  ;;
>    --disable-brlapi) brlapi="no"
>    ;;
>    --enable-profiler) profiler="yes"
> @@ -421,6 +425,7 @@ echo "                           Available drivers: $audio_possible_drivers"
>  echo "  --audio-card-list=LIST   set list of additional emulated audio cards"
>  echo "                           Available cards: ac97 adlib cs4231a gus"
>  echo "  --enable-mixemu          enable mixer emulation"
> +echo "  --disable-xen            disable xen backend driver support"
>  echo "  --disable-brlapi         disable BrlAPI"
>  echo "  --disable-vnc-tls        disable TLS encryption for VNC server"
>  echo "  --disable-curses         disable curses output"
> @@ -681,6 +686,22 @@ else
>  fi
>  
>  ##########################################
> +# xen probe
> +
> +if test "$xen" = "yes" ; then
> +cat > $TMPC <<EOF
> +#include <xs.h>
> +#include <xenctrl.h>
> +int main(void) { xs_daemon_open; xc_interface_open; }
> +EOF
> +   if $cc $ARCH_CFLAGS -c -o $TMPO $TMPC -lxenstore -lxenctrl 2> /dev/null ; then
> +      :
> +   else
> +      xen="no"
> +   fi
> +fi
> +
> +##########################################
>  # SDL probe
>  
>  sdl_too_old=no
> @@ -916,6 +937,7 @@ if test -n "$sparc_cpu"; then
>      echo "Target Sparc Arch $sparc_cpu"
>  fi
>  echo "kqemu support     $kqemu"
> +echo "xen support       $xen"
>  echo "brlapi support    $brlapi"
>  echo "Documentation     $build_docs"
>  [ ! -z "$uname_release" ] && \
> @@ -1167,6 +1189,11 @@ if test "$brlapi" = "yes" ; then
>    echo "#define CONFIG_BRLAPI 1" >> $config_h
>    echo "BRLAPI_LIBS=-lbrlapi" >> $config_mak
>  fi
> +if test "$xen" = "yes" ; then
> +  echo "CONFIG_XEN=yes" >> $config_mak
> +  echo "#define CONFIG_XEN 1" >> $config_h
> +  echo "XEN_LIBS=-lxenstore -lxenctrl" >> $config_mak
> +fi
>  
>  # XXX: suppress that
>  if [ "$bsd" = "yes" ] ; then
> diff --git a/hw/boards.h b/hw/boards.h
> index 22ac332..5931720 100644
> --- a/hw/boards.h
> +++ b/hw/boards.h
> @@ -29,6 +29,10 @@ extern QEMUMachine bareetraxfs_machine;
>  extern QEMUMachine pc_machine;
>  extern QEMUMachine isapc_machine;
>  
> +/* xen_machine.c */
> +extern QEMUMachine xenpv_machine;
> +extern QEMUMachine xenfv_machine;
>   

Why does xenfv need its own machine type?

>  /* ppc.c */
>  extern QEMUMachine prep_machine;
>  extern QEMUMachine core99_machine;
> diff --git a/hw/xen-machine.c b/hw/xen-machine.c
> new file mode 100644
> index 0000000..88f0f6e
> --- /dev/null
> +++ b/hw/xen-machine.c
> @@ -0,0 +1,83 @@
> +/*
> + * QEMU Xen PV Machine
> + *
> + * Copyright (c) 2007,08 Red Hat
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +
> +#include "hw.h"
> +#include "boards.h"
> +
> +#include "xen.h"
> +
> +/* -------------------------------------------------------------------- */
> +/* variables                                                            */
> +
> +int xen_domid;
> +
> +/* -------------------------------------------------------------------- */
> +/* paravirtualized xen guests                                           */
> +
> +static void xenpv_init(ram_addr_t ram_size, int vga_ram_size,
> +		       const char *boot_device, DisplayState *ds,
> +		       const char *kernel_filename,
> +		       const char *kernel_cmdline,
> +		       const char *initrd_filename,
> +		       const char *cpu_model)
> +{
> +    CPUState *env;
> +
> +    /* create dummy cpu, halted */
> +    if (cpu_model == NULL) {
> +#ifdef TARGET_X86_64
> +        cpu_model = "qemu64";
> +#else
> +        cpu_model = "qemu32";
> +#endif
> +    }
> +    env = cpu_init(cpu_model);
> +    env->halted = 1;
> +}
> +
> +QEMUMachine xenpv_machine = {
> +    "xenpv",
> +    "paravirtualized Xen machine",
> +    xenpv_init,
> +};
> +
> +/* -------------------------------------------------------------------- */
> +/* fully virtualized xen guests                                         */
> +
> +static void xenfv_init(ram_addr_t ram_size, int vga_ram_size,
> +		       const char *boot_device, DisplayState *ds,
> +		       const char *kernel_filename,
> +		       const char *kernel_cmdline,
> +		       const char *initrd_filename,
> +		       const char *cpu_model)
> +{
> +    /* to be done */
> +    fprintf(stderr, "%s: not implemented yet\n", __FUNCTION__);
> +}
> +
> +QEMUMachine xenfv_machine = {
> +    "xenfv",
> +    "fully virtualized Xen machine",
> +    xenfv_init,
> +};
> diff --git a/hw/xen.h b/hw/xen.h
> new file mode 100644
> index 0000000..19349b5
> --- /dev/null
> +++ b/hw/xen.h
> @@ -0,0 +1,12 @@
> +/*
> + * public xen header
> + *   stuff needed outside xen-*.c, i.e. interfaces to qemu.
> + *   should not depend on any xen headers being present in
> + *   /usr/include/xen, so it can be included unconditionally.
> + *
> + * internal bits for the xen backend drivers are in xen-backend.h
> + */
> +
> +/* xen-machine.c */
> +extern int xen_domid;
> +
> diff --git a/target-i386/machine.c b/target-i386/machine.c
> index 91dbd55..98ece17 100644
> --- a/target-i386/machine.c
> +++ b/target-i386/machine.c
> @@ -9,6 +9,9 @@ void register_machines(void)
>  {
>      qemu_register_machine(&pc_machine);
>      qemu_register_machine(&isapc_machine);
> +#ifdef CONFIG_XEN
> +    qemu_register_machine(&xenpv_machine);
> +#endif
>  }
>  
>  static void cpu_put_seg(QEMUFile *f, SegmentCache *dt)
> diff --git a/vl.c b/vl.c
> index 8801615..8aef3bd 100644
> --- a/vl.c
> +++ b/vl.c
> @@ -29,6 +29,7 @@
>  #include "hw/audiodev.h"
>  #include "hw/isa.h"
>  #include "hw/baum.h"
> +#include "hw/xen.h"
>  #include "net.h"
>  #include "console.h"
>  #include "sysemu.h"
> @@ -7737,6 +7738,9 @@ static void help(int exitcode)
>             "-startdate      select initial date of the clock\n"
>             "-icount [N|auto]\n"
>             "                Enable virtual instruction counter with 2^N clock ticks per instruction\n"
> +#ifdef CONFIG_XEN
> +	   "-domid          specify xen guest domain id\n"
> +#endif
>             "\n"
>             "During emulation, the following keys are useful:\n"
>             "ctrl-alt-f      toggle full screen\n"
> @@ -7842,6 +7846,9 @@ enum {
>      QEMU_OPTION_startdate,
>      QEMU_OPTION_tb_size,
>      QEMU_OPTION_icount,
> +#ifdef CONFIG_XEN
> +    QEMU_OPTION_domid,
> +#endif
>  };
>  
>  typedef struct QEMUOption {
> @@ -7930,6 +7937,9 @@ const QEMUOption qemu_options[] = {
>  #ifdef CONFIG_CURSES
>      { "curses", 0, QEMU_OPTION_curses },
>  #endif
> +#ifdef CONFIG_XEN
> +    { "domid", HAS_ARG, QEMU_OPTION_domid },
> +#endif
>  
>      /* temporary options */
>      { "usb", 0, QEMU_OPTION_usb },
> @@ -8150,7 +8160,7 @@ int main(int argc, char **argv)
>  #endif
>      uint32_t boot_devices_bitmap = 0;
>      int i;
> -    int snapshot, linux_boot, net_boot;
> +    int snapshot, linux_boot, net_boot, nodisk_ok;
>      const char *initrd_filename;
>      const char *kernel_filename, *kernel_cmdline;
>      const char *boot_devices = "";
> @@ -8787,6 +8797,11 @@ int main(int argc, char **argv)
>                      icount_time_shift = strtol(optarg, NULL, 0);
>                  }
>                  break;
> +#ifdef CONFIG_XEN
> +            case QEMU_OPTION_domid:
> +                xen_domid = atoi(optarg);
> +                break;
> +#endif
>              }
>          }
>      }
> @@ -8852,9 +8867,13 @@ int main(int argc, char **argv)
>      linux_boot = (kernel_filename != NULL);
>      net_boot = (boot_devices_bitmap >> ('n' - 'a')) & 0xF;
>  
> -    /* XXX: this should not be: some embedded targets just have flash */
> +    /* need a disk for this machine to boot ? */
> +    /* XXX: add embedded targets which just have flash */
> +    nodisk_ok = 0;
> +    if (0 == strcmp(machine->name, "xenpv"))
> +	nodisk_ok = 1;
>      if (!linux_boot && net_boot == 0 &&
> -        nb_drives_opt == 0)
> +        !nodisk_ok && nb_drives_opt == 0)
>          help(1);

This patch is pretty clean with the exception of this bit.  I think a 
cleaner way to do this would be to let the machine types specify whether 
a disk is needed or not.

Regards,

Anthony LIguori

>  
>      if (!linux_boot && *kernel_cmdline != '\0') {
>   

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 2/7] xen: backend driver core
  2008-07-28 13:17 ` [Qemu-devel] [PATCH 2/7] xen: backend driver core Gerd Hoffmann
@ 2008-07-28 14:13   ` Anthony Liguori
  2008-07-28 15:51     ` Gerd Hoffmann
  0 siblings, 1 reply; 64+ messages in thread
From: Anthony Liguori @ 2008-07-28 14:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: xen-devel, Gerd Hoffmann

Gerd Hoffmann wrote:
> This patch adds infrastructure for xen backend drivers living in qemu,
> so drivers don't need to implement common stuff on their own.  It's
> mostly xenbus management stuff: some functions to access xentore,
> setting up xenstore watches, callbacks on device discovery and state
> changes, handle event channel, ...
>
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  Makefile.target  |    2 +-
>  hw/list.h        |  169 ++++++++++++++
>  hw/xen-backend.c |  663 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  hw/xen-backend.h |  116 ++++++++++
>  hw/xen-machine.c |    5 +-
>  5 files changed, 953 insertions(+), 2 deletions(-)
>  create mode 100644 hw/list.h
>  create mode 100644 hw/xen-backend.c
>  create mode 100644 hw/xen-backend.h
>
> diff --git a/Makefile.target b/Makefile.target
> index 4f42582..0451048 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -516,7 +516,7 @@ LIBS += $(CONFIG_VNC_TLS_LIBS)
>  endif
>  
>  # xen backend driver support
> -XEN_OBJS := xen-machine.o
> +XEN_OBJS := xen-machine.o xen-backend.o
>  ifeq ($(CONFIG_XEN), yes)
>    OBJS += $(XEN_OBJS)
>    LIBS += $(XEN_LIBS)
> diff --git a/hw/list.h b/hw/list.h
> new file mode 100644
> index 0000000..fa9f790
> --- /dev/null
> +++ b/hw/list.h
>   

There's already a list implementation in audio/sys-queue.h

> diff --git a/hw/xen-backend.c b/hw/xen-backend.c
> new file mode 100644
> index 0000000..4819624
> --- /dev/null
> +++ b/hw/xen-backend.c
> @@ -0,0 +1,663 @@
> +/*
> + *  xen backend driver infrastructure
> + *
> + *  This program is free software; you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation; under version 2 of the License.
> + *
> + *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
> + */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <stdarg.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <fcntl.h>
> +#include <inttypes.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <sys/mman.h>
> +#include <sys/signal.h>
> +
> +#include <xs.h>
> +#include <xenctrl.h>
> +#include <xen/grant_table.h>
> +
> +#include "hw.h"
> +#include "qemu-char.h"
> +#include "xen-backend.h"
> +
> +/* ------------------------------------------------------------- */
> +
> +/* public */
> +int xen_xc;
> +struct xs_handle *xenstore = NULL;
> +
> +/* private */
> +static LIST_HEAD(xendevs);
> +static const char *root = "/local/domain/0/backend";
> +static int debug = 0;
> +
> +/* ------------------------------------------------------------- */
>   

I think it would be good to provide some more commenting in this file.  
Just a high level description of XenStore and how all of this stuff fits 
together would be nice.

> +int xenstore_write_str(const char *base, const char *node, const char *val)
> +{
> +    char abspath[BUFSIZE];
> +
> +    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
> +    if (!xs_write(xenstore, 0, abspath, val, strlen(val)))
> +	return -1;
> +    return 0;
> +}
> +
> +char *xenstore_read_str(const char *base, const char *node)
> +{
> +    char abspath[BUFSIZE];
> +    unsigned int len;
> +
> +    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
> +    return xs_read(xenstore, 0, abspath, &len);
> +}
> +
> +int xenstore_write_int(const char *base, const char *node, int ival)
> +{
> +    char val[32];
> +
> +    snprintf(val, sizeof(val), "%d", ival);
> +    return xenstore_write_str(base, node, val);
> +}
> +
> +int xenstore_read_int(const char *base, const char *node, int *ival)
> +{
> +    char *val;
> +    int rc = -1;
> +
> +    val = xenstore_read_str(base, node);
> +    if (val && 1 == sscanf(val, "%d", ival))
> +	rc = 0;
> +    free(val);
> +    return rc;
> +}
> +
> +int xenstore_write_be_str(struct xendev *xendev, const char *node, const char *val)
> +{
> +    return xenstore_write_str(xendev->be, node, val);
> +}
> +
> +int xenstore_write_be_int(struct xendev *xendev, const char *node, int ival)
> +{
> +    return xenstore_write_int(xendev->be, node, ival);
> +}
> +
> +char *xenstore_read_be_str(struct xendev *xendev, const char *node)
> +{
> +    return xenstore_read_str(xendev->be, node);
> +}
> +
> +int xenstore_read_be_int(struct xendev *xendev, const char *node, int *ival)
> +{
> +    return xenstore_read_int(xendev->be, node, ival);
> +}
> +
> +char *xenstore_read_fe_str(struct xendev *xendev, const char *node)
> +{
> +    return xenstore_read_str(xendev->fe, node);
> +}
> +
> +int xenstore_read_fe_int(struct xendev *xendev, const char *node, int *ival)
> +{
> +    return xenstore_read_int(xendev->fe, node, ival);
> +}
> +
> +/* ------------------------------------------------------------- */
> +
> +const char *xenbus_strstate(enum xenbus_state state)
> +{
> +	static const char *const name[] = {
> +		[ XenbusStateUnknown      ] = "Unknown",
> +		[ XenbusStateInitialising ] = "Initialising",
> +		[ XenbusStateInitWait     ] = "InitWait",
> +		[ XenbusStateInitialised  ] = "Initialised",
> +		[ XenbusStateConnected    ] = "Connected",
> +		[ XenbusStateClosing      ] = "Closing",
> +		[ XenbusStateClosed	  ] = "Closed",
> +	};
> +	return (state < ARRAY_SIZE(name)) ? name[state] : "INVALID";
> +}
> +
> +int xen_be_set_state(struct xendev *xendev, enum xenbus_state state)
> +{
> +    int rc;
> +
> +    rc = xenstore_write_be_int(xendev, "state", state);
> +    if (0 != rc)
>   

It's a nit, but try to avoid the defensive ifs.

> +	return rc;
> +    xen_be_printf(xendev, 1, "backend state: %s -> %s\n",
> +		  xenbus_strstate(xendev->be_state), xenbus_strstate(state));
> +    xendev->be_state = state;
> +    return 0;
> +}
> +
> +/* ------------------------------------------------------------- */
> +
> +struct xendev *xen_be_find_xendev(char *type, int dom, int dev)
> +{
> +    struct xendev *xendev;
> +    struct list_head *item;
> +
> +    list_for_each(item, &xendevs) {
> +	xendev = list_entry(item, struct xendev, next);
> +	if (xendev->dom != dom)
> +	    continue;
> +	if (xendev->dev != dev)
> +	    continue;
> +	if (0 != strcmp(xendev->type, type))
> +	    continue;
> +	return xendev;
> +    }
> +    return NULL;
> +}
> +
> +/*
> + * get xen backend device, allocate a new one if it doesn't exist.
> + */
> +static struct xendev *xen_be_get_xendev(char *type, int dom, int dev,
> +					struct devops *ops)
> +{
> +    struct xendev *xendev;
> +
> +    xendev = xen_be_find_xendev(type, dom, dev);
> +    if (xendev)
> +	return xendev;
> +
> +    /* init new xendev */
> +    xendev = malloc(ops->size);
> +    memset(xendev,0,ops->size);
>   

qemu_mallocz()

> +    xendev->type  = type;
> +    xendev->dom   = dom;
> +    xendev->dev   = dev;
> +    xendev->ops   = ops;
> +    snprintf(xendev->be, sizeof(xendev->be), "%s/%s/%d/%d",
> +	     root, xendev->type, xendev->dom, xendev->dev);
> +    snprintf(xendev->name, sizeof(xendev->name), "%s-%d",
> +	     xendev->type, xendev->dev);
> +
> +    xendev->debug      = debug;
> +    xendev->local_port = -1;
> +
> +    xendev->evtchndev = xc_evtchn_open();
> +    if (xendev->evtchndev < 0) {
> +	fprintf(stderr, "can't open evtchn device\n");
> +	free(xendev);
>   

qemu_free()

Considering all you're doing, the patch looks pretty nice.

Regards,

Anthony Liguori

> +	return NULL;
> +    }
> +    fcntl(xc_evtchn_fd(xendev->evtchndev), F_SETFD, FD_CLOEXEC);
> +
> +    if (ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
> +	xendev->gnttabdev = xc_gnttab_open();
> +	if (xendev->gnttabdev < 0) {
> +	    fprintf(stderr, "can't open gnttab device\n");
> +	    xc_evtchn_close(xendev->evtchndev);
> +	    free(xendev);
> +	    return NULL;
> +	}
> +    } else {
> +	xendev->gnttabdev = -1;
> +    }
> +
> +    list_add_tail(&xendev->next, &xendevs);
> +
> +    if (xendev->ops->alloc)
> +	xendev->ops->alloc(xendev);
> +
> +    return xendev;
> +}
> +
> +/*
> + * release xen backend device.
> + */
> +static struct xendev *xen_be_del_xendev(int dom, int dev)
> +{
> +    struct xendev *xendev;
> +    struct list_head *item, *tmp;
> +
> +    list_for_each_safe(item, tmp, &xendevs) {
> +	xendev = list_entry(item, struct xendev, next);
> +	if (xendev->dom != dom)
> +	    continue;
> +	if (xendev->dev != dev && dev != -1)
> +	    continue;
> +
> +	if (xendev->ops->free)
> +	    xendev->ops->free(xendev);
> +
> +	if (xendev->fe) {
> +	    char token[BUFSIZE];
> +	    snprintf(token, sizeof(token), "fe:%p", xendev);
> +	    xs_unwatch(xenstore, xendev->fe, token);
> +	    free(xendev->fe);
> +	}
> +
> +	if (xendev->evtchndev >= 0)
> +	    xc_evtchn_close(xendev->evtchndev);
> +	if (xendev->gnttabdev >= 0)
> +	    xc_gnttab_close(xendev->gnttabdev);
> +
> +	list_del(&xendev->next);
> +	free(xendev);
> +    }
> +    return NULL;
> +}
> +
> +/*
> + * Sync internal data structures on xenstore updates.
> + * Node specifies the changed field.  node = NULL means
> + * update all fields (used for initialization).
> + */
> +static void xen_be_backend_changed(struct xendev *xendev, const char *node)
> +{
> +    if (NULL == node  ||  0 == strcmp(node, "online")) {
> +	if (-1 == xenstore_read_be_int(xendev, "online", &xendev->online))
> +	    xendev->online = 0;
> +    }
> +
> +    if (node) {
> +	xen_be_printf(xendev, 2, "backend update: %s\n", node);
> +	if (xendev->ops->backend_changed)
> +	    xendev->ops->backend_changed(xendev, node);
> +    }
> +}
> +
> +static void xen_be_frontend_changed(struct xendev *xendev, const char *node)
> +{
> +    int fe_state;
> +
> +    if (NULL == node  ||  0 == strcmp(node, "state")) {
> +	if (-1 == xenstore_read_fe_int(xendev, "state", &fe_state))
> +	    fe_state = XenbusStateUnknown;
> +	if (xendev->fe_state != fe_state)
> +	    xen_be_printf(xendev, 1, "frontend state: %s -> %s\n",
> +			  xenbus_strstate(xendev->fe_state),
> +			  xenbus_strstate(fe_state));
> +	xendev->fe_state = fe_state;
> +    }
> +    if (NULL == node  ||  0 == strcmp(node, "protocol")) {
> +	free(xendev->protocol);
> +	xendev->protocol = xenstore_read_fe_str(xendev, "protocol");
> +	if (xendev->protocol)
> +	    xen_be_printf(xendev, 1, "frontend protocol: %s\n", xendev->protocol);
> +    }
> +
> +    if (node) {
> +	xen_be_printf(xendev, 2, "frontend update: %s\n", node);
> +	if (xendev->ops->frontend_changed)
> +	    xendev->ops->frontend_changed(xendev, node);
> +    }
> +}
> +
> +/* ------------------------------------------------------------- */
> +/* Check for possible state transitions and perform them.        */
> +
> +/*
> + * Initial xendev setup.  Read frontend path, register watch for it.
> + * Should succeed once xend finished setting up the backend device.
> + *
> + * Also sets initial state (-> Initializing) when done.  Which
> + * only affects the xendev->be_state variable as xenbus should
> + * already be put into that state by xend.
> + */
> +static int xen_be_try_setup(struct xendev *xendev)
> +{
> +    char token[BUFSIZE];
> +    int be_state;
> +
> +    if (-1 == xenstore_read_be_int(xendev, "state", &be_state)) {
> +	xen_be_printf(xendev, 0, "reading backend state failed\n");
> +	return -1;
> +    }
> +
> +    if (be_state != XenbusStateInitialising) {
> +	xen_be_printf(xendev, 0, "initial backend state is wrong (%s)\n",
> +		      xenbus_strstate(be_state));
> +	return -1;
> +    }
> +
> +    xendev->fe = xenstore_read_be_str(xendev, "frontend");
> +    if (NULL == xendev->fe) {
> +	xen_be_printf(xendev, 0, "reading frontend path failed\n");
> +	return -1;
> +    }
> +
> +    /* setup frontend watch */
> +    snprintf(token, sizeof(token), "fe:%p", xendev);
> +    if (!xs_watch(xenstore, xendev->fe, token)) {
> +	xen_be_printf(xendev, 0, "watching frontend path (%s) failed\n",
> +		      xendev->fe);
> +	return -1;
> +    }
> +    xen_be_set_state(xendev, XenbusStateInitialising);
> +
> +    xen_be_backend_changed(xendev, NULL);
> +    xen_be_frontend_changed(xendev, NULL);
> +    return 0;
> +}
> +
> +/*
> + * Try initialize xendev.  Prepare everything the backend can do
> + * without synchronizing with the frontend.  Fakes hotplug-status.  No
> + * hotplug involved here because this is about userspace drivers, thus
> + * there are kernel backend devices which could invoke hotplug.
> + *
> + * Goes to InitWait on success.
> + */
> +static int xen_be_try_init(struct xendev *xendev)
> +{
> +    int rc = 0;
> +
> +    if (!xendev->online) {
> +	xen_be_printf(xendev, 1, "not online\n");
> +	return -1;
> +    }
> +
> +    if (xendev->ops->init)
> +	rc = xendev->ops->init(xendev);
> +    if (0 != rc) {
> +	xen_be_printf(xendev, 1, "init() failed\n");
> +	return rc;
> +    }
> +
> +    xenstore_write_be_str(xendev, "hotplug-status", "connected");
> +    xen_be_set_state(xendev, XenbusStateInitWait);
> +    return 0;
> +}
> +
> +/*
> + * Try to connect xendev.  Depends on the frontend being ready
> + * for it (shared ring and evtchn info in xenstore, state being
> + * Initialised or Connected).
> + *
> + * Goes to Connected on success.
> + */
> +static int xen_be_try_connect(struct xendev *xendev)
> +{
> +    int rc = 0;
> +
> +    if (xendev->fe_state != XenbusStateInitialised  &&
> +	xendev->fe_state != XenbusStateConnected) {
> +	if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) {
> +	    xen_be_printf(xendev, 2, "frontend not ready, ignoring\n");
> +	} else {
> +	    xen_be_printf(xendev, 2, "frontend not ready (yet)\n");
> +	    return -1;
> +	}
> +    }
> +
> +    if (xendev->ops->connect)
> +	rc = xendev->ops->connect(xendev);
> +    if (0 != rc) {
> +	xen_be_printf(xendev, 0, "connect() failed\n");
> +	return rc;
> +    }
> +
> +    xen_be_set_state(xendev, XenbusStateConnected);
> +
> +#if 0
> +    if (xendev->ops->event)
> +	xendev->ops->event(xendev);
> +#endif
> +    return 0;
> +}
> +
> +/*
> + * Teardown connection.
> + *
> + * Goes to Closed when done.
> + */
> +static void xen_be_disconnect(struct xendev *xendev)
> +{
> +    if (xendev->be_state == XenbusStateClosed)
> +	return;
> +    if (xendev->ops->disconnect)
> +	xendev->ops->disconnect(xendev);
> +    xen_be_set_state(xendev, XenbusStateClosed);
> +}
> +
> +/*
> + * state change dispatcher function
> + */
> +void xen_be_check_state(struct xendev *xendev)
> +{
> +    int rc = 0;
> +
> +    /* frontend may request shutdown from almost anywhere */
> +    if (xendev->fe_state == XenbusStateClosing ||
> +	xendev->fe_state == XenbusStateClosed) {
> +	xen_be_disconnect(xendev);
> +	return;
> +    }
> +
> +    /* check for possible backend state transitions */
> +    for (;;) {
> +	switch (xendev->be_state) {
> +	case XenbusStateUnknown:
> +	    rc = xen_be_try_setup(xendev);
> +	    break;
> +	case XenbusStateInitialising:
> +	    rc = xen_be_try_init(xendev);
> +	    break;
> +	case XenbusStateInitWait:
> +	    rc = xen_be_try_connect(xendev);
> +	    break;
> +	default:
> +	    rc = -1;
> +	}
> +	if (0 != rc)
> +	    break;
> +    }
> +}
> +
> +/* ------------------------------------------------------------- */
> +
> +static int xenstore_scan(char *type, int dom, struct devops *ops)
> +{
> +    struct xendev *xendev;
> +    char path[BUFSIZE], token[BUFSIZE];
> +    char **dev = NULL;
> +    unsigned int cdev, j;
> +
> +    /* setup watch */
> +    snprintf(token, sizeof(token), "be:%p:%d:%p", type, dom, ops);
> +    snprintf(path, sizeof(path), "%s/%s/%d", root, type, dom);
> +    if (!xs_watch(xenstore, path, token)) {
> +	fprintf(stderr, "xen be: watching backend path (%s) failed\n", path);
> +	return -1;
> +    }
> +
> +    /* look for backends */
> +    dev = xs_directory(xenstore, 0, path, &cdev);
> +    if (!dev)
> +	return 0;
> +    for (j = 0; j < cdev; j++) {
> +	xendev = xen_be_get_xendev(type, dom, atoi(dev[j]), ops);
> +	if (NULL == xendev)
> +	    continue;
> +	xen_be_check_state(xendev);
> +    }
> +    free(dev);
> +    return 0;
> +}
> +
> +static void xenstore_update_be(char *watch, char *type, int dom,
> +			       struct devops *ops)
> +{
> +    struct xendev *xendev;
> +    char path[BUFSIZE];
> +    unsigned int len, dev;
> +
> +    len = snprintf(path, sizeof(path), "%s/%s/%d", root, type, dom);
> +    if (0 != strncmp(path, watch, len))
> +	return;
> +    if (2 != sscanf(watch+len, "/%u/%255s", &dev, path)) {
> +	strcpy(path, "");
> +	if (1 != sscanf(watch+len, "/%u", &dev))
> +	    dev = -1;
> +    }
> +    if (-1 == dev)
> +	return;
> +
> +    if (0) {
> +	/* FIXME: detect devices being deleted from xenstore ... */
> +	xen_be_del_xendev(dom, dev);
> +    }
> +
> +    xendev = xen_be_get_xendev(type, dom, dev, ops);
> +    if (NULL != xendev) {
> +	xen_be_backend_changed(xendev, path);
> +	xen_be_check_state(xendev);
> +    }
> +}
> +
> +static void xenstore_update_fe(char *watch, struct xendev *xendev)
> +{
> +    char *node;
> +    unsigned int len;
> +
> +    len = strlen(xendev->fe);
> +    if (0 != strncmp(xendev->fe, watch, len))
> +	return;
> +    if (watch[len] != '/')
> +	return;
> +    node = watch + len + 1;
> +
> +    xen_be_frontend_changed(xendev, node);
> +    xen_be_check_state(xendev);
> +}
> +
> +static void xenstore_update(void *unused)
> +{
> +    char **vec = NULL;
> +    intptr_t type, ops, ptr;
> +    unsigned int dom, count;
> +
> +    vec = xs_read_watch(xenstore, &count);
> +    if (NULL == vec)
> +	goto cleanup;
> +
> +    if (3 == sscanf(vec[XS_WATCH_TOKEN], "be:%" PRIxPTR ":%d:%" PRIxPTR,
> +		    &type, &dom, &ops))
> +	xenstore_update_be(vec[XS_WATCH_PATH], (void*)type, dom, (void*)ops);
> +    if (1 == sscanf(vec[XS_WATCH_TOKEN], "fe:%" PRIxPTR, &ptr))
> +	xenstore_update_fe(vec[XS_WATCH_PATH], (void*)ptr);
> +
> +cleanup:
> +    free(vec);
> +}
> +
> +static void xen_be_evtchn_event(void *opaque)
> +{
> +    struct xendev *xendev = opaque;
> +    evtchn_port_t port;
> +
> +    port = xc_evtchn_pending(xendev->evtchndev);
> +    if (port != xendev->local_port) {
> +	xen_be_printf(xendev, 0, "xc_evtchn_pending returned %d (expected %d)\n",
> +		      port, xendev->local_port);
> +	return;
> +    }
> +    xc_evtchn_unmask(xendev->evtchndev, port);
> +
> +    if (xendev->ops->event)
> +	xendev->ops->event(xendev);
> +}
> +
> +/* -------------------------------------------------------------------- */
> +
> +int xen_be_init(void)
> +{
> +    xenstore = xs_daemon_open();
> +    if (!xenstore) {
> +	fprintf(stderr, "can't connect to xenstored\n");
> +	return -1;
> +    }
> +
> +    if (qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update, NULL, NULL) < 0)
> +	goto err;
> +
> +    xen_xc = xc_interface_open();
> +    if (-1 == xen_xc) {
> +	fprintf(stderr, "can't open xen interface\n");
> +	goto err;
> +    }
> +    return 0;
> +
> +err:
> +    qemu_set_fd_handler(xs_fileno(xenstore), NULL, NULL, NULL);
> +    xs_daemon_close(xenstore);
> +    xenstore = NULL;
> +    
> +    return -1;
> +}
> +
> +int xen_be_register(char *type, struct devops *ops)
> +{
> +    return xenstore_scan(type, xen_domid, ops);
> +}
> +
> +int xen_be_bind_evtchn(struct xendev *xendev)
> +{
> +    if (xendev->local_port != -1)
> +	return 0;
> +    xendev->local_port = xc_evtchn_bind_interdomain
> +	(xendev->evtchndev, xendev->dom, xendev->remote_port);
> +    if (-1 == xendev->local_port) {
> +	xendev->local_port = 0;
> +	return -1;
> +    }
> +    qemu_set_fd_handler(xc_evtchn_fd(xendev->evtchndev),
> +			xen_be_evtchn_event, NULL, xendev);
> +#if 0
> +    xc_evtchn_unmask(xendev->evtchndev, xendev->local_port);
> +#endif
> +    return 0;
> +}
> +
> +void xen_be_unbind_evtchn(struct xendev *xendev)
> +{
> +    if (xendev->local_port == -1)
> +	return;
> +    qemu_set_fd_handler(xc_evtchn_fd(xendev->evtchndev), NULL, NULL, NULL);
> +    xc_evtchn_unbind(xendev->evtchndev, xendev->local_port);
> +    xendev->local_port = -1;
> +}
> +
> +int xen_be_send_notify(struct xendev *xendev)
> +{
> +    return xc_evtchn_notify(xendev->evtchndev, xendev->local_port);
> +}
> +
> +/*
> + * msg_level:
> + *  0 == errors.
> + *  1 == informative debug messages.
> + *  2 == noisy debug messages.
> + *  3 == will flood your log.
> + */
> +void xen_be_printf(struct xendev *xendev, int msg_level, const char *fmt, ...)
> +{
> +    va_list args;
> +
> +    if (msg_level > xendev->debug)
> +	return;
> +    fprintf(stderr, "xen be: %s: ", xendev->name);
> +    va_start(args, fmt);
> +    vfprintf(stderr, fmt, args);
> +    va_end(args);
> +}
> diff --git a/hw/xen-backend.h b/hw/xen-backend.h
> new file mode 100644
> index 0000000..db36ae7
> --- /dev/null
> +++ b/hw/xen-backend.h
> @@ -0,0 +1,116 @@
> +#include <stddef.h>
> +#include <xs.h>
> +#include <xenctrl.h>
> +#include <xen/elfnote.h>
> +#include <xen/elfstructs.h>
> +
> +#include <xen/io/xenbus.h>
> +
> +#include "list.h"
> +
> +#include "hw.h"
> +#include "xen.h"
> +
> +/*
> + * tweaks needed to build with different xen versions
> + *  0x00030205 -> 3.1.0
> + *  0x00030207 -> 3.2.0
> + *  0x00030208 -> unstable
> + */
> +#include <xen/xen-compat.h>
> +#if __XEN_LATEST_INTERFACE_VERSION__ < 0x00030207
> +# define xc_map_foreign_pages xc_map_foreign_batch
> +#endif
> +#if __XEN_LATEST_INTERFACE_VERSION__ < 0x00030208
> +# define xen_mb()  mb()
> +# define xen_rmb() rmb()
> +# define xen_wmb() wmb()
> +#endif
> +
> +/* ------------------------------------------------------------- */
> +
> +#define container_of(ptr, type, member) ({                      \
> +        const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
> +        (type *)( (char *)__mptr - offsetof(type,member) );})
> +
> +/* ------------------------------------------------------------- */
> +
> +#define BUFSIZE 1024
> +
> +struct xendev;
> +
> +/* driver uses grant tables  ->  open gntdev device (xendev->gnttabdev) */
> +#define DEVOPS_FLAG_NEED_GNTDEV   1
> +/* don't expect frontend doing correct state transitions (aka console quirk) */
> +#define DEVOPS_FLAG_IGNORE_STATE  2  
> +
> +struct devops {
> +    size_t    size;
> +    uint32_t  flags;
> +    void      (*alloc)(struct xendev *xendev);
> +    int       (*init)(struct xendev *xendev);
> +    int       (*connect)(struct xendev *xendev);
> +    void      (*event)(struct xendev *xendev);
> +    void      (*disconnect)(struct xendev *xendev);
> +    int       (*free)(struct xendev *xendev);
> +    void      (*backend_changed)(struct xendev *xendev, const char *node);
> +    void      (*frontend_changed)(struct xendev *xendev, const char *node);
> +};
> +
> +struct xendev {
> +    char               *type;
> +    int                dom;
> +    int                dev;
> +    char               name[64];
> +    int                debug;
> +
> +    enum xenbus_state  be_state;
> +    enum xenbus_state  fe_state;
> +    int                online;
> +    char               be[BUFSIZE];
> +    char               *fe;
> +    char               *protocol;
> +    int                remote_port;
> +    int                local_port;
> +
> +    int                evtchndev;
> +    int                gnttabdev;
> +
> +    struct devops      *ops;
> +    struct list_head   next;
> +};
> +
> +/* ------------------------------------------------------------- */
> +
> +/* variables */
> +extern int xen_domid; /* set by cmd line option, in vl.c */
> +extern int xen_xc;
> +extern struct xs_handle *xenstore;
> +
> +/* xenstore helper functions */
> +int xenstore_write_str(const char *base, const char *node, const char *val);
> +int xenstore_write_int(const char *base, const char *node, int ival);
> +char *xenstore_read_str(const char *base, const char *node);
> +int xenstore_read_int(const char *base, const char *node, int *ival);
> +
> +int xenstore_write_be_str(struct xendev *xendev, const char *node, const char *val);
> +int xenstore_write_be_int(struct xendev *xendev, const char *node, int ival);
> +char *xenstore_read_be_str(struct xendev *xendev, const char *node);
> +int xenstore_read_be_int(struct xendev *xendev, const char *node, int *ival);
> +char *xenstore_read_fe_str(struct xendev *xendev, const char *node);
> +int xenstore_read_fe_int(struct xendev *xendev, const char *node, int *ival);
> +
> +const char *xenbus_strstate(enum xenbus_state state);
> +struct xendev *xen_be_find_xendev(char *type, int dom, int dev);
> +void xen_be_check_state(struct xendev *xendev);
> +
> +/* xen backend driver bits */
> +int xen_be_init(void);
> +int xen_be_register(char *type, struct devops *ops);
> +int xen_be_set_state(struct xendev *xendev, enum xenbus_state state);
> +int xen_be_bind_evtchn(struct xendev *xendev);
> +void xen_be_unbind_evtchn(struct xendev *xendev);
> +int xen_be_send_notify(struct xendev *xendev);
> +void xen_be_printf(struct xendev *xendev, int msg_level, const char *fmt, ...)
> +    __attribute__ ((format(printf, 3, 4)));
> +
> diff --git a/hw/xen-machine.c b/hw/xen-machine.c
> index 88f0f6e..798c0a7 100644
> --- a/hw/xen-machine.c
> +++ b/hw/xen-machine.c
> @@ -25,7 +25,7 @@
>  #include "hw.h"
>  #include "boards.h"
>  
> -#include "xen.h"
> +#include "xen-backend.h"
>  
>  /* -------------------------------------------------------------------- */
>  /* variables                                                            */
> @@ -54,6 +54,9 @@ static void xenpv_init(ram_addr_t ram_size, int vga_ram_size,
>      }
>      env = cpu_init(cpu_model);
>      env->halted = 1;
> +
> +    /* setup xen backend handlers */
> +    xen_be_init();
>  }
>  
>  QEMUMachine xenpv_machine = {
>   

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 3/7] xen: add console backend driver.
  2008-07-28 13:17 ` [Qemu-devel] [PATCH 3/7] xen: add console backend driver Gerd Hoffmann
@ 2008-07-28 14:17   ` Anthony Liguori
  2008-07-28 15:43     ` Gerd Hoffmann
  0 siblings, 1 reply; 64+ messages in thread
From: Anthony Liguori @ 2008-07-28 14:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: xen-devel, Gerd Hoffmann

Gerd Hoffmann wrote:
> This patch adds a xenconsole backend driver.  It it based on current
> xen-unstable code.  It has been changed to make use of the common
> backend driver code.
>
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  Makefile.target  |    1 +
>  hw/xen-backend.h |    3 +
>  hw/xen-console.c |  271 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  hw/xen-machine.c |    2 +
>  4 files changed, 277 insertions(+), 0 deletions(-)
>  create mode 100644 hw/xen-console.c
>
> diff --git a/Makefile.target b/Makefile.target
> index 0451048..05619fa 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -517,6 +517,7 @@ endif
>  
>  # xen backend driver support
>  XEN_OBJS := xen-machine.o xen-backend.o
> +XEN_OBJS += xen-console.o
>  ifeq ($(CONFIG_XEN), yes)
>    OBJS += $(XEN_OBJS)
>    LIBS += $(XEN_LIBS)
> diff --git a/hw/xen-backend.h b/hw/xen-backend.h
> index db36ae7..55ffd31 100644
> --- a/hw/xen-backend.h
> +++ b/hw/xen-backend.h
> @@ -114,3 +114,6 @@ int xen_be_send_notify(struct xendev *xendev);
>  void xen_be_printf(struct xendev *xendev, int msg_level, const char *fmt, ...)
>      __attribute__ ((format(printf, 3, 4)));
>  
> +/* actual backend drivers */
> +struct devops xen_console_ops;      /* xen_console.c     */
> +
> diff --git a/hw/xen-console.c b/hw/xen-console.c
> new file mode 100644
> index 0000000..9c67f1b
> --- /dev/null
> +++ b/hw/xen-console.c
> @@ -0,0 +1,271 @@
> +/*
> + *  Copyright (C) International Business Machines  Corp., 2005
> + *  Author(s): Anthony Liguori <aliguori@us.ibm.com>
> + *
> + *  Copyright (C) Red Hat 2007
> + *
> + *  Xen Console
> + *
> + *  This program is free software; you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation; under version 2 of the License.
> + *
> + *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
> + */
> +
> +#include <malloc.h>
> +#include <stdlib.h>
> +#include <errno.h>
> +#include <string.h>
> +#include <sys/select.h>
> +#include <fcntl.h>
> +#include <unistd.h>
> +#include <termios.h>
> +#include <stdarg.h>
> +#include <sys/mman.h>
> +#include <xs.h>
> +#include <xen/io/console.h>
> +#include <xenctrl.h>
> +
> +#include "hw.h"
> +#include "sysemu.h"
> +#include "qemu-char.h"
> +#include "xen-backend.h"
> +
> +#define dolog(val, fmt, ...) fprintf(stderr, fmt "\n", ## __VA_ARGS__)
> +
> +struct buffer {
> +    uint8_t *data;
> +    size_t consumed;
> +    size_t size;
> +    size_t capacity;
> +    size_t max_capacity;
> +};
> +
> +struct xen_console {
> +    struct xendev     xendev;  /* must be first */
> +    struct buffer     buffer;
> +    char              console[BUFSIZE];
> +    int               ring_ref;
> +    void              *sring;
> +    CharDriverState   *chr;
> +    int               backlog;
> +};
> +
> +static void buffer_append(struct xen_console *con)
> +{
> +    struct buffer *buffer = &con->buffer;
> +    XENCONS_RING_IDX cons, prod, size;
> +    struct xencons_interface *intf = con->sring;
> +
> +    cons = intf->out_cons;
> +    prod = intf->out_prod;
> +    xen_mb();
> +
> +    size = prod - cons;
> +    if ((size == 0) || (size > sizeof(intf->out)))
> +	return;
> +
> +    if ((buffer->capacity - buffer->size) < size) {
> +	buffer->capacity += (size + 1024);
> +	buffer->data = realloc(buffer->data, buffer->capacity);
> +	if (buffer->data == NULL) {
> +	    dolog(LOG_ERR, "Memory allocation failed");
> +	    exit(ENOMEM);
> +	}
> +    }
> +
> +    while (cons != prod)
> +	buffer->data[buffer->size++] = intf->out[
> +	    MASK_XENCONS_IDX(cons++, intf->out)];
> +
> +    xen_mb();
> +    intf->out_cons = cons;
> +    xen_be_send_notify(&con->xendev);
> +
> +    if (buffer->max_capacity &&
> +	buffer->size > buffer->max_capacity) {
> +	/* Discard the middle of the data. */
> +
> +	size_t over = buffer->size - buffer->max_capacity;
> +	uint8_t *maxpos = buffer->data + buffer->max_capacity;
> +
> +	memmove(maxpos - over, maxpos, over);
> +	buffer->data = realloc(buffer->data, buffer->max_capacity);
> +	buffer->size = buffer->capacity = buffer->max_capacity;
> +
> +	if (buffer->consumed > buffer->max_capacity - over)
> +	    buffer->consumed = buffer->max_capacity - over;
> +    }
> +}
> +
> +static void buffer_advance(struct buffer *buffer, size_t len)
> +{
> +    buffer->consumed += len;
> +    if (buffer->consumed == buffer->size) {
> +	buffer->consumed = 0;
> +	buffer->size = 0;
> +    }
> +}
> +
> +static int ring_free_bytes(struct xen_console *con)
> +{
> +    struct xencons_interface *intf = con->sring;
> +    XENCONS_RING_IDX cons, prod, space;
> +
> +    cons = intf->in_cons;
> +    prod = intf->in_prod;
> +    xen_mb();
> +
> +    space = prod - cons;
> +    if (space > sizeof(intf->in))
> +	return 0; /* ring is screwed: ignore it */
> +
> +    return (sizeof(intf->in) - space);
> +}
> +
> +static int xencons_can_receive(void *opaque)
> +{
> +    struct xen_console *con = opaque;
> +    return ring_free_bytes(con);
> +}
> +
> +static void xencons_receive(void *opaque, const uint8_t *buf, int len)
> +{
> +    struct xen_console *con = opaque;
> +    struct xencons_interface *intf = con->sring;
> +    XENCONS_RING_IDX prod;
> +    int i, max;
> +
> +    max = ring_free_bytes(con);
> +    /* The can_receive() func limits this, but check again anyway */
> +    if (max < len)
> +	len = max;
> +
> +    prod = intf->in_prod;
> +    for (i = 0; i < len; i++) {
> +	intf->in[MASK_XENCONS_IDX(prod++, intf->in)] =
> +	    buf[i];
> +    }
> +    xen_wmb();
> +    intf->in_prod = prod;
> +    xen_be_send_notify(&con->xendev);
> +}
> +
> +static void xencons_send(struct xen_console *con)
> +{
> +    ssize_t len, size;
> +
> +    size = con->buffer.size - con->buffer.consumed;
> +    len = qemu_chr_write(con->chr, con->buffer.data + con->buffer.consumed,
> +			 size);
> +    if (len < 1) {
> +	if (!con->backlog) {
> +	    con->backlog = 1;
> +	    xen_be_printf(&con->xendev, 1, "backlog piling up, nobody listening?\n");
> +	}
> +    } else {
> +	buffer_advance(&con->buffer, len);
> +	if (con->backlog && len == size) {
> +	    con->backlog = 0;
> +	    xen_be_printf(&con->xendev, 1, "backlog is gone\n");
> +	}
> +    }
> +}
> +
> +/* -------------------------------------------------------------------- */
> +
> +static int con_init(struct xendev *xendev)
> +{
> +    struct xen_console *con = container_of(xendev, struct xen_console, xendev);
> +    char *type;
> +
> +    if (!serial_hds[con->xendev.dev]) {
> +	xen_be_printf(xendev, 1, "serial line %d not configured\n", con->xendev.dev);
> +	return -1;
> +    }
> +
> +    /* setup */
> +    snprintf(con->console, sizeof(con->console),
> +	     "/local/domain/%d/console", con->xendev.dom);
> +    con->chr = serial_hds[con->xendev.dev];
> +
> +    type = xenstore_read_str(con->console, "type");
> +    if (!type || 0 != strcmp(type, "ioemu")) {
> +	xen_be_printf(xendev, 1, "not for me (type=%s)\n", type);
> +	return -1;
> +    }
> +
> +    return 0;
> +}
> +
> +static int con_connect(struct xendev *xendev)
> +{
> +    struct xen_console *con = container_of(xendev, struct xen_console, xendev);
> +    int limit;
> +
> +    if (-1 == xenstore_read_int(con->console, "ring-ref", &con->ring_ref))
> +	return -1;
> +    if (-1 == xenstore_read_int(con->console, "port", &con->xendev.remote_port))
> +	return -1;
> +    if (0 == xenstore_read_int(con->console, "limit", &limit))
> +	con->buffer.max_capacity = limit;
> +
> +    con->sring = xc_map_foreign_range(xen_xc, con->xendev.dom,
> +				      XC_PAGE_SIZE,
> +				      PROT_READ|PROT_WRITE,
> +				      con->ring_ref);
> +    if (!con->sring)
> +	return -1;
> +
> +    xen_be_bind_evtchn(&con->xendev);
> +    qemu_chr_add_handlers(con->chr, xencons_can_receive, xencons_receive,
> +			  NULL, con);
> +
> +    xen_be_printf(xendev, 1, "ring mfn %d, remote port %d, local port %d, limit %zd\n",
> +		  con->ring_ref,
> +		  con->xendev.remote_port,
> +		  con->xendev.local_port,
> +		  con->buffer.max_capacity);
> +    return 0;
> +}
> +
> +static void con_disconnect(struct xendev *xendev)
> +{
> +    struct xen_console *con = container_of(xendev, struct xen_console, xendev);
> +
> +    qemu_chr_add_handlers(con->chr, NULL, NULL, NULL, NULL);
> +    xen_be_unbind_evtchn(&con->xendev);
> +
> +    if (con->sring) {
> +	munmap(con->sring, XC_PAGE_SIZE);
> +	con->sring = NULL;
> +    }
> +}
> +
> +static void con_event(struct xendev *xendev)
> +{
> +    struct xen_console *con = container_of(xendev, struct xen_console, xendev);
> +
> +    buffer_append(con);
> +    if (con->buffer.size - con->buffer.consumed)
> +	xencons_send(con);
> +}
> +
> +/* -------------------------------------------------------------------- */
> +
> +struct devops xen_console_ops = {
>   

I missed it in the previous patchset, but it would be nice to QEMU-ify 
these things.  For instance, 'struct xen_console' => 'XenConsole', 
'struct devopts' => 'XenDevOpts', etc.

Regards,

Anthony Liguori

> +    .size       = sizeof(struct xen_console),
> +    .flags      = DEVOPS_FLAG_IGNORE_STATE,
> +    .init       = con_init,
> +    .connect    = con_connect,
> +    .event      = con_event,
> +    .disconnect = con_disconnect,
> +};
> diff --git a/hw/xen-machine.c b/hw/xen-machine.c
> index 798c0a7..da10982 100644
> --- a/hw/xen-machine.c
> +++ b/hw/xen-machine.c
> @@ -57,6 +57,8 @@ static void xenpv_init(ram_addr_t ram_size, int vga_ram_size,
>  
>      /* setup xen backend handlers */
>      xen_be_init();
> +
> +    xen_be_register("console", &xen_console_ops);
>  }
>  
>  QEMUMachine xenpv_machine = {
>   

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 4/7] xen: add framebuffer backend driver
  2008-07-28 13:17 ` [Qemu-devel] [PATCH 4/7] xen: add framebuffer " Gerd Hoffmann
@ 2008-07-28 14:22   ` Anthony Liguori
  2008-07-28 14:41     ` Andreas Färber
  2008-07-30  9:20     ` Gerd Hoffmann
  0 siblings, 2 replies; 64+ messages in thread
From: Anthony Liguori @ 2008-07-28 14:22 UTC (permalink / raw)
  To: qemu-devel; +Cc: xen-devel, Gerd Hoffmann

Gerd Hoffmann wrote:
> This patch adds a frsamebuffer (and kbd+mouse) backend driver.  It
> it based on current xen-unstable code.  It has been changed to make
> use of the common backend driver code.  It also has been changed to
> compile with xen headers older than unstable (aka son-to-be 3.3).
>
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  Makefile.target      |    2 +-
>  hw/xen-backend.h     |    4 +
>  hw/xen-framebuffer.c |  925 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  hw/xen-machine.c     |    5 +
>  4 files changed, 935 insertions(+), 1 deletions(-)
>  create mode 100644 hw/xen-framebuffer.c
>
> diff --git a/Makefile.target b/Makefile.target
> index 05619fa..66d41ee 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -517,7 +517,7 @@ endif
>  
>  # xen backend driver support
>  XEN_OBJS := xen-machine.o xen-backend.o
> -XEN_OBJS += xen-console.o
> +XEN_OBJS += xen-console.o xen-framebuffer.o
>  ifeq ($(CONFIG_XEN), yes)
>    OBJS += $(XEN_OBJS)
>    LIBS += $(XEN_LIBS)
> diff --git a/hw/xen-backend.h b/hw/xen-backend.h
> index 55ffd31..3facf90 100644
> --- a/hw/xen-backend.h
> +++ b/hw/xen-backend.h
> @@ -116,4 +116,8 @@ void xen_be_printf(struct xendev *xendev, int msg_level, const char *fmt, ...)
>  
>  /* actual backend drivers */
>  struct devops xen_console_ops;      /* xen_console.c     */
> +struct devops xen_kbdmouse_ops;     /* xen_framebuffer.c */
> +struct devops xen_framebuffer_ops;  /* xen_framebuffer.c */
> +
> +void xen_set_display(int domid, DisplayState *ds);
>  
> diff --git a/hw/xen-framebuffer.c b/hw/xen-framebuffer.c
> new file mode 100644
> index 0000000..716eafd
> --- /dev/null
> +++ b/hw/xen-framebuffer.c
> @@ -0,0 +1,925 @@
> +/*
> + *  xen paravirt framebuffer backend
>
>   

No copyright?

> + *  This program is free software; you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation; under version 2 of the License.
> + *
> + *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
> + */
> +
> +#include <stdarg.h>
> +#include <stdlib.h>
> +#include <sys/types.h>
> +#include <fcntl.h>
> +#include <unistd.h>
> +#include <stdbool.h>
> +#include <sys/mman.h>
> +#include <errno.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <time.h>
> +
> +#include <xs.h>
> +#include <xenctrl.h>
> +#include <xen/event_channel.h>
> +#include <xen/io/xenbus.h>
> +#include <xen/io/fbif.h>
> +#include <xen/io/kbdif.h>
> +#include <xen/io/protocols.h>
> +
> +#include "hw.h"
> +#include "sysemu.h"
> +#include "console.h"
> +#include "qemu-char.h"
> +#include "xen-backend.h"
> +
> +#ifndef BTN_LEFT
> +#define BTN_LEFT 0x110 /* from <linux/input.h> */
> +#endif
> +
> +/* -------------------------------------------------------------------- */
> +
> +struct xen_common {
> +    struct xendev     xendev;  /* must be first */
> +    void              *page;
> +    DisplayState      *ds;
> +};
> +
> +struct xen_input {
> +    struct xen_common c;
> +    int abs_pointer_wanted; /* Whether guest supports absolute pointer */
> +    int button_state;       /* Last seen pointer button state */
> +    int extended;
> +    QEMUPutMouseEntry *qmouse;
> +};
> +
> +#define UP_QUEUE 8
> +
> +struct xen_fb {
> +    struct xen_common c;
> +    size_t            fb_len;
> +    int               row_stride;
> +    int               depth;
> +    int               width;
> +    int               height;
> +    int               offset;
> +    void              *pixels;
> +    int               feature_update;
> +    int               refresh_period;
> +    int               bug_trigger;
> +
> +    struct {
> +	int x,y,w,h;
> +    } up_rects[UP_QUEUE];
> +    int               up_count;
> +    int               up_fullscreen;
> +};
> +
> +/* -------------------------------------------------------------------- */
> +
> +static int common_bind(struct xen_common *c)
> +{
> +    int mfn;
> +
> +    if (-1 == xenstore_read_fe_int(&c->xendev, "page-ref", &mfn))
> +	return -1;
> +    if (-1 == xenstore_read_fe_int(&c->xendev, "event-channel", &c->xendev.remote_port))
> +	return -1;
> +
> +    xen_be_bind_evtchn(&c->xendev);
> +    xen_be_printf(&c->xendev, 1, "ring mfn %d, remote-port %d, local-port %d\n",
> +		  mfn, c->xendev.remote_port, c->xendev.local_port);
> +
> +    c->page = xc_map_foreign_range(xen_xc, c->xendev.dom,
> +				   XC_PAGE_SIZE,
> +				   PROT_READ | PROT_WRITE, mfn);
> +    if (NULL == c->page)
> +	return -1;
> +    return 0;
> +}
> +
> +static void common_unbind(struct xen_common *c)
> +{
> +    if (c->page) {
> +	munmap(c->page, XC_PAGE_SIZE);
> +	c->page = NULL;
> +    }
> +    xen_be_unbind_evtchn(&c->xendev);
> +}
> +
> +/* -------------------------------------------------------------------- */
> +
> +/*
> + * Tables to map from scancode to Linux input layer keycode.
> + * Scancodes are hardware-specific.  These maps assumes a
> + * standard AT or PS/2 keyboard which is what QEMU feeds us.
> + */
> +const unsigned char atkbd_set2_keycode[512] = {
> +
> +     0, 67, 65, 63, 61, 59, 60, 88,  0, 68, 66, 64, 62, 15, 41,117,
> +     0, 56, 42, 93, 29, 16,  2,  0,  0,  0, 44, 31, 30, 17,  3,  0,
> +     0, 46, 45, 32, 18,  5,  4, 95,  0, 57, 47, 33, 20, 19,  6,183,
> +     0, 49, 48, 35, 34, 21,  7,184,  0,  0, 50, 36, 22,  8,  9,185,
> +     0, 51, 37, 23, 24, 11, 10,  0,  0, 52, 53, 38, 39, 25, 12,  0,
> +     0, 89, 40,  0, 26, 13,  0,  0, 58, 54, 28, 27,  0, 43,  0, 85,
> +     0, 86, 91, 90, 92,  0, 14, 94,  0, 79,124, 75, 71,121,  0,  0,
> +    82, 83, 80, 76, 77, 72,  1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
> +
> +      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
> +    217,100,255,  0, 97,165,  0,  0,156,  0,  0,  0,  0,  0,  0,125,
> +    173,114,  0,113,  0,  0,  0,126,128,  0,  0,140,  0,  0,  0,127,
> +    159,  0,115,  0,164,  0,  0,116,158,  0,150,166,  0,  0,  0,142,
> +    157,  0,  0,  0,  0,  0,  0,  0,155,  0, 98,  0,  0,163,  0,  0,
> +    226,  0,  0,  0,  0,  0,  0,  0,  0,255, 96,  0,  0,  0,143,  0,
> +      0,  0,  0,  0,  0,  0,  0,  0,  0,107,  0,105,102,  0,  0,112,
> +    110,111,108,112,106,103,  0,119,  0,118,109,  0, 99,104,119,  0,
> +
> +};
> +
> +const unsigned char atkbd_unxlate_table[128] = {
> +
> +      0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
> +     21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
> +     35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
> +     50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88,  5,  6,  4, 12,  3,
> +     11,  2, 10,  1,  9,119,126,108,117,125,123,107,115,116,121,105,
> +    114,122,112,113,127, 96, 97,120,  7, 15, 23, 31, 39, 47, 55, 63,
> +     71, 79, 86, 94,  8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
> +     19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
> +
> +};
> +
> +static unsigned char scancode2linux[512];
> +
> +/* Send an event to the keyboard frontend driver */
> +static int xenfb_kbd_event(struct xen_input *xenfb,
> +			   union xenkbd_in_event *event)
> +{
> +    struct xenkbd_page *page = xenfb->c.page;
> +    uint32_t prod;
> +
> +    if (xenfb->c.xendev.be_state != XenbusStateConnected)
> +	return 0;
> +
> +    prod = page->in_prod;
> +    if (prod - page->in_cons == XENKBD_IN_RING_LEN) {
> +	errno = EAGAIN;
> +	return -1;
> +    }
> +
> +    xen_mb();		/* ensure ring space available */
> +    XENKBD_IN_RING_REF(page, prod) = *event;
> +    xen_wmb();		/* ensure ring contents visible */
> +    page->in_prod = prod + 1;
> +    return xen_be_send_notify(&xenfb->c.xendev);
> +}
> +
> +/* Send a keyboard (or mouse button) event */
> +static int xenfb_send_key(struct xen_input *xenfb, bool down, int keycode)
> +{
> +    union xenkbd_in_event event;
> +
> +    memset(&event, 0, XENKBD_IN_EVENT_SIZE);
> +    event.type = XENKBD_TYPE_KEY;
> +    event.key.pressed = down ? 1 : 0;
> +    event.key.keycode = keycode;
> +
> +    return xenfb_kbd_event(xenfb, &event);
> +}
> +
> +/* Send a relative mouse movement event */
> +static int xenfb_send_motion(struct xen_input *xenfb,
> +			     int rel_x, int rel_y, int rel_z)
> +{
> +    union xenkbd_in_event event;
> +
> +    memset(&event, 0, XENKBD_IN_EVENT_SIZE);
> +    event.type = XENKBD_TYPE_MOTION;
> +    event.motion.rel_x = rel_x;
> +    event.motion.rel_y = rel_y;
> +#if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030207
> +    event.motion.rel_z = rel_z;
> +#endif
> +
> +    return xenfb_kbd_event(xenfb, &event);
> +}
> +
> +/* Send an absolute mouse movement event */
> +static int xenfb_send_position(struct xen_input *xenfb,
> +			       int abs_x, int abs_y, int rel_z)
> +{
> +    union xenkbd_in_event event;
> +
> +    memset(&event, 0, XENKBD_IN_EVENT_SIZE);
> +    event.type = XENKBD_TYPE_POS;
> +    event.pos.abs_x = abs_x;
> +    event.pos.abs_y = abs_y;
> +#if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030207
> +    event.pos.rel_z = rel_z;
> +#endif
> +
> +    return xenfb_kbd_event(xenfb, &event);
> +}
> +
> +/*
> + * Send a key event from the client to the guest OS
> + * QEMU gives us a raw scancode from an AT / PS/2 style keyboard.
> + * We have to turn this into a Linux Input layer keycode.
> + *
> + * Extra complexity from the fact that with extended scancodes
> + * (like those produced by arrow keys) this method gets called
> + * twice, but we only want to send a single event. So we have to
> + * track the '0xe0' scancode state & collapse the extended keys
> + * as needed.
> + *
> + * Wish we could just send scancodes straight to the guest which
> + * already has code for dealing with this...
> + */
> +static void xenfb_key_event(void *opaque, int scancode)
> +{
> +    struct xen_input *xenfb = opaque;
> +    int down = 1;
> +
> +    if (scancode == 0xe0) {
> +	xenfb->extended = 1;
> +	return;
> +    } else if (scancode & 0x80) {
> +	scancode &= 0x7f;
> +	down = 0;
> +    }
> +    if (xenfb->extended) {
> +	scancode |= 0x80;
> +	xenfb->extended = 0;
> +    }
> +    xenfb_send_key(xenfb, down, scancode2linux[scancode]);
> +}
> +
> +/*
> + * Send a mouse event from the client to the guest OS
> + *
> + * The QEMU mouse can be in either relative, or absolute mode.
> + * Movement is sent separately from button state, which has to
> + * be encoded as virtual key events. We also don't actually get
> + * given any button up/down events, so have to track changes in
> + * the button state.
> + */
> +static void xenfb_mouse_event(void *opaque,
> +			      int dx, int dy, int dz, int button_state)
> +{
> +    struct xen_input *xenfb = opaque;
> +    int i;
> +
> +    if (xenfb->abs_pointer_wanted)
> +	xenfb_send_position(xenfb,
> +			    dx * (xenfb->c.ds->width - 1) / 0x7fff,
> +			    dy * (xenfb->c.ds->height - 1) / 0x7fff,
> +			    dz);
> +    else
> +	xenfb_send_motion(xenfb, dx, dy, dz);
> +
> +    for (i = 0 ; i < 8 ; i++) {
> +	int lastDown = xenfb->button_state & (1 << i);
> +	int down = button_state & (1 << i);
> +	if (down == lastDown)
> +	    continue;
> +
> +	if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0)
> +	    return;
> +    }
> +    xenfb->button_state = button_state;
> +}
> +
> +static int input_init(struct xendev *xendev)
> +{
> +    struct xen_input *in = container_of(xendev, struct xen_input, c.xendev);
> +    static int first = 1;
> +    int i;
> +
> +    if (first) {
> +	/* Prepare scancode mapping table */
> +	for (i = 0; i < 128; i++) {
> +	    scancode2linux[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
> +	    scancode2linux[i | 0x80] =
> +		atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
> +	}
> +	first = 0;
> +    }
> +
> +    if (!in->c.ds) {
> +        /* xen_set_display() below will set that and trigger us again */
> +        xen_be_printf(xendev, 1, "ds not set (yet)\n");
> +	return -1;
> +    }
> +
> +    xenstore_write_be_int(xendev, "feature-abs-pointer", 1);
> +    return 0;
> +}
> +
> +static int input_connect(struct xendev *xendev)
> +{
> +    struct xen_input *in = container_of(xendev, struct xen_input, c.xendev);
> +    int rc;
> +
> +    if (-1 == xenstore_read_fe_int(xendev, "request-abs-pointer", &in->abs_pointer_wanted))
> +	in->abs_pointer_wanted = 0;
> +
> +    rc = common_bind(&in->c);
> +    if (0 != rc)
> +	return rc;
> +
> +    qemu_add_kbd_event_handler(xenfb_key_event, in);
> +    in->qmouse = qemu_add_mouse_event_handler(xenfb_mouse_event, in,
> +					      in->abs_pointer_wanted,
> +					      "Xen PVFB Mouse");
> +    return 0;
> +}
> +
> +static void input_disconnect(struct xendev *xendev)
> +{
> +    struct xen_input *in = container_of(xendev, struct xen_input, c.xendev);
> +
> +    if (in->qmouse) {
> +	qemu_remove_mouse_event_handler(in->qmouse);
> +	in->qmouse = NULL;
> +    }
> +    qemu_add_kbd_event_handler(NULL, NULL);
> +    common_unbind(&in->c);
> +}
> +
> +static void input_event(struct xendev *xendev)
> +{
> +    struct xen_input *xenfb = container_of(xendev, struct xen_input, c.xendev);
> +    struct xenkbd_page *page = xenfb->c.page;
> +
> +    /* We don't understand any keyboard events, so just ignore them. */
> +    if (page->out_prod == page->out_cons)
> +	return;
> +    page->out_cons = page->out_prod;
> +    xen_be_send_notify(&xenfb->c.xendev);
> +}
> +
> +/* -------------------------------------------------------------------- */
> +
> +static void xenfb_copy_mfns(int mode, int count, unsigned long *dst, void *src)
> +{
> +    uint32_t *src32 = src;
> +    uint64_t *src64 = src;
> +    int i;
> +
> +    for (i = 0; i < count; i++)
> +	dst[i] = (mode == 32) ? src32[i] : src64[i];
> +}
> +
> +static int xenfb_map_fb(struct xen_fb *xenfb)
> +{
> +    struct xenfb_page *page = xenfb->c.page;
> +    char *protocol = xenfb->c.xendev.protocol;
> +    int n_fbmfns;
> +    int n_fbdirs;
> +    unsigned long *pgmfns = NULL;
> +    unsigned long *fbmfns = NULL;
> +    void *map, *pd;
> +    int mode, ret = -1;
> +
> +    /* default to native */
> +    pd = page->pd;
> +    mode = sizeof(unsigned long) * 8;
> +
> +    if (!protocol) {
> +	/*
> +	 * Undefined protocol, some guesswork needed.
> +	 *
> +	 * Old frontends which don't set the protocol use
> +	 * one page directory only, thus pd[1] must be zero.
> +	 * pd[1] of the 32bit struct layout and the lower
> +	 * 32 bits of pd[0] of the 64bit struct layout have
> +	 * the same location, so we can check that ...
> +	 */
> +	uint32_t *ptr32 = NULL;
> +	uint32_t *ptr64 = NULL;
> +#if defined(__i386__)
> +	ptr32 = (void*)page->pd;
> +	ptr64 = ((void*)page->pd) + 4;
> +#elif defined(__x86_64__)
> +	ptr32 = ((void*)page->pd) - 4;
> +	ptr64 = (void*)page->pd;
> +#endif
> +	if (ptr32) {
> +	    if (0 == ptr32[1]) {
> +		mode = 32;
> +		pd   = ptr32;
> +	    } else {
> +		mode = 64;
> +		pd   = ptr64;
> +	    }
> +	}
> +#if defined(__x86_64__)
> +    } else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_32)) {
> +	/* 64bit dom0, 32bit domU */
> +	mode = 32;
> +	pd   = ((void*)page->pd) - 4;
> +#elif defined(__i386__)
> +    } else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_64)) {
> +	/* 32bit dom0, 64bit domU */
> +	mode = 64;
> +	pd   = ((void*)page->pd) + 4;
> +#endif
> +    }
> +
> +    n_fbmfns = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
> +    n_fbdirs = n_fbmfns * mode / 8;
> +    n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
> +
> +    pgmfns = malloc(sizeof(unsigned long) * n_fbdirs);
> +    fbmfns = malloc(sizeof(unsigned long) * n_fbmfns);
> +    if (!pgmfns || !fbmfns)
> +	goto out;
> +
> +    xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd);
> +    map = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
> +			       PROT_READ, pgmfns, n_fbdirs);
> +    if (map == NULL)
> +	goto out;
> +    xenfb_copy_mfns(mode, n_fbmfns, fbmfns, map);
> +    munmap(map, n_fbdirs * XC_PAGE_SIZE);
> +
> +    xenfb->pixels = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
> +					 PROT_READ | PROT_WRITE, fbmfns, n_fbmfns);
> +    if (xenfb->pixels == NULL)
> +	goto out;
> +
> +    ret = 0; /* all is fine */
> +
> +out:
> +    if (pgmfns)
> +	free(pgmfns);
> +    if (fbmfns)
> +	free(fbmfns);
> +    return ret;
> +}
> +
> +static int xenfb_configure_fb(struct xen_fb *xenfb, size_t fb_len_lim,
> +			      int width, int height, int depth,
> +			      size_t fb_len, int offset, int row_stride)
> +{
> +    size_t mfn_sz = sizeof(*((struct xenfb_page *)0)->pd);
> +    size_t pd_len = sizeof(((struct xenfb_page *)0)->pd) / mfn_sz;
> +    size_t fb_pages = pd_len * XC_PAGE_SIZE / mfn_sz;
> +    size_t fb_len_max = fb_pages * XC_PAGE_SIZE;
> +    int max_width, max_height;
> +
> +    if (fb_len_lim > fb_len_max) {
> +	xen_be_printf(&xenfb->c.xendev, 0, "fb size limit %zu exceeds %zu, corrected\n",
> +		      fb_len_lim, fb_len_max);
> +	fb_len_lim = fb_len_max;
> +    }
> +    if (fb_len_lim && fb_len > fb_len_lim) {
> +	xen_be_printf(&xenfb->c.xendev, 0, "frontend fb size %zu limited to %zu\n",
> +		      fb_len, fb_len_lim);
> +	fb_len = fb_len_lim;
> +    }
> +    if (depth != 8 && depth != 16 && depth != 24 && depth != 32) {
> +	xen_be_printf(&xenfb->c.xendev, 0, "can't handle frontend fb depth %d\n",
> +		      depth);
> +	return -1;
> +    }
> +    if (row_stride < 0 || row_stride > fb_len) {
> +	xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend stride %d\n", row_stride);
> +	return -1;
> +    }
> +    max_width = row_stride / (depth / 8);
> +    if (width < 0 || width > max_width) {
> +	xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend width %d limited to %d\n",
> +		      width, max_width);
> +	width = max_width;
> +    }
> +    if (offset < 0 || offset >= fb_len) {
> +	xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend offset %d (max %zu)\n",
> +		      offset, fb_len - 1);
> +	return -1;
> +    }
> +    max_height = (fb_len - offset) / row_stride;
> +    if (height < 0 || height > max_height) {
> +	xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend height %d limited to %d\n",
> +		      height, max_height);
> +	height = max_height;
> +    }
> +    xenfb->fb_len = fb_len;
> +    xenfb->row_stride = row_stride;
> +    xenfb->depth = depth;
> +    xenfb->width = width;
> +    xenfb->height = height;
> +    xenfb->offset = offset;
> +    xen_be_printf(&xenfb->c.xendev, 1, "framebuffer %dx%dx%d offset %d stride %d\n",
> +		  width, height, depth, offset, row_stride);
> +    return 0;
> +}
> +
> +/* A convenient function for munging pixels between different depths */
> +#define BLT(SRC_T,DST_T,RSB,GSB,BSB,RDB,GDB,BDB)                        \
> +    for (line = y ; line < (y+h) ; line++) {				\
> +	SRC_T *src = (SRC_T *)(xenfb->pixels				\
> +			       + xenfb->offset				\
> +			       + (line * xenfb->row_stride)		\
> +			       + (x * xenfb->depth / 8));		\
> +	DST_T *dst = (DST_T *)(xenfb->c.ds->data				\
> +			       + (line * xenfb->c.ds->linesize)		\
> +			       + (x * xenfb->c.ds->depth / 8));		\
> +	int col;							\
> +	const int RSS = 32 - (RSB + GSB + BSB);				\
> +	const int GSS = 32 - (GSB + BSB);				\
> +	const int BSS = 32 - (BSB);					\
> +	const uint32_t RSM = (~0U) << (32 - RSB);			\
> +	const uint32_t GSM = (~0U) << (32 - GSB);			\
> +	const uint32_t BSM = (~0U) << (32 - BSB);			\
> +	const int RDS = 32 - (RDB + GDB + BDB);				\
> +	const int GDS = 32 - (GDB + BDB);				\
> +	const int BDS = 32 - (BDB);					\
> +	const uint32_t RDM = (~0U) << (32 - RDB);			\
> +	const uint32_t GDM = (~0U) << (32 - GDB);			\
> +	const uint32_t BDM = (~0U) << (32 - BDB);			\
> +	for (col = x ; col < (x+w) ; col++) {				\
> +	    uint32_t spix = *src;					\
> +	    *dst = (((spix << RSS) & RSM & RDM) >> RDS) |		\
> +		(((spix << GSS) & GSM & GDM) >> GDS) |			\
> +		(((spix << BSS) & BSM & BDM) >> BDS);			\
> +	    src = (SRC_T *) ((unsigned long) src + xenfb->depth / 8);	\
> +	    dst = (DST_T *) ((unsigned long) dst + xenfb->c.ds->depth / 8); \
> +	}								\
> +    }
>   

There are similar conversion macros in the VGA code.  I don't know how 
practical it would be to reuse them but it's at least worth looking at.

Regards,

Anthony Liguori

> +
> +/* This copies data from the guest framebuffer region, into QEMU's copy
> + * NB. QEMU's copy is stored in the pixel format of a) the local X
> + * server (SDL case) or b) the current VNC client pixel format.
> + * When shifting between colour depths we preserve the MSB.
> + */
> +static void xenfb_guest_copy(struct xen_fb *xenfb, int x, int y, int w, int h)
> +{
> +    int line;
> +
> +    if (1 /* !xenfb->c.ds->shared_buf */) {
> +	if (xenfb->depth == xenfb->c.ds->depth) { /* Perfect match can use fast path */
> +	    for (line = y ; line < (y+h) ; line++) {
> +		memcpy(xenfb->c.ds->data + (line * xenfb->c.ds->linesize) + (x * xenfb->c.ds->depth / 8),
> +		       xenfb->pixels + xenfb->offset + (line * xenfb->row_stride) + (x * xenfb->depth / 8),
> +		       w * xenfb->depth / 8);
> +	    }
> +	} else { /* Mismatch requires slow pixel munging */
> +	    /* 8 bit == r:3 g:3 b:2 */
> +	    /* 16 bit == r:5 g:6 b:5 */
> +	    /* 24 bit == r:8 g:8 b:8 */
> +	    /* 32 bit == r:8 g:8 b:8 (padding:8) */
> +	    if (xenfb->depth == 8) {
> +		if (xenfb->c.ds->depth == 16) {
> +		    BLT(uint8_t, uint16_t,   3, 3, 2,   5, 6, 5);
> +		} else if (xenfb->c.ds->depth == 32) {
> +		    BLT(uint8_t, uint32_t,   3, 3, 2,   8, 8, 8);
> +		}
> +	    } else if (xenfb->depth == 16) {
> +		if (xenfb->c.ds->depth == 8) {
> +		    BLT(uint16_t, uint8_t,   5, 6, 5,   3, 3, 2);
> +		} else if (xenfb->c.ds->depth == 32) {
> +		    BLT(uint16_t, uint32_t,  5, 6, 5,   8, 8, 8);
> +		}
> +	    } else if (xenfb->depth == 24 || xenfb->depth == 32) {
> +		if (xenfb->c.ds->depth == 8) {
> +		    BLT(uint32_t, uint8_t,   8, 8, 8,   3, 3, 2);
> +		} else if (xenfb->c.ds->depth == 16) {
> +		    BLT(uint32_t, uint16_t,  8, 8, 8,   5, 6, 5);
> +		} else if (xenfb->c.ds->depth == 32) {
> +		    BLT(uint32_t, uint32_t,  8, 8, 8,   8, 8, 8);
> +		}
> +	    }
> +	}
> +    }
> +    dpy_update(xenfb->c.ds, x, y, w, h);
> +}
> +
> +#ifdef XENFB_TYPE_REFRESH_PERIOD
> +static int xenfb_queue_full(struct xen_fb *xenfb)
> +{
> +    struct xenfb_page *page = xenfb->c.page;
> +    uint32_t cons, prod;
> +
> +    prod = page->in_prod;
> +    cons = page->in_cons;
> +    return prod - cons == XENFB_IN_RING_LEN;
> +}
> +
> +static void xenfb_send_event(struct xen_fb *xenfb, union xenfb_in_event *event)
> +{
> +    uint32_t prod;
> +    struct xenfb_page *page = xenfb->c.page;
> +
> +    prod = page->in_prod;
> +    /* caller ensures !xenfb_queue_full() */
> +    xen_mb();                   /* ensure ring space available */
> +    XENFB_IN_RING_REF(page, prod) = *event;
> +    xen_wmb();                  /* ensure ring contents visible */
> +    page->in_prod = prod + 1;
> +
> +    xen_be_send_notify(&xenfb->c.xendev);
> +}
> +
> +static void xenfb_send_refresh_period(struct xen_fb *xenfb, int period)
> +{
> +    union xenfb_in_event event;
> +
> +    memset(&event, 0, sizeof(event));
> +    event.type = XENFB_TYPE_REFRESH_PERIOD;
> +    event.refresh_period.period = period;
> +    xenfb_send_event(xenfb, &event);
> +}
> +#endif
> +
> +/*
> + * Periodic update of display.
> + * Also transmit the refresh interval to the frontend.
> + * 
> + * Never ever do any qemu display operations
> + * (resize, screen update) outside this function.
> + * Our screen might be inactive.  When asked for
> + * an update we know it is active.
> + */
> +static void xenfb_update(void *opaque)
> +{
> +    struct xen_fb *xenfb = opaque;
> +    int i;
> +
> +    if (xenfb->feature_update) {
> +#ifdef XENFB_TYPE_REFRESH_PERIOD
> +	int period;
> +
> +	if (xenfb_queue_full(xenfb))
> +	    return;
> +
> +        /*
> +         * TODO: xen's qemu-dm seems to have some patches to
> +         *       make the qemu display code avoid unneeded
> +         *       work.
> +         *        - Port them over.
> +         *        - Put ds->idle back into use then.
> +         *        - Same goes for ds->shared_buf btw.
> +         */
> +	if (0 /* xenfb->c.ds->idle */)
> +	    period =  XENFB_NO_REFRESH;
> +	else {
> +	    period = xenfb->c.ds->gui_timer_interval;
> +	    if (!period)
> +		period = 30; // GUI_REFRESH_INTERVAL (see vl.c)
> +	}
> +
> +	if (xenfb->refresh_period != period) {
> +	    dprintf("%s: %d\n", __FUNCTION__, period);
> +	    xenfb_send_refresh_period(xenfb, period);
> +	    xenfb->refresh_period = period;
> +	}
> +#else
> +	; /* nothing */
> +#endif
> +    } else {
> +	/* we don't get update notifications, thus use the
> +	 * sledge hammer approach ... */
> +	xenfb->up_fullscreen = 1;
> +    }
> +
> +    /* resize if needed */
> +    if (xenfb->width != xenfb->c.ds->width || xenfb->height != xenfb->c.ds->height) {
> +	xen_be_printf(&xenfb->c.xendev, 1, "update: resizing\n");
> +	dpy_resize(xenfb->c.ds, xenfb->width, xenfb->height);
> +	xenfb->up_fullscreen = 1;
> +    }
> +
> +    /* run queued updates */
> +    if (xenfb->up_fullscreen) {
> +	xen_be_printf(&xenfb->c.xendev, 3, "update: fullscreen\n");
> +	xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height);
> +    } else if (xenfb->up_count) {
> +	xen_be_printf(&xenfb->c.xendev, 3, "update: %d rects\n", xenfb->up_count);
> +	for (i = 0; i < xenfb->up_count; i++)
> +	    xenfb_guest_copy(xenfb,
> +			     xenfb->up_rects[i].x,
> +			     xenfb->up_rects[i].y,
> +			     xenfb->up_rects[i].w,
> +			     xenfb->up_rects[i].h);
> +    } else {
> +	xen_be_printf(&xenfb->c.xendev, 3, "update: nothing\n");
> +    }
> +    xenfb->up_count = 0;
> +    xenfb->up_fullscreen = 0;
> +}
> +
> +static void xenfb_handle_events(struct xen_fb *xenfb)
> +{
> +    uint32_t prod, cons;
> +    struct xenfb_page *page = xenfb->c.page;
> +
> +    prod = page->out_prod;
> +    if (prod == page->out_cons)
> +	return;
> +    xen_rmb();		/* ensure we see ring contents up to prod */
> +    for (cons = page->out_cons; cons != prod; cons++) {
> +	union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons);
> +	int x, y, w, h;
> +
> +	switch (event->type) {
> +	case XENFB_TYPE_UPDATE:
> +	    if (xenfb->up_count == UP_QUEUE)
> +		xenfb->up_fullscreen = 1;
> +	    if (xenfb->up_fullscreen)
> +		break;
> +	    x = MAX(event->update.x, 0);
> +	    y = MAX(event->update.y, 0);
> +	    w = MIN(event->update.width, xenfb->width - x);
> +	    h = MIN(event->update.height, xenfb->height - y);
> +	    if (w < 0 || h < 0) {
> +		fprintf(stderr, "xen be: %s: bogus update ignored\n",
> +			xenfb->c.xendev.name);
> +		break;
> +	    }
> +	    if (x != event->update.x || y != event->update.y
> +		|| w != event->update.width
> +		|| h != event->update.height) {
> +		fprintf(stderr, "xen be: %s: bogus update clipped\n",
> +			xenfb->c.xendev.name);
> +	    }
> +	    if (w == xenfb->width && h > xenfb->height / 2) {
> +		/* scroll detector: updated more than 50% of the lines,
> +		 * don't bother keeping track of the rectangles then */
> +		xenfb->up_fullscreen = 1;
> +	    } else {
> +		xenfb->up_rects[xenfb->up_count].x = x;
> +		xenfb->up_rects[xenfb->up_count].y = y;
> +		xenfb->up_rects[xenfb->up_count].w = w;
> +		xenfb->up_rects[xenfb->up_count].h = h;
> +		xenfb->up_count++;
> +	    }
> +	    break;
> +#ifdef XENFB_TYPE_RESIZE
> +	case XENFB_TYPE_RESIZE:
> +	    if (xenfb_configure_fb(xenfb, xenfb->fb_len,
> +				   event->resize.width,
> +				   event->resize.height,
> +				   event->resize.depth,
> +				   xenfb->fb_len,
> +				   event->resize.offset,
> +				   event->resize.stride) < 0)
> +		break;
> +	    xenfb_invalidate(xenfb);
> +	    break;
> +#endif
> +	}
> +    }
> +    xen_mb();		/* ensure we're done with ring contents */
> +    page->out_cons = cons;
> +}
> +
> +/* QEMU display state changed, so refresh the framebuffer copy */
> +static void xenfb_invalidate(void *opaque)
> +{
> +    struct xen_fb *xenfb = opaque;
> +    xenfb->up_fullscreen = 1;
> +}
> +
> +static int fb_init(struct xendev *xendev)
> +{
> +    struct xen_fb *fb = container_of(xendev, struct xen_fb, c.xendev);
> +
> +    if (!fb->c.ds) {
> +        /* xen_set_display() below will set that and trigger us again */
> +	xen_be_printf(xendev, 1, "ds not set (yet)\n");
> +	return -1;
> +    }
> +
> +    fb->refresh_period = -1;
> +
> +#ifdef XENFB_TYPE_RESIZE
> +    xenstore_write_be_int(xendev, "feature-resize", 1);
> +#endif
> +    return 0;
> +}
> +
> +static int fb_connect(struct xendev *xendev)
> +{
> +    struct xen_fb *fb = container_of(xendev, struct xen_fb, c.xendev);
> +    struct xenfb_page *fb_page;
> +    int videoram;
> +    int rc;
> +
> +    if (-1 == xenstore_read_fe_int(xendev, "feature-update", &fb->feature_update))
> +	fb->feature_update = 0;
> +    if (fb->feature_update)
> +	xenstore_write_be_int(xendev, "request-update", 1);
> +
> +    if (-1 == xenstore_read_fe_int(xendev, "videoram", &videoram))
> +	videoram = 0;
> +
> +    rc = common_bind(&fb->c);
> +    if (0 != rc)
> +	return rc;
> +
> +    fb_page = fb->c.page;
> +    rc = xenfb_configure_fb(fb, videoram * 1024 * 1024U,
> +			    fb_page->width, fb_page->height, fb_page->depth,
> +			    fb_page->mem_length, 0, fb_page->line_length);
> +    if (0 != rc)
> +	return rc;
> +
> +    rc = xenfb_map_fb(fb);
> +    if (0 != rc)
> +	return rc;
> +
> +    graphic_console_init(fb->c.ds,
> +			 xenfb_update,
> +			 xenfb_invalidate,
> +			 NULL,
> +			 NULL,
> +			 fb);
> +
> +    xen_be_printf(xendev, 1, "feature-update=%d, videoram=%d\n",
> +		  fb->feature_update, videoram);
> +
> +    return 0;
> +}
> +
> +static void fb_disconnect(struct xendev *xendev)
> +{
> +    struct xen_fb *fb = container_of(xendev, struct xen_fb, c.xendev);
> +
> +    /* FIXME: Hmm, un-init gfx display? can qemu handle that? */
> +    common_unbind(&fb->c);
> +}
> +
> +static void fb_frontend_changed(struct xendev *xendev, const char *node)
> +{
> +    struct xen_fb *fb = container_of(xendev, struct xen_fb, c.xendev);
> +
> +    /*
> +     * Set state to Connected *again* once the frontend switched
> +     * to connected.  We must trigger the watch a second time to
> +     * workaround a frontend bug.
> +     */
> +    if (0 == fb->bug_trigger && 0 == strcmp(node, "state") &&
> +	xendev->fe_state == XenbusStateConnected &&
> +	xendev->be_state == XenbusStateConnected) {
> +	xen_be_set_state(xendev, XenbusStateConnected);
> +	fb->bug_trigger = 1; /* only once */
> +    }
> +}
> +
> +static void fb_event(struct xendev *xendev)
> +{
> +    struct xen_fb *xenfb = container_of(xendev, struct xen_fb, c.xendev);
> +
> +    xenfb_handle_events(xenfb);
> +    xen_be_send_notify(&xenfb->c.xendev);
> +}
> +
> +/* -------------------------------------------------------------------- */
> +
> +struct devops xen_kbdmouse_ops = {
> +    .size       = sizeof(struct xen_input),
> +    .init       = input_init,
> +    .connect    = input_connect,
> +    .disconnect = input_disconnect,
> +    .event      = input_event,
> +};
> +
> +struct devops xen_framebuffer_ops = {
> +    .size       = sizeof(struct xen_fb),
> +    .init       = fb_init,
> +    .connect    = fb_connect,
> +    .disconnect = fb_disconnect,
> +    .event      = fb_event,
> +    .frontend_changed = fb_frontend_changed,
> +};
> +
> +static void xen_set_display_type(int domid, char *type, DisplayState *ds)
> +{
> +    struct xendev *xendev;
> +    struct xen_common *c;
> +
> +    xendev = xen_be_find_xendev(type, domid, 0);
> +    if (!xendev)
> +	return;
> +    c = container_of(xendev, struct xen_common, xendev);
> +    c->ds = ds;
> +    xen_be_printf(xendev, 1, "ds is %p\n", ds);
> +    /* retry ->init() */
> +    xen_be_check_state(xendev);
> +}
> +
> +void xen_set_display(int domid, DisplayState *ds)
> +{
> +    xen_set_display_type(domid, "vkbd", ds);
> +    xen_set_display_type(domid, "vfb", ds);
> +}
> diff --git a/hw/xen-machine.c b/hw/xen-machine.c
> index da10982..c03cb53 100644
> --- a/hw/xen-machine.c
> +++ b/hw/xen-machine.c
> @@ -59,6 +59,11 @@ static void xenpv_init(ram_addr_t ram_size, int vga_ram_size,
>      xen_be_init();
>  
>      xen_be_register("console", &xen_console_ops);
> +    xen_be_register("vkbd", &xen_kbdmouse_ops);
> +    xen_be_register("vfb", &xen_framebuffer_ops);
> +
> +    /* setup framebuffer */
> +    xen_set_display(xen_domid, ds);
>  }
>  
>  QEMUMachine xenpv_machine = {
>   

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 5/7] xen: add block device backend driver.
  2008-07-28 13:17 ` [Qemu-devel] [PATCH 5/7] xen: add block device " Gerd Hoffmann
@ 2008-07-28 14:25   ` Anthony Liguori
  0 siblings, 0 replies; 64+ messages in thread
From: Anthony Liguori @ 2008-07-28 14:25 UTC (permalink / raw)
  To: qemu-devel; +Cc: xen-devel, Gerd Hoffmann

Gerd Hoffmann wrote:
> This patch adds a block device backend driver to qemu.  It is a pure
> userspace implemention using the gntdev interface.  It uses "qdisk" as
> backend name in xenstore so it doesn't interfere with the other existing
> backends (blkback aka "vbd" and tapdisk aka "tap").
>
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  Makefile.target  |    2 +-
>  hw/xen-backend.h |    2 +
>  hw/xen-blkif.h   |  103 ++++++++
>  hw/xen-disk.c    |  681 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  hw/xen-machine.c |    1 +
>  sysemu.h         |    2 +-
>  vl.c             |    4 +
>  7 files changed, 793 insertions(+), 2 deletions(-)
>  create mode 100644 hw/xen-blkif.h
>  create mode 100644 hw/xen-disk.c
>
> diff --git a/Makefile.target b/Makefile.target
> index 66d41ee..2d599d2 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -517,7 +517,7 @@ endif
>  
>  # xen backend driver support
>  XEN_OBJS := xen-machine.o xen-backend.o
> -XEN_OBJS += xen-console.o xen-framebuffer.o
> +XEN_OBJS += xen-console.o xen-framebuffer.o xen-disk.o
>  ifeq ($(CONFIG_XEN), yes)
>    OBJS += $(XEN_OBJS)
>    LIBS += $(XEN_LIBS)
> diff --git a/hw/xen-backend.h b/hw/xen-backend.h
> index 3facf90..941b0a6 100644
> --- a/hw/xen-backend.h
> +++ b/hw/xen-backend.h
> @@ -10,6 +10,7 @@
>  
>  #include "hw.h"
>  #include "xen.h"
> +#include "sysemu.h"
>  
>  /*
>   * tweaks needed to build with different xen versions
> @@ -118,6 +119,7 @@ void xen_be_printf(struct xendev *xendev, int msg_level, const char *fmt, ...)
>  struct devops xen_console_ops;      /* xen_console.c     */
>  struct devops xen_kbdmouse_ops;     /* xen_framebuffer.c */
>  struct devops xen_framebuffer_ops;  /* xen_framebuffer.c */
> +struct devops xen_blkdev_ops;       /* xen_disk.c        */
>  
>  void xen_set_display(int domid, DisplayState *ds);
>  
> diff --git a/hw/xen-blkif.h b/hw/xen-blkif.h
> new file mode 100644
> index 0000000..254a5fd
> --- /dev/null
> +++ b/hw/xen-blkif.h
> @@ -0,0 +1,103 @@
> +#ifndef __XEN_BLKIF_H__
> +#define __XEN_BLKIF_H__
> +
> +#include <xen/io/ring.h>
> +#include <xen/io/blkif.h>
> +#include <xen/io/protocols.h>
> +
> +/* Not a real protocol.  Used to generate ring structs which contain
> + * the elements common to all protocols only.  This way we get a
> + * compiler-checkable way to use common struct elements, so we can
> + * avoid using switch(protocol) in a number of places.  */
> +struct blkif_common_request {
> +	char dummy;
> +};
> +struct blkif_common_response {
> +	char dummy;
> +};
> +
> +/* i386 protocol version */
> +#pragma pack(push, 4)
> +struct blkif_x86_32_request {
> +	uint8_t        operation;    /* BLKIF_OP_???                         */
> +	uint8_t        nr_segments;  /* number of segments                   */
> +	blkif_vdev_t   handle;       /* only for read/write requests         */
> +	uint64_t       id;           /* private guest value, echoed in resp  */
> +	blkif_sector_t sector_number;/* start sector idx on disk (r/w only)  */
> +	struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
> +};
> +struct blkif_x86_32_response {
> +	uint64_t        id;              /* copied from request */
> +	uint8_t         operation;       /* copied from request */
> +	int16_t         status;          /* BLKIF_RSP_???       */
> +};
> +typedef struct blkif_x86_32_request blkif_x86_32_request_t;
> +typedef struct blkif_x86_32_response blkif_x86_32_response_t;
> +#pragma pack(pop)
> +
> +/* x86_64 protocol version */
> +struct blkif_x86_64_request {
> +	uint8_t        operation;    /* BLKIF_OP_???                         */
> +	uint8_t        nr_segments;  /* number of segments                   */
> +	blkif_vdev_t   handle;       /* only for read/write requests         */
> +	uint64_t       __attribute__((__aligned__(8))) id;
> +	blkif_sector_t sector_number;/* start sector idx on disk (r/w only)  */
> +	struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
> +};
> +struct blkif_x86_64_response {
> +	uint64_t       __attribute__((__aligned__(8))) id;
> +	uint8_t         operation;       /* copied from request */
> +	int16_t         status;          /* BLKIF_RSP_???       */
> +};
> +typedef struct blkif_x86_64_request blkif_x86_64_request_t;
> +typedef struct blkif_x86_64_response blkif_x86_64_response_t;
> +
> +DEFINE_RING_TYPES(blkif_common, struct blkif_common_request, struct blkif_common_response);
> +DEFINE_RING_TYPES(blkif_x86_32, struct blkif_x86_32_request, struct blkif_x86_32_response);
> +DEFINE_RING_TYPES(blkif_x86_64, struct blkif_x86_64_request, struct blkif_x86_64_response);
> +
> +union blkif_back_rings {
> +	blkif_back_ring_t        native;
> +	blkif_common_back_ring_t common;
> +	blkif_x86_32_back_ring_t x86_32;
> +	blkif_x86_64_back_ring_t x86_64;
> +};
> +typedef union blkif_back_rings blkif_back_rings_t;
> +
> +enum blkif_protocol {
> +	BLKIF_PROTOCOL_NATIVE = 1,
> +	BLKIF_PROTOCOL_X86_32 = 2,
> +	BLKIF_PROTOCOL_X86_64 = 3,
> +};
> +
> +static void inline blkif_get_x86_32_req(blkif_request_t *dst, blkif_x86_32_request_t *src)
> +{
> +	int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST;
> +
> +	dst->operation = src->operation;
> +	dst->nr_segments = src->nr_segments;
> +	dst->handle = src->handle;
> +	dst->id = src->id;
> +	dst->sector_number = src->sector_number;
> +	if (n > src->nr_segments)
> +		n = src->nr_segments;
> +	for (i = 0; i < n; i++)
> +		dst->seg[i] = src->seg[i];
> +}
> +
> +static void inline blkif_get_x86_64_req(blkif_request_t *dst, blkif_x86_64_request_t *src)
> +{
> +	int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST;
> +
> +	dst->operation = src->operation;
> +	dst->nr_segments = src->nr_segments;
> +	dst->handle = src->handle;
> +	dst->id = src->id;
> +	dst->sector_number = src->sector_number;
> +	if (n > src->nr_segments)
> +		n = src->nr_segments;
> +	for (i = 0; i < n; i++)
> +		dst->seg[i] = src->seg[i];
> +}
> +
> +#endif /* __XEN_BLKIF_H__ */
> diff --git a/hw/xen-disk.c b/hw/xen-disk.c
> new file mode 100644
> index 0000000..6947363
> --- /dev/null
> +++ b/hw/xen-disk.c
> @@ -0,0 +1,681 @@
> +/*
> + *  xen paravirt block device backend
> + *
> + *  FIXME: the code is designed to handle multiple outstanding
> + *  requests (using aio or using threads), which isn't used right
> + *  now due to limitations of the qemu block driver interface.
> + *
> + *
> + *  This program is free software; you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation; under version 2 of the License.
> + *
> + *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
> + */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <stdarg.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <signal.h>
> +#include <inttypes.h>
> +#include <time.h>
> +#include <fcntl.h>
> +#include <errno.h>
> +#include <pthread.h>
>   

This doesn't seem to be needed?

Regards,

Anthony Liguori

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 6/7] xen: add net backend driver.
  2008-07-28 13:17 ` [Qemu-devel] [PATCH 6/7] xen: add net " Gerd Hoffmann
@ 2008-07-28 14:27   ` Anthony Liguori
  2008-07-28 15:45     ` Gerd Hoffmann
  0 siblings, 1 reply; 64+ messages in thread
From: Anthony Liguori @ 2008-07-28 14:27 UTC (permalink / raw)
  To: qemu-devel; +Cc: xen-devel, Gerd Hoffmann

Gerd Hoffmann wrote:
> This patch adds a network interface backend driver to qemu.  It is a pure
> userspace implemention using the gntdev interface.  It uses "qnet" as
> backend name in xenstore so it doesn't interfere with the netback
> backend (aka "vnif").
>
> The network backend is hooked into the corrosponding qemu vlan, i.e.
> vif 0 is hooked into vlan 0.  To make the packages actually arrive
> somewhere you additionally have to link the vlan to the outside world
> using the usual qemu command line options such as "-net tap,...".
>
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  Makefile.target  |    2 +-
>  hw/xen-backend.h |    1 +
>  hw/xen-machine.c |    1 +
>  hw/xen-nic.c     |  448 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 451 insertions(+), 1 deletions(-)
>  create mode 100644 hw/xen-nic.c
>
> diff --git a/Makefile.target b/Makefile.target
> index 2d599d2..281d7fa 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -517,7 +517,7 @@ endif
>  
>  # xen backend driver support
>  XEN_OBJS := xen-machine.o xen-backend.o
> -XEN_OBJS += xen-console.o xen-framebuffer.o xen-disk.o
> +XEN_OBJS += xen-console.o xen-framebuffer.o xen-disk.o xen-nic.o
>  ifeq ($(CONFIG_XEN), yes)
>    OBJS += $(XEN_OBJS)
>    LIBS += $(XEN_LIBS)
> diff --git a/hw/xen-backend.h b/hw/xen-backend.h
> index 941b0a6..2db2c3c 100644
> --- a/hw/xen-backend.h
> +++ b/hw/xen-backend.h
> @@ -120,6 +120,7 @@ struct devops xen_console_ops;      /* xen_console.c     */
>  struct devops xen_kbdmouse_ops;     /* xen_framebuffer.c */
>  struct devops xen_framebuffer_ops;  /* xen_framebuffer.c */
>  struct devops xen_blkdev_ops;       /* xen_disk.c        */
> +struct devops xen_netdev_ops;       /* xen_nic.c         */
>  
>  void xen_set_display(int domid, DisplayState *ds);
>  
> diff --git a/hw/xen-machine.c b/hw/xen-machine.c
> index 1b647a2..3fa4079 100644
> --- a/hw/xen-machine.c
> +++ b/hw/xen-machine.c
> @@ -62,6 +62,7 @@ static void xenpv_init(ram_addr_t ram_size, int vga_ram_size,
>      xen_be_register("vkbd", &xen_kbdmouse_ops);
>      xen_be_register("vfb", &xen_framebuffer_ops);
>      xen_be_register("qdisk", &xen_blkdev_ops);
> +    xen_be_register("qnic", &xen_netdev_ops);
>  
>      /* setup framebuffer */
>      xen_set_display(xen_domid, ds);
> diff --git a/hw/xen-nic.c b/hw/xen-nic.c
> new file mode 100644
> index 0000000..56d1474
> --- /dev/null
> +++ b/hw/xen-nic.c
> @@ -0,0 +1,448 @@
> +/*
> + *  xen paravirt network card backend
> + *
> + *  This program is free software; you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation; under version 2 of the License.
> + *
> + *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
> + */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <stdarg.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <signal.h>
> +#include <inttypes.h>
> +#include <fcntl.h>
> +#include <errno.h>
> +#include <pthread.h>
> +#include <sys/socket.h>
> +#include <sys/ioctl.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <sys/mman.h>
> +#include <sys/wait.h>
> +#include <linux/if.h>
> +#include <linux/if_tun.h>
> +
> +#include <xs.h>
> +#include <xenctrl.h>
> +#include <xen/io/xenbus.h>
> +#include <xen/io/netif.h>
> +
> +#include "hw.h"
> +#include "net.h"
> +#include "qemu-char.h"
> +#include "xen-backend.h"
> +
> +/* ------------------------------------------------------------- */
> +
> +struct netdev {
> +    struct xendev         xendev;  /* must be first */
> +    char                  *mac;
> +    int                   tx_work;
> +    int                   tx_ring_ref;
> +    int                   rx_ring_ref;
> +    struct netif_tx_sring *txs;
> +    struct netif_rx_sring *rxs;
> +    netif_tx_back_ring_t  tx_ring;
> +    netif_rx_back_ring_t  rx_ring;
> +    VLANClientState       *vs;
> +};
> +
> +/* ------------------------------------------------------------- */
> +
> +#define PROTO_TCP  6
> +#define PROTO_UDP 17
> +
> +static uint32_t checksum_add(int len, uint8_t *buf)
> +{
> +    uint32_t sum = 0;
> +    int i;
> +
> +    for (i = 0; i < len; i++) {
> +	if (i & 1)
> +	    sum += (uint32_t)buf[i];
> +	else
> +	    sum += (uint32_t)buf[i] << 8;
> +    }
> +    return sum;
> +}
> +
> +static uint16_t checksum_finish(uint32_t sum)
> +{
> +    while (sum>>16)
> +	sum = (sum & 0xFFFF)+(sum >> 16);
> +    return ~sum;
> +}
> +
> +static uint16_t checksum_tcpudp(uint16_t length, uint16_t proto,
> +				uint8_t *addrs, uint8_t *buf)
> +{
> +    uint32_t sum = 0;
> +
> +    sum += checksum_add(length, buf);         // payload
> +    sum += checksum_add(8, addrs);            // src + dst address
> +    sum += proto + length;                    // protocol & length
> +    return checksum_finish(sum);
> +}
> +
> +static void checksum_calculate(uint8_t *data, int length)
> +{
> +    int hlen, plen, proto, csum_offset;
> +    uint16_t csum;
> +
> +    if ((data[14] & 0xf0) != 0x40)
> +	return; /* not IPv4 */
> +    hlen  = (data[14] & 0x0f) * 4;
> +    plen  = (data[16] << 8 | data[17]) - hlen;
> +    proto = data[23];
> +
> +    switch (proto) {
> +    case PROTO_TCP:
> +	csum_offset = 16;
> +	break;
> +    case PROTO_UDP:
> +	csum_offset = 6;
> +	break;
> +    default:
> +	return;
> +    }
> +
> +    if (plen < csum_offset+2)
> +	return;
> +
> +    data[14+hlen+csum_offset]   = 0;
> +    data[14+hlen+csum_offset+1] = 0;
> +    csum = checksum_tcpudp(plen, proto, data+14+12, data+14+hlen);
> +    data[14+hlen+csum_offset]   = csum >> 8;
> +    data[14+hlen+csum_offset+1] = csum & 0xff;
> +}
>
>   

The same thing is done in e1000, I believe.  We'll also probably want to 
be able to support this for virtio so this would be pretty good to make 
common code.

Regards,

Anthony Liguori

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu
  2008-07-28 13:31 ` [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu Ian Jackson
@ 2008-07-28 14:33   ` Anthony Liguori
  2008-07-28 14:58     ` Ian Jackson
  2008-07-28 15:23     ` Gerd Hoffmann
  2008-07-28 14:43   ` Gerd Hoffmann
  1 sibling, 2 replies; 64+ messages in thread
From: Anthony Liguori @ 2008-07-28 14:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: xen-devel, Ian Jackson, Gerd Hoffmann

Ian Jackson wrote:
> Gerd Hoffmann writes ("[Qemu-devel] [PATCH 0/7] merge some xen bits into qemu"):
>   
>> Here are a bunch of patches which start adding xen support to qemu.
>> Overview (individual patches have longer descriptions):
>>     
>
> Just to clarify: as far as I can tell from the description,
> this code has scant relationship with Xen upstream.
>
> I'm generally in favour of pushing functionality out of the Xen branch
> of qemu into upstream.  But going by Gerd Hoffman's description I
> don't think that's what his branch is.  His code doesn't appear to be
> related to the Xen branch of qemu that we are using.
>   

I think it's more closely related to Xenite and Xenner.  Gerd: are you 
planning on folding in domain creation?  Right now it appears to be a 
helper launched after the domain creation.

> For example,
>
>   
>> With the first four patches in place upstream qemu can replace xen's
>> qemu-dm for paravirtual domains.  The block and nic backend drivers are
>> full userspace implementations using the grant table device (gntdev).
>>     
>
> we only use qemu-dm in paravirtualised domains for certain marginal
> functions - in many cases it is not used at all.  Certainly the
> functionality Gerd describes, such as xen backend block and network
> drivers, are not in our qemu tree and we do not intend for them to be
> there.
>   

There's no reason they couldn't be though.  It's just like blktap.

> In a Xen installation this functionality is in the dom0 (host) kernel.
>
>
> As far as I can see much of Gerd Hoffman's intended submission is
> effectively an _emulator_ for Xen guests.  That is, it emulates a Xen
> host without being one, so that a Xen domU can be run without the Xen
> hypervisor.  Am I right, Gerd ?
>   

No, it's definitely for use with Xen (hypervisor).  But it's different 
architecturally from how Xen uses QEMU in xen-unstable.

Personally, I really like the way Gerd has the code structured.  It 
seems like it could be used as almost a drop-in replacement for qemu-dm 
for PV guests.  HVM guests would require more work.  Of course, the 
net/disk support can be completely optionally.

With that said, it would be silly to have two Xen implementations within 
QEMU so there has to be some general agreement in the Xen community 
about how QEMU is going to be used before merging would make sense.  
That probably requires some discussion about how the HVM support would 
fit into this architecture.

Regards,

Anthony Liguori



> I don't think there's anything wrong with that from a qemu point of
> view.  Obviously we think that the genuine Xen hypervisor is much
> better :-) but it is right for people to have a choice, and having
> qemu emulate more environments is generally good.
>
> But if this functionality is to go into qemu upstream perhaps it
> should be distinguished from `real Xen' functions, because otherwise
> users are going to become very very confused.
>
> Ian.
>
>
>   

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 4/7] xen: add framebuffer backend driver
  2008-07-28 14:22   ` Anthony Liguori
@ 2008-07-28 14:41     ` Andreas Färber
  2008-07-30  9:59       ` Gerd Hoffmann
  2008-07-30  9:20     ` Gerd Hoffmann
  1 sibling, 1 reply; 64+ messages in thread
From: Andreas Färber @ 2008-07-28 14:41 UTC (permalink / raw)
  To: qemu-devel; +Cc: xen-devel, Gerd Hoffmann


Am 28.07.2008 um 16:22 schrieb Anthony Liguori:

> Gerd Hoffmann wrote:
>> This patch adds a frsamebuffer (and kbd+mouse) backend driver.  It
>> it based on current xen-unstable code.  It has been changed to make
>> use of the common backend driver code.  It also has been changed to
>> compile with xen headers older than unstable (aka son-to-be 3.3).
>>
>> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
>> ---
>> Makefile.target      |    2 +-
>> hw/xen-backend.h     |    4 +
>> hw/xen-framebuffer.c |  925 ++++++++++++++++++++++++++++++++++++++++ 
>> ++++++++++
>> hw/xen-machine.c     |    5 +
>> 4 files changed, 935 insertions(+), 1 deletions(-)
>> create mode 100644 hw/xen-framebuffer.c
>>
>> diff --git a/Makefile.target b/Makefile.target
>> index 05619fa..66d41ee 100644
>> --- a/Makefile.target
>> +++ b/Makefile.target
>> @@ -517,7 +517,7 @@ endif
>>  # xen backend driver support
>> XEN_OBJS := xen-machine.o xen-backend.o
>> -XEN_OBJS += xen-console.o
>> +XEN_OBJS += xen-console.o xen-framebuffer.o
>> ifeq ($(CONFIG_XEN), yes)
>>   OBJS += $(XEN_OBJS)
>>   LIBS += $(XEN_LIBS)
>> diff --git a/hw/xen-backend.h b/hw/xen-backend.h
>> index 55ffd31..3facf90 100644
>> --- a/hw/xen-backend.h
>> +++ b/hw/xen-backend.h
>> @@ -116,4 +116,8 @@ void xen_be_printf(struct xendev *xendev, int  
>> msg_level, const char *fmt, ...)
>>  /* actual backend drivers */
>> struct devops xen_console_ops;      /* xen_console.c     */
>> +struct devops xen_kbdmouse_ops;     /* xen_framebuffer.c */
>> +struct devops xen_framebuffer_ops;  /* xen_framebuffer.c */
>> +
>> +void xen_set_display(int domid, DisplayState *ds);
>> diff --git a/hw/xen-framebuffer.c b/hw/xen-framebuffer.c
>> new file mode 100644
>> index 0000000..716eafd
>> --- /dev/null
>> +++ b/hw/xen-framebuffer.c
>> @@ -0,0 +1,925 @@
>> +/*
>> + *  xen paravirt framebuffer backend
>>
>>
>
> No copyright?
>
>> + *  This program is free software; you can redistribute it and/or  
>> modify
>> + *  it under the terms of the GNU General Public License as  
>> published by
>> + *  the Free Software Foundation; under version 2 of the License.
>> + *
>> + *  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., 59 Temple Place, Suite 330, Boston, MA   
>> 02111-1307  USA
>> + */
>> +
>> +#include <stdarg.h>
>> +#include <stdlib.h>
>> +#include <sys/types.h>
>> +#include <fcntl.h>
>> +#include <unistd.h>
>> +#include <stdbool.h>
>> +#include <sys/mman.h>
>> +#include <errno.h>
>> +#include <stdio.h>
>> +#include <string.h>
>> +#include <time.h>
>> +
>> +#include <xs.h>
>> +#include <xenctrl.h>
>> +#include <xen/event_channel.h>
>> +#include <xen/io/xenbus.h>
>> +#include <xen/io/fbif.h>
>> +#include <xen/io/kbdif.h>
>> +#include <xen/io/protocols.h>
>> +
>> +#include "hw.h"
>> +#include "sysemu.h"
>> +#include "console.h"
>> +#include "qemu-char.h"
>> +#include "xen-backend.h"
>> +
>> +#ifndef BTN_LEFT
>> +#define BTN_LEFT 0x110 /* from <linux/input.h> */
>> +#endif
>> +
>> +/*  
>> -------------------------------------------------------------------- */
>> +
>> +struct xen_common {
>> +    struct xendev     xendev;  /* must be first */
>> +    void              *page;
>> +    DisplayState      *ds;
>> +};
>> +
>> +struct xen_input {
>> +    struct xen_common c;
>> +    int abs_pointer_wanted; /* Whether guest supports absolute  
>> pointer */
>> +    int button_state;       /* Last seen pointer button state */
>> +    int extended;
>> +    QEMUPutMouseEntry *qmouse;
>> +};
>> +
>> +#define UP_QUEUE 8
>> +
>> +struct xen_fb {
>> +    struct xen_common c;
>> +    size_t            fb_len;
>> +    int               row_stride;
>> +    int               depth;
>> +    int               width;
>> +    int               height;
>> +    int               offset;
>> +    void              *pixels;
>> +    int               feature_update;
>> +    int               refresh_period;
>> +    int               bug_trigger;
>> +
>> +    struct {
>> +	int x,y,w,h;
>> +    } up_rects[UP_QUEUE];
>> +    int               up_count;
>> +    int               up_fullscreen;
>> +};
>> +
>> +/*  
>> -------------------------------------------------------------------- */
>> +
>> +static int common_bind(struct xen_common *c)
>> +{
>> +    int mfn;
>> +
>> +    if (-1 == xenstore_read_fe_int(&c->xendev, "page-ref", &mfn))
>> +	return -1;
>> +    if (-1 == xenstore_read_fe_int(&c->xendev, "event-channel", &c- 
>> >xendev.remote_port))
>> +	return -1;
>> +
>> +    xen_be_bind_evtchn(&c->xendev);
>> +    xen_be_printf(&c->xendev, 1, "ring mfn %d, remote-port %d,  
>> local-port %d\n",
>> +		  mfn, c->xendev.remote_port, c->xendev.local_port);
>> +
>> +    c->page = xc_map_foreign_range(xen_xc, c->xendev.dom,
>> +				   XC_PAGE_SIZE,
>> +				   PROT_READ | PROT_WRITE, mfn);
>> +    if (NULL == c->page)
>> +	return -1;
>> +    return 0;
>> +}
>> +
>> +static void common_unbind(struct xen_common *c)
>> +{
>> +    if (c->page) {
>> +	munmap(c->page, XC_PAGE_SIZE);
>> +	c->page = NULL;
>> +    }
>> +    xen_be_unbind_evtchn(&c->xendev);
>> +}
>> +
>> +/*  
>> -------------------------------------------------------------------- */
>> +
>> +/*
>> + * Tables to map from scancode to Linux input layer keycode.
>> + * Scancodes are hardware-specific.  These maps assumes a
>> + * standard AT or PS/2 keyboard which is what QEMU feeds us.
>> + */
>> +const unsigned char atkbd_set2_keycode[512] = {
>> +
>> +     0, 67, 65, 63, 61, 59, 60, 88,  0, 68, 66, 64, 62, 15, 41,117,
>> +     0, 56, 42, 93, 29, 16,  2,  0,  0,  0, 44, 31, 30, 17,  3,  0,
>> +     0, 46, 45, 32, 18,  5,  4, 95,  0, 57, 47, 33, 20, 19,  6,183,
>> +     0, 49, 48, 35, 34, 21,  7,184,  0,  0, 50, 36, 22,  8,  9,185,
>> +     0, 51, 37, 23, 24, 11, 10,  0,  0, 52, 53, 38, 39, 25, 12,  0,
>> +     0, 89, 40,  0, 26, 13,  0,  0, 58, 54, 28, 27,  0, 43,  0, 85,
>> +     0, 86, 91, 90, 92,  0, 14, 94,  0, 79,124, 75, 71,121,  0,  0,
>> +    82, 83, 80, 76, 77, 72,  1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
>> +
>> +      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
>> +    217,100,255,  0, 97,165,  0,  0,156,  0,  0,  0,  0,  0,  0,125,
>> +    173,114,  0,113,  0,  0,  0,126,128,  0,  0,140,  0,  0,  0,127,
>> +    159,  0,115,  0,164,  0,  0,116,158,  0,150,166,  0,  0,  0,142,
>> +    157,  0,  0,  0,  0,  0,  0,  0,155,  0, 98,  0,  0,163,  0,  0,
>> +    226,  0,  0,  0,  0,  0,  0,  0,  0,255, 96,  0,  0,  0,143,  0,
>> +      0,  0,  0,  0,  0,  0,  0,  0,  0,107,  0,105,102,  0,  0,112,
>> +    110,111,108,112,106,103,  0,119,  0,118,109,  0, 99,104,119,  0,
>> +
>> +};
>> +
>> +const unsigned char atkbd_unxlate_table[128] = {
>> +
>> +      0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
>> +     21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
>> +     35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
>> +     50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88,  5,  6,  4, 12,  3,
>> +     11,  2, 10,  1,  9,119,126,108,117,125,123,107,115,116,121,105,
>> +    114,122,112,113,127, 96, 97,120,  7, 15, 23, 31, 39, 47, 55, 63,
>> +     71, 79, 86, 94,  8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
>> +     19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
>> +
>> +};
>> +
>> +static unsigned char scancode2linux[512];
>> +
>> +/* Send an event to the keyboard frontend driver */
>> +static int xenfb_kbd_event(struct xen_input *xenfb,
>> +			   union xenkbd_in_event *event)
>> +{
>> +    struct xenkbd_page *page = xenfb->c.page;
>> +    uint32_t prod;
>> +
>> +    if (xenfb->c.xendev.be_state != XenbusStateConnected)
>> +	return 0;
>> +
>> +    prod = page->in_prod;
>> +    if (prod - page->in_cons == XENKBD_IN_RING_LEN) {
>> +	errno = EAGAIN;
>> +	return -1;
>> +    }
>> +
>> +    xen_mb();		/* ensure ring space available */
>> +    XENKBD_IN_RING_REF(page, prod) = *event;
>> +    xen_wmb();		/* ensure ring contents visible */
>> +    page->in_prod = prod + 1;
>> +    return xen_be_send_notify(&xenfb->c.xendev);
>> +}
>> +
>> +/* Send a keyboard (or mouse button) event */
>> +static int xenfb_send_key(struct xen_input *xenfb, bool down, int  
>> keycode)
>> +{
>> +    union xenkbd_in_event event;
>> +
>> +    memset(&event, 0, XENKBD_IN_EVENT_SIZE);
>> +    event.type = XENKBD_TYPE_KEY;
>> +    event.key.pressed = down ? 1 : 0;
>> +    event.key.keycode = keycode;
>> +
>> +    return xenfb_kbd_event(xenfb, &event);
>> +}
>> +
>> +/* Send a relative mouse movement event */
>> +static int xenfb_send_motion(struct xen_input *xenfb,
>> +			     int rel_x, int rel_y, int rel_z)
>> +{
>> +    union xenkbd_in_event event;
>> +
>> +    memset(&event, 0, XENKBD_IN_EVENT_SIZE);
>> +    event.type = XENKBD_TYPE_MOTION;
>> +    event.motion.rel_x = rel_x;
>> +    event.motion.rel_y = rel_y;
>> +#if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030207
>> +    event.motion.rel_z = rel_z;
>> +#endif
>> +
>> +    return xenfb_kbd_event(xenfb, &event);
>> +}
>> +
>> +/* Send an absolute mouse movement event */
>> +static int xenfb_send_position(struct xen_input *xenfb,
>> +			       int abs_x, int abs_y, int rel_z)
>> +{
>> +    union xenkbd_in_event event;
>> +
>> +    memset(&event, 0, XENKBD_IN_EVENT_SIZE);
>> +    event.type = XENKBD_TYPE_POS;
>> +    event.pos.abs_x = abs_x;
>> +    event.pos.abs_y = abs_y;
>> +#if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030207
>> +    event.pos.rel_z = rel_z;
>> +#endif
>> +
>> +    return xenfb_kbd_event(xenfb, &event);
>> +}
>> +
>> +/*
>> + * Send a key event from the client to the guest OS
>> + * QEMU gives us a raw scancode from an AT / PS/2 style keyboard.
>> + * We have to turn this into a Linux Input layer keycode.
>> + *
>> + * Extra complexity from the fact that with extended scancodes
>> + * (like those produced by arrow keys) this method gets called
>> + * twice, but we only want to send a single event. So we have to
>> + * track the '0xe0' scancode state & collapse the extended keys
>> + * as needed.
>> + *
>> + * Wish we could just send scancodes straight to the guest which
>> + * already has code for dealing with this...
>> + */
>> +static void xenfb_key_event(void *opaque, int scancode)
>> +{
>> +    struct xen_input *xenfb = opaque;
>> +    int down = 1;
>> +
>> +    if (scancode == 0xe0) {
>> +	xenfb->extended = 1;
>> +	return;
>> +    } else if (scancode & 0x80) {
>> +	scancode &= 0x7f;
>> +	down = 0;
>> +    }
>> +    if (xenfb->extended) {
>> +	scancode |= 0x80;
>> +	xenfb->extended = 0;
>> +    }
>> +    xenfb_send_key(xenfb, down, scancode2linux[scancode]);
>> +}
>> +
>> +/*
>> + * Send a mouse event from the client to the guest OS
>> + *
>> + * The QEMU mouse can be in either relative, or absolute mode.
>> + * Movement is sent separately from button state, which has to
>> + * be encoded as virtual key events. We also don't actually get
>> + * given any button up/down events, so have to track changes in
>> + * the button state.
>> + */
>> +static void xenfb_mouse_event(void *opaque,
>> +			      int dx, int dy, int dz, int button_state)
>> +{
>> +    struct xen_input *xenfb = opaque;
>> +    int i;
>> +
>> +    if (xenfb->abs_pointer_wanted)
>> +	xenfb_send_position(xenfb,
>> +			    dx * (xenfb->c.ds->width - 1) / 0x7fff,
>> +			    dy * (xenfb->c.ds->height - 1) / 0x7fff,
>> +			    dz);
>> +    else
>> +	xenfb_send_motion(xenfb, dx, dy, dz);
>> +
>> +    for (i = 0 ; i < 8 ; i++) {
>> +	int lastDown = xenfb->button_state & (1 << i);
>> +	int down = button_state & (1 << i);
>> +	if (down == lastDown)
>> +	    continue;
>> +
>> +	if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0)
>> +	    return;
>> +    }
>> +    xenfb->button_state = button_state;
>> +}
>> +
>> +static int input_init(struct xendev *xendev)
>> +{
>> +    struct xen_input *in = container_of(xendev, struct xen_input,  
>> c.xendev);
>> +    static int first = 1;
>> +    int i;
>> +
>> +    if (first) {
>> +	/* Prepare scancode mapping table */
>> +	for (i = 0; i < 128; i++) {
>> +	    scancode2linux[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
>> +	    scancode2linux[i | 0x80] =
>> +		atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
>> +	}
>> +	first = 0;
>> +    }
>> +
>> +    if (!in->c.ds) {
>> +        /* xen_set_display() below will set that and trigger us  
>> again */
>> +        xen_be_printf(xendev, 1, "ds not set (yet)\n");
>> +	return -1;
>> +    }
>> +
>> +    xenstore_write_be_int(xendev, "feature-abs-pointer", 1);
>> +    return 0;
>> +}
>> +
>> +static int input_connect(struct xendev *xendev)
>> +{
>> +    struct xen_input *in = container_of(xendev, struct xen_input,  
>> c.xendev);
>> +    int rc;
>> +
>> +    if (-1 == xenstore_read_fe_int(xendev, "request-abs-pointer",  
>> &in->abs_pointer_wanted))
>> +	in->abs_pointer_wanted = 0;
>> +
>> +    rc = common_bind(&in->c);
>> +    if (0 != rc)
>> +	return rc;
>> +
>> +    qemu_add_kbd_event_handler(xenfb_key_event, in);
>> +    in->qmouse = qemu_add_mouse_event_handler(xenfb_mouse_event, in,
>> +					      in->abs_pointer_wanted,
>> +					      "Xen PVFB Mouse");
>> +    return 0;
>> +}
>> +
>> +static void input_disconnect(struct xendev *xendev)
>> +{
>> +    struct xen_input *in = container_of(xendev, struct xen_input,  
>> c.xendev);
>> +
>> +    if (in->qmouse) {
>> +	qemu_remove_mouse_event_handler(in->qmouse);
>> +	in->qmouse = NULL;
>> +    }
>> +    qemu_add_kbd_event_handler(NULL, NULL);
>> +    common_unbind(&in->c);
>> +}
>> +
>> +static void input_event(struct xendev *xendev)
>> +{
>> +    struct xen_input *xenfb = container_of(xendev, struct  
>> xen_input, c.xendev);
>> +    struct xenkbd_page *page = xenfb->c.page;
>> +
>> +    /* We don't understand any keyboard events, so just ignore  
>> them. */
>> +    if (page->out_prod == page->out_cons)
>> +	return;
>> +    page->out_cons = page->out_prod;
>> +    xen_be_send_notify(&xenfb->c.xendev);
>> +}
>> +
>> +/*  
>> -------------------------------------------------------------------- */
>> +
>> +static void xenfb_copy_mfns(int mode, int count, unsigned long  
>> *dst, void *src)
>> +{
>> +    uint32_t *src32 = src;
>> +    uint64_t *src64 = src;
>> +    int i;
>> +
>> +    for (i = 0; i < count; i++)
>> +	dst[i] = (mode == 32) ? src32[i] : src64[i];
>> +}
>> +
>> +static int xenfb_map_fb(struct xen_fb *xenfb)
>> +{
>> +    struct xenfb_page *page = xenfb->c.page;
>> +    char *protocol = xenfb->c.xendev.protocol;
>> +    int n_fbmfns;
>> +    int n_fbdirs;
>> +    unsigned long *pgmfns = NULL;
>> +    unsigned long *fbmfns = NULL;
>> +    void *map, *pd;
>> +    int mode, ret = -1;
>> +
>> +    /* default to native */
>> +    pd = page->pd;
>> +    mode = sizeof(unsigned long) * 8;
>> +
>> +    if (!protocol) {
>> +	/*
>> +	 * Undefined protocol, some guesswork needed.
>> +	 *
>> +	 * Old frontends which don't set the protocol use
>> +	 * one page directory only, thus pd[1] must be zero.
>> +	 * pd[1] of the 32bit struct layout and the lower
>> +	 * 32 bits of pd[0] of the 64bit struct layout have
>> +	 * the same location, so we can check that ...
>> +	 */
>> +	uint32_t *ptr32 = NULL;
>> +	uint32_t *ptr64 = NULL;
>> +#if defined(__i386__)
>> +	ptr32 = (void*)page->pd;
>> +	ptr64 = ((void*)page->pd) + 4;
>> +#elif defined(__x86_64__)
>> +	ptr32 = ((void*)page->pd) - 4;
>> +	ptr64 = (void*)page->pd;
>> +#endif
>> +	if (ptr32) {
>> +	    if (0 == ptr32[1]) {
>> +		mode = 32;
>> +		pd   = ptr32;
>> +	    } else {
>> +		mode = 64;
>> +		pd   = ptr64;
>> +	    }
>> +	}
>> +#if defined(__x86_64__)
>> +    } else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_32)) {
>> +	/* 64bit dom0, 32bit domU */
>> +	mode = 32;
>> +	pd   = ((void*)page->pd) - 4;
>> +#elif defined(__i386__)
>> +    } else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_64)) {
>> +	/* 32bit dom0, 64bit domU */
>> +	mode = 64;
>> +	pd   = ((void*)page->pd) + 4;
>> +#endif
>> +    }
>> +
>> +    n_fbmfns = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
>> +    n_fbdirs = n_fbmfns * mode / 8;
>> +    n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
>> +
>> +    pgmfns = malloc(sizeof(unsigned long) * n_fbdirs);
>> +    fbmfns = malloc(sizeof(unsigned long) * n_fbmfns);
>> +    if (!pgmfns || !fbmfns)
>> +	goto out;
>> +
>> +    xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd);
>> +    map = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
>> +			       PROT_READ, pgmfns, n_fbdirs);
>> +    if (map == NULL)
>> +	goto out;
>> +    xenfb_copy_mfns(mode, n_fbmfns, fbmfns, map);
>> +    munmap(map, n_fbdirs * XC_PAGE_SIZE);
>> +
>> +    xenfb->pixels = xc_map_foreign_pages(xen_xc, xenfb- 
>> >c.xendev.dom,
>> +					 PROT_READ | PROT_WRITE, fbmfns, n_fbmfns);
>> +    if (xenfb->pixels == NULL)
>> +	goto out;
>> +
>> +    ret = 0; /* all is fine */
>> +
>> +out:
>> +    if (pgmfns)
>> +	free(pgmfns);
>> +    if (fbmfns)
>> +	free(fbmfns);
>> +    return ret;
>> +}
>> +
>> +static int xenfb_configure_fb(struct xen_fb *xenfb, size_t  
>> fb_len_lim,
>> +			      int width, int height, int depth,
>> +			      size_t fb_len, int offset, int row_stride)
>> +{
>> +    size_t mfn_sz = sizeof(*((struct xenfb_page *)0)->pd);
>> +    size_t pd_len = sizeof(((struct xenfb_page *)0)->pd) / mfn_sz;
>> +    size_t fb_pages = pd_len * XC_PAGE_SIZE / mfn_sz;
>> +    size_t fb_len_max = fb_pages * XC_PAGE_SIZE;
>> +    int max_width, max_height;
>> +
>> +    if (fb_len_lim > fb_len_max) {
>> +	xen_be_printf(&xenfb->c.xendev, 0, "fb size limit %zu exceeds  
>> %zu, corrected\n",
>> +		      fb_len_lim, fb_len_max);
>> +	fb_len_lim = fb_len_max;
>> +    }
>> +    if (fb_len_lim && fb_len > fb_len_lim) {
>> +	xen_be_printf(&xenfb->c.xendev, 0, "frontend fb size %zu limited  
>> to %zu\n",
>> +		      fb_len, fb_len_lim);
>> +	fb_len = fb_len_lim;
>> +    }
>> +    if (depth != 8 && depth != 16 && depth != 24 && depth != 32) {
>> +	xen_be_printf(&xenfb->c.xendev, 0, "can't handle frontend fb  
>> depth %d\n",
>> +		      depth);
>> +	return -1;
>> +    }
>> +    if (row_stride < 0 || row_stride > fb_len) {
>> +	xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend stride %d 
>> \n", row_stride);
>> +	return -1;
>> +    }
>> +    max_width = row_stride / (depth / 8);
>> +    if (width < 0 || width > max_width) {
>> +	xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend width %d  
>> limited to %d\n",
>> +		      width, max_width);
>> +	width = max_width;
>> +    }
>> +    if (offset < 0 || offset >= fb_len) {
>> +	xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend offset %d  
>> (max %zu)\n",
>> +		      offset, fb_len - 1);
>> +	return -1;
>> +    }
>> +    max_height = (fb_len - offset) / row_stride;
>> +    if (height < 0 || height > max_height) {
>> +	xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend height %d  
>> limited to %d\n",
>> +		      height, max_height);
>> +	height = max_height;
>> +    }
>> +    xenfb->fb_len = fb_len;
>> +    xenfb->row_stride = row_stride;
>> +    xenfb->depth = depth;
>> +    xenfb->width = width;
>> +    xenfb->height = height;
>> +    xenfb->offset = offset;
>> +    xen_be_printf(&xenfb->c.xendev, 1, "framebuffer %dx%dx%d  
>> offset %d stride %d\n",
>> +		  width, height, depth, offset, row_stride);
>> +    return 0;
>> +}
>> +
>> +/* A convenient function for munging pixels between different  
>> depths */
>> +#define  
>> BLT(SRC_T,DST_T,RSB,GSB,BSB,RDB,GDB,BDB)                        \
>> +    for (line = y ; line < (y+h) ; line++) {				\
>> +	SRC_T *src = (SRC_T *)(xenfb->pixels				\
>> +			       + xenfb->offset				\
>> +			       + (line * xenfb->row_stride)		\
>> +			       + (x * xenfb->depth / 8));		\
>> +	DST_T *dst = (DST_T *)(xenfb->c.ds->data				\
>> +			       + (line * xenfb->c.ds->linesize)		\
>> +			       + (x * xenfb->c.ds->depth / 8));		\
>> +	int col;							\
>> +	const int RSS = 32 - (RSB + GSB + BSB);				\
>> +	const int GSS = 32 - (GSB + BSB);				\
>> +	const int BSS = 32 - (BSB);					\
>> +	const uint32_t RSM = (~0U) << (32 - RSB);			\
>> +	const uint32_t GSM = (~0U) << (32 - GSB);			\
>> +	const uint32_t BSM = (~0U) << (32 - BSB);			\
>> +	const int RDS = 32 - (RDB + GDB + BDB);				\
>> +	const int GDS = 32 - (GDB + BDB);				\
>> +	const int BDS = 32 - (BDB);					\
>> +	const uint32_t RDM = (~0U) << (32 - RDB);			\
>> +	const uint32_t GDM = (~0U) << (32 - GDB);			\
>> +	const uint32_t BDM = (~0U) << (32 - BDB);			\
>> +	for (col = x ; col < (x+w) ; col++) {				\
>> +	    uint32_t spix = *src;					\
>> +	    *dst = (((spix << RSS) & RSM & RDM) >> RDS) |		\
>> +		(((spix << GSS) & GSM & GDM) >> GDS) |			\
>> +		(((spix << BSS) & BSM & BDM) >> BDS);			\
>> +	    src = (SRC_T *) ((unsigned long) src + xenfb->depth / 8);	\
>> +	    dst = (DST_T *) ((unsigned long) dst + xenfb->c.ds->depth /  
>> 8); \
>> +	}								\
>> +    }
>>
>
> There are similar conversion macros in the VGA code.  I don't know  
> how practical it would be to reuse them but it's at least worth  
> looking at.

We created a file hw/pixel_ops.h to share code between vga.c and  
tcx.c, probably it can be extended to serve Xen as well.

Andreas

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu
  2008-07-28 13:31 ` [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu Ian Jackson
  2008-07-28 14:33   ` Anthony Liguori
@ 2008-07-28 14:43   ` Gerd Hoffmann
  1 sibling, 0 replies; 64+ messages in thread
From: Gerd Hoffmann @ 2008-07-28 14:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: xen-devel

Ian Jackson wrote:
> Gerd Hoffmann writes ("[Qemu-devel] [PATCH 0/7] merge some xen bits into qemu"):
>> Here are a bunch of patches which start adding xen support to qemu.
>> Overview (individual patches have longer descriptions):
> 
> Just to clarify: as far as I can tell from the description,
> this code has scant relationship with Xen upstream.

Patches #3 + #4 are largely based on qemu-dm code (as noted in the
individual patch  descriptions).

> I'm generally in favour of pushing functionality out of the Xen branch
> of qemu into upstream.  But going by Gerd Hoffman's description I
> don't think that's what his branch is.  His code doesn't appear to be
> related to the Xen branch of qemu that we are using.

I want to merge the *functionality*.  IMHO that doesn't mean that it
must be the *code* used by Xen at the moment.

> For example,
> 
>> With the first four patches in place upstream qemu can replace xen's
>> qemu-dm for paravirtual domains.  The block and nic backend drivers are
>> full userspace implementations using the grant table device (gntdev).
> 
> we only use qemu-dm in paravirtualised domains for certain marginal
> functions - in many cases it is not used at all.

It's used for xen console (optionally, can also be handled by
xenconsoled) and the virtual framebuffer.

> Certainly the
> functionality Gerd describes, such as xen backend block and network
> drivers, are not in our qemu tree and we do not intend for them to be
> there.

I want them be there though.  You can use them or not, that is your call.

> In a Xen installation this functionality is in the dom0 (host) kernel.

That is only half the story.  The block backend can run in userspace too
(when using blktap).  The block backend driver should be pretty much
identical to blktap functionality-wise.  The implementation is quite
different though.

> As far as I can see much of Gerd Hoffman's intended submission is
> effectively an _emulator_ for Xen guests.  That is, it emulates a Xen
> host without being one, so that a Xen domU can be run without the Xen
> hypervisor.  Am I right, Gerd ?

That is part of the longterm plan, yes.  I want qemu being able to do
both, run as device model for xen and also to boot xen guest images
without xen, using emulation.  If the intention would have been
emulation only I wouldn't have Cc'ed xen-devel for patch review.

The emulation bits are not in that patchset btw.

> But if this functionality is to go into qemu upstream perhaps it
> should be distinguished from `real Xen' functions, because otherwise
> users are going to become very very confused.

Huh?

cheers,
  Gerd

-- 
http://kraxel.fedorapeople.org/xenner/

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 1/7] xen: groundwork for xen support
  2008-07-28 14:04   ` Anthony Liguori
@ 2008-07-28 14:52     ` Gerd Hoffmann
  2008-07-29  8:10       ` [Xen-devel] " Daniel P. Berrange
  2008-07-28 23:14     ` Samuel Thibault
  1 sibling, 1 reply; 64+ messages in thread
From: Gerd Hoffmann @ 2008-07-28 14:52 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: xen-devel, qemu-devel

>> +/* xen_machine.c */
>> +extern QEMUMachine xenpv_machine;
>> +extern QEMUMachine xenfv_machine;
> 
> Why does xenfv need its own machine type?

This is how xen's qemu-dm handles it at the moment and I've decided to
do it the same way for simplicity.  I think qemu could also figure it
using a hypercall.

>> -    /* XXX: this should not be: some embedded targets just have flash */
>> +    /* need a disk for this machine to boot ? */
>> +    /* XXX: add embedded targets which just have flash */
>> +    nodisk_ok = 0;
>> +    if (0 == strcmp(machine->name, "xenpv"))
>> +    nodisk_ok = 1;
>>      if (!linux_boot && net_boot == 0 &&
>> -        nb_drives_opt == 0)
>> +        !nodisk_ok && nb_drives_opt == 0)
>>          help(1);
> 
> This patch is pretty clean with the exception of this bit.  I think a
> cleaner way to do this would be to let the machine types specify whether
> a disk is needed or not.

Agreed, I'll make it a machine_type field.

thanks,
  Gerd

-- 
http://kraxel.fedorapeople.org/xenner/

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu
  2008-07-28 14:33   ` Anthony Liguori
@ 2008-07-28 14:58     ` Ian Jackson
  2008-07-28 15:24       ` Anthony Liguori
  2008-07-29  8:26       ` Daniel P. Berrange
  2008-07-28 15:23     ` Gerd Hoffmann
  1 sibling, 2 replies; 64+ messages in thread
From: Ian Jackson @ 2008-07-28 14:58 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: xen-devel, qemu-devel, Gerd Hoffmann

Anthony Liguori writes ("Re: [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu"):
> I think it's more closely related to Xenite and Xenner.  Gerd: are you 
> planning on folding in domain creation?  Right now it appears to be a 
> helper launched after the domain creation.
...
> No, it's definitely for use with Xen (hypervisor).  But it's different 
> architecturally from how Xen uses QEMU in xen-unstable.

Xenner is an emulator for allowing Xen domUs to be booted without the
Xen hypervisor.

Xennite is an experimental replacement for the Xen userland management
stack in dom0: it moves more functionality from the Xen tools in dom0
into the qemu-dm process.  This is moving in almost the opposite
direction to Xen upstream is moving: we are moving qemu-dm into its
own tiny domain, so that the qemu code doesn't need to run as a
process in dom0; this has important security and scalability
advantages.

Ian.

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu
  2008-07-28 14:33   ` Anthony Liguori
  2008-07-28 14:58     ` Ian Jackson
@ 2008-07-28 15:23     ` Gerd Hoffmann
  1 sibling, 0 replies; 64+ messages in thread
From: Gerd Hoffmann @ 2008-07-28 15:23 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: xen-devel, Ian Jackson, qemu-devel

Anthony Liguori wrote:
> I think it's more closely related to Xenite and Xenner.  Gerd: are you
> planning on folding in domain creation?  Right now it appears to be a
> helper launched after the domain creation.

Not sure yet.  Given that xen upstream most likely wouldn't follow a
xenite-like model I'm not sure how useful it would be.  Shouldn't be
that much extra code though, and as long as it is an opt-in upstream xen
should be happy too ...

> It
> seems like it could be used as almost a drop-in replacement for qemu-dm
> for PV guests.

Yes, that is the intention.

> HVM guests would require more work.

Yes.  Not addressed (yet).  hvm is more code, more invasive and I also
hope that Glauber Costa's work on a cpu abstraction layer (for
emulation/kqemu/kvm) makes it easier to add xen hvm to the picture.

cheers,
  Gerd

-- 
http://kraxel.fedorapeople.org/xenner/

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu
  2008-07-28 14:58     ` Ian Jackson
@ 2008-07-28 15:24       ` Anthony Liguori
  2008-07-29  8:26       ` Daniel P. Berrange
  1 sibling, 0 replies; 64+ messages in thread
From: Anthony Liguori @ 2008-07-28 15:24 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel, qemu-devel, Gerd Hoffmann

Ian Jackson wrote:
> Anthony Liguori writes ("Re: [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu"):
>   
>> I think it's more closely related to Xenite and Xenner.  Gerd: are you 
>> planning on folding in domain creation?  Right now it appears to be a 
>> helper launched after the domain creation.
>>     
> ...
>   
>> No, it's definitely for use with Xen (hypervisor).  But it's different 
>> architecturally from how Xen uses QEMU in xen-unstable.
>>     
>
> Xenner is an emulator for allowing Xen domUs to be booted without the
> Xen hypervisor.
>   

Or "shim".  It's almost architecturally identical to the XenSource 
developed "shim" for Hyper-V.  It seems like a popular thing to do these 
days :-)

> Xennite is an experimental replacement for the Xen userland management
> stack in dom0: it moves more functionality from the Xen tools in dom0
> into the qemu-dm process.  This is moving in almost the opposite
> direction to Xen upstream is moving: we are moving qemu-dm into its
> own tiny domain, so that the qemu code doesn't need to run as a
> process in dom0; this has important security and scalability
> advantages.
>   

Are there separate requirements for stub domains verses Xennite?

Gerd's code is different than what's upstream in QEMU but the question 
is whether it's reconcilable with what's upstream.  If not, what makes 
it that way?

Regards,

Anthony Liguori

> Ian.
>   

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 3/7] xen: add console backend driver.
  2008-07-28 14:17   ` Anthony Liguori
@ 2008-07-28 15:43     ` Gerd Hoffmann
  2008-07-28 19:04       ` Anthony Liguori
  0 siblings, 1 reply; 64+ messages in thread
From: Gerd Hoffmann @ 2008-07-28 15:43 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: xen-devel, qemu-devel

>> +
>> +struct devops xen_console_ops = {
>>   
> 
> I missed it in the previous patchset, but it would be nice to QEMU-ify
> these things.  For instance, 'struct xen_console' => 'XenConsole',
> 'struct devopts' => 'XenDevOpts', etc.

Hmm, I will if I have to.

But I don't like that style very much and a quick grep through the qemu
header files shows that the CapsStyle isn't used consequently
everythere.  I see a happy style mix.  The core structures tend to be
CapsStyle though ...

cheers,
  Gerd

-- 
http://kraxel.fedorapeople.org/xenner/

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 6/7] xen: add net backend driver.
  2008-07-28 14:27   ` Anthony Liguori
@ 2008-07-28 15:45     ` Gerd Hoffmann
  0 siblings, 0 replies; 64+ messages in thread
From: Gerd Hoffmann @ 2008-07-28 15:45 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: xen-devel, qemu-devel

Anthony Liguori wrote:
> Gerd Hoffmann wrote:
>> +static void checksum_calculate(uint8_t *data, int length)
>> +{
> 
> The same thing is done in e1000, I believe.  We'll also probably want to
> be able to support this for virtio so this would be pretty good to make
> common code.

Good point, I'll split it into a separate patch and source file.

cheers,
  Gerd

-- 
http://kraxel.fedorapeople.org/xenner/

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 2/7] xen: backend driver core
  2008-07-28 14:13   ` Anthony Liguori
@ 2008-07-28 15:51     ` Gerd Hoffmann
  0 siblings, 0 replies; 64+ messages in thread
From: Gerd Hoffmann @ 2008-07-28 15:51 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: xen-devel, qemu-devel

Anthony Liguori wrote:
>> --- /dev/null
>> +++ b/hw/list.h
>>   
> 
> There's already a list implementation in audio/sys-queue.h

Well hidden ;)
Thanks for the pointer.

> I think it would be good to provide some more commenting in this file. 
> Just a high level description of XenStore and how all of this stuff fits
> together would be nice.

Probably a good idea, yes.

thanks,
  Gerd

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 3/7] xen: add console backend driver.
  2008-07-28 15:43     ` Gerd Hoffmann
@ 2008-07-28 19:04       ` Anthony Liguori
  0 siblings, 0 replies; 64+ messages in thread
From: Anthony Liguori @ 2008-07-28 19:04 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: xen-devel, qemu-devel

Gerd Hoffmann wrote:
>>> +
>>> +struct devops xen_console_ops = {
>>>   
>>>       
>> I missed it in the previous patchset, but it would be nice to QEMU-ify
>> these things.  For instance, 'struct xen_console' => 'XenConsole',
>> 'struct devopts' => 'XenDevOpts', etc.
>>     
>
> Hmm, I will if I have to.
>
> But I don't like that style very much and a quick grep through the qemu
> header files shows that the CapsStyle isn't used consequently
> everythere.  I see a happy style mix.  The core structures tend to be
> CapsStyle though ...
>   

I much prefer the Linux style myself, but I prefer consistency over any 
particular style.  I think it would be good to modify the code to be 
consistent with the rest of the core QEMU structure.

Regards,

Anthony Liguori

> cheers,
>   Gerd
>
>   

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Xen-devel] Re: [Qemu-devel] [PATCH 1/7] xen: groundwork for xen support
  2008-07-28 14:04   ` Anthony Liguori
  2008-07-28 14:52     ` Gerd Hoffmann
@ 2008-07-28 23:14     ` Samuel Thibault
  2008-07-29  7:38       ` Gerd Hoffmann
  1 sibling, 1 reply; 64+ messages in thread
From: Samuel Thibault @ 2008-07-28 23:14 UTC (permalink / raw)
  To: qemu-devel; +Cc: xen-devel, Gerd Hoffmann

Anthony Liguori, le Mon 28 Jul 2008 09:04:54 -0500, a écrit :
> >+/* xen_machine.c */
> >+extern QEMUMachine xenpv_machine;
> >+extern QEMUMachine xenfv_machine;
> 
> Why does xenfv need its own machine type?

IIRC that's at least because it adds its own Xen platform -specific PCI card.

Samuel

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Xen-devel] Re: [Qemu-devel] [PATCH 1/7] xen: groundwork for xen support
  2008-07-28 23:14     ` Samuel Thibault
@ 2008-07-29  7:38       ` Gerd Hoffmann
  2008-07-29  8:12         ` Daniel P. Berrange
  0 siblings, 1 reply; 64+ messages in thread
From: Gerd Hoffmann @ 2008-07-29  7:38 UTC (permalink / raw)
  To: Samuel Thibault, qemu-devel, xen-devel, Gerd Hoffmann

Samuel Thibault wrote:
> Anthony Liguori, le Mon 28 Jul 2008 09:04:54 -0500, a écrit :
>>> +/* xen_machine.c */
>>> +extern QEMUMachine xenpv_machine;
>>> +extern QEMUMachine xenfv_machine;
>> Why does xenfv need its own machine type?
> 
> IIRC that's at least because it adds its own Xen platform -specific PCI card.

That is only one tiny bit of the differences between paravirtual and
fully virtualized machines, there is plenty more.  The question is
whenever qemu should try figure itself whenever the virtual machine it
serves is fully virtualized or whenever we'll explicitly tell it qemu.

I think it is better to explicitly tell qemu whenever we want create a
paravirtual or a full virtualized machine.  First, because this is how
it is handled right now in xen (via -M [ xenpv | xenfv ] ), and second,
it leaves the door open to have qemu also create the domain.

cheers,
  Gerd

-- 
http://kraxel.fedorapeople.org/xenner/

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Xen-devel] Re: [Qemu-devel] [PATCH 1/7] xen: groundwork for xen support
  2008-07-28 14:52     ` Gerd Hoffmann
@ 2008-07-29  8:10       ` Daniel P. Berrange
  2008-07-29 13:32         ` Anthony Liguori
  0 siblings, 1 reply; 64+ messages in thread
From: Daniel P. Berrange @ 2008-07-29  8:10 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: xen-devel, qemu-devel

On Mon, Jul 28, 2008 at 04:52:28PM +0200, Gerd Hoffmann wrote:
> >> +/* xen_machine.c */
> >> +extern QEMUMachine xenpv_machine;
> >> +extern QEMUMachine xenfv_machine;
> > 
> > Why does xenfv need its own machine type?
> 
> This is how xen's qemu-dm handles it at the moment and I've decided to
> do it the same way for simplicity.  I think qemu could also figure it
> using a hypercall.

This is something I originally added to QEMU in Xen's tree. The basic
idea is that the 'xenpv' macjine is a machine which /only/ provides the
paravirtualized Xen backends drivers. The 'xenfv' machine type is just
the same as the 'pc' machine type, but with the /addition/ of the Xen
paravirtualized backends. Perhaps the latter could be thought of as
more of a 'xenpc' (cf 'pc' and 'isapc') becasue its a variation on the
regular PC machine type. Annoying that all the acronyms I come up with
only differ by one letter :-)

Daniel
-- 
|: Red Hat, Engineering, London   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Xen-devel] Re: [Qemu-devel] [PATCH 1/7] xen: groundwork for xen support
  2008-07-29  7:38       ` Gerd Hoffmann
@ 2008-07-29  8:12         ` Daniel P. Berrange
  2008-07-29  8:55           ` Gerd Hoffmann
  0 siblings, 1 reply; 64+ messages in thread
From: Daniel P. Berrange @ 2008-07-29  8:12 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: xen-devel, qemu-devel, Samuel Thibault

On Tue, Jul 29, 2008 at 09:38:01AM +0200, Gerd Hoffmann wrote:
> Samuel Thibault wrote:
> > Anthony Liguori, le Mon 28 Jul 2008 09:04:54 -0500, a écrit :
> >>> +/* xen_machine.c */
> >>> +extern QEMUMachine xenpv_machine;
> >>> +extern QEMUMachine xenfv_machine;
> >> Why does xenfv need its own machine type?
> > 
> > IIRC that's at least because it adds its own Xen platform -specific PCI card.
> 
> That is only one tiny bit of the differences between paravirtual and
> fully virtualized machines, there is plenty more.  The question is
> whenever qemu should try figure itself whenever the virtual machine it
> serves is fully virtualized or whenever we'll explicitly tell it qemu.
> 
> I think it is better to explicitly tell qemu whenever we want create a
> paravirtual or a full virtualized machine.  First, because this is how
> it is handled right now in xen (via -M [ xenpv | xenfv ] ), and second,
> it leaves the door open to have qemu also create the domain.

The setup process for 'xenpv' vs 'xenfv' is really very different. As I
mentioned in the other mail, 'xenfv' is really much closer to 'pc'
machine type, then 'xenpv'.  Thus I think its better to keep them
explicitly separate - they call out to shared code where needed anyway,
so there's no serious code duplication problem there.

Daniel
-- 
|: Red Hat, Engineering, London   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu
  2008-07-28 14:58     ` Ian Jackson
  2008-07-28 15:24       ` Anthony Liguori
@ 2008-07-29  8:26       ` Daniel P. Berrange
  1 sibling, 0 replies; 64+ messages in thread
From: Daniel P. Berrange @ 2008-07-29  8:26 UTC (permalink / raw)
  To: qemu-devel; +Cc: xen-devel, Gerd Hoffmann

On Mon, Jul 28, 2008 at 03:58:15PM +0100, Ian Jackson wrote:
> Anthony Liguori writes ("Re: [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu"):
> > I think it's more closely related to Xenite and Xenner.  Gerd: are you 
> > planning on folding in domain creation?  Right now it appears to be a 
> > helper launched after the domain creation.
> ...
> > No, it's definitely for use with Xen (hypervisor).  But it's different 
> > architecturally from how Xen uses QEMU in xen-unstable.
> 
> Xenner is an emulator for allowing Xen domUs to be booted without the
> Xen hypervisor.
> 
> Xennite is an experimental replacement for the Xen userland management
> stack in dom0: it moves more functionality from the Xen tools in dom0
> into the qemu-dm process.  This is moving in almost the opposite
> direction to Xen upstream is moving: we are moving qemu-dm into its
> own tiny domain, so that the qemu code doesn't need to run as a
> process in dom0; this has important security and scalability
> advantages.

Yes, to be clear that the Xennite code is *not* an official Xen project. 

It is my experimental work and I don't expect anyone to use it for real
in the near future. It does however align very well with Gerd's serious 
Xenner project (which is incredibly useful tool allowing admins to mix
and match Xen and KVM) since both Xenner & Xennite have much same needs
in  terms of QEMU support code

The motiviation with 'Xennite' is to make the process of launching
and managing an instance of a Xen guest, as close as possible to that
of KVM. Start QEMU to launch the Xen guest, interact with the monitor
to control it, and kill QEMU to destroy the Xen guest. I'd class it as
a proof-of-concept since I never got around to making stuff like save
and restore work - I postponed further work until Xen re-synced with a
new QEMU codebase.  We could have a long discussion about the pros/cons
of this idea vs the upstream Xen move to QEMU in stub domains, but that's
off topic for this list, so I'll leave it :-)  

Daniel
-- 
|: Red Hat, Engineering, London   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Xen-devel] Re: [Qemu-devel] [PATCH 1/7] xen: groundwork for xen support
  2008-07-29  8:12         ` Daniel P. Berrange
@ 2008-07-29  8:55           ` Gerd Hoffmann
  0 siblings, 0 replies; 64+ messages in thread
From: Gerd Hoffmann @ 2008-07-29  8:55 UTC (permalink / raw)
  To: Daniel P. Berrange, qemu-devel; +Cc: xen-devel, Samuel Thibault

Daniel P. Berrange wrote:

> The setup process for 'xenpv' vs 'xenfv' is really very different. As I
> mentioned in the other mail, 'xenfv' is really much closer to 'pc'
> machine type, then 'xenpv'.

Yes.  I think we will keep the xenpv machine type for sure.  For full
virtualization it might be more useful to just use the "pc" machine type
(and maybe make xenfv an alias for compatibility).

>From qemu's point of view xen and kvm are not very different: no cpu
emulation needed, some chips such as apic are handled by someone else
too, some additional devices might be there (xen platform device, virtio
devices).  So it would make sense to handle them the same way,
especially once we have the qemuaccel stuff in place which will add an
abstraction layer for this.

cheers,
  Gerd

-- 
http://kraxel.fedorapeople.org/xenner/

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Xen-devel] Re: [Qemu-devel] [PATCH 1/7] xen: groundwork for xen support
  2008-07-29  8:10       ` [Xen-devel] " Daniel P. Berrange
@ 2008-07-29 13:32         ` Anthony Liguori
  2008-07-29 14:24           ` Daniel P. Berrange
  2008-07-29 14:32           ` Gerd Hoffmann
  0 siblings, 2 replies; 64+ messages in thread
From: Anthony Liguori @ 2008-07-29 13:32 UTC (permalink / raw)
  To: Daniel P. Berrange; +Cc: xen-devel, Gerd Hoffmann, qemu-devel

Daniel P. Berrange wrote:
> On Mon, Jul 28, 2008 at 04:52:28PM +0200, Gerd Hoffmann wrote:
>   
>>>> +/* xen_machine.c */
>>>> +extern QEMUMachine xenpv_machine;
>>>> +extern QEMUMachine xenfv_machine;
>>>>         
>>> Why does xenfv need its own machine type?
>>>       
>> This is how xen's qemu-dm handles it at the moment and I've decided to
>> do it the same way for simplicity.  I think qemu could also figure it
>> using a hypercall.
>>     
>
> This is something I originally added to QEMU in Xen's tree. The basic
> idea is that the 'xenpv' macjine is a machine which /only/ provides the
> paravirtualized Xen backends drivers. The 'xenfv' machine type is just
> the same as the 'pc' machine type, but with the /addition/ of the Xen
> paravirtualized backends. Perhaps the latter could be thought of as
> more of a 'xenpc' (cf 'pc' and 'isapc') becasue its a variation on the
> regular PC machine type. Annoying that all the acronyms I come up with
> only differ by one letter :-)
>   

Why wouldn't the Xen backends be added by appropriate -net or -drive 
options?  For instance, qemu -drive file=foo.img,if=xen -net nic,model=xen

Regards,

Anthony Liguori

> Daniel
>   

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Xen-devel] Re: [Qemu-devel] [PATCH 1/7] xen: groundwork for xen support
  2008-07-29 13:32         ` Anthony Liguori
@ 2008-07-29 14:24           ` Daniel P. Berrange
  2008-07-29 19:11             ` Anthony Liguori
  2008-07-29 14:32           ` Gerd Hoffmann
  1 sibling, 1 reply; 64+ messages in thread
From: Daniel P. Berrange @ 2008-07-29 14:24 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: xen-devel, Gerd Hoffmann, qemu-devel

On Tue, Jul 29, 2008 at 08:32:11AM -0500, Anthony Liguori wrote:
> Daniel P. Berrange wrote:
> >On Mon, Jul 28, 2008 at 04:52:28PM +0200, Gerd Hoffmann wrote:
> >  
> >>>>+/* xen_machine.c */
> >>>>+extern QEMUMachine xenpv_machine;
> >>>>+extern QEMUMachine xenfv_machine;
> >>>>        
> >>>Why does xenfv need its own machine type?
> >>>      
> >>This is how xen's qemu-dm handles it at the moment and I've decided to
> >>do it the same way for simplicity.  I think qemu could also figure it
> >>using a hypercall.
> >>    
> >
> >This is something I originally added to QEMU in Xen's tree. The basic
> >idea is that the 'xenpv' macjine is a machine which /only/ provides the
> >paravirtualized Xen backends drivers. The 'xenfv' machine type is just
> >the same as the 'pc' machine type, but with the /addition/ of the Xen
> >paravirtualized backends. Perhaps the latter could be thought of as
> >more of a 'xenpc' (cf 'pc' and 'isapc') becasue its a variation on the
> >regular PC machine type. Annoying that all the acronyms I come up with
> >only differ by one letter :-)
> >  
> 
> Why wouldn't the Xen backends be added by appropriate -net or -drive 
> options?  For instance, qemu -drive file=foo.img,if=xen -net nic,model=xen

That would work for certain setup tasks, but not all. In Xen's branch
of QEMU, the machine init function has to set various hypervisor 
parameters which aren't directly associated with QEMU command line
args, and initialize things like the map-cache for > 4GB guest support.
In the Xennite work I had further stuff going on there too - more general
initialization of Xenstore parameters - eg stuffing the name & uuid from
QEMU's argv into right place in xenstore. 

Daniel
-- 
|: Red Hat, Engineering, London   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Xen-devel] Re: [Qemu-devel] [PATCH 1/7] xen: groundwork for xen support
  2008-07-29 13:32         ` Anthony Liguori
  2008-07-29 14:24           ` Daniel P. Berrange
@ 2008-07-29 14:32           ` Gerd Hoffmann
  1 sibling, 0 replies; 64+ messages in thread
From: Gerd Hoffmann @ 2008-07-29 14:32 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: xen-devel, qemu-devel

Anthony Liguori wrote:
> Daniel P. Berrange wrote:
>> This is something I originally added to QEMU in Xen's tree. The basic
>> idea is that the 'xenpv' macjine is a machine which /only/ provides the
>> paravirtualized Xen backends drivers. The 'xenfv' machine type is just
>> the same as the 'pc' machine type, but with the /addition/ of the Xen
>> paravirtualized backends. Perhaps the latter could be thought of as
>> more of a 'xenpc' (cf 'pc' and 'isapc') becasue its a variation on the
>> regular PC machine type. Annoying that all the acronyms I come up with
>> only differ by one letter :-)
> 
> Why wouldn't the Xen backends be added by appropriate -net or -drive
> options?  For instance, qemu -drive file=foo.img,if=xen -net nic,model=xen

They can and I plan to support exactly that syntax ;)


Lets us step back a bit.  xenbus handles all the device discovery.
xenstore holds (among other things) all the information xenbus needs to
discover devices.

The xen frontend devices (guest side of the split drivers) have the
configuration information in this xenstore path:

  /local/domain/$domid/device/$type/$nr/

The xen backend devices (host side of the split drivers) have the
configuration information in this path:

  /local/domain/$domid/backend/$type/$domid/$nr/

where the first domid is where the backend runs in (which is Domain-0
unless you are using driver domains).  The second domid is the guest
domain.  The $type doesn't need to be identical, so you can have
different backend drivers serving the same frontend driver.  Which
actually is the case for block devices (blkback & blktap).


The frontend and backend drivers usually scan their xenstore directories
on initialization and install xenstore watches to see devices come and go.

What needs to be done to create a xenbus device is create those two
directories (one frontend, one backend) and populate the nodes therein
with the information required (some generic, some device specific).


All the backend drivers in my patch series are using xenstore/xenbus for
device discovery as usual.  The last patch (#7) actually winds up
command line support: you can specify xen nics and disks then with the
syntax listed above, and qemu will go and create the xenstore
directories for backend and frontend.  It could also be someone else
creating them (xend, xenner), that will work equally well.

cheers,
  Gerd

-- 
http://kraxel.fedorapeople.org/xenner/

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Xen-devel] Re: [Qemu-devel] [PATCH 1/7] xen: groundwork for xen support
  2008-07-29 14:24           ` Daniel P. Berrange
@ 2008-07-29 19:11             ` Anthony Liguori
  2008-07-29 21:36               ` Gerd Hoffmann
  0 siblings, 1 reply; 64+ messages in thread
From: Anthony Liguori @ 2008-07-29 19:11 UTC (permalink / raw)
  To: Daniel P. Berrange; +Cc: xen-devel, Gerd Hoffmann, qemu-devel

Daniel P. Berrange wrote:
> On Tue, Jul 29, 2008 at 08:32:11AM -0500, Anthony Liguori wrote:
>   
>> Why wouldn't the Xen backends be added by appropriate -net or -drive 
>> options?  For instance, qemu -drive file=foo.img,if=xen -net nic,model=xen
>>     
>
> That would work for certain setup tasks, but not all. In Xen's branch
> of QEMU, the machine init function has to set various hypervisor 
> parameters which aren't directly associated with QEMU command line
> args, and initialize things like the map-cache for > 4GB guest support.
>   

map-cache is one of those things I don't expect to ever get merged.

> In the Xennite work I had further stuff going on there too - more general
> initialization of Xenstore parameters - eg stuffing the name & uuid from
> QEMU's argv into right place in xenstore. 
>   

Ideally, I'd like to see Xen/KVM integration look like this:

1) Xen support is detected in configure (libxc et al) and conditionally 
enabled.
2) When running on bare metal, detect whether KVM acceleration is 
available, also detect if kqemu acceleration is available
3) When running under Xen, detect that Xen is available, and create a 
full virt domain
4) If a user specifies a type=xen device, it should Just Work provided 
you are in a Xen environment (erroring appropriately)
5) A user can explicitly specify -M xenpv.  If running under Xen, this 
would create a Xen PV guest.  If running on bare metal, Xenner would be 
used to present a Xen shim layer.  This should work with KVM 
acceleration or without KVM acceleration.  Bonus points if it works with 
kqemu too.

For 1-4, the user experience should not be different at all.  This of 
course doesn't mean that users would be forced to interact directly with 
QEMU or that QEMU cannot be running within a stub domain.  It would be 
good if these things could be automatically detected though.

Regards,

Anthony Liguori

> Daniel
>   

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Xen-devel] Re: [Qemu-devel] [PATCH 1/7] xen: groundwork for xen support
  2008-07-29 19:11             ` Anthony Liguori
@ 2008-07-29 21:36               ` Gerd Hoffmann
  2008-07-29 21:48                 ` Anthony Liguori
  0 siblings, 1 reply; 64+ messages in thread
From: Gerd Hoffmann @ 2008-07-29 21:36 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: xen-devel, qemu-devel

Anthony Liguori wrote:
> Daniel P. Berrange wrote:
>> That would work for certain setup tasks, but not all. In Xen's branch
>> of QEMU, the machine init function has to set various hypervisor
>> parameters which aren't directly associated with QEMU command line
>> args, and initialize things like the map-cache for > 4GB guest support.
> 
> map-cache is one of those things I don't expect to ever get merged.

And the need for that will go away over time IMHO.  If your Dom0 is
64bit you have no address space pressure and thus no need for mapcache.
 Given we have 32-on-64 and non-PAE Xen is depricated anyway there is
almost no reason to not run 64bit Xen and Dom0.

> Ideally, I'd like to see Xen/KVM integration look like this:
> 
> 1) Xen support is detected in configure (libxc et al) and conditionally
> enabled.
> 2) When running on bare metal, detect whether KVM acceleration is
> available, also detect if kqemu acceleration is available
> 3) When running under Xen, detect that Xen is available, and create a
> full virt domain
> 4) If a user specifies a type=xen device, it should Just Work provided
> you are in a Xen environment (erroring appropriately)
> 5) A user can explicitly specify -M xenpv.  If running under Xen, this
> would create a Xen PV guest.  If running on bare metal, Xenner would be
> used to present a Xen shim layer.  This should work with KVM
> acceleration or without KVM acceleration.  Bonus points if it works with
> kqemu too.

I'm surprised how well you can read my mind.
Yes, I wanna have the bonus points ;)

There are two additional points you didn't see though:

For (3) and (5) qemu should support two modes:  First, attach to an
existing domain.  This is how Xen works today.  And we want get rid of
the qemu-dm fork, right?  Second, optionally also create the domain,
like Xenite.

(4) should also just work when you are *not* in a Xen environment[1]

cheers,
  Gerd

[1]  It actually does, btw.  Code isn't ready yet for merging.
     Stay tuned ;)

-- 
http://kraxel.fedorapeople.org/xenner/

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Xen-devel] Re: [Qemu-devel] [PATCH 1/7] xen: groundwork for xen support
  2008-07-29 21:36               ` Gerd Hoffmann
@ 2008-07-29 21:48                 ` Anthony Liguori
  0 siblings, 0 replies; 64+ messages in thread
From: Anthony Liguori @ 2008-07-29 21:48 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: Ian Jackson, xen-devel, qemu-devel, Samuel Thibault

Gerd Hoffmann wrote:
> Anthony Liguori wrote:
>   
>> map-cache is one of those things I don't expect to ever get merged.
>>     
>
> And the need for that will go away over time IMHO.  If your Dom0 is
> 64bit you have no address space pressure and thus no need for mapcache.
>  Given we have 32-on-64 and non-PAE Xen is depricated anyway there is
> almost no reason to not run 64bit Xen and Dom0.
>   

Right.

>> Ideally, I'd like to see Xen/KVM integration look like this:
>>
>> 1) Xen support is detected in configure (libxc et al) and conditionally
>> enabled.
>> 2) When running on bare metal, detect whether KVM acceleration is
>> available, also detect if kqemu acceleration is available
>> 3) When running under Xen, detect that Xen is available, and create a
>> full virt domain
>> 4) If a user specifies a type=xen device, it should Just Work provided
>> you are in a Xen environment (erroring appropriately)
>> 5) A user can explicitly specify -M xenpv.  If running under Xen, this
>> would create a Xen PV guest.  If running on bare metal, Xenner would be
>> used to present a Xen shim layer.  This should work with KVM
>> acceleration or without KVM acceleration.  Bonus points if it works with
>> kqemu too.
>>     
>
> I'm surprised how well you can read my mind.
>   

Scary, huh? :-)

> Yes, I wanna have the bonus points ;)
>
> There are two additional points you didn't see though:
>
> For (3) and (5) qemu should support two modes:  First, attach to an
> existing domain.  This is how Xen works today.  And we want get rid of
> the qemu-dm fork, right?  Second, optionally also create the domain,
> like Xenite.
>   

I have mixed feelings about this, but I don't think there's a way to 
support stub domains without this functionality.  Obviously, when you 
run QEMU within a stub domain, the guest domain has already been 
created.  Well, maybe it doesn't have to be that way but it seems most 
reasonable to do it that way.

> (4) should also just work when you are *not* in a Xen environment[1]
>   

I considered suggesting that but figured it would be too much.  I should 
have figured it was already working in some form :-)

So how does the upstream Xen community feel about all of this?  Is this 
a reasonable approach to merging Xen functionality into QEMU?

Regards,

Anthony Liguori

> cheers,
>   Gerd
>
> [1]  It actually does, btw.  Code isn't ready yet for merging.
>      Stay tuned ;)
>
>   

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 4/7] xen: add framebuffer backend driver
  2008-07-28 14:22   ` Anthony Liguori
  2008-07-28 14:41     ` Andreas Färber
@ 2008-07-30  9:20     ` Gerd Hoffmann
  2008-07-30 16:31       ` Markus Armbruster
  1 sibling, 1 reply; 64+ messages in thread
From: Gerd Hoffmann @ 2008-07-30  9:20 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: xen-devel, qemu-devel, Markus Armbruster

Anthony Liguori wrote:
> Gerd Hoffmann wrote:
>> +++ b/hw/xen-framebuffer.c
>> @@ -0,0 +1,925 @@
>> +/*
>> + *  xen paravirt framebuffer backend
> 
> No copyright?
> 

Well, qemu-dm's xenfb.c which I used as base didn't have one.
Guess most of this is Markus' code (CC'ed).

cheers,
  Gerd

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 4/7] xen: add framebuffer backend driver
  2008-07-28 14:41     ` Andreas Färber
@ 2008-07-30  9:59       ` Gerd Hoffmann
  2008-08-01 14:57         ` Anthony Liguori
  0 siblings, 1 reply; 64+ messages in thread
From: Gerd Hoffmann @ 2008-07-30  9:59 UTC (permalink / raw)
  To: Andreas Färber; +Cc: xen-devel, qemu-devel

  Hi,

>>> +/* A convenient function for munging pixels between different depths */
>>> +#define
>>> BLT(SRC_T,DST_T,RSB,GSB,BSB,RDB,GDB,BDB)                        \
>>> +    for (line = y ; line < (y+h) ; line++) {                \

>> There are similar conversion macros in the VGA code.  I don't know how
>> practical it would be to reuse them but it's at least worth looking at.
> 
> We created a file hw/pixel_ops.h to share code between vga.c and tcx.c,
> probably it can be extended to serve Xen as well.

Uhm, well, it isn't that easy.  Unifying that looks like a big job in
itself.  pixel_ops.h as-is isn't very helpful for xen-framebuffer.  The
xen-framebuffer macro isn't very useful to others.

What IMHO would be most useful is a set of generic conversion functions,
operating on scanline level, much like the ones created by
vga_template.h, but without dependencies on vga.c internals.

cheers,
  Gerd

-- 
http://kraxel.fedorapeople.org/xenner/

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 4/7] xen: add framebuffer backend driver
  2008-07-30  9:20     ` Gerd Hoffmann
@ 2008-07-30 16:31       ` Markus Armbruster
  2008-08-01 15:05         ` Anthony Liguori
  0 siblings, 1 reply; 64+ messages in thread
From: Markus Armbruster @ 2008-07-30 16:31 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: xen-devel, qemu-devel

Gerd Hoffmann <kraxel@redhat.com> writes:

> Anthony Liguori wrote:
>> Gerd Hoffmann wrote:
>>> +++ b/hw/xen-framebuffer.c
>>> @@ -0,0 +1,925 @@
>>> +/*
>>> + *  xen paravirt framebuffer backend
>> 
>> No copyright?
>> 
>
> Well, qemu-dm's xenfb.c which I used as base didn't have one.
> Guess most of this is Markus' code (CC'ed).
>
> cheers,
>   Gerd

Development history has been a bit more complicated than that :)

* Initial version: Anthony Liguori <anthony@codemonkey.ws>

  The link[*] to it has gone stale.  I don't think it had a copyright
  in the file that eventually mutated into the one we're discussing.

* Hacked into shape: me (xen-unstable changeset 12678).  No copyright
  in the source file.  Changeset carries:

  Signed-off-by: Markus Armbruster <armbru@redhat.com>
  Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>

* Additional changes (use "hg log tools/xenfb in xen-unstable" to list
  them) by:

  Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
  Signed-off-by: Gerd Hoffmann <kraxel@suse.de>
  Signed-off-by: Hirofumi Tsujimura <tsujimura.hirof@jp.fujitsu.com>
  Signed-off-by: Ian Campbell <ian.campbell@xensource.com>
  Signed-off-by: John Levon <john.levon@sun.com>
  Signed-off-by: Junko Ichino <ichino.junko@jp.fujitsu.com>
  Signed-off-by: Keir Fraser <keir@xensource.com>
  Signed-off-by: Markus Armbruster <armbru@redhat.com>
  Signed-off-by: Steven Smith <sos22@cam.ac.uk>
  Signed-off-by: Takanori Kasai <kasai.takanori@jp.fujitsu.com>
  Signed-off-by: Tsunehisa Doi <Doi.Tsunehisa@jp.fujitsu.com>

* Transformed from a separate program into a part of ioemu-dm:

  Signed-off-by: Daniel P. Berrange <berrange@redhat.com>

* Additional changes (use "hg log tools/xenfb" to list them) by:

  Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
  Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
  Signed-off-by: Keir Fraser <keir@xensource.com>
  Signed-off-by: Markus Armbruster <armbru@redhat.com>
  Signed-off-by: Pat Campbell <plc@novell.com>
  Signed-off-by: Samuel Thibault <samuel.thibault@eu.citrix.com>
  Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>

* Transformed to work on top of his common backend driver code in
  upstream QEMU:

  Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>

I guess a copyright note should include at least Anthony, me, Dan,
Pat, Gerd (in order of first major contribution).  Perhaps something
like:

 * Copyright (C) 2005-2006 Anthony Liguori <aliguori@us.ibm.com>
 * Copyright (C) 2006-2008 Red Hat, Inc., Markus Armbruster <armbru@redhat.com>,
 *     Daniel P. Berrange <berrange@redhat.com>,
 *     Gerd Hoffmann <kraxel@redhat.com>
 * Copyright (C) 2008 Pat Campbell <plc@novell.com>

Apologies if I missed someone!

[*] http://www.cs.utexas.edu/users/aliguori/xen-vfb-20060124.bundle

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 4/7] xen: add framebuffer backend driver
  2008-07-30  9:59       ` Gerd Hoffmann
@ 2008-08-01 14:57         ` Anthony Liguori
  0 siblings, 0 replies; 64+ messages in thread
From: Anthony Liguori @ 2008-08-01 14:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: Andreas Färber, xen-devel

Gerd Hoffmann wrote:
>   Hi,
>
>   
>>>> +/* A convenient function for munging pixels between different depths */
>>>> +#define
>>>> BLT(SRC_T,DST_T,RSB,GSB,BSB,RDB,GDB,BDB)                        \
>>>> +    for (line = y ; line < (y+h) ; line++) {                \
>>>>         
>
>   
>>> There are similar conversion macros in the VGA code.  I don't know how
>>> practical it would be to reuse them but it's at least worth looking at.
>>>       
>> We created a file hw/pixel_ops.h to share code between vga.c and tcx.c,
>> probably it can be extended to serve Xen as well.
>>     
>
> Uhm, well, it isn't that easy.  Unifying that looks like a big job in
> itself.  pixel_ops.h as-is isn't very helpful for xen-framebuffer.  The
> xen-framebuffer macro isn't very useful to others.
>   

Okay, the xen-framebuffer macros aren't that big so it's not a huge 
deal.  Was worth looking into though.  Thanks!

Regards,

Anthony Liguori

> What IMHO would be most useful is a set of generic conversion functions,
> operating on scanline level, much like the ones created by
> vga_template.h, but without dependencies on vga.c internals.
>
> cheers,
>   Gerd
>
>   

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 4/7] xen: add framebuffer backend driver
  2008-07-30 16:31       ` Markus Armbruster
@ 2008-08-01 15:05         ` Anthony Liguori
  0 siblings, 0 replies; 64+ messages in thread
From: Anthony Liguori @ 2008-08-01 15:05 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: xen-devel, Gerd Hoffmann, qemu-devel

Markus Armbruster wrote:
> Gerd Hoffmann <kraxel@redhat.com> writes:
>
>   
> I guess a copyright note should include at least Anthony, me, Dan,
> Pat, Gerd (in order of first major contribution).  Perhaps something
> like:
>
>  * Copyright (C) 2005-2006 Anthony Liguori <aliguori@us.ibm.com>
>   

Please add my copyright as:

* Copyright IBM, Corp. 2005-2006
*
* Authors:
*   Anthony Liguori <aliguori@us.ibm.com>

Regards,

Anthony Liguori

>  * Copyright (C) 2006-2008 Red Hat, Inc., Markus Armbruster <armbru@redhat.com>,
>  *     Daniel P. Berrange <berrange@redhat.com>,
>  *     Gerd Hoffmann <kraxel@redhat.com>
>  * Copyright (C) 2008 Pat Campbell <plc@novell.com>
>
> Apologies if I missed someone!
>
> [*] http://www.cs.utexas.edu/users/aliguori/xen-vfb-20060124.bundle
>   

^ permalink raw reply	[flat|nested] 64+ messages in thread

* [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu
@ 2008-08-04 15:50 Gerd Hoffmann
  2008-08-04 17:42 ` Anthony Liguori
  0 siblings, 1 reply; 64+ messages in thread
From: Gerd Hoffmann @ 2008-08-04 15:50 UTC (permalink / raw)
  To: qemu-devel, xen-devel; +Cc: Gerd Hoffmann

  Hi folks,

This is the second version of the xen support for qemu patch series,
addressing review comments.  Lots of little changes, the largest
change probably is the switch-over to the esisting sys-queue.h list
implementation instead of bringing in a copy of the linux kernel
list.h header.

The console and framebuffer backend drivers are largely based on the
xen code, the other bits are rewritten from scratch.  Nevertheless
the code should be functionally identical.

Overview (individual patches have longer descriptions):

  #1 -- groundwork: build system, cmd line options, ...
  #2 -- xen backend driver infrastructrure
  #3 -- xen console backend driver
  #4 -- xen framebuffer backend driver
  #5 -- xen block backend driver
  #6 -- xen nic backend driver
  #7 -- allow xen disks and nics being configured via qemu command
        line options.

With the first four patches in place upstream qemu can replace xen's
qemu-dm for paravirtual domains.  The block and nic backend drivers
are full userspace implementations using the grant table device
(gntdev).

xen support is implemented using another machine type.  xen's qemu-dm
already uses the machine type to switch between paravirtualized and
fully virtualized machines, so this was the natural choice.  qemu has
gets a new "xenpv" machine type additionally to the "pc" and "isapc"
ones.

Comments?

cheers,
  Gerd

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu
  2008-08-04 15:50 Gerd Hoffmann
@ 2008-08-04 17:42 ` Anthony Liguori
  2008-08-05  9:58   ` Gerd Hoffmann
  2008-08-05 10:46   ` Samuel Thibault
  0 siblings, 2 replies; 64+ messages in thread
From: Anthony Liguori @ 2008-08-04 17:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: xen-devel, Ian Jackson, Gerd Hoffmann, Samuel Thibault

Gerd Hoffmann wrote:
>   Hi folks,
>
> xen support is implemented using another machine type.  xen's qemu-dm
> already uses the machine type to switch between paravirtualized and
> fully virtualized machines, so this was the natural choice.  qemu has
> gets a new "xenpv" machine type additionally to the "pc" and "isapc"
> ones.
>
> Comments?
>   

Modulo some of the stylistic feedback that needs to be addressed, I 
think these series looks pretty good.  It fits pretty well into QEMU.  
Unless there are major objections, I'll apply an updated series once 
people have had some time to look through it.

However, I'd like to see agreement within the Xen community that this is 
the right approach first.  In particular, I would like to see these 
patches either merged with upstream Xen or for upstream Xen to plan to 
rebase against QEMU to pick them up and use them for PV support.  This 
doesn't mean they have to use the block and net backends of course.  I 
really don't want to support two implementations of Xen support in QEMU.

Regards,

Anthony Liguori

> cheers,
>   Gerd
>
>
>
>   

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu
  2008-08-04 17:42 ` Anthony Liguori
@ 2008-08-05  9:58   ` Gerd Hoffmann
  2008-08-05 10:15     ` Samuel Thibault
  2008-08-05 10:46   ` Samuel Thibault
  1 sibling, 1 reply; 64+ messages in thread
From: Gerd Hoffmann @ 2008-08-05  9:58 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: xen-devel, Ian Jackson, qemu-devel, Samuel Thibault

Anthony Liguori wrote:
> However, I'd like to see agreement within the Xen community that this
>  is the right approach first.  In particular, I would like to see 
> these patches either merged with upstream Xen or for upstream Xen to 
> plan to rebase against QEMU to pick them up and use them for PV 
> support.

Ian Jackson has a qemu git tree at
  http://www.chiark.greenend.org.uk/~ijackson/qemu-xen.git

As far I know it is rebased now and then and the long-term plan is to
get the delta to upstream qemu at least smaller.  Dunno whenever it ever
will be zero due to stuff like mapcache.

There are a few compatibility issues to be solved somehow before
upstream qemu is able to completely replace xen's qemu-dm:

(1) my patches use -domid to specify the domain id.  xen uses (used?) -d
instead.  Which isn't going to work because upstream qemu uses that
switch for something else.  Ian's tree supports both -d and -domid, with
a comment saying -d is deprecated.  So I think we have an agreement to
use -domid here ;)

(2) xen added a -domain-name switch.  upstream qemu has a -name switch.
my patches do not implement -domain-name, I use the name set via -name
instead.  IMHO xen should pick up the upstream way to do things here,
i.e. switch over to -name.

(3) vnc configuration is different.  This one is not so easy due to
xenstore being involved.  So the way things work are pretty xen specific
and don't make that much sense for upstream qemu.  The differences are:

Setting the vnc password:  qemu uses a monitor command.  xen reads it
from xenstore (set by xend).  I think we can just support both ways here.

xen has a -vncunused switch which makes qemu scan for a free vnc
display.  The tcp port actually used is written to xenstore.  Dunno how
to handle that one best.  First, I think should be a -vnc switch option
instead of a separate command line switch.  Second, propagating the used
port via xenstore doesn't make sense at all for upstream qemu ...

cheers,
  Gerd

-- 
http://kraxel.fedorapeople.org/xenner/

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu
  2008-08-05  9:58   ` Gerd Hoffmann
@ 2008-08-05 10:15     ` Samuel Thibault
  0 siblings, 0 replies; 64+ messages in thread
From: Samuel Thibault @ 2008-08-05 10:15 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: xen-devel, Ian Jackson, qemu-devel

Gerd Hoffmann, le Tue 05 Aug 2008 11:58:55 +0200, a écrit :
> Anthony Liguori wrote:
> > However, I'd like to see agreement within the Xen community that this
> >  is the right approach first.  In particular, I would like to see 
> > these patches either merged with upstream Xen or for upstream Xen to 
> > plan to rebase against QEMU to pick them up and use them for PV 
> > support.
> 
> Ian Jackson has a qemu git tree at
>   http://www.chiark.greenend.org.uk/~ijackson/qemu-xen.git
> 
> As far I know it is rebased now and then and the long-term plan is to
> get the delta to upstream qemu at least smaller.  Dunno whenever it ever
> will be zero due to stuff like mapcache.

There are two branches there: the xen branch is stuff that Ian indeed
doesn't intend to push.  The qemu branch is stuff that he wishes to
push.

Samuel

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu
  2008-08-04 17:42 ` Anthony Liguori
  2008-08-05  9:58   ` Gerd Hoffmann
@ 2008-08-05 10:46   ` Samuel Thibault
  2008-08-05 11:12     ` Gerd Hoffmann
  1 sibling, 1 reply; 64+ messages in thread
From: Samuel Thibault @ 2008-08-05 10:46 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: xen-devel, Ian Jackson, qemu-devel, Gerd Hoffmann

Anthony Liguori, le Mon 04 Aug 2008 12:42:38 -0500, a écrit :
> However, I'd like to see agreement within the Xen community that this is 
> the right approach first.

Unfortunately, Ian Jackson (who will continue to maintain his qemu
tree) is away this week.

> In particular, I would like to see these 
> patches either merged with upstream Xen or for upstream Xen to plan to 
> rebase against QEMU to pick them up and use them for PV support.

I have not had a precise look at e.g. the xenfb.c code, but if what Gerd
has submitted is exactly the same as xen-unstable's, then that part is
already merged :)

As for the rest, as Gerd said Ian is maintaining a rebased tree, which
is currently used by default in the upcoming xen 4.0 (aka 3.3).  He
won't rebase it until that release, but after that he will probably
regularly, with much less pain than previously anyway since we now have
a fine git tree.

Samuel

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu
  2008-08-05 10:46   ` Samuel Thibault
@ 2008-08-05 11:12     ` Gerd Hoffmann
  2008-08-05 11:29       ` Samuel Thibault
  0 siblings, 1 reply; 64+ messages in thread
From: Gerd Hoffmann @ 2008-08-05 11:12 UTC (permalink / raw)
  To: Samuel Thibault, Anthony Liguori, qemu-devel, xen-devel,
	Gerd Hoffmann, Ian Jackson

> I have not had a precise look at e.g. the xenfb.c code, but if what Gerd
> has submitted is exactly the same as xen-unstable's, then that part is
> already merged :)

It isn't exactly the same code.  For example the xenbus state engine has
been factored out into generic code, shared by all backend drivers.  The
behaviour should be identical though.

cheers,
  Gerd

-- 
http://kraxel.fedorapeople.org/xenner/

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu
  2008-08-05 11:12     ` Gerd Hoffmann
@ 2008-08-05 11:29       ` Samuel Thibault
  2008-08-05 13:18         ` Gerd Hoffmann
  0 siblings, 1 reply; 64+ messages in thread
From: Samuel Thibault @ 2008-08-05 11:29 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: xen-devel, Ian Jackson, qemu-devel

Gerd Hoffmann, le Tue 05 Aug 2008 13:12:35 +0200, a écrit :
> > I have not had a precise look at e.g. the xenfb.c code, but if what Gerd
> > has submitted is exactly the same as xen-unstable's, then that part is
> > already merged :)
> 
> It isn't exactly the same code.  For example the xenbus state engine has
> been factored out into generic code, shared by all backend drivers.

Then it'd probably be good to push that upstream Xen.

Samuel

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu
  2008-08-05 11:29       ` Samuel Thibault
@ 2008-08-05 13:18         ` Gerd Hoffmann
  2008-08-05 15:03           ` Samuel Thibault
  0 siblings, 1 reply; 64+ messages in thread
From: Gerd Hoffmann @ 2008-08-05 13:18 UTC (permalink / raw)
  To: Samuel Thibault, Gerd Hoffmann, Anthony Liguori, qemu-devel,
	xen-devel, Ian Jackson

Samuel Thibault wrote:
> Gerd Hoffmann, le Tue 05 Aug 2008 13:12:35 +0200, a écrit :
>>> I have not had a precise look at e.g. the xenfb.c code, but if what Gerd
>>> has submitted is exactly the same as xen-unstable's, then that part is
>>> already merged :)
>> It isn't exactly the same code.  For example the xenbus state engine has
>> been factored out into generic code, shared by all backend drivers.
> 
> Then it'd probably be good to push that upstream Xen.

I'm cross-posting the patches to xen-devel for a reason.

Whenever you want to pick them up now or just wait for them appear in
upstream qemu and handle it with the next rebase is your call.  But at
least reviewing and commenting now would be very helpful, so I don't
break things for xen by mistake and we can proceed with merging those bits.

cheers,
  Gerd

-- 
http://kraxel.fedorapeople.org/xenner/

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu
  2008-08-05 13:18         ` Gerd Hoffmann
@ 2008-08-05 15:03           ` Samuel Thibault
  2008-08-05 15:41             ` Samuel Thibault
  0 siblings, 1 reply; 64+ messages in thread
From: Samuel Thibault @ 2008-08-05 15:03 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: xen-devel, Ian Jackson, qemu-devel

Gerd Hoffmann, le Tue 05 Aug 2008 15:18:46 +0200, a écrit :
> Samuel Thibault wrote:
> > Then it'd probably be good to push that upstream Xen.
> 
> I'm cross-posting the patches to xen-devel for a reason.

Well, cross-posting qemu patches to xen-devel is not the same as posting
xen patches to xen-devel...

Samuel

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu
  2008-08-05 15:03           ` Samuel Thibault
@ 2008-08-05 15:41             ` Samuel Thibault
  2008-08-05 15:46               ` Anthony Liguori
                                 ` (2 more replies)
  0 siblings, 3 replies; 64+ messages in thread
From: Samuel Thibault @ 2008-08-05 15:41 UTC (permalink / raw)
  To: Gerd Hoffmann, Anthony Liguori, qemu-devel, xen-devel,
	Ian Jackson

Samuel Thibault, le Tue 05 Aug 2008 16:03:28 +0100, a écrit :
> Gerd Hoffmann, le Tue 05 Aug 2008 15:18:46 +0200, a écrit :
> > Samuel Thibault wrote:
> > > Then it'd probably be good to push that upstream Xen.
> > 
> > I'm cross-posting the patches to xen-devel for a reason.
> 
> Well, cross-posting qemu patches to xen-devel is not the same as posting
> xen patches to xen-devel...

Just to explain a bit more, now that I have read the patches a bit: what
is there is somehow far from the xen unstable tree, at least because
of the backend driver core, and because of other 'details' (renaming,
moving).  I doubt Ian will be happy to have to make the effort to merge
that in his tree and I guess he will probably just drop everything and
keep the xen-unstable version.

Samuel

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu
  2008-08-05 15:41             ` Samuel Thibault
@ 2008-08-05 15:46               ` Anthony Liguori
  2008-08-05 16:07                 ` Blue Swirl
  2008-08-05 15:47               ` Samuel Thibault
  2008-08-06 10:14               ` Gerd Hoffmann
  2 siblings, 1 reply; 64+ messages in thread
From: Anthony Liguori @ 2008-08-05 15:46 UTC (permalink / raw)
  To: Samuel Thibault, Gerd Hoffmann, Anthony Liguori, qemu-devel,
	xen-devel, Ian Jackson

Samuel Thibault wrote:
> Samuel Thibault, le Tue 05 Aug 2008 16:03:28 +0100, a écrit :
>   
>> Gerd Hoffmann, le Tue 05 Aug 2008 15:18:46 +0200, a écrit :
>>     
>> Well, cross-posting qemu patches to xen-devel is not the same as posting
>> xen patches to xen-devel...
>>     
>
> Just to explain a bit more, now that I have read the patches a bit: what
> is there is somehow far from the xen unstable tree, at least because
> of the backend driver core, and because of other 'details' (renaming,
> moving).  I doubt Ian will be happy to have to make the effort to merge
> that in his tree and I guess he will probably just drop everything and
> keep the xen-unstable version.
>   

Which is why ya'll need to work something out before we apply these 
patches to QEMU :-)

Regards,

Anthony Liguori

> Samuel
>   

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu
  2008-08-05 15:41             ` Samuel Thibault
  2008-08-05 15:46               ` Anthony Liguori
@ 2008-08-05 15:47               ` Samuel Thibault
  2008-08-06 10:14               ` Gerd Hoffmann
  2 siblings, 0 replies; 64+ messages in thread
From: Samuel Thibault @ 2008-08-05 15:47 UTC (permalink / raw)
  To: Gerd Hoffmann, Anthony Liguori, qemu-devel, xen-devel,
	Ian Jackson

Samuel Thibault, le Tue 05 Aug 2008 16:41:40 +0100, a écrit :
> Samuel Thibault, le Tue 05 Aug 2008 16:03:28 +0100, a écrit :
> > Gerd Hoffmann, le Tue 05 Aug 2008 15:18:46 +0200, a écrit :
> > > Samuel Thibault wrote:
> > > > Then it'd probably be good to push that upstream Xen.
> > > 
> > > I'm cross-posting the patches to xen-devel for a reason.
> > 
> > Well, cross-posting qemu patches to xen-devel is not the same as posting
> > xen patches to xen-devel...
> 
> Just to explain a bit more, now that I have read the patches a bit:

And to be even more explicit, by "I have read the patches", I mean: I
have applied them to upstream qemu, them vimdiffed the files there with
the ones from Ian's tree (sometimes with different names), in order
to have an idea of what the merge would be (i.e. the "xen patches" I
mentioned above, which is what we care about from the point of view of
xen-unstable).

Samuel

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu
  2008-08-05 15:46               ` Anthony Liguori
@ 2008-08-05 16:07                 ` Blue Swirl
  0 siblings, 0 replies; 64+ messages in thread
From: Blue Swirl @ 2008-08-05 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: xen-devel, Ian Jackson, Gerd Hoffmann, Samuel Thibault

On 8/5/08, Anthony Liguori <anthony@codemonkey.ws> wrote:
> Samuel Thibault wrote:
>
> > Samuel Thibault, le Tue 05 Aug 2008 16:03:28 +0100, a écrit :
> >
> >
> > > Gerd Hoffmann, le Tue 05 Aug 2008 15:18:46 +0200, a écrit :
> > >    Well, cross-posting qemu patches to xen-devel is not the same as
> posting
> > > xen patches to xen-devel...
> > >
> > >
> >
> > Just to explain a bit more, now that I have read the patches a bit: what
> > is there is somehow far from the xen unstable tree, at least because
> > of the backend driver core, and because of other 'details' (renaming,
> > moving).  I doubt Ian will be happy to have to make the effort to merge
> > that in his tree and I guess he will probably just drop everything and
> > keep the xen-unstable version.
> >
> >
>
>  Which is why ya'll need to work something out before we apply these patches
> to QEMU :-)

I'd salvage nodisk feature (useful for Sparc and embedded systems) and
if ever produced, patch that introduces qemu_realloc and does
s/realloc/qemu_realloc/g.

For global -Wall -Wstrict-prototypes flags probably the project
leaders should agree that it will be useful.

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu
  2008-08-05 15:41             ` Samuel Thibault
  2008-08-05 15:46               ` Anthony Liguori
  2008-08-05 15:47               ` Samuel Thibault
@ 2008-08-06 10:14               ` Gerd Hoffmann
  2008-08-06 10:23                 ` Samuel Thibault
  2 siblings, 1 reply; 64+ messages in thread
From: Gerd Hoffmann @ 2008-08-06 10:14 UTC (permalink / raw)
  To: Samuel Thibault, Gerd Hoffmann, Anthony Liguori, qemu-devel,
	xen-devel, Ian Jackson

Samuel Thibault wrote:
> Samuel Thibault, le Tue 05 Aug 2008 16:03:28 +0100, a écrit :
>> Gerd Hoffmann, le Tue 05 Aug 2008 15:18:46 +0200, a écrit :
>>> Samuel Thibault wrote:
>>>> Then it'd probably be good to push that upstream Xen.
>>> I'm cross-posting the patches to xen-devel for a reason.
>> Well, cross-posting qemu patches to xen-devel is not the same as posting
>> xen patches to xen-devel...
> 
> Just to explain a bit more, now that I have read the patches a bit: what
> is there is somehow far from the xen unstable tree, at least because
> of the backend driver core, and because of other 'details' (renaming,
> moving).  I doubt Ian will be happy to have to make the effort to merge
> that in his tree and I guess he will probably just drop everything and
> keep the xen-unstable version.

Sure, merging stuff upstream involves alot of work short-term, you'll
get the benefits long-term.

pv domain support is easy, as this is largely self-contained.  hvm will
be even more work, because hvm support is much more invasive and on top
of that the qemu interfaces will change to nicely support the various
ways to run code natively instead of emulated (kqemu, kvm, xen).

The rough way to merge would look like this:

  - drop xen_console.[ch]
  - drop xenfb.[ch]
  - drop xen_machine_pv.c

  - add xen.h
  - add xen-machine.c
  - add xen-backend.[ch]
  - add xen-console.c
  - add xen-framebuffer.c

  - wind up stuff in the Makefiles.
  - some global renames (domid -> xen_domid for example) as I took care
    to prefix global xen variables & functions with xen_.
  - probably some small fixups are needed ...

You probably wouldn't do that before the 3.3 (4.0?) release.  If you
keep the xenish vl.c version the differences between upstream qemu and
qemu-dm command line options and vnc handling go away.  The you can
gradually move qemu-dm to be more upstream-ish while also updating xend
accordingly.

Note that qemu-dm has a few optimizations in the qemu display code to
avoid unneeded work.  I'd suggest to submit them upstream.  The we can
enable the bits in xen-framebuffer.c which make use of them.
DisplayState->idle for example.

cheers,
  Gerd

-- 
http://kraxel.fedorapeople.org/xenner/

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu
  2008-08-06 10:14               ` Gerd Hoffmann
@ 2008-08-06 10:23                 ` Samuel Thibault
  2008-08-06 13:24                   ` Gerd Hoffmann
  0 siblings, 1 reply; 64+ messages in thread
From: Samuel Thibault @ 2008-08-06 10:23 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: xen-devel, Ian Jackson, qemu-devel

Gerd Hoffmann, le Wed 06 Aug 2008 12:14:25 +0200, a écrit :
> The rough way to merge would look like this:
> 
>   - drop xen_console.[ch]
>   - drop xenfb.[ch]
>   - drop xen_machine_pv.c
> 
>   - add xen.h
>   - add xen-machine.c
>   - add xen-backend.[ch]
>   - add xen-console.c
>   - add xen-framebuffer.c
> 
>   - wind up stuff in the Makefiles.
>   - some global renames (domid -> xen_domid for example) as I took care
>     to prefix global xen variables & functions with xen_.
>   - probably some small fixups are needed ...

You forgot the _test_ stage.  You are basically asking us to replace our
well-tested implementation with your implementation, that's quite a
move.  You are not even providing a patch for us to check that nothing
has been left behind...

> Note that qemu-dm has a few optimizations in the qemu display code to
> avoid unneeded work.  I'd suggest to submit them upstream.

That's planned, yes.  But you too could do the same for the device
backend core for instance...

> The you can gradually move qemu-dm to be more upstream-ish while also
> updating xend accordingly.

That's what we are already doing in Ian's tree.

Samuel

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu
  2008-08-06 10:23                 ` Samuel Thibault
@ 2008-08-06 13:24                   ` Gerd Hoffmann
  2008-08-06 13:39                     ` Samuel Thibault
  0 siblings, 1 reply; 64+ messages in thread
From: Gerd Hoffmann @ 2008-08-06 13:24 UTC (permalink / raw)
  To: Samuel Thibault, Gerd Hoffmann, Anthony Liguori, qemu-devel,
	xen-devel, Ian Jackson

  Hi,

> You forgot the _test_ stage.  You are basically asking us to replace our
> well-tested implementation with your implementation, that's quite a
> move.

Sure, and more will follow.  I'd expect the merge involves rewriting
large parts of the code anyway, especially the hvm bits due to the
nessesary interface cleanups in qemu, but also because the code must
pass the review process before it can be merged.  Pretty much like
upstreaming the xen support into the linux kernel.  All that also needs
testing, no doubt.

cheers,
  Gerd

-- 
http://kraxel.fedorapeople.org/xenner/

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu
  2008-08-06 13:24                   ` Gerd Hoffmann
@ 2008-08-06 13:39                     ` Samuel Thibault
  2008-08-06 14:18                       ` Gerd Hoffmann
  0 siblings, 1 reply; 64+ messages in thread
From: Samuel Thibault @ 2008-08-06 13:39 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: xen-devel, Ian Jackson, qemu-devel

Gerd Hoffmann, le Wed 06 Aug 2008 15:24:39 +0200, a écrit :
> > You forgot the _test_ stage.  You are basically asking us to replace our
> > well-tested implementation with your implementation, that's quite a
> > move.
> 
> Sure, and more will follow.

But by having it merged into just upstream qemu you won't magically get
Xen people actually test it, so it would be mostly dead code.

> Pretty much like upstreaming the xen support into the linux kernel.

There's a big difference here.  The upstream linux kernel merge won't be
merged back to the linux-2.6.18 tree.  And people do test upstream xen
support.

Samuel

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu
  2008-08-06 13:39                     ` Samuel Thibault
@ 2008-08-06 14:18                       ` Gerd Hoffmann
  2008-08-06 14:51                         ` Samuel Thibault
  0 siblings, 1 reply; 64+ messages in thread
From: Gerd Hoffmann @ 2008-08-06 14:18 UTC (permalink / raw)
  To: Samuel Thibault, Gerd Hoffmann, Anthony Liguori, qemu-devel,
	xen-devel, Ian Jackson

Samuel Thibault wrote:
> Gerd Hoffmann, le Wed 06 Aug 2008 15:24:39 +0200, a écrit :
>>> You forgot the _test_ stage.  You are basically asking us to replace our
>>> well-tested implementation with your implementation, that's quite a
>>> move.
>> Sure, and more will follow.
> 
> But by having it merged into just upstream qemu you won't magically get
> Xen people actually test it, so it would be mostly dead code.
> 
>> Pretty much like upstreaming the xen support into the linux kernel.
> 
> There's a big difference here.  The upstream linux kernel merge won't be
> merged back to the linux-2.6.18 tree.

Oh, we can also arrange things without merging back.  Stop rebasing
qemu-dm (pretty much like 2.6.18), additionally hook upstream qemu as-is
into testing (like pv_ops kernels).  Then start submitting patches to
qemu.  When done, zap old qemu-dm.

cheers,
  Gerd

-- 
http://kraxel.fedorapeople.org/xenner/

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu
  2008-08-06 14:18                       ` Gerd Hoffmann
@ 2008-08-06 14:51                         ` Samuel Thibault
  2008-08-06 15:25                           ` Gerd Hoffmann
  0 siblings, 1 reply; 64+ messages in thread
From: Samuel Thibault @ 2008-08-06 14:51 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: xen-devel, Ian Jackson, qemu-devel

Gerd Hoffmann, le Wed 06 Aug 2008 16:18:51 +0200, a écrit :
> Samuel Thibault wrote:
> > But by having it merged into just upstream qemu you won't magically get
> > Xen people actually test it, so it would be mostly dead code.
> > 
> >> Pretty much like upstreaming the xen support into the linux kernel.
> > 
> > There's a big difference here.  The upstream linux kernel merge won't be
> > merged back to the linux-2.6.18 tree.
> 
> Oh, we can also arrange things without merging back.  Stop rebasing
> qemu-dm (pretty much like 2.6.18), additionally hook upstream qemu as-is
> into testing (like pv_ops kernels).  Then start submitting patches to
> qemu.  When done, zap old qemu-dm.

Again, there's a difference.  The interface between Linux and Xen has
always been meant to be a "public" thing.  The interface between ioemu
and the other xen components has not, and changing it is considered fine
(we still do it).  Sure that could be cleaned up, but that's probably
not something that should happen on the upstream qemu side.

Samuel

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu
  2008-08-06 14:51                         ` Samuel Thibault
@ 2008-08-06 15:25                           ` Gerd Hoffmann
  0 siblings, 0 replies; 64+ messages in thread
From: Gerd Hoffmann @ 2008-08-06 15:25 UTC (permalink / raw)
  To: Samuel Thibault, Gerd Hoffmann, Anthony Liguori, qemu-devel,
	xen-devel, Ian Jackson

Samuel Thibault wrote:
>> Oh, we can also arrange things without merging back.  Stop rebasing
>> qemu-dm (pretty much like 2.6.18), additionally hook upstream qemu as-is
>> into testing (like pv_ops kernels).  Then start submitting patches to
>> qemu.  When done, zap old qemu-dm.
> 
> Again, there's a difference.  The interface between Linux and Xen has
> always been meant to be a "public" thing.  The interface between ioemu
> and the other xen components has not, and changing it is considered fine
> (we still do it).  Sure that could be cleaned up, but that's probably
> not something that should happen on the upstream qemu side.

Hmm.  That makes me think that starting over from scratch really is the
best option.  Drop the old cruft, design a clean interface, code it up,
discuss it in public and submit to upstream qemu.

cheers,
  Gerd

-- 
http://kraxel.fedorapeople.org/xenner/

^ permalink raw reply	[flat|nested] 64+ messages in thread

* [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu
@ 2008-10-28 12:23 Gerd Hoffmann
  0 siblings, 0 replies; 64+ messages in thread
From: Gerd Hoffmann @ 2008-10-28 12:23 UTC (permalink / raw)
  To: qemu-devel, xen-devel; +Cc: Gerd Hoffmann

  Hi folks,

This is version #5 of the xen support for qemu patch series.

It has been quiet for a while, mostly due to qemu-xen lagging behind
qemu-upstream.  Now it catched up with upstream, so it is time to make
some progress here.  Not many changes since the last time I posted the
patches.  Some prelimary stuff has been merged and thus is gone, some
bugs have been fixed, some adaptions to recent changes happend.

The console and framebuffer backend drivers are largely based on the
xen code, the other bits are rewritten from scratch.  Nevertheless
the code should be functionally identical.

Overview (individual patches have longer descriptions):

  #1 -- groundwork: build system, cmd line options, ...
  #2 -- xen backend driver infrastructrure
  #3 -- xen console backend driver
  #4 -- xen framebuffer backend driver

  #5 -- xen block backend driver
  #6 -- xen nic backend driver
  #7 -- allow xen disks and nics being configured via qemu command
        line options.

With first next four patches in place upstream qemu can replace xen's
qemu-dm for paravirtual domains.  Due to some small differences in
the command line syntax it can't work as drop-in replacement though.

The last three patches add full userspace implementations of block and
nic backend drivers using the grant table device (gntdev) and command
line support config support for setting up these backends.

xen support is implemented using another machine type.  xen's qemu-dm
already uses the machine type to switch between paravirtualized and
fully virtualized machines, so this was the natural choice.  qemu
gets a new "xenpv" machine type additionally to the "pc" and "isapc"
ones.

The patches are also available here (Patches 0002 -> 0008):
	http://kraxel.fedorapeople.org/patches/qemu-upstream/


There is also a patch queue for qemu-xen, located here:
	http://kraxel.fedorapeople.org/patches/qemu-xen/

There also a '-b' (no whitespace changes) version for easier review:
	http://kraxel.fedorapeople.org/patches/qemu-xen/no-ws/

The qemu-xen patch series has a slightly different ordering to make the
patch queue more bisect-friendly.  Also the command line syntax is
unchanged, so we don't break qemu-dm <=> xend interaction.  It should
work just fine as drop-in replacement, without regressions, with the
additional bonus that the framebuffer handles a restart cycle correctly
(i.e. pvgrub in graphical mode actually works).

Comments?

cheers,
  Gerd

^ permalink raw reply	[flat|nested] 64+ messages in thread

end of thread, other threads:[~2008-10-28 12:23 UTC | newest]

Thread overview: 64+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-07-28 13:17 [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu Gerd Hoffmann
2008-07-28 13:17 ` [Qemu-devel] [PATCH 1/7] xen: groundwork for xen support Gerd Hoffmann
2008-07-28 14:04   ` Anthony Liguori
2008-07-28 14:52     ` Gerd Hoffmann
2008-07-29  8:10       ` [Xen-devel] " Daniel P. Berrange
2008-07-29 13:32         ` Anthony Liguori
2008-07-29 14:24           ` Daniel P. Berrange
2008-07-29 19:11             ` Anthony Liguori
2008-07-29 21:36               ` Gerd Hoffmann
2008-07-29 21:48                 ` Anthony Liguori
2008-07-29 14:32           ` Gerd Hoffmann
2008-07-28 23:14     ` Samuel Thibault
2008-07-29  7:38       ` Gerd Hoffmann
2008-07-29  8:12         ` Daniel P. Berrange
2008-07-29  8:55           ` Gerd Hoffmann
2008-07-28 13:17 ` [Qemu-devel] [PATCH 2/7] xen: backend driver core Gerd Hoffmann
2008-07-28 14:13   ` Anthony Liguori
2008-07-28 15:51     ` Gerd Hoffmann
2008-07-28 13:17 ` [Qemu-devel] [PATCH 3/7] xen: add console backend driver Gerd Hoffmann
2008-07-28 14:17   ` Anthony Liguori
2008-07-28 15:43     ` Gerd Hoffmann
2008-07-28 19:04       ` Anthony Liguori
2008-07-28 13:17 ` [Qemu-devel] [PATCH 4/7] xen: add framebuffer " Gerd Hoffmann
2008-07-28 14:22   ` Anthony Liguori
2008-07-28 14:41     ` Andreas Färber
2008-07-30  9:59       ` Gerd Hoffmann
2008-08-01 14:57         ` Anthony Liguori
2008-07-30  9:20     ` Gerd Hoffmann
2008-07-30 16:31       ` Markus Armbruster
2008-08-01 15:05         ` Anthony Liguori
2008-07-28 13:17 ` [Qemu-devel] [PATCH 5/7] xen: add block device " Gerd Hoffmann
2008-07-28 14:25   ` Anthony Liguori
2008-07-28 13:17 ` [Qemu-devel] [PATCH 6/7] xen: add net " Gerd Hoffmann
2008-07-28 14:27   ` Anthony Liguori
2008-07-28 15:45     ` Gerd Hoffmann
2008-07-28 13:17 ` [Qemu-devel] [PATCH 7/7] xen: blk & nic configuration via cmd line Gerd Hoffmann
     [not found] <m2n.s.1KNSd3-002QXI@chiark.greenend.org.uk>
2008-07-28 13:31 ` [Qemu-devel] [PATCH 0/7] merge some xen bits into qemu Ian Jackson
2008-07-28 14:33   ` Anthony Liguori
2008-07-28 14:58     ` Ian Jackson
2008-07-28 15:24       ` Anthony Liguori
2008-07-29  8:26       ` Daniel P. Berrange
2008-07-28 15:23     ` Gerd Hoffmann
2008-07-28 14:43   ` Gerd Hoffmann
  -- strict thread matches above, loose matches on Subject: below --
2008-08-04 15:50 Gerd Hoffmann
2008-08-04 17:42 ` Anthony Liguori
2008-08-05  9:58   ` Gerd Hoffmann
2008-08-05 10:15     ` Samuel Thibault
2008-08-05 10:46   ` Samuel Thibault
2008-08-05 11:12     ` Gerd Hoffmann
2008-08-05 11:29       ` Samuel Thibault
2008-08-05 13:18         ` Gerd Hoffmann
2008-08-05 15:03           ` Samuel Thibault
2008-08-05 15:41             ` Samuel Thibault
2008-08-05 15:46               ` Anthony Liguori
2008-08-05 16:07                 ` Blue Swirl
2008-08-05 15:47               ` Samuel Thibault
2008-08-06 10:14               ` Gerd Hoffmann
2008-08-06 10:23                 ` Samuel Thibault
2008-08-06 13:24                   ` Gerd Hoffmann
2008-08-06 13:39                     ` Samuel Thibault
2008-08-06 14:18                       ` Gerd Hoffmann
2008-08-06 14:51                         ` Samuel Thibault
2008-08-06 15:25                           ` Gerd Hoffmann
2008-10-28 12:23 Gerd Hoffmann

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).