All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 00/10] xen: pv domain support.
@ 2009-04-01 21:39 ` Gerd Hoffmann
  0 siblings, 0 replies; 61+ messages in thread
From: Gerd Hoffmann @ 2009-04-01 21:39 UTC (permalink / raw)
  To: qemu-devel, xen-devel; +Cc: Gerd Hoffmann

  Hi,

It's been a while, but after a looooooooooooong time we've (hopefully)
finally sorted the merging issues with qemu-xen.  So here is a fresh
version of the xen support for qemu patch series.  Short overview
(individual patches have longer descriptions):

  #1  - groundwork for xen support (makefiles, configure, ...).
  #2  - backend driver core (common code used by all backends).
  #3  - add console backend driver.
  #4  - add framebuffer backend driver.

With these four patches in place upstream qemu is functional aequivalent
to qemu-xen for paravirtual guests.  The patches are merged into
qemu-xen already, with the exception of a few framebuffer bits which got
hold back due to displaystate work.

  #5  - add block device backend driver.
  #6  - add net backend driver.

These two patches add backend drivers for disk and network to qemu.

  #7  - blk & nic configuration via cmd line.
  #8  - pv domain builder.
  #9  - simplify vga selection
  #10 - add -vga xenfb option, configure xenfb

These patches add support to qemu for creating xen pv guests.  That way
one can run xen guests without xend.  Patch #8 is the domain builder
code itself.  The other patches add support for configuring devices (fb,
disk, nic) via command line.

cheers,
  Gerd

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

* [PATCH 00/10] xen: pv domain support.
@ 2009-04-01 21:39 ` Gerd Hoffmann
  0 siblings, 0 replies; 61+ messages in thread
From: Gerd Hoffmann @ 2009-04-01 21:39 UTC (permalink / raw)
  To: qemu-devel, xen-devel; +Cc: Gerd Hoffmann

  Hi,

It's been a while, but after a looooooooooooong time we've (hopefully)
finally sorted the merging issues with qemu-xen.  So here is a fresh
version of the xen support for qemu patch series.  Short overview
(individual patches have longer descriptions):

  #1  - groundwork for xen support (makefiles, configure, ...).
  #2  - backend driver core (common code used by all backends).
  #3  - add console backend driver.
  #4  - add framebuffer backend driver.

With these four patches in place upstream qemu is functional aequivalent
to qemu-xen for paravirtual guests.  The patches are merged into
qemu-xen already, with the exception of a few framebuffer bits which got
hold back due to displaystate work.

  #5  - add block device backend driver.
  #6  - add net backend driver.

These two patches add backend drivers for disk and network to qemu.

  #7  - blk & nic configuration via cmd line.
  #8  - pv domain builder.
  #9  - simplify vga selection
  #10 - add -vga xenfb option, configure xenfb

These patches add support to qemu for creating xen pv guests.  That way
one can run xen guests without xend.  Patch #8 is the domain builder
code itself.  The other patches add support for configuring devices (fb,
disk, nic) via command line.

cheers,
  Gerd

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

* [Qemu-devel] [PATCH 01/10] xen: groundwork for xen support
  2009-04-01 21:39 ` Gerd Hoffmann
@ 2009-04-01 21:39   ` Gerd Hoffmann
  -1 siblings, 0 replies; 61+ messages in thread
From: Gerd Hoffmann @ 2009-04-01 21:39 UTC (permalink / raw)
  To: qemu-devel, xen-devel; +Cc: Gerd Hoffmann

- configure script and build system changes.
- wind up new machine type.
- add -xen-* command line options.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 Makefile.target       |    8 +++++
 configure             |   34 +++++++++++++++++++++++
 hw/boards.h           |    3 ++
 hw/xen.h              |   20 ++++++++++++++
 hw/xen_machine_pv.c   |   70 +++++++++++++++++++++++++++++++++++++++++++++++++
 qemu-options.hx       |   11 +++++++
 target-i386/machine.c |    3 ++
 vl.c                  |   12 ++++++++
 8 files changed, 161 insertions(+), 0 deletions(-)
 create mode 100644 hw/xen.h
 create mode 100644 hw/xen_machine_pv.c

diff --git a/Makefile.target b/Makefile.target
index 046427d..1da8055 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -563,6 +563,14 @@ ifdef CONFIG_BLUEZ
 LIBS += $(CONFIG_BLUEZ_LIBS)
 endif
 
+# xen backend driver support
+XEN_OBJS := xen_machine_pv.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 5c62c59..212f2e9 100755
--- a/configure
+++ b/configure
@@ -189,6 +189,7 @@ aix="no"
 blobs="yes"
 fdt="yes"
 sdl_x11="no"
+xen="yes"
 
 # OS specific
 if check_define __linux__ ; then
@@ -406,6 +407,8 @@ for opt do
   ;;
   --disable-kqemu) kqemu="no"
   ;;
+  --disable-xen) xen="no"
+  ;;
   --disable-brlapi) brlapi="no"
   ;;
   --disable-bluez) bluez="no"
@@ -555,6 +558,7 @@ echo "                           Available drivers: $audio_possible_drivers"
 echo "  --audio-card-list=LIST   set list of emulated audio cards [$audio_card_list]"
 echo "                           Available cards: $audio_possible_cards"
 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-vnc-sasl       disable SASL encryption for VNC server"
@@ -768,6 +772,22 @@ else
 fi
 
 ##########################################
+# xen probe
+
+if test "$xen" = "yes" ; then
+cat > $TMPC <<EOF
+#include <xenctrl.h>
+#include <xs.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
@@ -1197,6 +1217,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" ] && \
@@ -1496,6 +1517,9 @@ if test "$bluez" = "yes" ; then
   echo "CONFIG_BLUEZ_LIBS=$bluez_libs" >> $config_mak
   echo "#define CONFIG_BLUEZ 1" >> $config_h
 fi
+if test "$xen" = "yes" ; then
+  echo "XEN_LIBS=-lxenstore -lxenctrl" >> $config_mak
+fi
 if test "$aio" = "yes" ; then
   echo "#define CONFIG_AIO 1" >> $config_h
   echo "CONFIG_AIO=yes" >> $config_mak
@@ -1657,6 +1681,11 @@ case "$target_cpu" in
       echo "KVM_CFLAGS=$kvm_cflags" >> $config_mak
       echo "#define CONFIG_KVM 1" >> $config_h
     fi
+    if test "$xen" = "yes" -a "$target_softmmu" = "yes";
+    then
+      echo "CONFIG_XEN=yes" >> $config_mak
+      echo "#define CONFIG_XEN 1" >> $config_h
+    fi
   ;;
   x86_64)
     echo "TARGET_ARCH=x86_64" >> $config_mak
@@ -1672,6 +1701,11 @@ case "$target_cpu" in
       echo "KVM_CFLAGS=$kvm_cflags" >> $config_mak
       echo "#define CONFIG_KVM 1" >> $config_h
     fi
+    if test "$xen" = "yes" -a "$target_softmmu" = "yes"
+    then
+      echo "CONFIG_XEN=yes" >> $config_mak
+      echo "#define CONFIG_XEN 1" >> $config_h
+    fi
   ;;
   alpha)
     echo "TARGET_ARCH=alpha" >> $config_mak
diff --git a/hw/boards.h b/hw/boards.h
index 1e18ba6..215ccdc 100644
--- a/hw/boards.h
+++ b/hw/boards.h
@@ -34,6 +34,9 @@ extern QEMUMachine axisdev88_machine;
 extern QEMUMachine pc_machine;
 extern QEMUMachine isapc_machine;
 
+/* xen_machine.c */
+extern QEMUMachine xenpv_machine;
+
 /* ppc.c */
 extern QEMUMachine prep_machine;
 extern QEMUMachine core99_machine;
diff --git a/hw/xen.h b/hw/xen.h
new file mode 100644
index 0000000..3c8da41
--- /dev/null
+++ b/hw/xen.h
@@ -0,0 +1,20 @@
+#ifndef QEMU_HW_XEN_H
+#define QEMU_HW_XEN_H 1
+/*
+ * public xen header
+ *   stuff needed outside xen-*.c, i.e. interfaces to qemu.
+ *   must not depend on any xen headers being present in
+ *   /usr/include/xen, so it can be included unconditionally.
+ */
+
+/* xen-machine.c */
+enum xen_mode {
+    XEN_EMULATE = 0,  // xen emulation, using xenner (default)
+    XEN_CREATE,       // create xen domain
+    XEN_ATTACH        // attach to xen domain created by xend
+};
+
+extern uint32_t xen_domid;
+extern enum xen_mode xen_mode;
+
+#endif /* QEMU_HW_XEN_H */
diff --git a/hw/xen_machine_pv.c b/hw/xen_machine_pv.c
new file mode 100644
index 0000000..21b5d9e
--- /dev/null
+++ b/hw/xen_machine_pv.c
@@ -0,0 +1,70 @@
+/*
+ * QEMU Xen PV Machine
+ *
+ * Copyright (c) 2007 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 "pc.h"
+#include "sysemu.h"
+#include "boards.h"
+#include "xen.h"
+
+uint32_t xen_domid;
+enum xen_mode xen_mode = XEN_EMULATE;
+
+static void xen_init_pv(ram_addr_t ram_size, int vga_ram_size,
+			const char *boot_device,
+			const char *kernel_filename,
+			const char *kernel_cmdline,
+			const char *initrd_filename,
+			const char *cpu_model)
+{
+    CPUState *env;
+
+    /* Initialize a dummy CPU */
+    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 = {
+    .name = "xenpv",
+    .desc = "Xen Para-virtualized PC",
+    .init = xen_init_pv,
+    .ram_require = (4 * 1024 * 1024) | RAMSIZE_FIXED,
+    .max_cpus = 1,
+};
+
+/*
+ * Local variables:
+ *  indent-tabs-mode: nil
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
diff --git a/qemu-options.hx b/qemu-options.hx
index 6c58e2a..895fa89 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1294,6 +1294,17 @@ Enable KVM full virtualization support. This option is only available
 if KVM support is enabled when compiling.
 ETEXI
 
+#ifdef CONFIG_XEN
+DEF("xen-domid", HAS_ARG, QEMU_OPTION_xen_domid,
+    "-xen-domid id   specify xen guest domain id\n")
+DEF("xen-create", 0, QEMU_OPTION_xen_create,
+    "-xen-create     create domain using xen hypercalls, bypassing xend\n"
+    "                warning: should not be used when xend is in use\n")
+DEF("xen-attach", 0, QEMU_OPTION_xen_attach,
+    "-xen-attach     attach to existing xen domain\n"
+    "                xend will use this when starting qemu\n")
+#endif
+
 DEF("no-reboot", 0, QEMU_OPTION_no_reboot, \
     "-no-reboot      exit instead of rebooting\n")
 STEXI
diff --git a/target-i386/machine.c b/target-i386/machine.c
index 1cf49d5..1b0d36d 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 5e6c621..76fca5a 100644
--- a/vl.c
+++ b/vl.c
@@ -138,6 +138,7 @@ int main(int argc, char **argv)
 #include "hw/isa.h"
 #include "hw/baum.h"
 #include "hw/bt.h"
+#include "hw/xen.h"
 #include "bt-host.h"
 #include "net.h"
 #include "monitor.h"
@@ -4943,6 +4944,17 @@ int main(int argc, char **argv, char **envp)
                 run_as = optarg;
                 break;
 #endif
+#ifdef CONFIG_XEN
+            case QEMU_OPTION_xen_domid:
+                xen_domid = atoi(optarg);
+                break;
+            case QEMU_OPTION_xen_create:
+                xen_mode = XEN_CREATE;
+                break;
+            case QEMU_OPTION_xen_attach:
+                xen_mode = XEN_ATTACH;
+                break;
+#endif
             }
         }
     }
-- 
1.6.1.3

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

* [PATCH 01/10] xen: groundwork for xen support
@ 2009-04-01 21:39   ` Gerd Hoffmann
  0 siblings, 0 replies; 61+ messages in thread
From: Gerd Hoffmann @ 2009-04-01 21:39 UTC (permalink / raw)
  To: qemu-devel, xen-devel; +Cc: Gerd Hoffmann

- configure script and build system changes.
- wind up new machine type.
- add -xen-* command line options.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 Makefile.target       |    8 +++++
 configure             |   34 +++++++++++++++++++++++
 hw/boards.h           |    3 ++
 hw/xen.h              |   20 ++++++++++++++
 hw/xen_machine_pv.c   |   70 +++++++++++++++++++++++++++++++++++++++++++++++++
 qemu-options.hx       |   11 +++++++
 target-i386/machine.c |    3 ++
 vl.c                  |   12 ++++++++
 8 files changed, 161 insertions(+), 0 deletions(-)
 create mode 100644 hw/xen.h
 create mode 100644 hw/xen_machine_pv.c

diff --git a/Makefile.target b/Makefile.target
index 046427d..1da8055 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -563,6 +563,14 @@ ifdef CONFIG_BLUEZ
 LIBS += $(CONFIG_BLUEZ_LIBS)
 endif
 
+# xen backend driver support
+XEN_OBJS := xen_machine_pv.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 5c62c59..212f2e9 100755
--- a/configure
+++ b/configure
@@ -189,6 +189,7 @@ aix="no"
 blobs="yes"
 fdt="yes"
 sdl_x11="no"
+xen="yes"
 
 # OS specific
 if check_define __linux__ ; then
@@ -406,6 +407,8 @@ for opt do
   ;;
   --disable-kqemu) kqemu="no"
   ;;
+  --disable-xen) xen="no"
+  ;;
   --disable-brlapi) brlapi="no"
   ;;
   --disable-bluez) bluez="no"
@@ -555,6 +558,7 @@ echo "                           Available drivers: $audio_possible_drivers"
 echo "  --audio-card-list=LIST   set list of emulated audio cards [$audio_card_list]"
 echo "                           Available cards: $audio_possible_cards"
 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-vnc-sasl       disable SASL encryption for VNC server"
@@ -768,6 +772,22 @@ else
 fi
 
 ##########################################
+# xen probe
+
+if test "$xen" = "yes" ; then
+cat > $TMPC <<EOF
+#include <xenctrl.h>
+#include <xs.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
@@ -1197,6 +1217,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" ] && \
@@ -1496,6 +1517,9 @@ if test "$bluez" = "yes" ; then
   echo "CONFIG_BLUEZ_LIBS=$bluez_libs" >> $config_mak
   echo "#define CONFIG_BLUEZ 1" >> $config_h
 fi
+if test "$xen" = "yes" ; then
+  echo "XEN_LIBS=-lxenstore -lxenctrl" >> $config_mak
+fi
 if test "$aio" = "yes" ; then
   echo "#define CONFIG_AIO 1" >> $config_h
   echo "CONFIG_AIO=yes" >> $config_mak
@@ -1657,6 +1681,11 @@ case "$target_cpu" in
       echo "KVM_CFLAGS=$kvm_cflags" >> $config_mak
       echo "#define CONFIG_KVM 1" >> $config_h
     fi
+    if test "$xen" = "yes" -a "$target_softmmu" = "yes";
+    then
+      echo "CONFIG_XEN=yes" >> $config_mak
+      echo "#define CONFIG_XEN 1" >> $config_h
+    fi
   ;;
   x86_64)
     echo "TARGET_ARCH=x86_64" >> $config_mak
@@ -1672,6 +1701,11 @@ case "$target_cpu" in
       echo "KVM_CFLAGS=$kvm_cflags" >> $config_mak
       echo "#define CONFIG_KVM 1" >> $config_h
     fi
+    if test "$xen" = "yes" -a "$target_softmmu" = "yes"
+    then
+      echo "CONFIG_XEN=yes" >> $config_mak
+      echo "#define CONFIG_XEN 1" >> $config_h
+    fi
   ;;
   alpha)
     echo "TARGET_ARCH=alpha" >> $config_mak
diff --git a/hw/boards.h b/hw/boards.h
index 1e18ba6..215ccdc 100644
--- a/hw/boards.h
+++ b/hw/boards.h
@@ -34,6 +34,9 @@ extern QEMUMachine axisdev88_machine;
 extern QEMUMachine pc_machine;
 extern QEMUMachine isapc_machine;
 
+/* xen_machine.c */
+extern QEMUMachine xenpv_machine;
+
 /* ppc.c */
 extern QEMUMachine prep_machine;
 extern QEMUMachine core99_machine;
diff --git a/hw/xen.h b/hw/xen.h
new file mode 100644
index 0000000..3c8da41
--- /dev/null
+++ b/hw/xen.h
@@ -0,0 +1,20 @@
+#ifndef QEMU_HW_XEN_H
+#define QEMU_HW_XEN_H 1
+/*
+ * public xen header
+ *   stuff needed outside xen-*.c, i.e. interfaces to qemu.
+ *   must not depend on any xen headers being present in
+ *   /usr/include/xen, so it can be included unconditionally.
+ */
+
+/* xen-machine.c */
+enum xen_mode {
+    XEN_EMULATE = 0,  // xen emulation, using xenner (default)
+    XEN_CREATE,       // create xen domain
+    XEN_ATTACH        // attach to xen domain created by xend
+};
+
+extern uint32_t xen_domid;
+extern enum xen_mode xen_mode;
+
+#endif /* QEMU_HW_XEN_H */
diff --git a/hw/xen_machine_pv.c b/hw/xen_machine_pv.c
new file mode 100644
index 0000000..21b5d9e
--- /dev/null
+++ b/hw/xen_machine_pv.c
@@ -0,0 +1,70 @@
+/*
+ * QEMU Xen PV Machine
+ *
+ * Copyright (c) 2007 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 "pc.h"
+#include "sysemu.h"
+#include "boards.h"
+#include "xen.h"
+
+uint32_t xen_domid;
+enum xen_mode xen_mode = XEN_EMULATE;
+
+static void xen_init_pv(ram_addr_t ram_size, int vga_ram_size,
+			const char *boot_device,
+			const char *kernel_filename,
+			const char *kernel_cmdline,
+			const char *initrd_filename,
+			const char *cpu_model)
+{
+    CPUState *env;
+
+    /* Initialize a dummy CPU */
+    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 = {
+    .name = "xenpv",
+    .desc = "Xen Para-virtualized PC",
+    .init = xen_init_pv,
+    .ram_require = (4 * 1024 * 1024) | RAMSIZE_FIXED,
+    .max_cpus = 1,
+};
+
+/*
+ * Local variables:
+ *  indent-tabs-mode: nil
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
diff --git a/qemu-options.hx b/qemu-options.hx
index 6c58e2a..895fa89 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1294,6 +1294,17 @@ Enable KVM full virtualization support. This option is only available
 if KVM support is enabled when compiling.
 ETEXI
 
+#ifdef CONFIG_XEN
+DEF("xen-domid", HAS_ARG, QEMU_OPTION_xen_domid,
+    "-xen-domid id   specify xen guest domain id\n")
+DEF("xen-create", 0, QEMU_OPTION_xen_create,
+    "-xen-create     create domain using xen hypercalls, bypassing xend\n"
+    "                warning: should not be used when xend is in use\n")
+DEF("xen-attach", 0, QEMU_OPTION_xen_attach,
+    "-xen-attach     attach to existing xen domain\n"
+    "                xend will use this when starting qemu\n")
+#endif
+
 DEF("no-reboot", 0, QEMU_OPTION_no_reboot, \
     "-no-reboot      exit instead of rebooting\n")
 STEXI
diff --git a/target-i386/machine.c b/target-i386/machine.c
index 1cf49d5..1b0d36d 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 5e6c621..76fca5a 100644
--- a/vl.c
+++ b/vl.c
@@ -138,6 +138,7 @@ int main(int argc, char **argv)
 #include "hw/isa.h"
 #include "hw/baum.h"
 #include "hw/bt.h"
+#include "hw/xen.h"
 #include "bt-host.h"
 #include "net.h"
 #include "monitor.h"
@@ -4943,6 +4944,17 @@ int main(int argc, char **argv, char **envp)
                 run_as = optarg;
                 break;
 #endif
+#ifdef CONFIG_XEN
+            case QEMU_OPTION_xen_domid:
+                xen_domid = atoi(optarg);
+                break;
+            case QEMU_OPTION_xen_create:
+                xen_mode = XEN_CREATE;
+                break;
+            case QEMU_OPTION_xen_attach:
+                xen_mode = XEN_ATTACH;
+                break;
+#endif
             }
         }
     }
-- 
1.6.1.3

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

* [Qemu-devel] [PATCH 02/10] xen: backend driver core
  2009-04-01 21:39 ` Gerd Hoffmann
@ 2009-04-01 21:39   ` Gerd Hoffmann
  -1 siblings, 0 replies; 61+ messages in thread
From: Gerd Hoffmann @ 2009-04-01 21:39 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/xen_backend.c    |  691 +++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/xen_backend.h    |   86 +++++++
 hw/xen_common.h     |   34 +++
 hw/xen_machine_pv.c |    8 +-
 5 files changed, 819 insertions(+), 2 deletions(-)
 create mode 100644 hw/xen_backend.c
 create mode 100644 hw/xen_backend.h
 create mode 100644 hw/xen_common.h

diff --git a/Makefile.target b/Makefile.target
index 1da8055..dd8c0cb 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -564,7 +564,7 @@ LIBS += $(CONFIG_BLUEZ_LIBS)
 endif
 
 # xen backend driver support
-XEN_OBJS := xen_machine_pv.o
+XEN_OBJS := xen_machine_pv.o xen_backend.o
 ifeq ($(CONFIG_XEN), yes)
   OBJS += $(XEN_OBJS)
   LIBS += $(XEN_LIBS)
diff --git a/hw/xen_backend.c b/hw/xen_backend.c
new file mode 100644
index 0000000..2678dfa
--- /dev/null
+++ b/hw/xen_backend.c
@@ -0,0 +1,691 @@
+/*
+ *  xen backend driver infrastructure
+ *  (c) 2008 Gerd Hoffmann <kraxel@redhat.com>
+ *
+ *  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
+ */
+
+/*
+ * TODO: add some xenbus / xenstore concepts overview here.
+ */
+
+#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 TAILQ_HEAD(XenDeviceHead, XenDevice) xendevs = TAILQ_HEAD_INITIALIZER(xendevs);
+static int debug = 0;
+
+/* ------------------------------------------------------------- */
+
+int xenstore_write_str(const char *base, const char *node, const char *val)
+{
+    char abspath[XEN_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[XEN_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;
+    qemu_free(val);
+    return rc;
+}
+
+int xenstore_write_be_str(struct XenDevice *xendev, const char *node, const char *val)
+{
+    return xenstore_write_str(xendev->be, node, val);
+}
+
+int xenstore_write_be_int(struct XenDevice *xendev, const char *node, int ival)
+{
+    return xenstore_write_int(xendev->be, node, ival);
+}
+
+char *xenstore_read_be_str(struct XenDevice *xendev, const char *node)
+{
+    return xenstore_read_str(xendev->be, node);
+}
+
+int xenstore_read_be_int(struct XenDevice *xendev, const char *node, int *ival)
+{
+    return xenstore_read_int(xendev->be, node, ival);
+}
+
+char *xenstore_read_fe_str(struct XenDevice *xendev, const char *node)
+{
+    return xenstore_read_str(xendev->fe, node);
+}
+
+int xenstore_read_fe_int(struct XenDevice *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 XenDevice *xendev, enum xenbus_state state)
+{
+    int rc;
+
+    rc = xenstore_write_be_int(xendev, "state", state);
+    if (rc < 0)
+	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 XenDevice *xen_be_find_xendev(const char *type, int dom, int dev)
+{
+    struct XenDevice *xendev;
+
+    TAILQ_FOREACH(xendev, &xendevs, 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 XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
+                                           struct XenDevOps *ops)
+{
+    struct XenDevice *xendev;
+    char *dom0;
+
+    xendev = xen_be_find_xendev(type, dom, dev);
+    if (xendev)
+	return xendev;
+
+    /* init new xendev */
+    xendev = qemu_mallocz(ops->size);
+    if (!xendev)
+        return NULL;
+    xendev->type  = type;
+    xendev->dom   = dom;
+    xendev->dev   = dev;
+    xendev->ops   = ops;
+
+    dom0 = xs_get_domain_path(xenstore, 0);
+    snprintf(xendev->be, sizeof(xendev->be), "%s/backend/%s/%d/%d",
+	     dom0, xendev->type, xendev->dom, xendev->dev);
+    snprintf(xendev->name, sizeof(xendev->name), "%s-%d",
+	     xendev->type, xendev->dev);
+    free(dom0);
+
+    xendev->debug      = debug;
+    xendev->local_port = -1;
+
+    xendev->evtchndev = xc_evtchn_open();
+    if (xendev->evtchndev < 0) {
+	fprintf(stderr, "can't open evtchn device\n");
+	qemu_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);
+	    qemu_free(xendev);
+	    return NULL;
+	}
+    } else {
+	xendev->gnttabdev = -1;
+    }
+
+    TAILQ_INSERT_TAIL(&xendevs, xendev, next);
+
+    if (xendev->ops->alloc)
+	xendev->ops->alloc(xendev);
+
+    return xendev;
+}
+
+/*
+ * release xen backend device.
+ */
+static struct XenDevice *xen_be_del_xendev(int dom, int dev)
+{
+    struct XenDevice *xendev, *xnext;
+
+    /*
+     * This is pretty much like TAILQ_FOREACH(xendev, &xendevs, next) but
+     * we save the next pointer in xnext because we might free xendev.
+     */
+    xnext = xendevs.tqh_first;
+    while (xnext) {
+        xendev = xnext;
+        xnext = xendev->next.tqe_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[XEN_BUFSIZE];
+	    snprintf(token, sizeof(token), "fe:%p", xendev);
+	    xs_unwatch(xenstore, xendev->fe, token);
+	    qemu_free(xendev->fe);
+	}
+
+	if (xendev->evtchndev >= 0)
+	    xc_evtchn_close(xendev->evtchndev);
+	if (xendev->gnttabdev >= 0)
+	    xc_gnttab_close(xendev->gnttabdev);
+
+	TAILQ_REMOVE(&xendevs, xendev, next);
+	qemu_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 XenDevice *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 XenDevice *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")) {
+	qemu_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 XenDevice *xendev)
+{
+    char token[XEN_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 XenDevice *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 XenDevice *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);
+    return 0;
+}
+
+/*
+ * Teardown connection.
+ *
+ * Goes to Closed when done.
+ */
+static void xen_be_disconnect(struct XenDevice *xendev, enum xenbus_state state)
+{
+    if (xendev->be_state != XenbusStateClosing &&
+        xendev->be_state != XenbusStateClosed  &&
+        xendev->ops->disconnect)
+	xendev->ops->disconnect(xendev);
+    if (xendev->be_state != state)
+        xen_be_set_state(xendev, state);
+}
+
+/*
+ * Try to reset xendev, for reconnection by another frontend instance.
+ */
+static int xen_be_try_reset(struct XenDevice *xendev)
+{
+    if (xendev->fe_state != XenbusStateInitialising)
+        return -1;
+
+    xen_be_printf(xendev, 1, "device reset (for re-connect)\n");
+    xen_be_set_state(xendev, XenbusStateInitialising);
+    return 0;
+}
+
+/*
+ * state change dispatcher function
+ */
+void xen_be_check_state(struct XenDevice *xendev)
+{
+    int rc = 0;
+
+    /* frontend may request shutdown from almost anywhere */
+    if (xendev->fe_state == XenbusStateClosing ||
+	xendev->fe_state == XenbusStateClosed) {
+	xen_be_disconnect(xendev, xendev->fe_state);
+	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;
+        case XenbusStateClosed:
+            rc = xen_be_try_reset(xendev);
+            break;
+	default:
+	    rc = -1;
+	}
+	if (0 != rc)
+	    break;
+    }
+}
+
+/* ------------------------------------------------------------- */
+
+static int xenstore_scan(const char *type, int dom, struct XenDevOps *ops)
+{
+    struct XenDevice *xendev;
+    char path[XEN_BUFSIZE], token[XEN_BUFSIZE];
+    char **dev = NULL, *dom0;
+    unsigned int cdev, j;
+
+    /* setup watch */
+    dom0 = xs_get_domain_path(xenstore, 0);
+    snprintf(token, sizeof(token), "be:%p:%d:%p", type, dom, ops);
+    snprintf(path, sizeof(path), "%s/backend/%s/%d", dom0, type, dom);
+    free(dom0);
+    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);
+    }
+    qemu_free(dev);
+    return 0;
+}
+
+static void xenstore_update_be(char *watch, char *type, int dom,
+			       struct XenDevOps *ops)
+{
+    struct XenDevice *xendev;
+    char path[XEN_BUFSIZE], *dom0;
+    unsigned int len, dev;
+
+    dom0 = xs_get_domain_path(xenstore, 0);
+    len = snprintf(path, sizeof(path), "%s/backend/%s/%d", dom0, type, dom);
+    free(dom0);
+    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 XenDevice *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:
+    qemu_free(vec);
+}
+
+static void xen_be_evtchn_event(void *opaque)
+{
+    struct XenDevice *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(const char *type, struct XenDevOps *ops)
+{
+    return xenstore_scan(type, xen_domid, ops);
+}
+
+int xen_be_bind_evtchn(struct XenDevice *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) {
+	xen_be_printf(xendev, 0, "xc_evtchn_bind_interdomain failed\n");
+	return -1;
+    }
+    xen_be_printf(xendev, 2, "bind evtchn port %d\n", xendev->local_port);
+    qemu_set_fd_handler(xc_evtchn_fd(xendev->evtchndev),
+			xen_be_evtchn_event, NULL, xendev);
+    return 0;
+}
+
+void xen_be_unbind_evtchn(struct XenDevice *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);
+    xen_be_printf(xendev, 2, "unbind evtchn port %d\n", xendev->local_port);
+    xendev->local_port = -1;
+}
+
+int xen_be_send_notify(struct XenDevice *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 XenDevice *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..a1243f6
--- /dev/null
+++ b/hw/xen_backend.h
@@ -0,0 +1,86 @@
+#ifndef QEMU_HW_XEN_BACKEND_H
+#define QEMU_HW_XEN_BACKEND_H 1
+
+#include "xen_common.h"
+
+/* ------------------------------------------------------------- */
+
+#define XEN_BUFSIZE 1024
+
+struct XenDevice;
+
+/* 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 XenDevOps {
+    size_t    size;
+    uint32_t  flags;
+    void      (*alloc)(struct XenDevice *xendev);
+    int       (*init)(struct XenDevice *xendev);
+    int       (*connect)(struct XenDevice *xendev);
+    void      (*event)(struct XenDevice *xendev);
+    void      (*disconnect)(struct XenDevice *xendev);
+    int       (*free)(struct XenDevice *xendev);
+    void      (*backend_changed)(struct XenDevice *xendev, const char *node);
+    void      (*frontend_changed)(struct XenDevice *xendev, const char *node);
+};
+
+struct XenDevice {
+    const 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[XEN_BUFSIZE];
+    char               *fe;
+    char               *protocol;
+    int                remote_port;
+    int                local_port;
+
+    int                evtchndev;
+    int                gnttabdev;
+
+    struct XenDevOps   *ops;
+    TAILQ_ENTRY(XenDevice) next;
+};
+
+/* ------------------------------------------------------------- */
+
+/* variables */
+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 XenDevice *xendev, const char *node, const char *val);
+int xenstore_write_be_int(struct XenDevice *xendev, const char *node, int ival);
+char *xenstore_read_be_str(struct XenDevice *xendev, const char *node);
+int xenstore_read_be_int(struct XenDevice *xendev, const char *node, int *ival);
+char *xenstore_read_fe_str(struct XenDevice *xendev, const char *node);
+int xenstore_read_fe_int(struct XenDevice *xendev, const char *node, int *ival);
+
+const char *xenbus_strstate(enum xenbus_state state);
+struct XenDevice *xen_be_find_xendev(const char *type, int dom, int dev);
+void xen_be_check_state(struct XenDevice *xendev);
+
+/* xen backend driver bits */
+int xen_be_init(void);
+int xen_be_register(const char *type, struct XenDevOps *ops);
+int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state);
+int xen_be_bind_evtchn(struct XenDevice *xendev);
+void xen_be_unbind_evtchn(struct XenDevice *xendev);
+int xen_be_send_notify(struct XenDevice *xendev);
+void xen_be_printf(struct XenDevice *xendev, int msg_level, const char *fmt, ...)
+    __attribute__ ((format(printf, 3, 4)));
+
+#endif /* QEMU_HW_XEN_BACKEND_H */
diff --git a/hw/xen_common.h b/hw/xen_common.h
new file mode 100644
index 0000000..7562567
--- /dev/null
+++ b/hw/xen_common.h
@@ -0,0 +1,34 @@
+#ifndef QEMU_HW_XEN_COMMON_H
+#define QEMU_HW_XEN_COMMON_H 1
+
+#include <stddef.h>
+#include <inttypes.h>
+
+#include <xenctrl.h>
+#include <xs.h>
+#include <xen/io/xenbus.h>
+
+#include "hw.h"
+#include "xen.h"
+#include "sys-queue.h"   /* BSD list implementation */
+
+/*
+ * 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__ < 0x00030205
+# define evtchn_port_or_error_t int
+#endif
+#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
+
+#endif /* QEMU_HW_XEN_COMMON_H */
diff --git a/hw/xen_machine_pv.c b/hw/xen_machine_pv.c
index 21b5d9e..0696bcf 100644
--- a/hw/xen_machine_pv.c
+++ b/hw/xen_machine_pv.c
@@ -26,7 +26,7 @@
 #include "pc.h"
 #include "sysemu.h"
 #include "boards.h"
-#include "xen.h"
+#include "xen_backend.h"
 
 uint32_t xen_domid;
 enum xen_mode xen_mode = XEN_EMULATE;
@@ -50,6 +50,12 @@ static void xen_init_pv(ram_addr_t ram_size, int vga_ram_size,
     }
     env = cpu_init(cpu_model);
     env->halted = 1;
+
+    /* Initialize backend core & drivers */
+    if (-1 == xen_be_init()) {
+        fprintf(stderr, "%s: xen backend core setup failed\n", __FUNCTION__);
+        exit(1);
+    }
 }
 
 QEMUMachine xenpv_machine = {
-- 
1.6.1.3

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

* [PATCH 02/10] xen: backend driver core
@ 2009-04-01 21:39   ` Gerd Hoffmann
  0 siblings, 0 replies; 61+ messages in thread
From: Gerd Hoffmann @ 2009-04-01 21:39 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/xen_backend.c    |  691 +++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/xen_backend.h    |   86 +++++++
 hw/xen_common.h     |   34 +++
 hw/xen_machine_pv.c |    8 +-
 5 files changed, 819 insertions(+), 2 deletions(-)
 create mode 100644 hw/xen_backend.c
 create mode 100644 hw/xen_backend.h
 create mode 100644 hw/xen_common.h

diff --git a/Makefile.target b/Makefile.target
index 1da8055..dd8c0cb 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -564,7 +564,7 @@ LIBS += $(CONFIG_BLUEZ_LIBS)
 endif
 
 # xen backend driver support
-XEN_OBJS := xen_machine_pv.o
+XEN_OBJS := xen_machine_pv.o xen_backend.o
 ifeq ($(CONFIG_XEN), yes)
   OBJS += $(XEN_OBJS)
   LIBS += $(XEN_LIBS)
diff --git a/hw/xen_backend.c b/hw/xen_backend.c
new file mode 100644
index 0000000..2678dfa
--- /dev/null
+++ b/hw/xen_backend.c
@@ -0,0 +1,691 @@
+/*
+ *  xen backend driver infrastructure
+ *  (c) 2008 Gerd Hoffmann <kraxel@redhat.com>
+ *
+ *  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
+ */
+
+/*
+ * TODO: add some xenbus / xenstore concepts overview here.
+ */
+
+#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 TAILQ_HEAD(XenDeviceHead, XenDevice) xendevs = TAILQ_HEAD_INITIALIZER(xendevs);
+static int debug = 0;
+
+/* ------------------------------------------------------------- */
+
+int xenstore_write_str(const char *base, const char *node, const char *val)
+{
+    char abspath[XEN_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[XEN_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;
+    qemu_free(val);
+    return rc;
+}
+
+int xenstore_write_be_str(struct XenDevice *xendev, const char *node, const char *val)
+{
+    return xenstore_write_str(xendev->be, node, val);
+}
+
+int xenstore_write_be_int(struct XenDevice *xendev, const char *node, int ival)
+{
+    return xenstore_write_int(xendev->be, node, ival);
+}
+
+char *xenstore_read_be_str(struct XenDevice *xendev, const char *node)
+{
+    return xenstore_read_str(xendev->be, node);
+}
+
+int xenstore_read_be_int(struct XenDevice *xendev, const char *node, int *ival)
+{
+    return xenstore_read_int(xendev->be, node, ival);
+}
+
+char *xenstore_read_fe_str(struct XenDevice *xendev, const char *node)
+{
+    return xenstore_read_str(xendev->fe, node);
+}
+
+int xenstore_read_fe_int(struct XenDevice *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 XenDevice *xendev, enum xenbus_state state)
+{
+    int rc;
+
+    rc = xenstore_write_be_int(xendev, "state", state);
+    if (rc < 0)
+	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 XenDevice *xen_be_find_xendev(const char *type, int dom, int dev)
+{
+    struct XenDevice *xendev;
+
+    TAILQ_FOREACH(xendev, &xendevs, 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 XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
+                                           struct XenDevOps *ops)
+{
+    struct XenDevice *xendev;
+    char *dom0;
+
+    xendev = xen_be_find_xendev(type, dom, dev);
+    if (xendev)
+	return xendev;
+
+    /* init new xendev */
+    xendev = qemu_mallocz(ops->size);
+    if (!xendev)
+        return NULL;
+    xendev->type  = type;
+    xendev->dom   = dom;
+    xendev->dev   = dev;
+    xendev->ops   = ops;
+
+    dom0 = xs_get_domain_path(xenstore, 0);
+    snprintf(xendev->be, sizeof(xendev->be), "%s/backend/%s/%d/%d",
+	     dom0, xendev->type, xendev->dom, xendev->dev);
+    snprintf(xendev->name, sizeof(xendev->name), "%s-%d",
+	     xendev->type, xendev->dev);
+    free(dom0);
+
+    xendev->debug      = debug;
+    xendev->local_port = -1;
+
+    xendev->evtchndev = xc_evtchn_open();
+    if (xendev->evtchndev < 0) {
+	fprintf(stderr, "can't open evtchn device\n");
+	qemu_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);
+	    qemu_free(xendev);
+	    return NULL;
+	}
+    } else {
+	xendev->gnttabdev = -1;
+    }
+
+    TAILQ_INSERT_TAIL(&xendevs, xendev, next);
+
+    if (xendev->ops->alloc)
+	xendev->ops->alloc(xendev);
+
+    return xendev;
+}
+
+/*
+ * release xen backend device.
+ */
+static struct XenDevice *xen_be_del_xendev(int dom, int dev)
+{
+    struct XenDevice *xendev, *xnext;
+
+    /*
+     * This is pretty much like TAILQ_FOREACH(xendev, &xendevs, next) but
+     * we save the next pointer in xnext because we might free xendev.
+     */
+    xnext = xendevs.tqh_first;
+    while (xnext) {
+        xendev = xnext;
+        xnext = xendev->next.tqe_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[XEN_BUFSIZE];
+	    snprintf(token, sizeof(token), "fe:%p", xendev);
+	    xs_unwatch(xenstore, xendev->fe, token);
+	    qemu_free(xendev->fe);
+	}
+
+	if (xendev->evtchndev >= 0)
+	    xc_evtchn_close(xendev->evtchndev);
+	if (xendev->gnttabdev >= 0)
+	    xc_gnttab_close(xendev->gnttabdev);
+
+	TAILQ_REMOVE(&xendevs, xendev, next);
+	qemu_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 XenDevice *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 XenDevice *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")) {
+	qemu_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 XenDevice *xendev)
+{
+    char token[XEN_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 XenDevice *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 XenDevice *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);
+    return 0;
+}
+
+/*
+ * Teardown connection.
+ *
+ * Goes to Closed when done.
+ */
+static void xen_be_disconnect(struct XenDevice *xendev, enum xenbus_state state)
+{
+    if (xendev->be_state != XenbusStateClosing &&
+        xendev->be_state != XenbusStateClosed  &&
+        xendev->ops->disconnect)
+	xendev->ops->disconnect(xendev);
+    if (xendev->be_state != state)
+        xen_be_set_state(xendev, state);
+}
+
+/*
+ * Try to reset xendev, for reconnection by another frontend instance.
+ */
+static int xen_be_try_reset(struct XenDevice *xendev)
+{
+    if (xendev->fe_state != XenbusStateInitialising)
+        return -1;
+
+    xen_be_printf(xendev, 1, "device reset (for re-connect)\n");
+    xen_be_set_state(xendev, XenbusStateInitialising);
+    return 0;
+}
+
+/*
+ * state change dispatcher function
+ */
+void xen_be_check_state(struct XenDevice *xendev)
+{
+    int rc = 0;
+
+    /* frontend may request shutdown from almost anywhere */
+    if (xendev->fe_state == XenbusStateClosing ||
+	xendev->fe_state == XenbusStateClosed) {
+	xen_be_disconnect(xendev, xendev->fe_state);
+	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;
+        case XenbusStateClosed:
+            rc = xen_be_try_reset(xendev);
+            break;
+	default:
+	    rc = -1;
+	}
+	if (0 != rc)
+	    break;
+    }
+}
+
+/* ------------------------------------------------------------- */
+
+static int xenstore_scan(const char *type, int dom, struct XenDevOps *ops)
+{
+    struct XenDevice *xendev;
+    char path[XEN_BUFSIZE], token[XEN_BUFSIZE];
+    char **dev = NULL, *dom0;
+    unsigned int cdev, j;
+
+    /* setup watch */
+    dom0 = xs_get_domain_path(xenstore, 0);
+    snprintf(token, sizeof(token), "be:%p:%d:%p", type, dom, ops);
+    snprintf(path, sizeof(path), "%s/backend/%s/%d", dom0, type, dom);
+    free(dom0);
+    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);
+    }
+    qemu_free(dev);
+    return 0;
+}
+
+static void xenstore_update_be(char *watch, char *type, int dom,
+			       struct XenDevOps *ops)
+{
+    struct XenDevice *xendev;
+    char path[XEN_BUFSIZE], *dom0;
+    unsigned int len, dev;
+
+    dom0 = xs_get_domain_path(xenstore, 0);
+    len = snprintf(path, sizeof(path), "%s/backend/%s/%d", dom0, type, dom);
+    free(dom0);
+    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 XenDevice *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:
+    qemu_free(vec);
+}
+
+static void xen_be_evtchn_event(void *opaque)
+{
+    struct XenDevice *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(const char *type, struct XenDevOps *ops)
+{
+    return xenstore_scan(type, xen_domid, ops);
+}
+
+int xen_be_bind_evtchn(struct XenDevice *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) {
+	xen_be_printf(xendev, 0, "xc_evtchn_bind_interdomain failed\n");
+	return -1;
+    }
+    xen_be_printf(xendev, 2, "bind evtchn port %d\n", xendev->local_port);
+    qemu_set_fd_handler(xc_evtchn_fd(xendev->evtchndev),
+			xen_be_evtchn_event, NULL, xendev);
+    return 0;
+}
+
+void xen_be_unbind_evtchn(struct XenDevice *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);
+    xen_be_printf(xendev, 2, "unbind evtchn port %d\n", xendev->local_port);
+    xendev->local_port = -1;
+}
+
+int xen_be_send_notify(struct XenDevice *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 XenDevice *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..a1243f6
--- /dev/null
+++ b/hw/xen_backend.h
@@ -0,0 +1,86 @@
+#ifndef QEMU_HW_XEN_BACKEND_H
+#define QEMU_HW_XEN_BACKEND_H 1
+
+#include "xen_common.h"
+
+/* ------------------------------------------------------------- */
+
+#define XEN_BUFSIZE 1024
+
+struct XenDevice;
+
+/* 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 XenDevOps {
+    size_t    size;
+    uint32_t  flags;
+    void      (*alloc)(struct XenDevice *xendev);
+    int       (*init)(struct XenDevice *xendev);
+    int       (*connect)(struct XenDevice *xendev);
+    void      (*event)(struct XenDevice *xendev);
+    void      (*disconnect)(struct XenDevice *xendev);
+    int       (*free)(struct XenDevice *xendev);
+    void      (*backend_changed)(struct XenDevice *xendev, const char *node);
+    void      (*frontend_changed)(struct XenDevice *xendev, const char *node);
+};
+
+struct XenDevice {
+    const 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[XEN_BUFSIZE];
+    char               *fe;
+    char               *protocol;
+    int                remote_port;
+    int                local_port;
+
+    int                evtchndev;
+    int                gnttabdev;
+
+    struct XenDevOps   *ops;
+    TAILQ_ENTRY(XenDevice) next;
+};
+
+/* ------------------------------------------------------------- */
+
+/* variables */
+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 XenDevice *xendev, const char *node, const char *val);
+int xenstore_write_be_int(struct XenDevice *xendev, const char *node, int ival);
+char *xenstore_read_be_str(struct XenDevice *xendev, const char *node);
+int xenstore_read_be_int(struct XenDevice *xendev, const char *node, int *ival);
+char *xenstore_read_fe_str(struct XenDevice *xendev, const char *node);
+int xenstore_read_fe_int(struct XenDevice *xendev, const char *node, int *ival);
+
+const char *xenbus_strstate(enum xenbus_state state);
+struct XenDevice *xen_be_find_xendev(const char *type, int dom, int dev);
+void xen_be_check_state(struct XenDevice *xendev);
+
+/* xen backend driver bits */
+int xen_be_init(void);
+int xen_be_register(const char *type, struct XenDevOps *ops);
+int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state);
+int xen_be_bind_evtchn(struct XenDevice *xendev);
+void xen_be_unbind_evtchn(struct XenDevice *xendev);
+int xen_be_send_notify(struct XenDevice *xendev);
+void xen_be_printf(struct XenDevice *xendev, int msg_level, const char *fmt, ...)
+    __attribute__ ((format(printf, 3, 4)));
+
+#endif /* QEMU_HW_XEN_BACKEND_H */
diff --git a/hw/xen_common.h b/hw/xen_common.h
new file mode 100644
index 0000000..7562567
--- /dev/null
+++ b/hw/xen_common.h
@@ -0,0 +1,34 @@
+#ifndef QEMU_HW_XEN_COMMON_H
+#define QEMU_HW_XEN_COMMON_H 1
+
+#include <stddef.h>
+#include <inttypes.h>
+
+#include <xenctrl.h>
+#include <xs.h>
+#include <xen/io/xenbus.h>
+
+#include "hw.h"
+#include "xen.h"
+#include "sys-queue.h"   /* BSD list implementation */
+
+/*
+ * 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__ < 0x00030205
+# define evtchn_port_or_error_t int
+#endif
+#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
+
+#endif /* QEMU_HW_XEN_COMMON_H */
diff --git a/hw/xen_machine_pv.c b/hw/xen_machine_pv.c
index 21b5d9e..0696bcf 100644
--- a/hw/xen_machine_pv.c
+++ b/hw/xen_machine_pv.c
@@ -26,7 +26,7 @@
 #include "pc.h"
 #include "sysemu.h"
 #include "boards.h"
-#include "xen.h"
+#include "xen_backend.h"
 
 uint32_t xen_domid;
 enum xen_mode xen_mode = XEN_EMULATE;
@@ -50,6 +50,12 @@ static void xen_init_pv(ram_addr_t ram_size, int vga_ram_size,
     }
     env = cpu_init(cpu_model);
     env->halted = 1;
+
+    /* Initialize backend core & drivers */
+    if (-1 == xen_be_init()) {
+        fprintf(stderr, "%s: xen backend core setup failed\n", __FUNCTION__);
+        exit(1);
+    }
 }
 
 QEMUMachine xenpv_machine = {
-- 
1.6.1.3

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

* [Qemu-devel] [PATCH 03/10] xen: add console backend driver.
  2009-04-01 21:39 ` Gerd Hoffmann
@ 2009-04-01 21:39   ` Gerd Hoffmann
  -1 siblings, 0 replies; 61+ messages in thread
From: Gerd Hoffmann @ 2009-04-01 21:39 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    |  276 +++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/xen_machine_pv.c |    1 +
 4 files changed, 281 insertions(+), 0 deletions(-)
 create mode 100644 hw/xen_console.c

diff --git a/Makefile.target b/Makefile.target
index dd8c0cb..b22f7e1 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -565,6 +565,7 @@ endif
 
 # xen backend driver support
 XEN_OBJS := xen_machine_pv.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 a1243f6..4744713 100644
--- a/hw/xen_backend.h
+++ b/hw/xen_backend.h
@@ -83,4 +83,7 @@ int xen_be_send_notify(struct XenDevice *xendev);
 void xen_be_printf(struct XenDevice *xendev, int msg_level, const char *fmt, ...)
     __attribute__ ((format(printf, 3, 4)));
 
+/* actual backend drivers */
+extern struct XenDevOps xen_console_ops;      /* xen_console.c     */
+
 #endif /* QEMU_HW_XEN_BACKEND_H */
diff --git a/hw/xen_console.c b/hw/xen_console.c
new file mode 100644
index 0000000..c172cf2
--- /dev/null
+++ b/hw/xen_console.c
@@ -0,0 +1,276 @@
+/*
+ *  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 <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 XenConsole {
+    struct XenDevice  xendev;  /* must be first */
+    struct buffer     buffer;
+    char              console[XEN_BUFSIZE];
+    int               ring_ref;
+    void              *sring;
+    CharDriverState   *chr;
+    int               backlog;
+};
+
+static void buffer_append(struct XenConsole *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 = qemu_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 = qemu_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 XenConsole *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 XenConsole *con = opaque;
+    return ring_free_bytes(con);
+}
+
+static void xencons_receive(void *opaque, const uint8_t *buf, int len)
+{
+    struct XenConsole *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 XenConsole *con)
+{
+    ssize_t len, size;
+
+    size = con->buffer.size - con->buffer.consumed;
+    if (con->chr)
+        len = qemu_chr_write(con->chr, con->buffer.data + con->buffer.consumed,
+                             size);
+    else
+        len = 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 XenDevice *xendev)
+{
+    struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
+    char *type, *dom;
+
+    /* setup */
+    dom = xs_get_domain_path(xenstore, con->xendev.dom);
+    snprintf(con->console, sizeof(con->console), "%s/console", dom);
+    free(dom);
+
+    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;
+    }
+
+    if (!serial_hds[con->xendev.dev])
+	xen_be_printf(xendev, 1, "WARNING: serial line %d not configured\n",
+                      con->xendev.dev);
+    else
+        con->chr = serial_hds[con->xendev.dev];
+
+    return 0;
+}
+
+static int con_connect(struct XenDevice *xendev)
+{
+    struct XenConsole *con = container_of(xendev, struct XenConsole, 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);
+    if (con->chr)
+        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 XenDevice *xendev)
+{
+    struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
+
+    if (con->chr)
+        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 XenDevice *xendev)
+{
+    struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
+
+    buffer_append(con);
+    if (con->buffer.size - con->buffer.consumed)
+	xencons_send(con);
+}
+
+/* -------------------------------------------------------------------- */
+
+struct XenDevOps xen_console_ops = {
+    .size       = sizeof(struct XenConsole),
+    .flags      = DEVOPS_FLAG_IGNORE_STATE,
+    .init       = con_init,
+    .connect    = con_connect,
+    .event      = con_event,
+    .disconnect = con_disconnect,
+};
diff --git a/hw/xen_machine_pv.c b/hw/xen_machine_pv.c
index 0696bcf..cf2e0a3 100644
--- a/hw/xen_machine_pv.c
+++ b/hw/xen_machine_pv.c
@@ -56,6 +56,7 @@ static void xen_init_pv(ram_addr_t ram_size, int vga_ram_size,
         fprintf(stderr, "%s: xen backend core setup failed\n", __FUNCTION__);
         exit(1);
     }
+    xen_be_register("console", &xen_console_ops);
 }
 
 QEMUMachine xenpv_machine = {
-- 
1.6.1.3

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

* [PATCH 03/10] xen: add console backend driver.
@ 2009-04-01 21:39   ` Gerd Hoffmann
  0 siblings, 0 replies; 61+ messages in thread
From: Gerd Hoffmann @ 2009-04-01 21:39 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    |  276 +++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/xen_machine_pv.c |    1 +
 4 files changed, 281 insertions(+), 0 deletions(-)
 create mode 100644 hw/xen_console.c

diff --git a/Makefile.target b/Makefile.target
index dd8c0cb..b22f7e1 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -565,6 +565,7 @@ endif
 
 # xen backend driver support
 XEN_OBJS := xen_machine_pv.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 a1243f6..4744713 100644
--- a/hw/xen_backend.h
+++ b/hw/xen_backend.h
@@ -83,4 +83,7 @@ int xen_be_send_notify(struct XenDevice *xendev);
 void xen_be_printf(struct XenDevice *xendev, int msg_level, const char *fmt, ...)
     __attribute__ ((format(printf, 3, 4)));
 
+/* actual backend drivers */
+extern struct XenDevOps xen_console_ops;      /* xen_console.c     */
+
 #endif /* QEMU_HW_XEN_BACKEND_H */
diff --git a/hw/xen_console.c b/hw/xen_console.c
new file mode 100644
index 0000000..c172cf2
--- /dev/null
+++ b/hw/xen_console.c
@@ -0,0 +1,276 @@
+/*
+ *  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 <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 XenConsole {
+    struct XenDevice  xendev;  /* must be first */
+    struct buffer     buffer;
+    char              console[XEN_BUFSIZE];
+    int               ring_ref;
+    void              *sring;
+    CharDriverState   *chr;
+    int               backlog;
+};
+
+static void buffer_append(struct XenConsole *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 = qemu_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 = qemu_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 XenConsole *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 XenConsole *con = opaque;
+    return ring_free_bytes(con);
+}
+
+static void xencons_receive(void *opaque, const uint8_t *buf, int len)
+{
+    struct XenConsole *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 XenConsole *con)
+{
+    ssize_t len, size;
+
+    size = con->buffer.size - con->buffer.consumed;
+    if (con->chr)
+        len = qemu_chr_write(con->chr, con->buffer.data + con->buffer.consumed,
+                             size);
+    else
+        len = 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 XenDevice *xendev)
+{
+    struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
+    char *type, *dom;
+
+    /* setup */
+    dom = xs_get_domain_path(xenstore, con->xendev.dom);
+    snprintf(con->console, sizeof(con->console), "%s/console", dom);
+    free(dom);
+
+    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;
+    }
+
+    if (!serial_hds[con->xendev.dev])
+	xen_be_printf(xendev, 1, "WARNING: serial line %d not configured\n",
+                      con->xendev.dev);
+    else
+        con->chr = serial_hds[con->xendev.dev];
+
+    return 0;
+}
+
+static int con_connect(struct XenDevice *xendev)
+{
+    struct XenConsole *con = container_of(xendev, struct XenConsole, 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);
+    if (con->chr)
+        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 XenDevice *xendev)
+{
+    struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
+
+    if (con->chr)
+        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 XenDevice *xendev)
+{
+    struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
+
+    buffer_append(con);
+    if (con->buffer.size - con->buffer.consumed)
+	xencons_send(con);
+}
+
+/* -------------------------------------------------------------------- */
+
+struct XenDevOps xen_console_ops = {
+    .size       = sizeof(struct XenConsole),
+    .flags      = DEVOPS_FLAG_IGNORE_STATE,
+    .init       = con_init,
+    .connect    = con_connect,
+    .event      = con_event,
+    .disconnect = con_disconnect,
+};
diff --git a/hw/xen_machine_pv.c b/hw/xen_machine_pv.c
index 0696bcf..cf2e0a3 100644
--- a/hw/xen_machine_pv.c
+++ b/hw/xen_machine_pv.c
@@ -56,6 +56,7 @@ static void xen_init_pv(ram_addr_t ram_size, int vga_ram_size,
         fprintf(stderr, "%s: xen backend core setup failed\n", __FUNCTION__);
         exit(1);
     }
+    xen_be_register("console", &xen_console_ops);
 }
 
 QEMUMachine xenpv_machine = {
-- 
1.6.1.3

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

* [Qemu-devel] [PATCH 04/10] xen: add framebuffer backend driver
  2009-04-01 21:39 ` Gerd Hoffmann
@ 2009-04-01 21:39   ` Gerd Hoffmann
  -1 siblings, 0 replies; 61+ messages in thread
From: Gerd Hoffmann @ 2009-04-01 21:39 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 release 3.3

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 Makefile.target     |    2 +-
 hw/xen_backend.h    |    4 +
 hw/xen_machine_pv.c |    5 +
 hw/xenfb.c          | 1018 +++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 1028 insertions(+), 1 deletions(-)
 create mode 100644 hw/xenfb.c

diff --git a/Makefile.target b/Makefile.target
index b22f7e1..e824675 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -565,7 +565,7 @@ endif
 
 # xen backend driver support
 XEN_OBJS := xen_machine_pv.o xen_backend.o
-XEN_OBJS += xen_console.o
+XEN_OBJS += xen_console.o xenfb.o
 ifeq ($(CONFIG_XEN), yes)
   OBJS += $(XEN_OBJS)
   LIBS += $(XEN_LIBS)
diff --git a/hw/xen_backend.h b/hw/xen_backend.h
index 4744713..e9a4e2d 100644
--- a/hw/xen_backend.h
+++ b/hw/xen_backend.h
@@ -85,5 +85,9 @@ void xen_be_printf(struct XenDevice *xendev, int msg_level, const char *fmt, ...
 
 /* actual backend drivers */
 extern struct XenDevOps xen_console_ops;      /* xen_console.c     */
+extern struct XenDevOps xen_kbdmouse_ops;     /* xen_framebuffer.c */
+extern struct XenDevOps xen_framebuffer_ops;  /* xen_framebuffer.c */
+
+void xen_init_display(int domid);
 
 #endif /* QEMU_HW_XEN_BACKEND_H */
diff --git a/hw/xen_machine_pv.c b/hw/xen_machine_pv.c
index cf2e0a3..fee794a 100644
--- a/hw/xen_machine_pv.c
+++ b/hw/xen_machine_pv.c
@@ -57,6 +57,11 @@ static void xen_init_pv(ram_addr_t ram_size, int vga_ram_size,
         exit(1);
     }
     xen_be_register("console", &xen_console_ops);
+    xen_be_register("vkbd", &xen_kbdmouse_ops);
+    xen_be_register("vfb", &xen_framebuffer_ops);
+
+    /* setup framebuffer */
+    xen_init_display(xen_domid);
 }
 
 QEMUMachine xenpv_machine = {
diff --git a/hw/xenfb.c b/hw/xenfb.c
new file mode 100644
index 0000000..c9947d7
--- /dev/null
+++ b/hw/xenfb.c
@@ -0,0 +1,1018 @@
+/*
+ *  xen paravirt framebuffer backend
+ *
+ *  Copyright IBM, Corp. 2005-2006
+ *  Copyright Red Hat, Inc. 2006-2008
+ *
+ *  Authors:
+ *       Anthony Liguori <aliguori@us.ibm.com>,
+ *       Markus Armbruster <armbru@redhat.com>,
+ *       Daniel P. Berrange <berrange@redhat.com>,
+ *       Pat Campbell <plc@novell.com>,
+ *       Gerd Hoffmann <kraxel@redhat.com>
+ *
+ *  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 common {
+    struct XenDevice  xendev;  /* must be first */
+    void              *page;
+    DisplayState      *ds;
+};
+
+struct XenInput {
+    struct 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 XenFB {
+    struct common     c;
+    size_t            fb_len;
+    int               row_stride;
+    int               depth;
+    int               width;
+    int               height;
+    int               offset;
+    void              *pixels;
+    int               fbpages;
+    int               feature_update;
+    int               refresh_period;
+    int               bug_trigger;
+    int               have_console;
+    int               do_resize;
+
+    struct {
+	int x,y,w,h;
+    } up_rects[UP_QUEUE];
+    int               up_count;
+    int               up_fullscreen;
+};
+
+/* -------------------------------------------------------------------- */
+
+static int common_bind(struct 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;
+
+    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;
+
+    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);
+
+    return 0;
+}
+
+static void common_unbind(struct common *c)
+{
+    xen_be_unbind_evtchn(&c->xendev);
+    if (c->page) {
+	munmap(c->page, XC_PAGE_SIZE);
+	c->page = NULL;
+    }
+}
+
+/* -------------------------------------------------------------------- */
+
+#if 0
+/*
+ * These two tables are not needed any more, but left in here
+ * intentionally as documentation, to show how scancode2linux[]
+ * was generated.
+ *
+ * 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
+
+};
+#endif
+
+/*
+ * 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];
+ * }
+ */
+static const unsigned char scancode2linux[512] = {
+      0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+     16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+     32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+     48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+     64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+     80, 81, 82, 83, 99,  0, 86, 87, 88,117,  0,  0, 95,183,184,185,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     93,  0,  0, 89,  0,  0, 85, 91, 90, 92,  0, 94,  0,124,121,  0,
+
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    165,  0,  0,  0,  0,  0,  0,  0,  0,163,  0,  0, 96, 97,  0,  0,
+    113,140,164,  0,166,  0,  0,  0,  0,  0,255,  0,  0,  0,114,  0,
+    115,  0,150,  0,  0, 98,255, 99,100,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,119,119,102,103,104,  0,105,112,106,118,107,
+    108,109,110,111,  0,  0,  0,  0,  0,  0,  0,125,126,127,116,142,
+      0,  0,  0,143,  0,217,156,173,128,159,158,157,155,226,  0,112,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+};
+
+/* Send an event to the keyboard frontend driver */
+static int xenfb_kbd_event(struct XenInput *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;
+    if (!page)
+        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 XenInput *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 XenInput *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 XenInput *xenfb,
+			       int abs_x, int abs_y, int 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.abs_z = z;
+#endif
+#if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030208
+    event.pos.rel_z = 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 XenInput *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 XenInput *xenfb = opaque;
+    int dw = ds_get_width(xenfb->c.ds);
+    int dh = ds_get_height(xenfb->c.ds);
+    int i;
+
+    if (xenfb->abs_pointer_wanted)
+	xenfb_send_position(xenfb,
+			    dx * (dw - 1) / 0x7fff,
+			    dy * (dh - 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 XenDevice *xendev)
+{
+    struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
+
+    if (!in->c.ds) {
+        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 XenDevice *xendev)
+{
+    struct XenInput *in = container_of(xendev, struct XenInput, 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 XenDevice *xendev)
+{
+    struct XenInput *in = container_of(xendev, struct XenInput, 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 XenDevice *xendev)
+{
+    struct XenInput *xenfb = container_of(xendev, struct XenInput, 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 XenFB *xenfb)
+{
+    struct xenfb_page *page = xenfb->c.page;
+    char *protocol = xenfb->c.xendev.protocol;
+    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
+    }
+
+    if (xenfb->pixels) {
+        munmap(xenfb->pixels, xenfb->fbpages * XC_PAGE_SIZE);
+        xenfb->pixels = NULL;
+    }
+
+    xenfb->fbpages = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
+    n_fbdirs = xenfb->fbpages * mode / 8;
+    n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
+
+    pgmfns = qemu_mallocz(sizeof(unsigned long) * n_fbdirs);
+    fbmfns = qemu_mallocz(sizeof(unsigned long) * xenfb->fbpages);
+    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, xenfb->fbpages, 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, xenfb->fbpages);
+    if (xenfb->pixels == NULL)
+	goto out;
+
+    ret = 0; /* all is fine */
+
+out:
+    qemu_free(pgmfns);
+    qemu_free(fbmfns);
+    return ret;
+}
+
+static int xenfb_configure_fb(struct XenFB *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;
+    xenfb->up_fullscreen = 1;
+    xenfb->do_resize = 1;
+    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 *)(data					\
+			       + (line * linesize)			\
+			       + (x * bpp / 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 + bpp / 8);		\
+	}								\
+    }
+
+
+/*
+ * This copies data from the guest framebuffer region, into QEMU's
+ * displaysurface. qemu uses 16 or 32 bpp.  In case the pv framebuffer
+ * uses something else we must convert and copy, otherwise we can
+ * supply the buffer directly and no thing here.
+ */
+static void xenfb_guest_copy(struct XenFB *xenfb, int x, int y, int w, int h)
+{
+    int line, oops = 0;
+    int bpp = ds_get_bits_per_pixel(xenfb->c.ds);
+    int linesize = ds_get_linesize(xenfb->c.ds);
+    uint8_t *data = ds_get_data(xenfb->c.ds);
+
+    if (!is_buffer_shared(xenfb->c.ds->surface)) {
+        switch (xenfb->depth) {
+        case 8:
+            if (bpp == 16) {
+                BLT(uint8_t, uint16_t,   3, 3, 2,   5, 6, 5);
+            } else if (bpp == 32) {
+                BLT(uint8_t, uint32_t,   3, 3, 2,   8, 8, 8);
+            } else {
+                oops = 1;
+            }
+            break;
+        case 24:
+            if (bpp == 16) {
+                BLT(uint32_t, uint16_t,  8, 8, 8,   5, 6, 5);
+            } else if (bpp == 32) {
+                BLT(uint32_t, uint32_t,  8, 8, 8,   8, 8, 8);
+            } else {
+                oops = 1;
+            }
+            break;
+        default:
+            oops = 1;
+	}
+    }
+    if (oops) /* should not happen */
+        xen_be_printf(&xenfb->c.xendev, 0, "%s: oops: convert %d -> %d bpp?\n",
+                      __FUNCTION__, xenfb->depth, bpp);
+
+    dpy_update(xenfb->c.ds, x, y, w, h);
+}
+
+#ifdef XENFB_TYPE_REFRESH_PERIOD
+static int xenfb_queue_full(struct XenFB *xenfb)
+{
+    struct xenfb_page *page = xenfb->c.page;
+    uint32_t cons, prod;
+
+    if (!page)
+        return 1;
+
+    prod = page->in_prod;
+    cons = page->in_cons;
+    return prod - cons == XENFB_IN_RING_LEN;
+}
+
+static void xenfb_send_event(struct XenFB *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 XenFB *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 XenFB *xenfb = opaque;
+    struct DisplayChangeListener *l;
+    int dw = ds_get_width(xenfb->c.ds);
+    int dh = ds_get_height(xenfb->c.ds);
+    int i;
+
+    if (xenfb->c.xendev.be_state != XenbusStateConnected)
+        return;
+
+    if (xenfb->feature_update) {
+#ifdef XENFB_TYPE_REFRESH_PERIOD
+        int period = 99999999;
+        int idle = 1;
+
+	if (xenfb_queue_full(xenfb))
+	    return;
+
+        for (l = xenfb->c.ds->listeners; l != NULL; l = l->next) {
+            if (l->idle)
+                continue;
+            idle = 0;
+            if (!l->gui_timer_interval) {
+                if (period > GUI_REFRESH_INTERVAL)
+                    period = GUI_REFRESH_INTERVAL;
+            } else {
+                if (period > l->gui_timer_interval)
+                    period = l->gui_timer_interval;
+            }
+        }
+        if (idle)
+	    period = XENFB_NO_REFRESH;
+
+	if (xenfb->refresh_period != period) {
+	    xenfb_send_refresh_period(xenfb, period);
+	    xenfb->refresh_period = period;
+            xen_be_printf(&xenfb->c.xendev, 1, "refresh period: %d\n", 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->do_resize) {
+        xenfb->do_resize = 0;
+        switch (xenfb->depth) {
+        case 16:
+        case 32:
+            /* console.c supported depth -> buffer can be used directly */
+            qemu_free_displaysurface(xenfb->c.ds);
+            xenfb->c.ds->surface = qemu_create_displaysurface_from
+                (xenfb->width, xenfb->height, xenfb->depth,
+                 xenfb->row_stride, xenfb->pixels + xenfb->offset);
+            break;
+        default:
+            /* we must convert stuff */
+            qemu_resize_displaysurface(xenfb->c.ds,
+                                       xenfb->width, xenfb->height);
+            break;
+        }
+        xen_be_printf(&xenfb->c.xendev, 1, "update: resizing: %dx%d @ %d bpp%s\n",
+                      xenfb->width, xenfb->height, xenfb->depth,
+                      is_buffer_shared(xenfb->c.ds->surface) ? " (shared)" : "");
+        dpy_resize(xenfb->c.ds);
+        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;
+}
+
+/* QEMU display state changed, so refresh the framebuffer copy */
+static void xenfb_invalidate(void *opaque)
+{
+    struct XenFB *xenfb = opaque;
+    xenfb->up_fullscreen = 1;
+}
+
+static void xenfb_handle_events(struct XenFB *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;
+}
+
+static int fb_init(struct XenDevice *xendev)
+{
+    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
+
+    fb->refresh_period = -1;
+
+#ifdef XENFB_TYPE_RESIZE
+    xenstore_write_be_int(xendev, "feature-resize", 1);
+#endif
+    return 0;
+}
+
+static int fb_connect(struct XenDevice *xendev)
+{
+    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
+    struct xenfb_page *fb_page;
+    int videoram;
+    int rc;
+
+    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;
+
+#if 0  /* handled in xen_init_display() for now */
+    if (!fb->have_console) {
+        fb->c.ds = graphic_console_init(xenfb_update,
+                                        xenfb_invalidate,
+                                        NULL,
+                                        NULL,
+                                        fb);
+        fb->have_console = 1;
+    }
+#endif
+
+    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);
+
+    xen_be_printf(xendev, 1, "feature-update=%d, videoram=%d\n",
+		  fb->feature_update, videoram);
+    return 0;
+}
+
+static void fb_disconnect(struct XenDevice *xendev)
+{
+    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
+
+    /*
+     * FIXME: qemu can't un-init gfx display (yet?).
+     *   Replacing the framebuffer with anonymous shared memory
+     *   instead.  This releases the guest pages and keeps qemu happy.
+     */
+    fb->pixels = mmap(fb->pixels, fb->fbpages * XC_PAGE_SIZE,
+                      PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON,
+                      -1, 0);
+    common_unbind(&fb->c);
+    fb->feature_update = 0;
+    fb->bug_trigger    = 0;
+}
+
+static void fb_frontend_changed(struct XenDevice *xendev, const char *node)
+{
+    struct XenFB *fb = container_of(xendev, struct XenFB, 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_printf(xendev, 2, "re-trigger connected (frontend bug)\n");
+        xen_be_set_state(xendev, XenbusStateConnected);
+        fb->bug_trigger = 1; /* only once */
+    }
+}
+
+static void fb_event(struct XenDevice *xendev)
+{
+    struct XenFB *xenfb = container_of(xendev, struct XenFB, c.xendev);
+
+    xenfb_handle_events(xenfb);
+    xen_be_send_notify(&xenfb->c.xendev);
+}
+
+/* -------------------------------------------------------------------- */
+
+struct XenDevOps xen_kbdmouse_ops = {
+    .size       = sizeof(struct XenInput),
+    .init       = input_init,
+    .connect    = input_connect,
+    .disconnect = input_disconnect,
+    .event      = input_event,
+};
+
+struct XenDevOps xen_framebuffer_ops = {
+    .size       = sizeof(struct XenFB),
+    .init       = fb_init,
+    .connect    = fb_connect,
+    .disconnect = fb_disconnect,
+    .event      = fb_event,
+    .frontend_changed = fb_frontend_changed,
+};
+
+/*
+ * FIXME/TODO: Kill this.
+ * Temporary needed while DisplayState reorganization is in flight.
+ */
+void xen_init_display(int domid)
+{
+    struct XenDevice *xfb, *xin;
+    struct XenFB *fb;
+    struct XenInput *in;
+    int i = 0;
+
+wait_more:
+    i++;
+    main_loop_wait(10); /* miliseconds */
+    xfb = xen_be_find_xendev("vfb", domid, 0);
+    xin = xen_be_find_xendev("vkbd", domid, 0);
+    if (!xfb || !xin) {
+        if (i < 256)
+            goto wait_more;
+        fprintf(stderr, "%s: displaystate setup failed\n", __FUNCTION__);
+        return;
+    }
+
+    /* vfb */
+    fb = container_of(xfb, struct XenFB, c.xendev);
+    fb->c.ds = graphic_console_init(xenfb_update,
+                                    xenfb_invalidate,
+                                    NULL,
+                                    NULL,
+                                    fb);
+    fb->have_console = 1;
+
+    /* vkbd */
+    in = container_of(xin, struct XenInput, c.xendev);
+    in->c.ds = fb->c.ds;
+
+    /* retry ->init() */
+    xen_be_check_state(xin);
+    xen_be_check_state(xfb);
+}
-- 
1.6.1.3

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

* [PATCH 04/10] xen: add framebuffer backend driver
@ 2009-04-01 21:39   ` Gerd Hoffmann
  0 siblings, 0 replies; 61+ messages in thread
From: Gerd Hoffmann @ 2009-04-01 21:39 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 release 3.3

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 Makefile.target     |    2 +-
 hw/xen_backend.h    |    4 +
 hw/xen_machine_pv.c |    5 +
 hw/xenfb.c          | 1018 +++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 1028 insertions(+), 1 deletions(-)
 create mode 100644 hw/xenfb.c

diff --git a/Makefile.target b/Makefile.target
index b22f7e1..e824675 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -565,7 +565,7 @@ endif
 
 # xen backend driver support
 XEN_OBJS := xen_machine_pv.o xen_backend.o
-XEN_OBJS += xen_console.o
+XEN_OBJS += xen_console.o xenfb.o
 ifeq ($(CONFIG_XEN), yes)
   OBJS += $(XEN_OBJS)
   LIBS += $(XEN_LIBS)
diff --git a/hw/xen_backend.h b/hw/xen_backend.h
index 4744713..e9a4e2d 100644
--- a/hw/xen_backend.h
+++ b/hw/xen_backend.h
@@ -85,5 +85,9 @@ void xen_be_printf(struct XenDevice *xendev, int msg_level, const char *fmt, ...
 
 /* actual backend drivers */
 extern struct XenDevOps xen_console_ops;      /* xen_console.c     */
+extern struct XenDevOps xen_kbdmouse_ops;     /* xen_framebuffer.c */
+extern struct XenDevOps xen_framebuffer_ops;  /* xen_framebuffer.c */
+
+void xen_init_display(int domid);
 
 #endif /* QEMU_HW_XEN_BACKEND_H */
diff --git a/hw/xen_machine_pv.c b/hw/xen_machine_pv.c
index cf2e0a3..fee794a 100644
--- a/hw/xen_machine_pv.c
+++ b/hw/xen_machine_pv.c
@@ -57,6 +57,11 @@ static void xen_init_pv(ram_addr_t ram_size, int vga_ram_size,
         exit(1);
     }
     xen_be_register("console", &xen_console_ops);
+    xen_be_register("vkbd", &xen_kbdmouse_ops);
+    xen_be_register("vfb", &xen_framebuffer_ops);
+
+    /* setup framebuffer */
+    xen_init_display(xen_domid);
 }
 
 QEMUMachine xenpv_machine = {
diff --git a/hw/xenfb.c b/hw/xenfb.c
new file mode 100644
index 0000000..c9947d7
--- /dev/null
+++ b/hw/xenfb.c
@@ -0,0 +1,1018 @@
+/*
+ *  xen paravirt framebuffer backend
+ *
+ *  Copyright IBM, Corp. 2005-2006
+ *  Copyright Red Hat, Inc. 2006-2008
+ *
+ *  Authors:
+ *       Anthony Liguori <aliguori@us.ibm.com>,
+ *       Markus Armbruster <armbru@redhat.com>,
+ *       Daniel P. Berrange <berrange@redhat.com>,
+ *       Pat Campbell <plc@novell.com>,
+ *       Gerd Hoffmann <kraxel@redhat.com>
+ *
+ *  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 common {
+    struct XenDevice  xendev;  /* must be first */
+    void              *page;
+    DisplayState      *ds;
+};
+
+struct XenInput {
+    struct 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 XenFB {
+    struct common     c;
+    size_t            fb_len;
+    int               row_stride;
+    int               depth;
+    int               width;
+    int               height;
+    int               offset;
+    void              *pixels;
+    int               fbpages;
+    int               feature_update;
+    int               refresh_period;
+    int               bug_trigger;
+    int               have_console;
+    int               do_resize;
+
+    struct {
+	int x,y,w,h;
+    } up_rects[UP_QUEUE];
+    int               up_count;
+    int               up_fullscreen;
+};
+
+/* -------------------------------------------------------------------- */
+
+static int common_bind(struct 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;
+
+    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;
+
+    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);
+
+    return 0;
+}
+
+static void common_unbind(struct common *c)
+{
+    xen_be_unbind_evtchn(&c->xendev);
+    if (c->page) {
+	munmap(c->page, XC_PAGE_SIZE);
+	c->page = NULL;
+    }
+}
+
+/* -------------------------------------------------------------------- */
+
+#if 0
+/*
+ * These two tables are not needed any more, but left in here
+ * intentionally as documentation, to show how scancode2linux[]
+ * was generated.
+ *
+ * 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
+
+};
+#endif
+
+/*
+ * 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];
+ * }
+ */
+static const unsigned char scancode2linux[512] = {
+      0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+     16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+     32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+     48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+     64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+     80, 81, 82, 83, 99,  0, 86, 87, 88,117,  0,  0, 95,183,184,185,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     93,  0,  0, 89,  0,  0, 85, 91, 90, 92,  0, 94,  0,124,121,  0,
+
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    165,  0,  0,  0,  0,  0,  0,  0,  0,163,  0,  0, 96, 97,  0,  0,
+    113,140,164,  0,166,  0,  0,  0,  0,  0,255,  0,  0,  0,114,  0,
+    115,  0,150,  0,  0, 98,255, 99,100,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,119,119,102,103,104,  0,105,112,106,118,107,
+    108,109,110,111,  0,  0,  0,  0,  0,  0,  0,125,126,127,116,142,
+      0,  0,  0,143,  0,217,156,173,128,159,158,157,155,226,  0,112,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+};
+
+/* Send an event to the keyboard frontend driver */
+static int xenfb_kbd_event(struct XenInput *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;
+    if (!page)
+        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 XenInput *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 XenInput *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 XenInput *xenfb,
+			       int abs_x, int abs_y, int 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.abs_z = z;
+#endif
+#if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030208
+    event.pos.rel_z = 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 XenInput *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 XenInput *xenfb = opaque;
+    int dw = ds_get_width(xenfb->c.ds);
+    int dh = ds_get_height(xenfb->c.ds);
+    int i;
+
+    if (xenfb->abs_pointer_wanted)
+	xenfb_send_position(xenfb,
+			    dx * (dw - 1) / 0x7fff,
+			    dy * (dh - 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 XenDevice *xendev)
+{
+    struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
+
+    if (!in->c.ds) {
+        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 XenDevice *xendev)
+{
+    struct XenInput *in = container_of(xendev, struct XenInput, 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 XenDevice *xendev)
+{
+    struct XenInput *in = container_of(xendev, struct XenInput, 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 XenDevice *xendev)
+{
+    struct XenInput *xenfb = container_of(xendev, struct XenInput, 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 XenFB *xenfb)
+{
+    struct xenfb_page *page = xenfb->c.page;
+    char *protocol = xenfb->c.xendev.protocol;
+    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
+    }
+
+    if (xenfb->pixels) {
+        munmap(xenfb->pixels, xenfb->fbpages * XC_PAGE_SIZE);
+        xenfb->pixels = NULL;
+    }
+
+    xenfb->fbpages = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
+    n_fbdirs = xenfb->fbpages * mode / 8;
+    n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
+
+    pgmfns = qemu_mallocz(sizeof(unsigned long) * n_fbdirs);
+    fbmfns = qemu_mallocz(sizeof(unsigned long) * xenfb->fbpages);
+    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, xenfb->fbpages, 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, xenfb->fbpages);
+    if (xenfb->pixels == NULL)
+	goto out;
+
+    ret = 0; /* all is fine */
+
+out:
+    qemu_free(pgmfns);
+    qemu_free(fbmfns);
+    return ret;
+}
+
+static int xenfb_configure_fb(struct XenFB *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;
+    xenfb->up_fullscreen = 1;
+    xenfb->do_resize = 1;
+    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 *)(data					\
+			       + (line * linesize)			\
+			       + (x * bpp / 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 + bpp / 8);		\
+	}								\
+    }
+
+
+/*
+ * This copies data from the guest framebuffer region, into QEMU's
+ * displaysurface. qemu uses 16 or 32 bpp.  In case the pv framebuffer
+ * uses something else we must convert and copy, otherwise we can
+ * supply the buffer directly and no thing here.
+ */
+static void xenfb_guest_copy(struct XenFB *xenfb, int x, int y, int w, int h)
+{
+    int line, oops = 0;
+    int bpp = ds_get_bits_per_pixel(xenfb->c.ds);
+    int linesize = ds_get_linesize(xenfb->c.ds);
+    uint8_t *data = ds_get_data(xenfb->c.ds);
+
+    if (!is_buffer_shared(xenfb->c.ds->surface)) {
+        switch (xenfb->depth) {
+        case 8:
+            if (bpp == 16) {
+                BLT(uint8_t, uint16_t,   3, 3, 2,   5, 6, 5);
+            } else if (bpp == 32) {
+                BLT(uint8_t, uint32_t,   3, 3, 2,   8, 8, 8);
+            } else {
+                oops = 1;
+            }
+            break;
+        case 24:
+            if (bpp == 16) {
+                BLT(uint32_t, uint16_t,  8, 8, 8,   5, 6, 5);
+            } else if (bpp == 32) {
+                BLT(uint32_t, uint32_t,  8, 8, 8,   8, 8, 8);
+            } else {
+                oops = 1;
+            }
+            break;
+        default:
+            oops = 1;
+	}
+    }
+    if (oops) /* should not happen */
+        xen_be_printf(&xenfb->c.xendev, 0, "%s: oops: convert %d -> %d bpp?\n",
+                      __FUNCTION__, xenfb->depth, bpp);
+
+    dpy_update(xenfb->c.ds, x, y, w, h);
+}
+
+#ifdef XENFB_TYPE_REFRESH_PERIOD
+static int xenfb_queue_full(struct XenFB *xenfb)
+{
+    struct xenfb_page *page = xenfb->c.page;
+    uint32_t cons, prod;
+
+    if (!page)
+        return 1;
+
+    prod = page->in_prod;
+    cons = page->in_cons;
+    return prod - cons == XENFB_IN_RING_LEN;
+}
+
+static void xenfb_send_event(struct XenFB *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 XenFB *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 XenFB *xenfb = opaque;
+    struct DisplayChangeListener *l;
+    int dw = ds_get_width(xenfb->c.ds);
+    int dh = ds_get_height(xenfb->c.ds);
+    int i;
+
+    if (xenfb->c.xendev.be_state != XenbusStateConnected)
+        return;
+
+    if (xenfb->feature_update) {
+#ifdef XENFB_TYPE_REFRESH_PERIOD
+        int period = 99999999;
+        int idle = 1;
+
+	if (xenfb_queue_full(xenfb))
+	    return;
+
+        for (l = xenfb->c.ds->listeners; l != NULL; l = l->next) {
+            if (l->idle)
+                continue;
+            idle = 0;
+            if (!l->gui_timer_interval) {
+                if (period > GUI_REFRESH_INTERVAL)
+                    period = GUI_REFRESH_INTERVAL;
+            } else {
+                if (period > l->gui_timer_interval)
+                    period = l->gui_timer_interval;
+            }
+        }
+        if (idle)
+	    period = XENFB_NO_REFRESH;
+
+	if (xenfb->refresh_period != period) {
+	    xenfb_send_refresh_period(xenfb, period);
+	    xenfb->refresh_period = period;
+            xen_be_printf(&xenfb->c.xendev, 1, "refresh period: %d\n", 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->do_resize) {
+        xenfb->do_resize = 0;
+        switch (xenfb->depth) {
+        case 16:
+        case 32:
+            /* console.c supported depth -> buffer can be used directly */
+            qemu_free_displaysurface(xenfb->c.ds);
+            xenfb->c.ds->surface = qemu_create_displaysurface_from
+                (xenfb->width, xenfb->height, xenfb->depth,
+                 xenfb->row_stride, xenfb->pixels + xenfb->offset);
+            break;
+        default:
+            /* we must convert stuff */
+            qemu_resize_displaysurface(xenfb->c.ds,
+                                       xenfb->width, xenfb->height);
+            break;
+        }
+        xen_be_printf(&xenfb->c.xendev, 1, "update: resizing: %dx%d @ %d bpp%s\n",
+                      xenfb->width, xenfb->height, xenfb->depth,
+                      is_buffer_shared(xenfb->c.ds->surface) ? " (shared)" : "");
+        dpy_resize(xenfb->c.ds);
+        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;
+}
+
+/* QEMU display state changed, so refresh the framebuffer copy */
+static void xenfb_invalidate(void *opaque)
+{
+    struct XenFB *xenfb = opaque;
+    xenfb->up_fullscreen = 1;
+}
+
+static void xenfb_handle_events(struct XenFB *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;
+}
+
+static int fb_init(struct XenDevice *xendev)
+{
+    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
+
+    fb->refresh_period = -1;
+
+#ifdef XENFB_TYPE_RESIZE
+    xenstore_write_be_int(xendev, "feature-resize", 1);
+#endif
+    return 0;
+}
+
+static int fb_connect(struct XenDevice *xendev)
+{
+    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
+    struct xenfb_page *fb_page;
+    int videoram;
+    int rc;
+
+    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;
+
+#if 0  /* handled in xen_init_display() for now */
+    if (!fb->have_console) {
+        fb->c.ds = graphic_console_init(xenfb_update,
+                                        xenfb_invalidate,
+                                        NULL,
+                                        NULL,
+                                        fb);
+        fb->have_console = 1;
+    }
+#endif
+
+    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);
+
+    xen_be_printf(xendev, 1, "feature-update=%d, videoram=%d\n",
+		  fb->feature_update, videoram);
+    return 0;
+}
+
+static void fb_disconnect(struct XenDevice *xendev)
+{
+    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
+
+    /*
+     * FIXME: qemu can't un-init gfx display (yet?).
+     *   Replacing the framebuffer with anonymous shared memory
+     *   instead.  This releases the guest pages and keeps qemu happy.
+     */
+    fb->pixels = mmap(fb->pixels, fb->fbpages * XC_PAGE_SIZE,
+                      PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON,
+                      -1, 0);
+    common_unbind(&fb->c);
+    fb->feature_update = 0;
+    fb->bug_trigger    = 0;
+}
+
+static void fb_frontend_changed(struct XenDevice *xendev, const char *node)
+{
+    struct XenFB *fb = container_of(xendev, struct XenFB, 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_printf(xendev, 2, "re-trigger connected (frontend bug)\n");
+        xen_be_set_state(xendev, XenbusStateConnected);
+        fb->bug_trigger = 1; /* only once */
+    }
+}
+
+static void fb_event(struct XenDevice *xendev)
+{
+    struct XenFB *xenfb = container_of(xendev, struct XenFB, c.xendev);
+
+    xenfb_handle_events(xenfb);
+    xen_be_send_notify(&xenfb->c.xendev);
+}
+
+/* -------------------------------------------------------------------- */
+
+struct XenDevOps xen_kbdmouse_ops = {
+    .size       = sizeof(struct XenInput),
+    .init       = input_init,
+    .connect    = input_connect,
+    .disconnect = input_disconnect,
+    .event      = input_event,
+};
+
+struct XenDevOps xen_framebuffer_ops = {
+    .size       = sizeof(struct XenFB),
+    .init       = fb_init,
+    .connect    = fb_connect,
+    .disconnect = fb_disconnect,
+    .event      = fb_event,
+    .frontend_changed = fb_frontend_changed,
+};
+
+/*
+ * FIXME/TODO: Kill this.
+ * Temporary needed while DisplayState reorganization is in flight.
+ */
+void xen_init_display(int domid)
+{
+    struct XenDevice *xfb, *xin;
+    struct XenFB *fb;
+    struct XenInput *in;
+    int i = 0;
+
+wait_more:
+    i++;
+    main_loop_wait(10); /* miliseconds */
+    xfb = xen_be_find_xendev("vfb", domid, 0);
+    xin = xen_be_find_xendev("vkbd", domid, 0);
+    if (!xfb || !xin) {
+        if (i < 256)
+            goto wait_more;
+        fprintf(stderr, "%s: displaystate setup failed\n", __FUNCTION__);
+        return;
+    }
+
+    /* vfb */
+    fb = container_of(xfb, struct XenFB, c.xendev);
+    fb->c.ds = graphic_console_init(xenfb_update,
+                                    xenfb_invalidate,
+                                    NULL,
+                                    NULL,
+                                    fb);
+    fb->have_console = 1;
+
+    /* vkbd */
+    in = container_of(xin, struct XenInput, c.xendev);
+    in->c.ds = fb->c.ds;
+
+    /* retry ->init() */
+    xen_be_check_state(xin);
+    xen_be_check_state(xfb);
+}
-- 
1.6.1.3

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

* [Qemu-devel] [PATCH 05/10] xen: add block device backend driver.
  2009-04-01 21:39 ` Gerd Hoffmann
@ 2009-04-01 21:39   ` Gerd Hoffmann
  -1 siblings, 0 replies; 61+ messages in thread
From: Gerd Hoffmann @ 2009-04-01 21:39 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       |  799 +++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/xen_machine_pv.c |    1 +
 sysemu.h            |    2 +-
 vl.c                |    6 +-
 7 files changed, 912 insertions(+), 3 deletions(-)
 create mode 100644 hw/xen_blkif.h
 create mode 100644 hw/xen_disk.c

diff --git a/Makefile.target b/Makefile.target
index e824675..b66ff27 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -565,7 +565,7 @@ endif
 
 # xen backend driver support
 XEN_OBJS := xen_machine_pv.o xen_backend.o
-XEN_OBJS += xen_console.o xenfb.o
+XEN_OBJS += xen_console.o xenfb.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 e9a4e2d..dd426dd 100644
--- a/hw/xen_backend.h
+++ b/hw/xen_backend.h
@@ -2,6 +2,7 @@
 #define QEMU_HW_XEN_BACKEND_H 1
 
 #include "xen_common.h"
+#include "sysemu.h"
 
 /* ------------------------------------------------------------- */
 
@@ -87,6 +88,7 @@ void xen_be_printf(struct XenDevice *xendev, int msg_level, const char *fmt, ...
 extern struct XenDevOps xen_console_ops;      /* xen_console.c     */
 extern struct XenDevOps xen_kbdmouse_ops;     /* xen_framebuffer.c */
 extern struct XenDevOps xen_framebuffer_ops;  /* xen_framebuffer.c */
+extern struct XenDevOps xen_blkdev_ops;       /* xen_disk.c        */
 
 void xen_init_display(int domid);
 
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..33b2dfd
--- /dev/null
+++ b/hw/xen_disk.c
@@ -0,0 +1,799 @@
+/*
+ *  xen paravirt block device backend
+ *
+ *  (c) Gerd Hoffmann <kraxel@redhat.com>
+ *
+ *  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
+ */
+
+/*
+ *  FIXME: the code is designed to handle multiple outstanding
+ *         requests, which isn't used right now.  Plan is to
+ *         switch over to the aio block functions once they got
+ *         vector support.
+ */
+
+#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 <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 "hw.h"
+#include "block_int.h"
+#include "qemu-char.h"
+#include "xen_blkif.h"
+#include "xen_backend.h"
+
+/* ------------------------------------------------------------- */
+
+static int syncwrite    = 0;
+static int batch_maps   = 0;
+
+static int max_requests = 32;
+static int use_aio      = 1;
+
+/* ------------------------------------------------------------- */
+
+#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;
+
+    /* aio status */
+    int                 aio_inflight;
+    int                 aio_errors;
+
+    struct XenBlkDev    *blkdev;
+    LIST_ENTRY(ioreq)   list;
+};
+
+struct XenBlkDev {
+    struct XenDevice    xendev;  /* must be first */
+    char                *params;
+    char                *mode;
+    char                *type;
+    char                *dev;
+    char                *devtype;
+    const char          *fileproto;
+    const char          *filename;
+    int                 ring_ref;
+    void                *sring;
+    int64_t             file_blk;
+    int64_t             file_size;
+    int                 protocol;
+    blkif_back_rings_t  rings;
+    int                 more_work;
+    int                 cnt_map;
+
+    /* request lists */
+    LIST_HEAD(inflight_head, ioreq) inflight;
+    LIST_HEAD(finished_head, ioreq) finished;
+    LIST_HEAD(freelist_head, ioreq) freelist;
+    int                 requests_total;
+    int                 requests_inflight;
+    int                 requests_finished;
+
+    /* qemu block driver */
+    int                 index;
+    BlockDriverState    *bs;
+    QEMUBH              *bh;
+};
+
+/* ------------------------------------------------------------- */
+
+static struct ioreq *ioreq_start(struct XenBlkDev *blkdev)
+{
+    struct ioreq *ioreq = NULL;
+
+    if (LIST_EMPTY(&blkdev->freelist)) {
+	if (blkdev->requests_total >= max_requests)
+	    goto out;
+	/* allocate new struct */
+	ioreq = qemu_mallocz(sizeof(*ioreq));
+	if (NULL == ioreq)
+	    goto out;
+	ioreq->blkdev = blkdev;
+	blkdev->requests_total++;
+    } else {
+	/* get one from freelist */
+	ioreq = LIST_FIRST(&blkdev->freelist);
+	LIST_REMOVE(ioreq, list);
+    }
+    LIST_INSERT_HEAD(&blkdev->inflight, ioreq, list);
+    blkdev->requests_inflight++;
+
+out:
+    return ioreq;
+}
+
+static void ioreq_finish(struct ioreq *ioreq)
+{
+    struct XenBlkDev *blkdev = ioreq->blkdev;
+
+    LIST_REMOVE(ioreq, list);
+    LIST_INSERT_HEAD(&blkdev->finished, ioreq, list);
+    blkdev->requests_inflight--;
+    blkdev->requests_finished++;
+}
+
+static void ioreq_release(struct ioreq *ioreq)
+{
+    struct XenBlkDev *blkdev = ioreq->blkdev;
+
+    LIST_REMOVE(ioreq, list);
+    memset(ioreq, 0, sizeof(*ioreq));
+    ioreq->blkdev = blkdev;
+    LIST_INSERT_HEAD(&blkdev->freelist, ioreq, list);
+    blkdev->requests_finished--;
+}
+
+/*
+ * translate request into iovec + start offset + end offset
+ * do sanity checks along the way
+ */
+static int ioreq_parse(struct ioreq *ioreq)
+{
+    struct XenBlkDev *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 (0 == ioreq->vecs)
+        return;
+    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 (0 == ioreq->vecs)
+        return 0;
+    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_sync(struct ioreq *ioreq)
+{
+    struct XenBlkDev *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);
+    ioreq_finish(ioreq);
+    return 0;
+
+err:
+    ioreq->status = BLKIF_RSP_ERROR;
+    return -1;
+}
+
+static void qemu_aio_complete(void *opaque, int ret)
+{
+    struct ioreq *ioreq = opaque;
+
+    if (ret != 0) {
+        xen_be_printf(&ioreq->blkdev->xendev, 0, "%s I/O error\n",
+                      ioreq->req.operation == BLKIF_OP_READ ? "read" : "write");
+        ioreq->aio_errors++;
+    }
+
+    ioreq->aio_inflight--;
+    if (ioreq->aio_inflight > 0)
+        return;
+
+    ioreq->status = ioreq->aio_errors ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY;
+    ioreq_unmap(ioreq);
+    ioreq_finish(ioreq);
+    qemu_bh_schedule(ioreq->blkdev->bh);
+}
+
+static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
+{
+    struct XenBlkDev *blkdev = ioreq->blkdev;
+    int i, len = 0;
+    off_t pos;
+
+    if (-1 == ioreq_map(ioreq))
+	goto err;
+
+    ioreq->aio_inflight++;
+    if (ioreq->presync)
+	bdrv_flush(blkdev->bs); /* FIXME: aio_flush() ??? */
+
+    switch (ioreq->req.operation) {
+    case BLKIF_OP_READ:
+	pos = ioreq->start;
+	for (i = 0; i < ioreq->vecs; i++) {
+            ioreq->aio_inflight++;
+            bdrv_aio_read(blkdev->bs, pos / BLOCK_SIZE,
+                          ioreq->vec[i].iov_base,
+                          ioreq->vec[i].iov_len / BLOCK_SIZE,
+                          qemu_aio_complete, ioreq);
+	    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++) {
+            ioreq->aio_inflight++;
+            bdrv_aio_write(blkdev->bs, pos / BLOCK_SIZE,
+                           ioreq->vec[i].iov_base,
+                           ioreq->vec[i].iov_len / BLOCK_SIZE,
+                           qemu_aio_complete, ioreq);
+	    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); /* FIXME: aio_flush() ??? */
+    qemu_aio_complete(ioreq, 0);
+
+    return 0;
+
+err:
+    ioreq->status = BLKIF_RSP_ERROR;
+    return -1;
+}
+
+static int blk_send_response_one(struct ioreq *ioreq)
+{
+    struct XenBlkDev  *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 XenBlkDev *blkdev)
+{
+    struct ioreq *ioreq;
+    int send_notify = 0;
+
+    while (!LIST_EMPTY(&blkdev->finished)) {
+        ioreq = LIST_FIRST(&blkdev->finished);
+	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 XenBlkDev *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 XenBlkDev *blkdev)
+{
+    RING_IDX rc, rp;
+    struct ioreq *ioreq;
+
+    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'. */
+
+    if (use_aio)
+        blk_send_response_all(blkdev);
+    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;
+        }
+
+        if (use_aio) {
+            /* run i/o in aio mode */
+            ioreq_runio_qemu_aio(ioreq);
+        } else {
+            /* run i/o in sync mode */
+            ioreq_runio_qemu_sync(ioreq);
+        }
+    }
+    if (!use_aio)
+        blk_send_response_all(blkdev);
+
+    if (blkdev->more_work && blkdev->requests_inflight < max_requests)
+        qemu_bh_schedule(blkdev->bh);
+}
+
+/* ------------------------------------------------------------- */
+
+static void blk_bh(void *opaque)
+{
+    struct XenBlkDev *blkdev = opaque;
+    blk_handle_requests(blkdev);
+}
+
+static void blk_alloc(struct XenDevice *xendev)
+{
+    struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
+
+    LIST_INIT(&blkdev->inflight);
+    LIST_INIT(&blkdev->finished);
+    LIST_INIT(&blkdev->freelist);
+    blkdev->bh = qemu_bh_new(blk_bh, blkdev);
+    if (xen_mode != XEN_EMULATE)
+        batch_maps = 1;
+}
+
+static int blk_init(struct XenDevice *xendev)
+{
+    struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
+    int mode, qflags, have_barriers, 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");
+    if (NULL == blkdev->devtype)
+	blkdev->devtype = xenstore_read_be_str(&blkdev->xendev, "device-type");
+
+    /* 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;
+    }
+
+    /* cdrom ? */
+    if (blkdev->devtype && !strcmp(blkdev->devtype, "cdrom"))
+	info  |= VDISK_CDROM;
+
+    /* init qemu block driver */
+    blkdev->index = (blkdev->xendev.dev - 202 * 256) / 16;
+    blkdev->index = drive_get_index(IF_XEN, 0, blkdev->index);
+    if (blkdev->index == -1) {
+        /* setup via xenbus -> create new block driver instance */
+        xen_be_printf(&blkdev->xendev, 2, "create new bdrv (xenbus setup)\n");
+	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 {
+        /* setup via qemu cmdline -> already setup for us */
+        xen_be_printf(&blkdev->xendev, 2, "get configured bdrv (cmdline setup)\n");
+	blkdev->bs = drives_table[blkdev->index].bdrv;
+    }
+    blkdev->file_blk  = BLOCK_SIZE;
+    blkdev->file_size = bdrv_getlength(blkdev->bs);
+    if (blkdev->file_size < 0) {
+        xen_be_printf(&blkdev->xendev, 1, "bdrv_getlength: %d (%s) | drv %s\n",
+                      (int)blkdev->file_size, strerror(-blkdev->file_size),
+                      blkdev->bs->drv ? blkdev->bs->drv->format_name : "-");
+	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 XenDevice *xendev)
+{
+    struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, 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 (blkdev->xendev.protocol) {
+        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 XenDevice *xendev)
+{
+    struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
+
+    if (blkdev->bs) {
+        if (blkdev->index == -1) {
+            /* close/delete only if we created it ourself */
+            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 XenDevice *xendev)
+{
+    struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
+    struct ioreq *ioreq;
+
+    while (!LIST_EMPTY(&blkdev->freelist)) {
+	ioreq = LIST_FIRST(&blkdev->freelist);
+        LIST_REMOVE(ioreq, list);
+	qemu_free(ioreq);
+    }
+
+    qemu_free(blkdev->params);
+    qemu_free(blkdev->mode);
+    qemu_bh_delete(blkdev->bh);
+    return 0;
+}
+
+static void blk_event(struct XenDevice *xendev)
+{
+    struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
+
+    qemu_bh_schedule(blkdev->bh);
+}
+
+struct XenDevOps xen_blkdev_ops = {
+    .size       = sizeof(struct XenBlkDev),
+    .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_pv.c b/hw/xen_machine_pv.c
index fee794a..46f5df8 100644
--- a/hw/xen_machine_pv.c
+++ b/hw/xen_machine_pv.c
@@ -59,6 +59,7 @@ static void xen_init_pv(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_init_display(xen_domid);
diff --git a/sysemu.h b/sysemu.h
index 3eab34b..7b356b3 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -127,7 +127,7 @@ extern unsigned int nb_prom_envs;
 #endif
 
 typedef enum {
-    IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD, IF_VIRTIO
+    IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD, IF_VIRTIO, IF_XEN
 } BlockInterfaceType;
 
 typedef enum {
diff --git a/vl.c b/vl.c
index 76fca5a..edf9ea9 100644
--- a/vl.c
+++ b/vl.c
@@ -2364,7 +2364,10 @@ int drive_init(struct drive_opt *arg, int snapshot, void *opaque)
         } else if (!strcmp(buf, "virtio")) {
             type = IF_VIRTIO;
             max_devs = 0;
-        } else {
+	} 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;
 	}
@@ -2578,6 +2581,7 @@ int drive_init(struct drive_opt *arg, int snapshot, void *opaque)
     switch(type) {
     case IF_IDE:
     case IF_SCSI:
+    case IF_XEN:
         switch(media) {
 	case MEDIA_DISK:
             if (cyls != 0) {
-- 
1.6.1.3

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

* [PATCH 05/10] xen: add block device backend driver.
@ 2009-04-01 21:39   ` Gerd Hoffmann
  0 siblings, 0 replies; 61+ messages in thread
From: Gerd Hoffmann @ 2009-04-01 21:39 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       |  799 +++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/xen_machine_pv.c |    1 +
 sysemu.h            |    2 +-
 vl.c                |    6 +-
 7 files changed, 912 insertions(+), 3 deletions(-)
 create mode 100644 hw/xen_blkif.h
 create mode 100644 hw/xen_disk.c

diff --git a/Makefile.target b/Makefile.target
index e824675..b66ff27 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -565,7 +565,7 @@ endif
 
 # xen backend driver support
 XEN_OBJS := xen_machine_pv.o xen_backend.o
-XEN_OBJS += xen_console.o xenfb.o
+XEN_OBJS += xen_console.o xenfb.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 e9a4e2d..dd426dd 100644
--- a/hw/xen_backend.h
+++ b/hw/xen_backend.h
@@ -2,6 +2,7 @@
 #define QEMU_HW_XEN_BACKEND_H 1
 
 #include "xen_common.h"
+#include "sysemu.h"
 
 /* ------------------------------------------------------------- */
 
@@ -87,6 +88,7 @@ void xen_be_printf(struct XenDevice *xendev, int msg_level, const char *fmt, ...
 extern struct XenDevOps xen_console_ops;      /* xen_console.c     */
 extern struct XenDevOps xen_kbdmouse_ops;     /* xen_framebuffer.c */
 extern struct XenDevOps xen_framebuffer_ops;  /* xen_framebuffer.c */
+extern struct XenDevOps xen_blkdev_ops;       /* xen_disk.c        */
 
 void xen_init_display(int domid);
 
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..33b2dfd
--- /dev/null
+++ b/hw/xen_disk.c
@@ -0,0 +1,799 @@
+/*
+ *  xen paravirt block device backend
+ *
+ *  (c) Gerd Hoffmann <kraxel@redhat.com>
+ *
+ *  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
+ */
+
+/*
+ *  FIXME: the code is designed to handle multiple outstanding
+ *         requests, which isn't used right now.  Plan is to
+ *         switch over to the aio block functions once they got
+ *         vector support.
+ */
+
+#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 <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 "hw.h"
+#include "block_int.h"
+#include "qemu-char.h"
+#include "xen_blkif.h"
+#include "xen_backend.h"
+
+/* ------------------------------------------------------------- */
+
+static int syncwrite    = 0;
+static int batch_maps   = 0;
+
+static int max_requests = 32;
+static int use_aio      = 1;
+
+/* ------------------------------------------------------------- */
+
+#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;
+
+    /* aio status */
+    int                 aio_inflight;
+    int                 aio_errors;
+
+    struct XenBlkDev    *blkdev;
+    LIST_ENTRY(ioreq)   list;
+};
+
+struct XenBlkDev {
+    struct XenDevice    xendev;  /* must be first */
+    char                *params;
+    char                *mode;
+    char                *type;
+    char                *dev;
+    char                *devtype;
+    const char          *fileproto;
+    const char          *filename;
+    int                 ring_ref;
+    void                *sring;
+    int64_t             file_blk;
+    int64_t             file_size;
+    int                 protocol;
+    blkif_back_rings_t  rings;
+    int                 more_work;
+    int                 cnt_map;
+
+    /* request lists */
+    LIST_HEAD(inflight_head, ioreq) inflight;
+    LIST_HEAD(finished_head, ioreq) finished;
+    LIST_HEAD(freelist_head, ioreq) freelist;
+    int                 requests_total;
+    int                 requests_inflight;
+    int                 requests_finished;
+
+    /* qemu block driver */
+    int                 index;
+    BlockDriverState    *bs;
+    QEMUBH              *bh;
+};
+
+/* ------------------------------------------------------------- */
+
+static struct ioreq *ioreq_start(struct XenBlkDev *blkdev)
+{
+    struct ioreq *ioreq = NULL;
+
+    if (LIST_EMPTY(&blkdev->freelist)) {
+	if (blkdev->requests_total >= max_requests)
+	    goto out;
+	/* allocate new struct */
+	ioreq = qemu_mallocz(sizeof(*ioreq));
+	if (NULL == ioreq)
+	    goto out;
+	ioreq->blkdev = blkdev;
+	blkdev->requests_total++;
+    } else {
+	/* get one from freelist */
+	ioreq = LIST_FIRST(&blkdev->freelist);
+	LIST_REMOVE(ioreq, list);
+    }
+    LIST_INSERT_HEAD(&blkdev->inflight, ioreq, list);
+    blkdev->requests_inflight++;
+
+out:
+    return ioreq;
+}
+
+static void ioreq_finish(struct ioreq *ioreq)
+{
+    struct XenBlkDev *blkdev = ioreq->blkdev;
+
+    LIST_REMOVE(ioreq, list);
+    LIST_INSERT_HEAD(&blkdev->finished, ioreq, list);
+    blkdev->requests_inflight--;
+    blkdev->requests_finished++;
+}
+
+static void ioreq_release(struct ioreq *ioreq)
+{
+    struct XenBlkDev *blkdev = ioreq->blkdev;
+
+    LIST_REMOVE(ioreq, list);
+    memset(ioreq, 0, sizeof(*ioreq));
+    ioreq->blkdev = blkdev;
+    LIST_INSERT_HEAD(&blkdev->freelist, ioreq, list);
+    blkdev->requests_finished--;
+}
+
+/*
+ * translate request into iovec + start offset + end offset
+ * do sanity checks along the way
+ */
+static int ioreq_parse(struct ioreq *ioreq)
+{
+    struct XenBlkDev *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 (0 == ioreq->vecs)
+        return;
+    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 (0 == ioreq->vecs)
+        return 0;
+    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_sync(struct ioreq *ioreq)
+{
+    struct XenBlkDev *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);
+    ioreq_finish(ioreq);
+    return 0;
+
+err:
+    ioreq->status = BLKIF_RSP_ERROR;
+    return -1;
+}
+
+static void qemu_aio_complete(void *opaque, int ret)
+{
+    struct ioreq *ioreq = opaque;
+
+    if (ret != 0) {
+        xen_be_printf(&ioreq->blkdev->xendev, 0, "%s I/O error\n",
+                      ioreq->req.operation == BLKIF_OP_READ ? "read" : "write");
+        ioreq->aio_errors++;
+    }
+
+    ioreq->aio_inflight--;
+    if (ioreq->aio_inflight > 0)
+        return;
+
+    ioreq->status = ioreq->aio_errors ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY;
+    ioreq_unmap(ioreq);
+    ioreq_finish(ioreq);
+    qemu_bh_schedule(ioreq->blkdev->bh);
+}
+
+static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
+{
+    struct XenBlkDev *blkdev = ioreq->blkdev;
+    int i, len = 0;
+    off_t pos;
+
+    if (-1 == ioreq_map(ioreq))
+	goto err;
+
+    ioreq->aio_inflight++;
+    if (ioreq->presync)
+	bdrv_flush(blkdev->bs); /* FIXME: aio_flush() ??? */
+
+    switch (ioreq->req.operation) {
+    case BLKIF_OP_READ:
+	pos = ioreq->start;
+	for (i = 0; i < ioreq->vecs; i++) {
+            ioreq->aio_inflight++;
+            bdrv_aio_read(blkdev->bs, pos / BLOCK_SIZE,
+                          ioreq->vec[i].iov_base,
+                          ioreq->vec[i].iov_len / BLOCK_SIZE,
+                          qemu_aio_complete, ioreq);
+	    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++) {
+            ioreq->aio_inflight++;
+            bdrv_aio_write(blkdev->bs, pos / BLOCK_SIZE,
+                           ioreq->vec[i].iov_base,
+                           ioreq->vec[i].iov_len / BLOCK_SIZE,
+                           qemu_aio_complete, ioreq);
+	    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); /* FIXME: aio_flush() ??? */
+    qemu_aio_complete(ioreq, 0);
+
+    return 0;
+
+err:
+    ioreq->status = BLKIF_RSP_ERROR;
+    return -1;
+}
+
+static int blk_send_response_one(struct ioreq *ioreq)
+{
+    struct XenBlkDev  *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 XenBlkDev *blkdev)
+{
+    struct ioreq *ioreq;
+    int send_notify = 0;
+
+    while (!LIST_EMPTY(&blkdev->finished)) {
+        ioreq = LIST_FIRST(&blkdev->finished);
+	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 XenBlkDev *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 XenBlkDev *blkdev)
+{
+    RING_IDX rc, rp;
+    struct ioreq *ioreq;
+
+    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'. */
+
+    if (use_aio)
+        blk_send_response_all(blkdev);
+    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;
+        }
+
+        if (use_aio) {
+            /* run i/o in aio mode */
+            ioreq_runio_qemu_aio(ioreq);
+        } else {
+            /* run i/o in sync mode */
+            ioreq_runio_qemu_sync(ioreq);
+        }
+    }
+    if (!use_aio)
+        blk_send_response_all(blkdev);
+
+    if (blkdev->more_work && blkdev->requests_inflight < max_requests)
+        qemu_bh_schedule(blkdev->bh);
+}
+
+/* ------------------------------------------------------------- */
+
+static void blk_bh(void *opaque)
+{
+    struct XenBlkDev *blkdev = opaque;
+    blk_handle_requests(blkdev);
+}
+
+static void blk_alloc(struct XenDevice *xendev)
+{
+    struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
+
+    LIST_INIT(&blkdev->inflight);
+    LIST_INIT(&blkdev->finished);
+    LIST_INIT(&blkdev->freelist);
+    blkdev->bh = qemu_bh_new(blk_bh, blkdev);
+    if (xen_mode != XEN_EMULATE)
+        batch_maps = 1;
+}
+
+static int blk_init(struct XenDevice *xendev)
+{
+    struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
+    int mode, qflags, have_barriers, 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");
+    if (NULL == blkdev->devtype)
+	blkdev->devtype = xenstore_read_be_str(&blkdev->xendev, "device-type");
+
+    /* 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;
+    }
+
+    /* cdrom ? */
+    if (blkdev->devtype && !strcmp(blkdev->devtype, "cdrom"))
+	info  |= VDISK_CDROM;
+
+    /* init qemu block driver */
+    blkdev->index = (blkdev->xendev.dev - 202 * 256) / 16;
+    blkdev->index = drive_get_index(IF_XEN, 0, blkdev->index);
+    if (blkdev->index == -1) {
+        /* setup via xenbus -> create new block driver instance */
+        xen_be_printf(&blkdev->xendev, 2, "create new bdrv (xenbus setup)\n");
+	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 {
+        /* setup via qemu cmdline -> already setup for us */
+        xen_be_printf(&blkdev->xendev, 2, "get configured bdrv (cmdline setup)\n");
+	blkdev->bs = drives_table[blkdev->index].bdrv;
+    }
+    blkdev->file_blk  = BLOCK_SIZE;
+    blkdev->file_size = bdrv_getlength(blkdev->bs);
+    if (blkdev->file_size < 0) {
+        xen_be_printf(&blkdev->xendev, 1, "bdrv_getlength: %d (%s) | drv %s\n",
+                      (int)blkdev->file_size, strerror(-blkdev->file_size),
+                      blkdev->bs->drv ? blkdev->bs->drv->format_name : "-");
+	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 XenDevice *xendev)
+{
+    struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, 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 (blkdev->xendev.protocol) {
+        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 XenDevice *xendev)
+{
+    struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
+
+    if (blkdev->bs) {
+        if (blkdev->index == -1) {
+            /* close/delete only if we created it ourself */
+            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 XenDevice *xendev)
+{
+    struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
+    struct ioreq *ioreq;
+
+    while (!LIST_EMPTY(&blkdev->freelist)) {
+	ioreq = LIST_FIRST(&blkdev->freelist);
+        LIST_REMOVE(ioreq, list);
+	qemu_free(ioreq);
+    }
+
+    qemu_free(blkdev->params);
+    qemu_free(blkdev->mode);
+    qemu_bh_delete(blkdev->bh);
+    return 0;
+}
+
+static void blk_event(struct XenDevice *xendev)
+{
+    struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
+
+    qemu_bh_schedule(blkdev->bh);
+}
+
+struct XenDevOps xen_blkdev_ops = {
+    .size       = sizeof(struct XenBlkDev),
+    .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_pv.c b/hw/xen_machine_pv.c
index fee794a..46f5df8 100644
--- a/hw/xen_machine_pv.c
+++ b/hw/xen_machine_pv.c
@@ -59,6 +59,7 @@ static void xen_init_pv(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_init_display(xen_domid);
diff --git a/sysemu.h b/sysemu.h
index 3eab34b..7b356b3 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -127,7 +127,7 @@ extern unsigned int nb_prom_envs;
 #endif
 
 typedef enum {
-    IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD, IF_VIRTIO
+    IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD, IF_VIRTIO, IF_XEN
 } BlockInterfaceType;
 
 typedef enum {
diff --git a/vl.c b/vl.c
index 76fca5a..edf9ea9 100644
--- a/vl.c
+++ b/vl.c
@@ -2364,7 +2364,10 @@ int drive_init(struct drive_opt *arg, int snapshot, void *opaque)
         } else if (!strcmp(buf, "virtio")) {
             type = IF_VIRTIO;
             max_devs = 0;
-        } else {
+	} 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;
 	}
@@ -2578,6 +2581,7 @@ int drive_init(struct drive_opt *arg, int snapshot, void *opaque)
     switch(type) {
     case IF_IDE:
     case IF_SCSI:
+    case IF_XEN:
         switch(media) {
 	case MEDIA_DISK:
             if (cyls != 0) {
-- 
1.6.1.3

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

* [Qemu-devel] [PATCH 06/10] xen: add net backend driver.
  2009-04-01 21:39 ` Gerd Hoffmann
@ 2009-04-01 21:39   ` Gerd Hoffmann
  -1 siblings, 0 replies; 61+ messages in thread
From: Gerd Hoffmann @ 2009-04-01 21:39 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_pv.c |    1 +
 hw/xen_nic.c        |  396 +++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 399 insertions(+), 1 deletions(-)
 create mode 100644 hw/xen_nic.c

diff --git a/Makefile.target b/Makefile.target
index b66ff27..4b071eb 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -565,7 +565,7 @@ endif
 
 # xen backend driver support
 XEN_OBJS := xen_machine_pv.o xen_backend.o
-XEN_OBJS += xen_console.o xenfb.o xen_disk.o
+XEN_OBJS += xen_console.o xenfb.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 dd426dd..4e4be14 100644
--- a/hw/xen_backend.h
+++ b/hw/xen_backend.h
@@ -89,6 +89,7 @@ extern struct XenDevOps xen_console_ops;      /* xen_console.c     */
 extern struct XenDevOps xen_kbdmouse_ops;     /* xen_framebuffer.c */
 extern struct XenDevOps xen_framebuffer_ops;  /* xen_framebuffer.c */
 extern struct XenDevOps xen_blkdev_ops;       /* xen_disk.c        */
+extern struct XenDevOps xen_netdev_ops;       /* xen_nic.c         */
 
 void xen_init_display(int domid);
 
diff --git a/hw/xen_machine_pv.c b/hw/xen_machine_pv.c
index 46f5df8..50fdd15 100644
--- a/hw/xen_machine_pv.c
+++ b/hw/xen_machine_pv.c
@@ -60,6 +60,7 @@ static void xen_init_pv(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_init_display(xen_domid);
diff --git a/hw/xen_nic.c b/hw/xen_nic.c
new file mode 100644
index 0000000..0c01859
--- /dev/null
+++ b/hw/xen_nic.c
@@ -0,0 +1,396 @@
+/*
+ *  xen paravirt network card backend
+ *
+ *  (c) Gerd Hoffmann <kraxel@redhat.com>
+ *
+ *  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 XenNetDev {
+    struct XenDevice      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;
+};
+
+/* ------------------------------------------------------------- */
+
+static void net_tx_response(struct XenNetDev *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 XenNetDev *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 XenNetDev *netdev)
+{
+    netif_tx_request_t txreq;
+    RING_IDX rc, rp;
+    void *page;
+    void *tmpbuf = NULL;
+
+    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: tx gref dereference failed (%d)\n",
+                              txreq.gref);
+		net_tx_error(netdev, &txreq, rc);
+		continue;
+	    }
+	    if (txreq.flags & NETTXF_csum_blank) {
+                /* have read-only mapping -> can't fill checksum in-place */
+                if (!tmpbuf)
+                    tmpbuf = malloc(PAGE_SIZE);
+                memcpy(tmpbuf, page + txreq.offset, txreq.size);
+		net_checksum_calculate(tmpbuf, txreq.size);
+                qemu_send_packet(netdev->vs, tmpbuf, txreq.size);
+            } else {
+                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;
+    }
+    free(tmpbuf);
+}
+
+/* ------------------------------------------------------------- */
+
+static void net_rx_response(struct XenNetDev *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 XenNetDev *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 XenNetDev *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: rx gref dereference failed (%d)\n",
+                      rxreq.gref);
+	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 XenDevice *xendev)
+{
+    struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, 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, "xen", NULL,
+                                      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 XenDevice *xendev)
+{
+    struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, 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 XenDevice *xendev)
+{
+    struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, 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;
+    }
+    if (netdev->vs) {
+        qemu_del_vlan_client(netdev->vs);
+        netdev->vs = NULL;
+    }
+}
+
+static void net_event(struct XenDevice *xendev)
+{
+    struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
+    net_tx_packets(netdev);
+}
+
+/* ------------------------------------------------------------- */
+
+struct XenDevOps xen_netdev_ops = {
+    .size       = sizeof(struct XenNetDev),
+    .flags      = DEVOPS_FLAG_NEED_GNTDEV,
+    .init       = net_init,
+    .connect    = net_connect,
+    .event      = net_event,
+    .disconnect = net_disconnect,
+};
-- 
1.6.1.3

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

* [PATCH 06/10] xen: add net backend driver.
@ 2009-04-01 21:39   ` Gerd Hoffmann
  0 siblings, 0 replies; 61+ messages in thread
From: Gerd Hoffmann @ 2009-04-01 21:39 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_pv.c |    1 +
 hw/xen_nic.c        |  396 +++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 399 insertions(+), 1 deletions(-)
 create mode 100644 hw/xen_nic.c

diff --git a/Makefile.target b/Makefile.target
index b66ff27..4b071eb 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -565,7 +565,7 @@ endif
 
 # xen backend driver support
 XEN_OBJS := xen_machine_pv.o xen_backend.o
-XEN_OBJS += xen_console.o xenfb.o xen_disk.o
+XEN_OBJS += xen_console.o xenfb.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 dd426dd..4e4be14 100644
--- a/hw/xen_backend.h
+++ b/hw/xen_backend.h
@@ -89,6 +89,7 @@ extern struct XenDevOps xen_console_ops;      /* xen_console.c     */
 extern struct XenDevOps xen_kbdmouse_ops;     /* xen_framebuffer.c */
 extern struct XenDevOps xen_framebuffer_ops;  /* xen_framebuffer.c */
 extern struct XenDevOps xen_blkdev_ops;       /* xen_disk.c        */
+extern struct XenDevOps xen_netdev_ops;       /* xen_nic.c         */
 
 void xen_init_display(int domid);
 
diff --git a/hw/xen_machine_pv.c b/hw/xen_machine_pv.c
index 46f5df8..50fdd15 100644
--- a/hw/xen_machine_pv.c
+++ b/hw/xen_machine_pv.c
@@ -60,6 +60,7 @@ static void xen_init_pv(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_init_display(xen_domid);
diff --git a/hw/xen_nic.c b/hw/xen_nic.c
new file mode 100644
index 0000000..0c01859
--- /dev/null
+++ b/hw/xen_nic.c
@@ -0,0 +1,396 @@
+/*
+ *  xen paravirt network card backend
+ *
+ *  (c) Gerd Hoffmann <kraxel@redhat.com>
+ *
+ *  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 XenNetDev {
+    struct XenDevice      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;
+};
+
+/* ------------------------------------------------------------- */
+
+static void net_tx_response(struct XenNetDev *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 XenNetDev *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 XenNetDev *netdev)
+{
+    netif_tx_request_t txreq;
+    RING_IDX rc, rp;
+    void *page;
+    void *tmpbuf = NULL;
+
+    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: tx gref dereference failed (%d)\n",
+                              txreq.gref);
+		net_tx_error(netdev, &txreq, rc);
+		continue;
+	    }
+	    if (txreq.flags & NETTXF_csum_blank) {
+                /* have read-only mapping -> can't fill checksum in-place */
+                if (!tmpbuf)
+                    tmpbuf = malloc(PAGE_SIZE);
+                memcpy(tmpbuf, page + txreq.offset, txreq.size);
+		net_checksum_calculate(tmpbuf, txreq.size);
+                qemu_send_packet(netdev->vs, tmpbuf, txreq.size);
+            } else {
+                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;
+    }
+    free(tmpbuf);
+}
+
+/* ------------------------------------------------------------- */
+
+static void net_rx_response(struct XenNetDev *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 XenNetDev *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 XenNetDev *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: rx gref dereference failed (%d)\n",
+                      rxreq.gref);
+	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 XenDevice *xendev)
+{
+    struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, 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, "xen", NULL,
+                                      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 XenDevice *xendev)
+{
+    struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, 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 XenDevice *xendev)
+{
+    struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, 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;
+    }
+    if (netdev->vs) {
+        qemu_del_vlan_client(netdev->vs);
+        netdev->vs = NULL;
+    }
+}
+
+static void net_event(struct XenDevice *xendev)
+{
+    struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
+    net_tx_packets(netdev);
+}
+
+/* ------------------------------------------------------------- */
+
+struct XenDevOps xen_netdev_ops = {
+    .size       = sizeof(struct XenNetDev),
+    .flags      = DEVOPS_FLAG_NEED_GNTDEV,
+    .init       = net_init,
+    .connect    = net_connect,
+    .event      = net_event,
+    .disconnect = net_disconnect,
+};
-- 
1.6.1.3

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

* [Qemu-devel] [PATCH 07/10] xen: blk & nic configuration via cmd line.
  2009-04-01 21:39 ` Gerd Hoffmann
@ 2009-04-01 21:39   ` Gerd Hoffmann
  -1 siblings, 0 replies; 61+ messages in thread
From: Gerd Hoffmann @ 2009-04-01 21:39 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.c    |    1 +
 hw/xen_backend.h    |    8 +++
 hw/xen_devconfig.c  |  145 +++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/xen_machine_pv.c |   19 +++++++
 5 files changed, 174 insertions(+), 1 deletions(-)
 create mode 100644 hw/xen_devconfig.c

diff --git a/Makefile.target b/Makefile.target
index 4b071eb..8bae243 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -564,7 +564,7 @@ LIBS += $(CONFIG_BLUEZ_LIBS)
 endif
 
 # xen backend driver support
-XEN_OBJS := xen_machine_pv.o xen_backend.o
+XEN_OBJS := xen_machine_pv.o xen_backend.o xen_devconfig.o
 XEN_OBJS += xen_console.o xenfb.o xen_disk.o xen_nic.o
 ifeq ($(CONFIG_XEN), yes)
   OBJS += $(XEN_OBJS)
diff --git a/hw/xen_backend.c b/hw/xen_backend.c
index 2678dfa..2bd4433 100644
--- a/hw/xen_backend.c
+++ b/hw/xen_backend.c
@@ -45,6 +45,7 @@
 /* public */
 int xen_xc;
 struct xs_handle *xenstore = NULL;
+const char *xen_protocol;
 
 /* private */
 static TAILQ_HEAD(XenDeviceHead, XenDevice) xendevs = TAILQ_HEAD_INITIALIZER(xendevs);
diff --git a/hw/xen_backend.h b/hw/xen_backend.h
index 4e4be14..7f1804e 100644
--- a/hw/xen_backend.h
+++ b/hw/xen_backend.h
@@ -3,6 +3,8 @@
 
 #include "xen_common.h"
 #include "sysemu.h"
+#include "net.h"
+#include "block_int.h"
 
 /* ------------------------------------------------------------- */
 
@@ -56,6 +58,7 @@ struct XenDevice {
 /* variables */
 extern int xen_xc;
 extern struct xs_handle *xenstore;
+extern const char *xen_protocol;
 
 /* xenstore helper functions */
 int xenstore_write_str(const char *base, const char *node, const char *val);
@@ -93,4 +96,9 @@ extern struct XenDevOps xen_netdev_ops;       /* xen_nic.c         */
 
 void xen_init_display(int domid);
 
+/* configuration (aka xenbus setup) */
+void xen_config_cleanup(void);
+int xen_config_dev_blk(DriveInfo *disk);
+int xen_config_dev_nic(NICInfo *nic);
+
 #endif /* QEMU_HW_XEN_BACKEND_H */
diff --git a/hw/xen_devconfig.c b/hw/xen_devconfig.c
new file mode 100644
index 0000000..0ef8012
--- /dev/null
+++ b/hw/xen_devconfig.c
@@ -0,0 +1,145 @@
+#include "xen_backend.h"
+
+/* ------------------------------------------------------------- */
+
+struct xs_dirs {
+    char *xs_dir;
+    TAILQ_ENTRY(xs_dirs) list;
+};
+static TAILQ_HEAD(xs_dirs_head, xs_dirs) xs_cleanup = TAILQ_HEAD_INITIALIZER(xs_cleanup);
+
+static void xen_config_cleanup_dir(char *dir)
+{
+    struct xs_dirs *d;
+
+    d = qemu_malloc(sizeof(*d));
+    if (!d)
+        return;
+    d->xs_dir = dir;
+    TAILQ_INSERT_TAIL(&xs_cleanup, d, list);
+}
+
+void xen_config_cleanup(void)
+{
+    struct xs_dirs *d;
+
+    fprintf(stderr, "xen be: %s\n", __FUNCTION__);
+    TAILQ_FOREACH(d, &xs_cleanup, list) {
+	xs_rm(xenstore, 0, d->xs_dir);
+    }
+}
+
+/* ------------------------------------------------------------- */
+
+static int xen_config_dev_mkdir(char *dev, int p)
+{
+    struct xs_permissions perms[2] = {{
+            .id    = 0, /* set owner: dom0 */
+        },{
+            .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(qemu_strdup(dev));
+
+    if (!xs_set_permissions(xenstore, 0, dev, perms, 2)) {
+	fprintf(stderr, "%s: xs_set_permissions failed\n", __FUNCTION__);
+	return -1;
+    }
+    return 0;
+}
+
+static int xen_config_dev_dirs(const char *ftype, const char *btype, int vdev,
+			       char *fe, char *be, int len)
+{
+    char *dom;
+
+    dom = xs_get_domain_path(xenstore, xen_domid);
+    snprintf(fe, len, "%s/device/%s/%d", dom, ftype, vdev);
+    free(dom);
+
+    dom = xs_get_domain_path(xenstore, 0);
+    snprintf(be, len, "%s/backend/%s/%d/%d", dom, btype, xen_domid, vdev);
+    free(dom);
+
+    xen_config_dev_mkdir(fe, XS_PERM_READ | 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 (xen_protocol)
+        xenstore_write_str(fe, "protocol", xen_protocol);
+
+    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;
+    const char *devtype = cdrom ? "cdrom" : "disk";
+    const 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_pv.c b/hw/xen_machine_pv.c
index 50fdd15..8c471c2 100644
--- a/hw/xen_machine_pv.c
+++ b/hw/xen_machine_pv.c
@@ -39,6 +39,7 @@ static void xen_init_pv(ram_addr_t ram_size, int vga_ram_size,
 			const char *cpu_model)
 {
     CPUState *env;
+    int i, index;
 
     /* Initialize a dummy CPU */
     if (cpu_model == NULL) {
@@ -62,6 +63,24 @@ static void xen_init_pv(ram_addr_t ram_size, int vga_ram_size,
     xen_be_register("qdisk", &xen_blkdev_ops);
     xen_be_register("qnic", &xen_netdev_ops);
 
+    /* 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);
+
     /* setup framebuffer */
     xen_init_display(xen_domid);
 }
-- 
1.6.1.3

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

* [PATCH 07/10] xen: blk & nic configuration via cmd line.
@ 2009-04-01 21:39   ` Gerd Hoffmann
  0 siblings, 0 replies; 61+ messages in thread
From: Gerd Hoffmann @ 2009-04-01 21:39 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.c    |    1 +
 hw/xen_backend.h    |    8 +++
 hw/xen_devconfig.c  |  145 +++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/xen_machine_pv.c |   19 +++++++
 5 files changed, 174 insertions(+), 1 deletions(-)
 create mode 100644 hw/xen_devconfig.c

diff --git a/Makefile.target b/Makefile.target
index 4b071eb..8bae243 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -564,7 +564,7 @@ LIBS += $(CONFIG_BLUEZ_LIBS)
 endif
 
 # xen backend driver support
-XEN_OBJS := xen_machine_pv.o xen_backend.o
+XEN_OBJS := xen_machine_pv.o xen_backend.o xen_devconfig.o
 XEN_OBJS += xen_console.o xenfb.o xen_disk.o xen_nic.o
 ifeq ($(CONFIG_XEN), yes)
   OBJS += $(XEN_OBJS)
diff --git a/hw/xen_backend.c b/hw/xen_backend.c
index 2678dfa..2bd4433 100644
--- a/hw/xen_backend.c
+++ b/hw/xen_backend.c
@@ -45,6 +45,7 @@
 /* public */
 int xen_xc;
 struct xs_handle *xenstore = NULL;
+const char *xen_protocol;
 
 /* private */
 static TAILQ_HEAD(XenDeviceHead, XenDevice) xendevs = TAILQ_HEAD_INITIALIZER(xendevs);
diff --git a/hw/xen_backend.h b/hw/xen_backend.h
index 4e4be14..7f1804e 100644
--- a/hw/xen_backend.h
+++ b/hw/xen_backend.h
@@ -3,6 +3,8 @@
 
 #include "xen_common.h"
 #include "sysemu.h"
+#include "net.h"
+#include "block_int.h"
 
 /* ------------------------------------------------------------- */
 
@@ -56,6 +58,7 @@ struct XenDevice {
 /* variables */
 extern int xen_xc;
 extern struct xs_handle *xenstore;
+extern const char *xen_protocol;
 
 /* xenstore helper functions */
 int xenstore_write_str(const char *base, const char *node, const char *val);
@@ -93,4 +96,9 @@ extern struct XenDevOps xen_netdev_ops;       /* xen_nic.c         */
 
 void xen_init_display(int domid);
 
+/* configuration (aka xenbus setup) */
+void xen_config_cleanup(void);
+int xen_config_dev_blk(DriveInfo *disk);
+int xen_config_dev_nic(NICInfo *nic);
+
 #endif /* QEMU_HW_XEN_BACKEND_H */
diff --git a/hw/xen_devconfig.c b/hw/xen_devconfig.c
new file mode 100644
index 0000000..0ef8012
--- /dev/null
+++ b/hw/xen_devconfig.c
@@ -0,0 +1,145 @@
+#include "xen_backend.h"
+
+/* ------------------------------------------------------------- */
+
+struct xs_dirs {
+    char *xs_dir;
+    TAILQ_ENTRY(xs_dirs) list;
+};
+static TAILQ_HEAD(xs_dirs_head, xs_dirs) xs_cleanup = TAILQ_HEAD_INITIALIZER(xs_cleanup);
+
+static void xen_config_cleanup_dir(char *dir)
+{
+    struct xs_dirs *d;
+
+    d = qemu_malloc(sizeof(*d));
+    if (!d)
+        return;
+    d->xs_dir = dir;
+    TAILQ_INSERT_TAIL(&xs_cleanup, d, list);
+}
+
+void xen_config_cleanup(void)
+{
+    struct xs_dirs *d;
+
+    fprintf(stderr, "xen be: %s\n", __FUNCTION__);
+    TAILQ_FOREACH(d, &xs_cleanup, list) {
+	xs_rm(xenstore, 0, d->xs_dir);
+    }
+}
+
+/* ------------------------------------------------------------- */
+
+static int xen_config_dev_mkdir(char *dev, int p)
+{
+    struct xs_permissions perms[2] = {{
+            .id    = 0, /* set owner: dom0 */
+        },{
+            .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(qemu_strdup(dev));
+
+    if (!xs_set_permissions(xenstore, 0, dev, perms, 2)) {
+	fprintf(stderr, "%s: xs_set_permissions failed\n", __FUNCTION__);
+	return -1;
+    }
+    return 0;
+}
+
+static int xen_config_dev_dirs(const char *ftype, const char *btype, int vdev,
+			       char *fe, char *be, int len)
+{
+    char *dom;
+
+    dom = xs_get_domain_path(xenstore, xen_domid);
+    snprintf(fe, len, "%s/device/%s/%d", dom, ftype, vdev);
+    free(dom);
+
+    dom = xs_get_domain_path(xenstore, 0);
+    snprintf(be, len, "%s/backend/%s/%d/%d", dom, btype, xen_domid, vdev);
+    free(dom);
+
+    xen_config_dev_mkdir(fe, XS_PERM_READ | 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 (xen_protocol)
+        xenstore_write_str(fe, "protocol", xen_protocol);
+
+    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;
+    const char *devtype = cdrom ? "cdrom" : "disk";
+    const 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_pv.c b/hw/xen_machine_pv.c
index 50fdd15..8c471c2 100644
--- a/hw/xen_machine_pv.c
+++ b/hw/xen_machine_pv.c
@@ -39,6 +39,7 @@ static void xen_init_pv(ram_addr_t ram_size, int vga_ram_size,
 			const char *cpu_model)
 {
     CPUState *env;
+    int i, index;
 
     /* Initialize a dummy CPU */
     if (cpu_model == NULL) {
@@ -62,6 +63,24 @@ static void xen_init_pv(ram_addr_t ram_size, int vga_ram_size,
     xen_be_register("qdisk", &xen_blkdev_ops);
     xen_be_register("qnic", &xen_netdev_ops);
 
+    /* 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);
+
     /* setup framebuffer */
     xen_init_display(xen_domid);
 }
-- 
1.6.1.3

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

* [Qemu-devel] [PATCH 08/10] xen: pv domain builder.
  2009-04-01 21:39 ` Gerd Hoffmann
@ 2009-04-01 21:39   ` Gerd Hoffmann
  -1 siblings, 0 replies; 61+ messages in thread
From: Gerd Hoffmann @ 2009-04-01 21:39 UTC (permalink / raw)
  To: qemu-devel, xen-devel; +Cc: Gerd Hoffmann

This adds domain building support for paravirtual domains to qemu.
This allows booting xen guests directly with qemu, without Xend
and the management stack.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 Makefile.target      |    2 +-
 configure            |    2 +-
 hw/xen_backend.h     |    3 +
 hw/xen_devconfig.c   |   29 +++++
 hw/xen_domainbuild.c |  293 ++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/xen_domainbuild.h |   13 +++
 hw/xen_machine_pv.c  |   19 ++++
 7 files changed, 359 insertions(+), 2 deletions(-)
 create mode 100644 hw/xen_domainbuild.c
 create mode 100644 hw/xen_domainbuild.h

diff --git a/Makefile.target b/Makefile.target
index 8bae243..626a846 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -564,7 +564,7 @@ LIBS += $(CONFIG_BLUEZ_LIBS)
 endif
 
 # xen backend driver support
-XEN_OBJS := xen_machine_pv.o xen_backend.o xen_devconfig.o
+XEN_OBJS := xen_machine_pv.o xen_backend.o xen_devconfig.o xen_domainbuild.o
 XEN_OBJS += xen_console.o xenfb.o xen_disk.o xen_nic.o
 ifeq ($(CONFIG_XEN), yes)
   OBJS += $(XEN_OBJS)
diff --git a/configure b/configure
index 212f2e9..9e7738e 100755
--- a/configure
+++ b/configure
@@ -1518,7 +1518,7 @@ if test "$bluez" = "yes" ; then
   echo "#define CONFIG_BLUEZ 1" >> $config_h
 fi
 if test "$xen" = "yes" ; then
-  echo "XEN_LIBS=-lxenstore -lxenctrl" >> $config_mak
+  echo "XEN_LIBS=-lxenstore -lxenctrl -lxenguest" >> $config_mak
 fi
 if test "$aio" = "yes" ; then
   echo "#define CONFIG_AIO 1" >> $config_h
diff --git a/hw/xen_backend.h b/hw/xen_backend.h
index 7f1804e..4dbfdb4 100644
--- a/hw/xen_backend.h
+++ b/hw/xen_backend.h
@@ -100,5 +100,8 @@ void xen_init_display(int domid);
 void xen_config_cleanup(void);
 int xen_config_dev_blk(DriveInfo *disk);
 int xen_config_dev_nic(NICInfo *nic);
+int xen_config_dev_vfb(int vdev, const char *type);
+int xen_config_dev_vkbd(int vdev);
+int xen_config_dev_console(int vdev);
 
 #endif /* QEMU_HW_XEN_BACKEND_H */
diff --git a/hw/xen_devconfig.c b/hw/xen_devconfig.c
index 0ef8012..1417e71 100644
--- a/hw/xen_devconfig.c
+++ b/hw/xen_devconfig.c
@@ -143,3 +143,32 @@ int xen_config_dev_nic(NICInfo *nic)
     /* common stuff */
     return xen_config_dev_all(fe, be);
 }
+
+int xen_config_dev_vfb(int vdev, const char *type)
+{
+    char fe[256], be[256];
+
+    xen_config_dev_dirs("vfb", "vfb", vdev, fe, be, sizeof(fe));
+
+    /* backend */
+    xenstore_write_str(be, "type",  type);
+
+    /* common stuff */
+    return xen_config_dev_all(fe, be);
+}
+
+int xen_config_dev_vkbd(int vdev)
+{
+    char fe[256], be[256];
+
+    xen_config_dev_dirs("vkbd", "vkbd", vdev, fe, be, sizeof(fe));
+    return xen_config_dev_all(fe, be);
+}
+
+int xen_config_dev_console(int vdev)
+{
+    char fe[256], be[256];
+
+    xen_config_dev_dirs("console", "console", vdev, fe, be, sizeof(fe));
+    return xen_config_dev_all(fe, be);
+}
diff --git a/hw/xen_domainbuild.c b/hw/xen_domainbuild.c
new file mode 100644
index 0000000..9814b8d
--- /dev/null
+++ b/hw/xen_domainbuild.c
@@ -0,0 +1,293 @@
+#include <signal.h>
+#include "xen_backend.h"
+#include "xen_domainbuild.h"
+#include "sysemu.h"
+#include "qemu-timer.h"
+
+#include <xenguest.h>
+
+static int xenstore_domain_mkdir(char *path)
+{
+    struct xs_permissions perms_ro[] = {{
+            .id    = 0, /* set owner: dom0 */
+        },{
+            .id    = xen_domid,
+            .perms = XS_PERM_READ,
+        }};
+    struct xs_permissions perms_rw[] = {{
+            .id    = 0, /* set owner: dom0 */
+        },{
+            .id    = xen_domid,
+            .perms = XS_PERM_READ | XS_PERM_WRITE,
+        }};
+    const char *writable[] = { "device", "control", "error", NULL };
+    char subpath[256];
+    int i;
+
+    if (!xs_mkdir(xenstore, 0, path)) {
+        fprintf(stderr, "%s: xs_mkdir %s: failed\n", __FUNCTION__, path);
+	return -1;
+    }
+    if (!xs_set_permissions(xenstore, 0, path, perms_ro, 2)) {
+        fprintf(stderr, "%s: xs.set_permissions failed\n", __FUNCTION__);
+	return -1;
+    }
+
+    for (i = 0; writable[i]; i++) {
+        snprintf(subpath, sizeof(subpath), "%s/%s", path, writable[i]);
+        if (!xs_mkdir(xenstore, 0, subpath)) {
+            fprintf(stderr, "%s: xs.mkdir %s: failed\n", __FUNCTION__, subpath);
+            return -1;
+        }
+        if (!xs_set_permissions(xenstore, 0, subpath, perms_rw, 2)) {
+            fprintf(stderr, "%s: xs.set_permissions failed\n", __FUNCTION__);
+            return -1;
+        }
+    }
+    return 0;
+}
+
+int xenstore_domain_init1(const char *kernel, const char *ramdisk,
+                          const char *cmdline)
+{
+    char *dom, uuid_string[42], vm[256], path[256];
+    int i;
+
+    snprintf(uuid_string, sizeof(uuid_string), UUID_FMT,
+             qemu_uuid[0], qemu_uuid[1], qemu_uuid[2], qemu_uuid[3],
+             qemu_uuid[4], qemu_uuid[5], qemu_uuid[6], qemu_uuid[7],
+             qemu_uuid[8], qemu_uuid[9], qemu_uuid[10], qemu_uuid[11],
+             qemu_uuid[12], qemu_uuid[13], qemu_uuid[14], qemu_uuid[15]);
+    dom = xs_get_domain_path(xenstore, xen_domid);
+    snprintf(vm,  sizeof(vm),  "/vm/%s", uuid_string);
+
+    xenstore_domain_mkdir(dom);
+
+    xenstore_write_str(vm, "image/ostype",  "linux");
+    if (kernel)
+        xenstore_write_str(vm, "image/kernel",  kernel);
+    if (ramdisk)
+        xenstore_write_str(vm, "image/ramdisk", ramdisk);
+    if (cmdline)
+        xenstore_write_str(vm, "image/cmdline", cmdline);
+
+    /* name + id */
+    xenstore_write_str(vm,  "name",   qemu_name ? qemu_name : "no-name");
+    xenstore_write_str(vm,  "uuid",   uuid_string);
+    xenstore_write_str(dom, "name",   qemu_name ? qemu_name : "no-name");
+    xenstore_write_int(dom, "domid",  xen_domid);
+    xenstore_write_str(dom, "vm",     vm);
+
+    /* memory */
+    xenstore_write_int(dom, "memory/target", ram_size >> 10);  // kB
+    xenstore_write_int(vm, "memory",         ram_size >> 20);  // MB
+    xenstore_write_int(vm, "maxmem",         ram_size >> 20);  // MB
+
+    /* cpus */
+    for (i = 0; i < smp_cpus; i++) {
+	snprintf(path, sizeof(path), "cpu/%d/availability",i);
+	xenstore_write_str(dom, path, "online");
+    }
+    xenstore_write_int(vm, "vcpu_avail",  smp_cpus);
+    xenstore_write_int(vm, "vcpus",       smp_cpus);
+
+    /* vnc password */
+    xenstore_write_str(vm, "vncpassword", "" /* FIXME */);
+
+    free(dom);
+    return 0;
+}
+
+int xenstore_domain_init2(int xenstore_port, int xenstore_mfn,
+                          int console_port, int console_mfn)
+{
+    char *dom;
+
+    dom = xs_get_domain_path(xenstore, xen_domid);
+
+    /* signal new domain */
+    xs_introduce_domain(xenstore,
+                        xen_domid,
+                        xenstore_mfn,
+                        xenstore_port);
+
+    /* xenstore */
+    xenstore_write_int(dom, "store/ring-ref",   xenstore_mfn);
+    xenstore_write_int(dom, "store/port",       xenstore_port);
+
+    /* console */
+    xenstore_write_str(dom, "console/type",     "ioemu");
+    xenstore_write_int(dom, "console/limit",    128 * 1024);
+    xenstore_write_int(dom, "console/ring-ref", console_mfn);
+    xenstore_write_int(dom, "console/port",     console_port);
+    xen_config_dev_console(0);
+
+    free(dom);
+    return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static QEMUTimer *xen_poll;
+
+/* check domain state once per second */
+static void xen_domain_poll(void *opaque)
+{
+    struct xc_dominfo info;
+    int rc;
+
+    rc = xc_domain_getinfo(xen_xc, xen_domid, 1, &info);
+    if ((1 != rc) || (info.domid != xen_domid)) {
+        fprintf(stderr, "xen: domain %d is gone\n", xen_domid);
+        goto quit;
+    }
+    if (info.dying) {
+        fprintf(stderr, "xen: domain %d is dying (%s%s)\n", xen_domid,
+                info.crashed  ? "crashed"  : "",
+                info.shutdown ? "shutdown" : "");
+        goto quit;
+    }
+
+    qemu_mod_timer(xen_poll, qemu_get_clock(rt_clock) + 1000);
+    return;
+
+quit:
+    qemu_system_shutdown_request();
+    return;
+}
+
+static void xen_domain_watcher(void)
+{
+    int qemu_running = 1;
+    int fd[2], i, rc;
+    char byte;
+
+    pipe(fd);
+    if (0 != fork())
+        return; /* not child */
+
+    /* close all file handles, except stdio/out/err,
+     * our watch pipe and the xen interface handle */
+    for (i = 3; i < 256; i++) {
+        if (i == fd[0])
+            continue;
+        if (i == xen_xc)
+            continue;
+        close(i);
+    }
+
+    /* ignore term signals */
+    signal(SIGINT,  SIG_IGN);
+    signal(SIGTERM, SIG_IGN);
+
+    /* wait for qemu exiting */
+    while (qemu_running) {
+        rc = read(fd[0], &byte, 1);
+        switch (rc) {
+        case -1:
+            if (EINTR == errno)
+                continue;
+            fprintf(stderr, "%s: Huh? read error: %s\n", __FUNCTION__, strerror(errno));
+            qemu_running = 0;
+            break;
+        case 0:
+            /* EOF -> qemu exited */
+            qemu_running = 0;
+            break;
+        default:
+            fprintf(stderr, "%s: Huh? data on the watch pipe?\n", __FUNCTION__);
+            break;
+        }
+    }
+
+    /* cleanup */
+    fprintf(stderr, "%s: destroy domain %d\n", __FUNCTION__, xen_domid);
+    xc_domain_destroy(xen_xc, xen_domid);
+    _exit(0);
+}
+
+/* normal cleanup */
+static void xen_domain_cleanup(void)
+{
+    char *dom;
+
+    dom = xs_get_domain_path(xenstore, xen_domid);
+    if (dom) {
+        xs_rm(xenstore, 0, dom);
+        free(dom);
+    }
+    xs_release_domain(xenstore, xen_domid);
+}
+
+int xen_domain_build_pv(const char *kernel, const char *ramdisk,
+                        const char *cmdline)
+{
+    uint32_t ssidref = 0;
+    uint32_t flags = 0;
+    xen_domain_handle_t uuid;
+    unsigned int xenstore_port = 0, console_port = 0;
+    unsigned long xenstore_mfn = 0, console_mfn = 0;
+    int rc;
+
+    memcpy(uuid, qemu_uuid, sizeof(uuid));
+    rc = xc_domain_create(xen_xc, ssidref, uuid, flags, &xen_domid);
+    if (rc < 0) {
+        fprintf(stderr, "xen: xc_domain_create() failed\n");
+        goto err;
+    }
+    fprintf(stderr, "xen: created domain %d\n", xen_domid);
+    atexit(xen_domain_cleanup);
+    xen_domain_watcher();
+
+    xenstore_domain_init1(kernel, ramdisk, cmdline);
+
+    rc = xc_domain_max_vcpus(xen_xc, xen_domid, smp_cpus);
+    if (rc < 0) {
+        fprintf(stderr, "xen: xc_domain_max_vcpus() failed\n");
+        goto err;
+    }
+
+#if 0
+    rc = xc_domain_setcpuweight(xen_xc, xen_domid, 256);
+    if (rc < 0) {
+        fprintf(stderr, "xen: xc_domain_setcpuweight() failed\n");
+        goto err;
+    }
+#endif
+
+    rc = xc_domain_setmaxmem(xen_xc, xen_domid, ram_size >> 10);
+    if (rc < 0) {
+        fprintf(stderr, "xen: xc_domain_setmaxmem() failed\n");
+        goto err;
+    }
+
+    xenstore_port = xc_evtchn_alloc_unbound(xen_xc, xen_domid, 0);
+    console_port = xc_evtchn_alloc_unbound(xen_xc, xen_domid, 0);
+
+    rc = xc_linux_build(xen_xc, xen_domid, ram_size >> 20,
+                        kernel, ramdisk, cmdline,
+                        0, flags,
+                        xenstore_port, &xenstore_mfn,
+                        console_port, &console_mfn);
+    if (rc < 0) {
+        fprintf(stderr, "xen: xc_linux_build() failed\n");
+        goto err;
+    }
+
+    xenstore_domain_init2(xenstore_port, xenstore_mfn,
+                          console_port, console_mfn);
+
+    fprintf(stderr, "xen: unpausing domain %d\n", xen_domid);
+    rc = xc_domain_unpause(xen_xc, xen_domid);
+    if (rc < 0) {
+        fprintf(stderr, "xen: xc_domain_unpause() failed\n");
+        goto err;
+    }
+
+    xen_poll = qemu_new_timer(rt_clock, xen_domain_poll, NULL);
+    qemu_mod_timer(xen_poll, qemu_get_clock(rt_clock) + 1000);
+    return 0;
+
+err:
+    return -1;
+}
diff --git a/hw/xen_domainbuild.h b/hw/xen_domainbuild.h
new file mode 100644
index 0000000..dea0121
--- /dev/null
+++ b/hw/xen_domainbuild.h
@@ -0,0 +1,13 @@
+#ifndef QEMU_HW_XEN_DOMAINBUILD_H
+#define QEMU_HW_XEN_DOMAINBUILD_H 1
+
+#include "xen_common.h"
+
+int xenstore_domain_init1(const char *kernel, const char *ramdisk,
+                          const char *cmdline);
+int xenstore_domain_init2(int xenstore_port, int xenstore_mfn,
+                          int console_port, int console_mfn);
+int xen_domain_build_pv(const char *kernel, const char *ramdisk,
+                        const char *cmdline);
+
+#endif /* QEMU_HW_XEN_DOMAINBUILD_H */
diff --git a/hw/xen_machine_pv.c b/hw/xen_machine_pv.c
index 8c471c2..5607127 100644
--- a/hw/xen_machine_pv.c
+++ b/hw/xen_machine_pv.c
@@ -27,6 +27,7 @@
 #include "sysemu.h"
 #include "boards.h"
 #include "xen_backend.h"
+#include "xen_domainbuild.h"
 
 uint32_t xen_domid;
 enum xen_mode xen_mode = XEN_EMULATE;
@@ -57,6 +58,24 @@ static void xen_init_pv(ram_addr_t ram_size, int vga_ram_size,
         fprintf(stderr, "%s: xen backend core setup failed\n", __FUNCTION__);
         exit(1);
     }
+
+    switch (xen_mode) {
+    case XEN_ATTACH:
+        /* nothing to do, xend handles everything */
+        break;
+    case XEN_CREATE:
+        if (xen_domain_build_pv(kernel_filename, initrd_filename,
+                                kernel_cmdline) < 0) {
+            fprintf(stderr, "xen pv domain creation failed\n");
+            exit(1);
+        }
+        break;
+    case XEN_EMULATE:
+        fprintf(stderr, "xen emulation not implemented (yet)\n");
+        exit(1);
+        break;
+    }
+
     xen_be_register("console", &xen_console_ops);
     xen_be_register("vkbd", &xen_kbdmouse_ops);
     xen_be_register("vfb", &xen_framebuffer_ops);
-- 
1.6.1.3

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

* [PATCH 08/10] xen: pv domain builder.
@ 2009-04-01 21:39   ` Gerd Hoffmann
  0 siblings, 0 replies; 61+ messages in thread
From: Gerd Hoffmann @ 2009-04-01 21:39 UTC (permalink / raw)
  To: qemu-devel, xen-devel; +Cc: Gerd Hoffmann

This adds domain building support for paravirtual domains to qemu.
This allows booting xen guests directly with qemu, without Xend
and the management stack.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 Makefile.target      |    2 +-
 configure            |    2 +-
 hw/xen_backend.h     |    3 +
 hw/xen_devconfig.c   |   29 +++++
 hw/xen_domainbuild.c |  293 ++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/xen_domainbuild.h |   13 +++
 hw/xen_machine_pv.c  |   19 ++++
 7 files changed, 359 insertions(+), 2 deletions(-)
 create mode 100644 hw/xen_domainbuild.c
 create mode 100644 hw/xen_domainbuild.h

diff --git a/Makefile.target b/Makefile.target
index 8bae243..626a846 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -564,7 +564,7 @@ LIBS += $(CONFIG_BLUEZ_LIBS)
 endif
 
 # xen backend driver support
-XEN_OBJS := xen_machine_pv.o xen_backend.o xen_devconfig.o
+XEN_OBJS := xen_machine_pv.o xen_backend.o xen_devconfig.o xen_domainbuild.o
 XEN_OBJS += xen_console.o xenfb.o xen_disk.o xen_nic.o
 ifeq ($(CONFIG_XEN), yes)
   OBJS += $(XEN_OBJS)
diff --git a/configure b/configure
index 212f2e9..9e7738e 100755
--- a/configure
+++ b/configure
@@ -1518,7 +1518,7 @@ if test "$bluez" = "yes" ; then
   echo "#define CONFIG_BLUEZ 1" >> $config_h
 fi
 if test "$xen" = "yes" ; then
-  echo "XEN_LIBS=-lxenstore -lxenctrl" >> $config_mak
+  echo "XEN_LIBS=-lxenstore -lxenctrl -lxenguest" >> $config_mak
 fi
 if test "$aio" = "yes" ; then
   echo "#define CONFIG_AIO 1" >> $config_h
diff --git a/hw/xen_backend.h b/hw/xen_backend.h
index 7f1804e..4dbfdb4 100644
--- a/hw/xen_backend.h
+++ b/hw/xen_backend.h
@@ -100,5 +100,8 @@ void xen_init_display(int domid);
 void xen_config_cleanup(void);
 int xen_config_dev_blk(DriveInfo *disk);
 int xen_config_dev_nic(NICInfo *nic);
+int xen_config_dev_vfb(int vdev, const char *type);
+int xen_config_dev_vkbd(int vdev);
+int xen_config_dev_console(int vdev);
 
 #endif /* QEMU_HW_XEN_BACKEND_H */
diff --git a/hw/xen_devconfig.c b/hw/xen_devconfig.c
index 0ef8012..1417e71 100644
--- a/hw/xen_devconfig.c
+++ b/hw/xen_devconfig.c
@@ -143,3 +143,32 @@ int xen_config_dev_nic(NICInfo *nic)
     /* common stuff */
     return xen_config_dev_all(fe, be);
 }
+
+int xen_config_dev_vfb(int vdev, const char *type)
+{
+    char fe[256], be[256];
+
+    xen_config_dev_dirs("vfb", "vfb", vdev, fe, be, sizeof(fe));
+
+    /* backend */
+    xenstore_write_str(be, "type",  type);
+
+    /* common stuff */
+    return xen_config_dev_all(fe, be);
+}
+
+int xen_config_dev_vkbd(int vdev)
+{
+    char fe[256], be[256];
+
+    xen_config_dev_dirs("vkbd", "vkbd", vdev, fe, be, sizeof(fe));
+    return xen_config_dev_all(fe, be);
+}
+
+int xen_config_dev_console(int vdev)
+{
+    char fe[256], be[256];
+
+    xen_config_dev_dirs("console", "console", vdev, fe, be, sizeof(fe));
+    return xen_config_dev_all(fe, be);
+}
diff --git a/hw/xen_domainbuild.c b/hw/xen_domainbuild.c
new file mode 100644
index 0000000..9814b8d
--- /dev/null
+++ b/hw/xen_domainbuild.c
@@ -0,0 +1,293 @@
+#include <signal.h>
+#include "xen_backend.h"
+#include "xen_domainbuild.h"
+#include "sysemu.h"
+#include "qemu-timer.h"
+
+#include <xenguest.h>
+
+static int xenstore_domain_mkdir(char *path)
+{
+    struct xs_permissions perms_ro[] = {{
+            .id    = 0, /* set owner: dom0 */
+        },{
+            .id    = xen_domid,
+            .perms = XS_PERM_READ,
+        }};
+    struct xs_permissions perms_rw[] = {{
+            .id    = 0, /* set owner: dom0 */
+        },{
+            .id    = xen_domid,
+            .perms = XS_PERM_READ | XS_PERM_WRITE,
+        }};
+    const char *writable[] = { "device", "control", "error", NULL };
+    char subpath[256];
+    int i;
+
+    if (!xs_mkdir(xenstore, 0, path)) {
+        fprintf(stderr, "%s: xs_mkdir %s: failed\n", __FUNCTION__, path);
+	return -1;
+    }
+    if (!xs_set_permissions(xenstore, 0, path, perms_ro, 2)) {
+        fprintf(stderr, "%s: xs.set_permissions failed\n", __FUNCTION__);
+	return -1;
+    }
+
+    for (i = 0; writable[i]; i++) {
+        snprintf(subpath, sizeof(subpath), "%s/%s", path, writable[i]);
+        if (!xs_mkdir(xenstore, 0, subpath)) {
+            fprintf(stderr, "%s: xs.mkdir %s: failed\n", __FUNCTION__, subpath);
+            return -1;
+        }
+        if (!xs_set_permissions(xenstore, 0, subpath, perms_rw, 2)) {
+            fprintf(stderr, "%s: xs.set_permissions failed\n", __FUNCTION__);
+            return -1;
+        }
+    }
+    return 0;
+}
+
+int xenstore_domain_init1(const char *kernel, const char *ramdisk,
+                          const char *cmdline)
+{
+    char *dom, uuid_string[42], vm[256], path[256];
+    int i;
+
+    snprintf(uuid_string, sizeof(uuid_string), UUID_FMT,
+             qemu_uuid[0], qemu_uuid[1], qemu_uuid[2], qemu_uuid[3],
+             qemu_uuid[4], qemu_uuid[5], qemu_uuid[6], qemu_uuid[7],
+             qemu_uuid[8], qemu_uuid[9], qemu_uuid[10], qemu_uuid[11],
+             qemu_uuid[12], qemu_uuid[13], qemu_uuid[14], qemu_uuid[15]);
+    dom = xs_get_domain_path(xenstore, xen_domid);
+    snprintf(vm,  sizeof(vm),  "/vm/%s", uuid_string);
+
+    xenstore_domain_mkdir(dom);
+
+    xenstore_write_str(vm, "image/ostype",  "linux");
+    if (kernel)
+        xenstore_write_str(vm, "image/kernel",  kernel);
+    if (ramdisk)
+        xenstore_write_str(vm, "image/ramdisk", ramdisk);
+    if (cmdline)
+        xenstore_write_str(vm, "image/cmdline", cmdline);
+
+    /* name + id */
+    xenstore_write_str(vm,  "name",   qemu_name ? qemu_name : "no-name");
+    xenstore_write_str(vm,  "uuid",   uuid_string);
+    xenstore_write_str(dom, "name",   qemu_name ? qemu_name : "no-name");
+    xenstore_write_int(dom, "domid",  xen_domid);
+    xenstore_write_str(dom, "vm",     vm);
+
+    /* memory */
+    xenstore_write_int(dom, "memory/target", ram_size >> 10);  // kB
+    xenstore_write_int(vm, "memory",         ram_size >> 20);  // MB
+    xenstore_write_int(vm, "maxmem",         ram_size >> 20);  // MB
+
+    /* cpus */
+    for (i = 0; i < smp_cpus; i++) {
+	snprintf(path, sizeof(path), "cpu/%d/availability",i);
+	xenstore_write_str(dom, path, "online");
+    }
+    xenstore_write_int(vm, "vcpu_avail",  smp_cpus);
+    xenstore_write_int(vm, "vcpus",       smp_cpus);
+
+    /* vnc password */
+    xenstore_write_str(vm, "vncpassword", "" /* FIXME */);
+
+    free(dom);
+    return 0;
+}
+
+int xenstore_domain_init2(int xenstore_port, int xenstore_mfn,
+                          int console_port, int console_mfn)
+{
+    char *dom;
+
+    dom = xs_get_domain_path(xenstore, xen_domid);
+
+    /* signal new domain */
+    xs_introduce_domain(xenstore,
+                        xen_domid,
+                        xenstore_mfn,
+                        xenstore_port);
+
+    /* xenstore */
+    xenstore_write_int(dom, "store/ring-ref",   xenstore_mfn);
+    xenstore_write_int(dom, "store/port",       xenstore_port);
+
+    /* console */
+    xenstore_write_str(dom, "console/type",     "ioemu");
+    xenstore_write_int(dom, "console/limit",    128 * 1024);
+    xenstore_write_int(dom, "console/ring-ref", console_mfn);
+    xenstore_write_int(dom, "console/port",     console_port);
+    xen_config_dev_console(0);
+
+    free(dom);
+    return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static QEMUTimer *xen_poll;
+
+/* check domain state once per second */
+static void xen_domain_poll(void *opaque)
+{
+    struct xc_dominfo info;
+    int rc;
+
+    rc = xc_domain_getinfo(xen_xc, xen_domid, 1, &info);
+    if ((1 != rc) || (info.domid != xen_domid)) {
+        fprintf(stderr, "xen: domain %d is gone\n", xen_domid);
+        goto quit;
+    }
+    if (info.dying) {
+        fprintf(stderr, "xen: domain %d is dying (%s%s)\n", xen_domid,
+                info.crashed  ? "crashed"  : "",
+                info.shutdown ? "shutdown" : "");
+        goto quit;
+    }
+
+    qemu_mod_timer(xen_poll, qemu_get_clock(rt_clock) + 1000);
+    return;
+
+quit:
+    qemu_system_shutdown_request();
+    return;
+}
+
+static void xen_domain_watcher(void)
+{
+    int qemu_running = 1;
+    int fd[2], i, rc;
+    char byte;
+
+    pipe(fd);
+    if (0 != fork())
+        return; /* not child */
+
+    /* close all file handles, except stdio/out/err,
+     * our watch pipe and the xen interface handle */
+    for (i = 3; i < 256; i++) {
+        if (i == fd[0])
+            continue;
+        if (i == xen_xc)
+            continue;
+        close(i);
+    }
+
+    /* ignore term signals */
+    signal(SIGINT,  SIG_IGN);
+    signal(SIGTERM, SIG_IGN);
+
+    /* wait for qemu exiting */
+    while (qemu_running) {
+        rc = read(fd[0], &byte, 1);
+        switch (rc) {
+        case -1:
+            if (EINTR == errno)
+                continue;
+            fprintf(stderr, "%s: Huh? read error: %s\n", __FUNCTION__, strerror(errno));
+            qemu_running = 0;
+            break;
+        case 0:
+            /* EOF -> qemu exited */
+            qemu_running = 0;
+            break;
+        default:
+            fprintf(stderr, "%s: Huh? data on the watch pipe?\n", __FUNCTION__);
+            break;
+        }
+    }
+
+    /* cleanup */
+    fprintf(stderr, "%s: destroy domain %d\n", __FUNCTION__, xen_domid);
+    xc_domain_destroy(xen_xc, xen_domid);
+    _exit(0);
+}
+
+/* normal cleanup */
+static void xen_domain_cleanup(void)
+{
+    char *dom;
+
+    dom = xs_get_domain_path(xenstore, xen_domid);
+    if (dom) {
+        xs_rm(xenstore, 0, dom);
+        free(dom);
+    }
+    xs_release_domain(xenstore, xen_domid);
+}
+
+int xen_domain_build_pv(const char *kernel, const char *ramdisk,
+                        const char *cmdline)
+{
+    uint32_t ssidref = 0;
+    uint32_t flags = 0;
+    xen_domain_handle_t uuid;
+    unsigned int xenstore_port = 0, console_port = 0;
+    unsigned long xenstore_mfn = 0, console_mfn = 0;
+    int rc;
+
+    memcpy(uuid, qemu_uuid, sizeof(uuid));
+    rc = xc_domain_create(xen_xc, ssidref, uuid, flags, &xen_domid);
+    if (rc < 0) {
+        fprintf(stderr, "xen: xc_domain_create() failed\n");
+        goto err;
+    }
+    fprintf(stderr, "xen: created domain %d\n", xen_domid);
+    atexit(xen_domain_cleanup);
+    xen_domain_watcher();
+
+    xenstore_domain_init1(kernel, ramdisk, cmdline);
+
+    rc = xc_domain_max_vcpus(xen_xc, xen_domid, smp_cpus);
+    if (rc < 0) {
+        fprintf(stderr, "xen: xc_domain_max_vcpus() failed\n");
+        goto err;
+    }
+
+#if 0
+    rc = xc_domain_setcpuweight(xen_xc, xen_domid, 256);
+    if (rc < 0) {
+        fprintf(stderr, "xen: xc_domain_setcpuweight() failed\n");
+        goto err;
+    }
+#endif
+
+    rc = xc_domain_setmaxmem(xen_xc, xen_domid, ram_size >> 10);
+    if (rc < 0) {
+        fprintf(stderr, "xen: xc_domain_setmaxmem() failed\n");
+        goto err;
+    }
+
+    xenstore_port = xc_evtchn_alloc_unbound(xen_xc, xen_domid, 0);
+    console_port = xc_evtchn_alloc_unbound(xen_xc, xen_domid, 0);
+
+    rc = xc_linux_build(xen_xc, xen_domid, ram_size >> 20,
+                        kernel, ramdisk, cmdline,
+                        0, flags,
+                        xenstore_port, &xenstore_mfn,
+                        console_port, &console_mfn);
+    if (rc < 0) {
+        fprintf(stderr, "xen: xc_linux_build() failed\n");
+        goto err;
+    }
+
+    xenstore_domain_init2(xenstore_port, xenstore_mfn,
+                          console_port, console_mfn);
+
+    fprintf(stderr, "xen: unpausing domain %d\n", xen_domid);
+    rc = xc_domain_unpause(xen_xc, xen_domid);
+    if (rc < 0) {
+        fprintf(stderr, "xen: xc_domain_unpause() failed\n");
+        goto err;
+    }
+
+    xen_poll = qemu_new_timer(rt_clock, xen_domain_poll, NULL);
+    qemu_mod_timer(xen_poll, qemu_get_clock(rt_clock) + 1000);
+    return 0;
+
+err:
+    return -1;
+}
diff --git a/hw/xen_domainbuild.h b/hw/xen_domainbuild.h
new file mode 100644
index 0000000..dea0121
--- /dev/null
+++ b/hw/xen_domainbuild.h
@@ -0,0 +1,13 @@
+#ifndef QEMU_HW_XEN_DOMAINBUILD_H
+#define QEMU_HW_XEN_DOMAINBUILD_H 1
+
+#include "xen_common.h"
+
+int xenstore_domain_init1(const char *kernel, const char *ramdisk,
+                          const char *cmdline);
+int xenstore_domain_init2(int xenstore_port, int xenstore_mfn,
+                          int console_port, int console_mfn);
+int xen_domain_build_pv(const char *kernel, const char *ramdisk,
+                        const char *cmdline);
+
+#endif /* QEMU_HW_XEN_DOMAINBUILD_H */
diff --git a/hw/xen_machine_pv.c b/hw/xen_machine_pv.c
index 8c471c2..5607127 100644
--- a/hw/xen_machine_pv.c
+++ b/hw/xen_machine_pv.c
@@ -27,6 +27,7 @@
 #include "sysemu.h"
 #include "boards.h"
 #include "xen_backend.h"
+#include "xen_domainbuild.h"
 
 uint32_t xen_domid;
 enum xen_mode xen_mode = XEN_EMULATE;
@@ -57,6 +58,24 @@ static void xen_init_pv(ram_addr_t ram_size, int vga_ram_size,
         fprintf(stderr, "%s: xen backend core setup failed\n", __FUNCTION__);
         exit(1);
     }
+
+    switch (xen_mode) {
+    case XEN_ATTACH:
+        /* nothing to do, xend handles everything */
+        break;
+    case XEN_CREATE:
+        if (xen_domain_build_pv(kernel_filename, initrd_filename,
+                                kernel_cmdline) < 0) {
+            fprintf(stderr, "xen pv domain creation failed\n");
+            exit(1);
+        }
+        break;
+    case XEN_EMULATE:
+        fprintf(stderr, "xen emulation not implemented (yet)\n");
+        exit(1);
+        break;
+    }
+
     xen_be_register("console", &xen_console_ops);
     xen_be_register("vkbd", &xen_kbdmouse_ops);
     xen_be_register("vfb", &xen_framebuffer_ops);
-- 
1.6.1.3

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

* [Qemu-devel] [PATCH 09/10] simplify vga selection
  2009-04-01 21:39 ` Gerd Hoffmann
@ 2009-04-01 21:39   ` Gerd Hoffmann
  -1 siblings, 0 replies; 61+ messages in thread
From: Gerd Hoffmann @ 2009-04-01 21:39 UTC (permalink / raw)
  To: qemu-devel, xen-devel; +Cc: Gerd Hoffmann


Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 vl.c |   15 ++++-----------
 1 files changed, 4 insertions(+), 11 deletions(-)

diff --git a/vl.c b/vl.c
index edf9ea9..243fc0f 100644
--- a/vl.c
+++ b/vl.c
@@ -4149,23 +4149,16 @@ static void select_vgahw (const char *p)
 {
     const char *opts;
 
+    cirrus_vga_enabled = 0;
+    std_vga_enabled = 0;
+    vmsvga_enabled = 0;
     if (strstart(p, "std", &opts)) {
         std_vga_enabled = 1;
-        cirrus_vga_enabled = 0;
-        vmsvga_enabled = 0;
     } else if (strstart(p, "cirrus", &opts)) {
         cirrus_vga_enabled = 1;
-        std_vga_enabled = 0;
-        vmsvga_enabled = 0;
     } else if (strstart(p, "vmware", &opts)) {
-        cirrus_vga_enabled = 0;
-        std_vga_enabled = 0;
         vmsvga_enabled = 1;
-    } else if (strstart(p, "none", &opts)) {
-        cirrus_vga_enabled = 0;
-        std_vga_enabled = 0;
-        vmsvga_enabled = 0;
-    } else {
+    } else if (!strstart(p, "none", &opts)) {
     invalid_vga:
         fprintf(stderr, "Unknown vga type: %s\n", p);
         exit(1);
-- 
1.6.1.3

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

* [PATCH 09/10] simplify vga selection
@ 2009-04-01 21:39   ` Gerd Hoffmann
  0 siblings, 0 replies; 61+ messages in thread
From: Gerd Hoffmann @ 2009-04-01 21:39 UTC (permalink / raw)
  To: qemu-devel, xen-devel; +Cc: Gerd Hoffmann


Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 vl.c |   15 ++++-----------
 1 files changed, 4 insertions(+), 11 deletions(-)

diff --git a/vl.c b/vl.c
index edf9ea9..243fc0f 100644
--- a/vl.c
+++ b/vl.c
@@ -4149,23 +4149,16 @@ static void select_vgahw (const char *p)
 {
     const char *opts;
 
+    cirrus_vga_enabled = 0;
+    std_vga_enabled = 0;
+    vmsvga_enabled = 0;
     if (strstart(p, "std", &opts)) {
         std_vga_enabled = 1;
-        cirrus_vga_enabled = 0;
-        vmsvga_enabled = 0;
     } else if (strstart(p, "cirrus", &opts)) {
         cirrus_vga_enabled = 1;
-        std_vga_enabled = 0;
-        vmsvga_enabled = 0;
     } else if (strstart(p, "vmware", &opts)) {
-        cirrus_vga_enabled = 0;
-        std_vga_enabled = 0;
         vmsvga_enabled = 1;
-    } else if (strstart(p, "none", &opts)) {
-        cirrus_vga_enabled = 0;
-        std_vga_enabled = 0;
-        vmsvga_enabled = 0;
-    } else {
+    } else if (!strstart(p, "none", &opts)) {
     invalid_vga:
         fprintf(stderr, "Unknown vga type: %s\n", p);
         exit(1);
-- 
1.6.1.3

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

* [Qemu-devel] [PATCH 10/10] xen: add -vga xenfb option, configure xenfb
  2009-04-01 21:39 ` Gerd Hoffmann
@ 2009-04-01 21:39   ` Gerd Hoffmann
  -1 siblings, 0 replies; 61+ messages in thread
From: Gerd Hoffmann @ 2009-04-01 21:39 UTC (permalink / raw)
  To: qemu-devel, xen-devel; +Cc: Gerd Hoffmann


Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/xen_machine_pv.c |    6 ++++++
 qemu-options.hx     |    2 +-
 sysemu.h            |    1 +
 vl.c                |    4 ++++
 4 files changed, 12 insertions(+), 1 deletions(-)

diff --git a/hw/xen_machine_pv.c b/hw/xen_machine_pv.c
index 5607127..0e12bfe 100644
--- a/hw/xen_machine_pv.c
+++ b/hw/xen_machine_pv.c
@@ -82,6 +82,12 @@ static void xen_init_pv(ram_addr_t ram_size, int vga_ram_size,
     xen_be_register("qdisk", &xen_blkdev_ops);
     xen_be_register("qnic", &xen_netdev_ops);
 
+    /* configure framebuffer */
+    if (xenfb_enabled) {
+        xen_config_dev_vfb(0, "vnc");
+        xen_config_dev_vkbd(0);
+    }
+
     /* configure disks */
     for (i = 0; i < 16; i++) {
         index = drive_get_index(IF_XEN, 0, i);
diff --git a/qemu-options.hx b/qemu-options.hx
index 895fa89..79c71ac 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -452,7 +452,7 @@ Rotate graphical output 90 deg left (only PXA LCD).
 ETEXI
 
 DEF("vga", HAS_ARG, QEMU_OPTION_vga,
-    "-vga [std|cirrus|vmware|none]\n"
+    "-vga [std|cirrus|vmware|xenfb|none]\n"
     "                select video card type\n")
 STEXI
 @item -vga @var{type}
diff --git a/sysemu.h b/sysemu.h
index 7b356b3..e22612b 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -87,6 +87,7 @@ extern int bios_size;
 extern int cirrus_vga_enabled;
 extern int std_vga_enabled;
 extern int vmsvga_enabled;
+extern int xenfb_enabled;
 extern int graphic_width;
 extern int graphic_height;
 extern int graphic_depth;
diff --git a/vl.c b/vl.c
index 243fc0f..1d9ea73 100644
--- a/vl.c
+++ b/vl.c
@@ -215,6 +215,7 @@ static int rtc_date_offset = -1; /* -1 means no change */
 int cirrus_vga_enabled = 1;
 int std_vga_enabled = 0;
 int vmsvga_enabled = 0;
+int xenfb_enabled = 0;
 #ifdef TARGET_SPARC
 int graphic_width = 1024;
 int graphic_height = 768;
@@ -4152,12 +4153,15 @@ static void select_vgahw (const char *p)
     cirrus_vga_enabled = 0;
     std_vga_enabled = 0;
     vmsvga_enabled = 0;
+    xenfb_enabled = 0;
     if (strstart(p, "std", &opts)) {
         std_vga_enabled = 1;
     } else if (strstart(p, "cirrus", &opts)) {
         cirrus_vga_enabled = 1;
     } else if (strstart(p, "vmware", &opts)) {
         vmsvga_enabled = 1;
+    } else if (strstart(p, "xenfb", &opts)) {
+        xenfb_enabled = 1;
     } else if (!strstart(p, "none", &opts)) {
     invalid_vga:
         fprintf(stderr, "Unknown vga type: %s\n", p);
-- 
1.6.1.3

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

* [PATCH 10/10] xen: add -vga xenfb option, configure xenfb
@ 2009-04-01 21:39   ` Gerd Hoffmann
  0 siblings, 0 replies; 61+ messages in thread
From: Gerd Hoffmann @ 2009-04-01 21:39 UTC (permalink / raw)
  To: qemu-devel, xen-devel; +Cc: Gerd Hoffmann


Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/xen_machine_pv.c |    6 ++++++
 qemu-options.hx     |    2 +-
 sysemu.h            |    1 +
 vl.c                |    4 ++++
 4 files changed, 12 insertions(+), 1 deletions(-)

diff --git a/hw/xen_machine_pv.c b/hw/xen_machine_pv.c
index 5607127..0e12bfe 100644
--- a/hw/xen_machine_pv.c
+++ b/hw/xen_machine_pv.c
@@ -82,6 +82,12 @@ static void xen_init_pv(ram_addr_t ram_size, int vga_ram_size,
     xen_be_register("qdisk", &xen_blkdev_ops);
     xen_be_register("qnic", &xen_netdev_ops);
 
+    /* configure framebuffer */
+    if (xenfb_enabled) {
+        xen_config_dev_vfb(0, "vnc");
+        xen_config_dev_vkbd(0);
+    }
+
     /* configure disks */
     for (i = 0; i < 16; i++) {
         index = drive_get_index(IF_XEN, 0, i);
diff --git a/qemu-options.hx b/qemu-options.hx
index 895fa89..79c71ac 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -452,7 +452,7 @@ Rotate graphical output 90 deg left (only PXA LCD).
 ETEXI
 
 DEF("vga", HAS_ARG, QEMU_OPTION_vga,
-    "-vga [std|cirrus|vmware|none]\n"
+    "-vga [std|cirrus|vmware|xenfb|none]\n"
     "                select video card type\n")
 STEXI
 @item -vga @var{type}
diff --git a/sysemu.h b/sysemu.h
index 7b356b3..e22612b 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -87,6 +87,7 @@ extern int bios_size;
 extern int cirrus_vga_enabled;
 extern int std_vga_enabled;
 extern int vmsvga_enabled;
+extern int xenfb_enabled;
 extern int graphic_width;
 extern int graphic_height;
 extern int graphic_depth;
diff --git a/vl.c b/vl.c
index 243fc0f..1d9ea73 100644
--- a/vl.c
+++ b/vl.c
@@ -215,6 +215,7 @@ static int rtc_date_offset = -1; /* -1 means no change */
 int cirrus_vga_enabled = 1;
 int std_vga_enabled = 0;
 int vmsvga_enabled = 0;
+int xenfb_enabled = 0;
 #ifdef TARGET_SPARC
 int graphic_width = 1024;
 int graphic_height = 768;
@@ -4152,12 +4153,15 @@ static void select_vgahw (const char *p)
     cirrus_vga_enabled = 0;
     std_vga_enabled = 0;
     vmsvga_enabled = 0;
+    xenfb_enabled = 0;
     if (strstart(p, "std", &opts)) {
         std_vga_enabled = 1;
     } else if (strstart(p, "cirrus", &opts)) {
         cirrus_vga_enabled = 1;
     } else if (strstart(p, "vmware", &opts)) {
         vmsvga_enabled = 1;
+    } else if (strstart(p, "xenfb", &opts)) {
+        xenfb_enabled = 1;
     } else if (!strstart(p, "none", &opts)) {
     invalid_vga:
         fprintf(stderr, "Unknown vga type: %s\n", p);
-- 
1.6.1.3

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

* Re: [Qemu-devel] [PATCH 00/10] xen: pv domain support.
  2009-04-01 21:39 ` Gerd Hoffmann
                   ` (10 preceding siblings ...)
  (?)
@ 2009-04-01 23:41 ` Anthony Liguori
  2009-04-02 15:32   ` Ian Jackson
  -1 siblings, 1 reply; 61+ messages in thread
From: Anthony Liguori @ 2009-04-01 23:41 UTC (permalink / raw)
  To: qemu-devel; +Cc: xen-devel, Ian Jackson, Gerd Hoffmann

Gerd Hoffmann wrote:
>   Hi,
>
> It's been a while, but after a looooooooooooong time we've (hopefully)
> finally sorted the merging issues with qemu-xen.  So here is a fresh
> version of the xen support for qemu patch series.  Short overview
> (individual patches have longer descriptions):
>   

Have these made their way into qemu-xen-unstable?  If not, has Ian at 
least Acked them?

Regards,

Anthony Liguori

>   #1  - groundwork for xen support (makefiles, configure, ...).
>   #2  - backend driver core (common code used by all backends).
>   #3  - add console backend driver.
>   #4  - add framebuffer backend driver.
>
> With these four patches in place upstream qemu is functional aequivalent
> to qemu-xen for paravirtual guests.  The patches are merged into
> qemu-xen already, with the exception of a few framebuffer bits which got
> hold back due to displaystate work.
>
>   #5  - add block device backend driver.
>   #6  - add net backend driver.
>
> These two patches add backend drivers for disk and network to qemu.
>
>   #7  - blk & nic configuration via cmd line.
>   #8  - pv domain builder.
>   #9  - simplify vga selection
>   #10 - add -vga xenfb option, configure xenfb
>
> These patches add support to qemu for creating xen pv guests.  That way
> one can run xen guests without xend.  Patch #8 is the domain builder
> code itself.  The other patches add support for configuring devices (fb,
> disk, nic) via command line.
>
> cheers,
>   Gerd
>
>
>
>   

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

* Re: [Qemu-devel] [PATCH 00/10] xen: pv domain support.
  2009-04-01 23:41 ` [Qemu-devel] [PATCH 00/10] xen: pv domain support Anthony Liguori
@ 2009-04-02 15:32   ` Ian Jackson
  0 siblings, 0 replies; 61+ messages in thread
From: Ian Jackson @ 2009-04-02 15:32 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: xen-devel, qemu-devel, Gerd Hoffmann

Anthony Liguori writes ("Re: [Qemu-devel] [PATCH 00/10] xen: pv domain support."):
> Gerd Hoffmann wrote:
> > It's been a while, but after a looooooooooooong time we've (hopefully)
> > finally sorted the merging issues with qemu-xen.  So here is a fresh
> > version of the xen support for qemu patch series.  Short overview
> > (individual patches have longer descriptions):

Well done and thanks for persisting.

> Have these made their way into qemu-xen-unstable?  If not, has Ian at 
> least Acked them?

Some but not all of these are in qemu-xen-unstable.  Not all of Gerd's
patches ought to go via qemu-xen-unstable - some should go direct.

I've just merged up again from qemu-upstream at the 0.10.0 branch
point so that qemu-xen-unstable staging is now reasonably recent.
After I have fixed the resulting breakage and got that code through
our tests into the main qemu-xen-untable we (Xen) will be in freeze
and I'll have some time to look at Gerd's patches and comment and/or
ack them individually.

So please wait just a few more days if that's not too inconvenient.

I'm sorry this process is so slow but the massively improved rate of
qemu development (yay!) has meant that we have been playing catch-up
quite a bit.  (Often, resolving conflicts between changes in upstream
which are very similar but not identical to ones in our tree, so
happily resulting in me being able to drop changes entirely.)

Ian.

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

* Re: [Qemu-devel] [PATCH 01/10] xen: groundwork for xen support
  2009-04-01 21:39   ` Gerd Hoffmann
@ 2009-04-02 16:37     ` Blue Swirl
  -1 siblings, 0 replies; 61+ messages in thread
From: Blue Swirl @ 2009-04-02 16:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: xen-devel, Gerd Hoffmann

On 4/2/09, Gerd Hoffmann <kraxel@redhat.com> wrote:
> - configure script and build system changes.
>  - wind up new machine type.
>  - add -xen-* command line options.
>
>  Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>

>  +  $(XEN_OBJS) : CFLAGS += -Wall -Wmissing-prototypes -Wstrict-prototypes

This should not be necessary, we already use all these flags.

>  +/*
>  + * Local variables:
>  + *  indent-tabs-mode: nil
>  + *  c-indent-level: 4
>  + *  c-basic-offset: 4
>  + *  tab-width: 4
>  + * End:
>  + */

Please remove.

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

* Re: [PATCH 01/10] xen: groundwork for xen support
@ 2009-04-02 16:37     ` Blue Swirl
  0 siblings, 0 replies; 61+ messages in thread
From: Blue Swirl @ 2009-04-02 16:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: xen-devel, Gerd Hoffmann

On 4/2/09, Gerd Hoffmann <kraxel@redhat.com> wrote:
> - configure script and build system changes.
>  - wind up new machine type.
>  - add -xen-* command line options.
>
>  Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>

>  +  $(XEN_OBJS) : CFLAGS += -Wall -Wmissing-prototypes -Wstrict-prototypes

This should not be necessary, we already use all these flags.

>  +/*
>  + * Local variables:
>  + *  indent-tabs-mode: nil
>  + *  c-indent-level: 4
>  + *  c-basic-offset: 4
>  + *  tab-width: 4
>  + * End:
>  + */

Please remove.

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

* Re: [Qemu-devel] [PATCH 02/10] xen: backend driver core
  2009-04-01 21:39   ` Gerd Hoffmann
@ 2009-04-02 16:49     ` Blue Swirl
  -1 siblings, 0 replies; 61+ messages in thread
From: Blue Swirl @ 2009-04-02 16:49 UTC (permalink / raw)
  To: qemu-devel; +Cc: xen-devel, Gerd Hoffmann

On 4/2/09, Gerd Hoffmann <kraxel@redhat.com> 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>

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

The address is now 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

>  +    if (NULL == node  ||  0 == strcmp(node, "online")) {
>  +       if (-1 == xenstore_read_be_int(xendev, "online", &xendev->online))

This style is alien.

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

* Re: [PATCH 02/10] xen: backend driver core
@ 2009-04-02 16:49     ` Blue Swirl
  0 siblings, 0 replies; 61+ messages in thread
From: Blue Swirl @ 2009-04-02 16:49 UTC (permalink / raw)
  To: qemu-devel; +Cc: xen-devel, Gerd Hoffmann

On 4/2/09, Gerd Hoffmann <kraxel@redhat.com> 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>

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

The address is now 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

>  +    if (NULL == node  ||  0 == strcmp(node, "online")) {
>  +       if (-1 == xenstore_read_be_int(xendev, "online", &xendev->online))

This style is alien.

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

* Re: [Qemu-devel] [PATCH 04/10] xen: add framebuffer backend driver
  2009-04-01 21:39   ` Gerd Hoffmann
@ 2009-04-02 16:57     ` Blue Swirl
  -1 siblings, 0 replies; 61+ messages in thread
From: Blue Swirl @ 2009-04-02 16:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: xen-devel, Gerd Hoffmann

On 4/2/09, Gerd Hoffmann <kraxel@redhat.com> 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 release 3.3
>
>  Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>

>  +    pgmfns = qemu_mallocz(sizeof(unsigned long) * n_fbdirs);
>  +    fbmfns = qemu_mallocz(sizeof(unsigned long) * xenfb->fbpages);
>  +    if (!pgmfns || !fbmfns)
>  +       goto out;

This check should be removed, qemu_malloc will abort if we're out of memory.

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

* Re: [PATCH 04/10] xen: add framebuffer backend driver
@ 2009-04-02 16:57     ` Blue Swirl
  0 siblings, 0 replies; 61+ messages in thread
From: Blue Swirl @ 2009-04-02 16:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: xen-devel, Gerd Hoffmann

On 4/2/09, Gerd Hoffmann <kraxel@redhat.com> 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 release 3.3
>
>  Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>

>  +    pgmfns = qemu_mallocz(sizeof(unsigned long) * n_fbdirs);
>  +    fbmfns = qemu_mallocz(sizeof(unsigned long) * xenfb->fbpages);
>  +    if (!pgmfns || !fbmfns)
>  +       goto out;

This check should be removed, qemu_malloc will abort if we're out of memory.

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

* Re: [Qemu-devel] [PATCH 05/10] xen: add block device backend driver.
  2009-04-01 21:39   ` Gerd Hoffmann
  (?)
@ 2009-04-02 17:02   ` Christoph Hellwig
  2009-04-03 20:11     ` Gerd Hoffmann
                       ` (2 more replies)
  -1 siblings, 3 replies; 61+ messages in thread
From: Christoph Hellwig @ 2009-04-02 17:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: xen-devel, Gerd Hoffmann

On Wed, Apr 01, 2009 at 11:39:37PM +0200, Gerd Hoffmann wrote:
> +static void inline blkif_get_x86_32_req(blkif_request_t *dst, blkif_x86_32_request_t *src)
> +{

> +static void inline blkif_get_x86_64_req(blkif_request_t *dst, blkif_x86_64_request_t *src)
> +{

I think you'd be better of moving them to the .c file as normal static
function and leave the inlining decisions to the compiler.

> +
> +/*
> + *  FIXME: the code is designed to handle multiple outstanding
> + *         requests, which isn't used right now.  Plan is to
> + *         switch over to the aio block functions once they got
> + *         vector support.
> + */

We already have bdrv_aio_readv/writev which currently linearize the
buffer underneath.  Hopefully Anthony will have commited the patch to
implement the real one while I'm writing this, too :)

After those patches bdrv_aio_read/write will be gone so this code won't
compile anymore, too.

> +static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
> +{
> +    struct XenBlkDev *blkdev = ioreq->blkdev;
> +    int i, len = 0;
> +    off_t pos;
> +
> +    if (-1 == ioreq_map(ioreq))
> +	goto err;
> +
> +    ioreq->aio_inflight++;
> +    if (ioreq->presync)
> +	bdrv_flush(blkdev->bs); /* FIXME: aio_flush() ??? */
> +
> +    switch (ioreq->req.operation) {
> +    case BLKIF_OP_READ:
> +	pos = ioreq->start;
> +	for (i = 0; i < ioreq->vecs; i++) {
> +            ioreq->aio_inflight++;
> +            bdrv_aio_read(blkdev->bs, pos / BLOCK_SIZE,
> +                          ioreq->vec[i].iov_base,
> +                          ioreq->vec[i].iov_len / BLOCK_SIZE,
> +                          qemu_aio_complete, ioreq);
> +	    len += ioreq->vec[i].iov_len;
> +	    pos += ioreq->vec[i].iov_len;
> +	}

hdrv_flush doesn't actually empty the aio queues but only issues
a fsync.  So we could still re-order requeuests around the barrier
with this implementation.  I will soon submit a real block-layer level
barrier implementation that just allows to flag a bdrv_aio_read/write
request as barrier and deal with this under the hood.

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

* Re: [Qemu-devel] [PATCH 08/10] xen: pv domain builder.
  2009-04-01 21:39   ` Gerd Hoffmann
@ 2009-04-02 17:06     ` Blue Swirl
  -1 siblings, 0 replies; 61+ messages in thread
From: Blue Swirl @ 2009-04-02 17:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: xen-devel, Gerd Hoffmann

On 4/2/09, Gerd Hoffmann <kraxel@redhat.com> wrote:
> This adds domain building support for paravirtual domains to qemu.
>  This allows booting xen guests directly with qemu, without Xend
>  and the management stack.
>
>  Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>

>  +    /* close all file handles, except stdio/out/err,
>  +     * our watch pipe and the xen interface handle */
>  +    for (i = 3; i < 256; i++) {

You should use getdtablesize() or sysconf(_SC_OPEN_MAX) instead of 256.

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

* Re: [PATCH 08/10] xen: pv domain builder.
@ 2009-04-02 17:06     ` Blue Swirl
  0 siblings, 0 replies; 61+ messages in thread
From: Blue Swirl @ 2009-04-02 17:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: xen-devel, Gerd Hoffmann

On 4/2/09, Gerd Hoffmann <kraxel@redhat.com> wrote:
> This adds domain building support for paravirtual domains to qemu.
>  This allows booting xen guests directly with qemu, without Xend
>  and the management stack.
>
>  Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>

>  +    /* close all file handles, except stdio/out/err,
>  +     * our watch pipe and the xen interface handle */
>  +    for (i = 3; i < 256; i++) {

You should use getdtablesize() or sysconf(_SC_OPEN_MAX) instead of 256.

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

* Re: [Qemu-devel] [PATCH 00/10] xen: pv domain support.
  2009-04-01 21:39 ` Gerd Hoffmann
@ 2009-04-02 21:14   ` Laurent Vivier
  -1 siblings, 0 replies; 61+ messages in thread
From: Laurent Vivier @ 2009-04-02 21:14 UTC (permalink / raw)
  To: qemu-devel; +Cc: xen-devel, Gerd Hoffmann

Le mercredi 01 avril 2009 à 23:39 +0200, Gerd Hoffmann a écrit :
> Hi,

Hi,

> It's been a while, but after a looooooooooooong time we've (hopefully)
> finally sorted the merging issues with qemu-xen.  So here is a fresh
> version of the xen support for qemu patch series.  Short overview
> (individual patches have longer descriptions):

Could you explain how to use it.

Do you need a xend and xenstored running on the host ?

Regards,
Laurent

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

* Re: [PATCH 00/10] xen: pv domain support.
@ 2009-04-02 21:14   ` Laurent Vivier
  0 siblings, 0 replies; 61+ messages in thread
From: Laurent Vivier @ 2009-04-02 21:14 UTC (permalink / raw)
  To: qemu-devel; +Cc: xen-devel, Gerd Hoffmann

Le mercredi 01 avril 2009 à 23:39 +0200, Gerd Hoffmann a écrit :
> Hi,

Hi,

> It's been a while, but after a looooooooooooong time we've (hopefully)
> finally sorted the merging issues with qemu-xen.  So here is a fresh
> version of the xen support for qemu patch series.  Short overview
> (individual patches have longer descriptions):

Could you explain how to use it.

Do you need a xend and xenstored running on the host ?

Regards,
Laurent

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

* Re: [Qemu-devel] [PATCH 01/10] xen: groundwork for xen support
  2009-04-02 16:37     ` Blue Swirl
  (?)
@ 2009-04-03 19:58     ` Gerd Hoffmann
  -1 siblings, 0 replies; 61+ messages in thread
From: Gerd Hoffmann @ 2009-04-03 19:58 UTC (permalink / raw)
  To: Blue Swirl; +Cc: xen-devel, qemu-devel

Blue Swirl wrote:
> On 4/2/09, Gerd Hoffmann <kraxel@redhat.com> wrote:
>> - configure script and build system changes.
>>  - wind up new machine type.
>>  - add -xen-* command line options.
>>
>>  Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> 
>>  +  $(XEN_OBJS) : CFLAGS += -Wall -Wmissing-prototypes -Wstrict-prototypes
> 
> This should not be necessary, we already use all these flags.

Great, will drop this.

> 
>>  +/*
>>  + * Local variables:
>>  + *  indent-tabs-mode: nil
>>  + *  c-indent-level: 4
>>  + *  c-basic-offset: 4
>>  + *  tab-width: 4
>>  + * End:
>>  + */
> 
> Please remove.

Yep.

cheers,
  Gerd

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

* Re: [Qemu-devel] [PATCH 02/10] xen: backend driver core
  2009-04-02 16:49     ` Blue Swirl
  (?)
@ 2009-04-03 19:59     ` Gerd Hoffmann
  -1 siblings, 0 replies; 61+ messages in thread
From: Gerd Hoffmann @ 2009-04-03 19:59 UTC (permalink / raw)
  To: Blue Swirl; +Cc: xen-devel, qemu-devel

Blue Swirl wrote:
> On 4/2/09, Gerd Hoffmann <kraxel@redhat.com> 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>
> 
>>  + *  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
> 
> The address is now 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

Will fix.

>>  +    if (NULL == node  ||  0 == strcmp(node, "online")) {
>>  +       if (-1 == xenstore_read_be_int(xendev, "online", &xendev->online))
> 
> This style is alien.

Oops.  Still one of them.  I though I've killed them all, will check again.

cheers,
  Gerd

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

* Re: [Qemu-devel] [PATCH 05/10] xen: add block device backend driver.
  2009-04-02 17:02   ` [Qemu-devel] " Christoph Hellwig
@ 2009-04-03 20:11     ` Gerd Hoffmann
  2009-04-05 13:49     ` Anthony Liguori
  2009-04-07 10:22     ` Gerd Hoffmann
  2 siblings, 0 replies; 61+ messages in thread
From: Gerd Hoffmann @ 2009-04-03 20:11 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: xen-devel, qemu-devel

Christoph Hellwig wrote:
> On Wed, Apr 01, 2009 at 11:39:37PM +0200, Gerd Hoffmann wrote:
>> +static void inline blkif_get_x86_32_req(blkif_request_t *dst, blkif_x86_32_request_t *src)
>> +{
> 
>> +static void inline blkif_get_x86_64_req(blkif_request_t *dst, blkif_x86_64_request_t *src)
>> +{
> 
> I think you'd be better of moving them to the .c file as normal static
> function and leave the inlining decisions to the compiler.

The .h file is a straight copy, thats why I left it as is.  I can
cut&paste it into the source file as well, I don't care that much.

>> +
>> +/*
>> + *  FIXME: the code is designed to handle multiple outstanding
>> + *         requests, which isn't used right now.  Plan is to
>> + *         switch over to the aio block functions once they got
>> + *         vector support.
>> + */
> 
> We already have bdrv_aio_readv/writev which currently linearize the
> buffer underneath.

Right, will adapt and kill the FIXME.

> Hopefully Anthony will have commited the patch to
> implement the real one while I'm writing this, too :)

Linus committed the preadv syscall patches too (abi is not final yet
though).

>> +    if (ioreq->presync)
>> +	bdrv_flush(blkdev->bs); /* FIXME: aio_flush() ??? */

> hdrv_flush doesn't actually empty the aio queues but only issues
> a fsync.  So we could still re-order requeuests around the barrier
> with this implementation.

Thats why there is a FIXME ...

>  I will soon submit a real block-layer level
> barrier implementation that just allows to flag a bdrv_aio_read/write
> request as barrier and deal with this under the hood.

Great.

cheers,
  Gerd

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

* Re: [Qemu-devel] [PATCH 00/10] xen: pv domain support.
  2009-04-02 21:14   ` Laurent Vivier
  (?)
@ 2009-04-03 20:24   ` Gerd Hoffmann
  2009-04-03 23:04       ` Alexander Graf
  -1 siblings, 1 reply; 61+ messages in thread
From: Gerd Hoffmann @ 2009-04-03 20:24 UTC (permalink / raw)
  To: Laurent Vivier; +Cc: xen-devel, qemu-devel

Laurent Vivier wrote:
> Le mercredi 01 avril 2009 à 23:39 +0200, Gerd Hoffmann a écrit :
>> Hi,
> 
> Hi,
> 
>> It's been a while, but after a looooooooooooong time we've (hopefully)
>> finally sorted the merging issues with qemu-xen.  So here is a fresh
>> version of the xen support for qemu patch series.  Short overview
>> (individual patches have longer descriptions):
> 
> Could you explain how to use it.
> 
> Do you need a xend and xenstored running on the host ?

Depends ;)

Long term plan is to have three ways of supporting xen guests in qemu
(pv only for now):

#1: Xen emulation (aka xenner).  No code for this is submitted (yet).
    That will allow running xen kernels in qemu.  No xend, no xenstored
    needed.  Also no Xen hypervisor.

#2: Make qemu attach to an existing domain.  That is the way qemu-dm
    (xenified qemu version) works right now:  xend creates the domain,
    and qemu attaches to it to provide console and framebuffer backend.
    Obviously needs both xend and xenstored.

#3: Make qemu create xen domains.  xenstored is still needed then.  You
    can run without xend though.

#2 works with the first 4 patches applied.
#3 works with all patches applied.
#1 needs more patches which are bitrotting in my git repo right now.
   I'll dig them out once this patchset is merged.

cheers,
  Gerd

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

* Re: [Qemu-devel] [PATCH 00/10] xen: pv domain support.
  2009-04-03 20:24   ` [Qemu-devel] " Gerd Hoffmann
@ 2009-04-03 23:04       ` Alexander Graf
  0 siblings, 0 replies; 61+ messages in thread
From: Alexander Graf @ 2009-04-03 23:04 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: xen-devel, Laurent Vivier, qemu-devel


On 03.04.2009, at 22:24, Gerd Hoffmann wrote:

> Laurent Vivier wrote:
>> Le mercredi 01 avril 2009 à 23:39 +0200, Gerd Hoffmann a écrit :
>>> Hi,
>>
>> Hi,
>>
>>> It's been a while, but after a looooooooooooong time we've  
>>> (hopefully)
>>> finally sorted the merging issues with qemu-xen.  So here is a fresh
>>> version of the xen support for qemu patch series.  Short overview
>>> (individual patches have longer descriptions):
>>
>> Could you explain how to use it.
>>
>> Do you need a xend and xenstored running on the host ?
>
> Depends ;)
>
> Long term plan is to have three ways of supporting xen guests in qemu
> (pv only for now):

One idea I had for full virtualization in a Xen environment would be  
an PV vmenter/vmexit framework - either by implementing a completely  
new abstraction or simple traps for privileged operations like VMRUN.

That way we could have a kvm that talks to xen for the VM, rendering  
kvm useful on Xen dom0s, giving people the best of both worlds.

That was only one of the ideas that came up while talking to people  
why running kvm on xen isn't as easy as just recompiling :-). Would  
you think of such a thing as useful?

Alex

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

* Re: [PATCH 00/10] xen: pv domain support.
@ 2009-04-03 23:04       ` Alexander Graf
  0 siblings, 0 replies; 61+ messages in thread
From: Alexander Graf @ 2009-04-03 23:04 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: xen-devel, Laurent Vivier, qemu-devel


On 03.04.2009, at 22:24, Gerd Hoffmann wrote:

> Laurent Vivier wrote:
>> Le mercredi 01 avril 2009 à 23:39 +0200, Gerd Hoffmann a écrit :
>>> Hi,
>>
>> Hi,
>>
>>> It's been a while, but after a looooooooooooong time we've  
>>> (hopefully)
>>> finally sorted the merging issues with qemu-xen.  So here is a fresh
>>> version of the xen support for qemu patch series.  Short overview
>>> (individual patches have longer descriptions):
>>
>> Could you explain how to use it.
>>
>> Do you need a xend and xenstored running on the host ?
>
> Depends ;)
>
> Long term plan is to have three ways of supporting xen guests in qemu
> (pv only for now):

One idea I had for full virtualization in a Xen environment would be  
an PV vmenter/vmexit framework - either by implementing a completely  
new abstraction or simple traps for privileged operations like VMRUN.

That way we could have a kvm that talks to xen for the VM, rendering  
kvm useful on Xen dom0s, giving people the best of both worlds.

That was only one of the ideas that came up while talking to people  
why running kvm on xen isn't as easy as just recompiling :-). Would  
you think of such a thing as useful?

Alex

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

* Re: [Qemu-devel] [PATCH 00/10] xen: pv domain support.
  2009-04-03 23:04       ` Alexander Graf
  (?)
@ 2009-04-05  8:48       ` Avi Kivity
  2009-04-05 11:17           ` Alexander Graf
  -1 siblings, 1 reply; 61+ messages in thread
From: Avi Kivity @ 2009-04-05  8:48 UTC (permalink / raw)
  To: qemu-devel; +Cc: xen-devel, Gerd Hoffmann, Laurent Vivier

Alexander Graf wrote:
>
> One idea I had for full virtualization in a Xen environment would be 
> an PV vmenter/vmexit framework - either by implementing a completely 
> new abstraction or simple traps for privileged operations like VMRUN.
>
> That way we could have a kvm that talks to xen for the VM, rendering 
> kvm useful on Xen dom0s, giving people the best of both worlds.
>
> That was only one of the ideas that came up while talking to people 
> why running kvm on xen isn't as easy as just recompiling :-). Would 
> you think of such a thing as useful?
>
>

Why would anyone want to do that?  If you've got Xen running, just start 
up a Xen guest.


-- 
I have a truly marvellous patch that fixes the bug which this
signature is too narrow to contain.

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

* Re: [Qemu-devel] [PATCH 00/10] xen: pv domain support.
  2009-04-05  8:48       ` [Qemu-devel] " Avi Kivity
@ 2009-04-05 11:17           ` Alexander Graf
  0 siblings, 0 replies; 61+ messages in thread
From: Alexander Graf @ 2009-04-05 11:17 UTC (permalink / raw)
  To: Avi Kivity; +Cc: qemu-devel, xen-devel, Gerd Hoffmann, Laurent Vivier


On 05.04.2009, at 10:48, Avi Kivity wrote:

> Alexander Graf wrote:
>>
>> One idea I had for full virtualization in a Xen environment would  
>> be an PV vmenter/vmexit framework - either by implementing a  
>> completely new abstraction or simple traps for privileged  
>> operations like VMRUN.
>>
>> That way we could have a kvm that talks to xen for the VM,  
>> rendering kvm useful on Xen dom0s, giving people the best of both  
>> worlds.
>>
>> That was only one of the ideas that came up while talking to people  
>> why running kvm on xen isn't as easy as just recompiling :-). Would  
>> you think of such a thing as useful?
>>
>>
>
> Why would anyone want to do that?  If you've got Xen running, just  
> start up a Xen guest.

I'm not saying it's a great idea - that's why I didn't even consider  
to develop it yet :-).

Basically it would solve two problems:

1) Migration path. If you could already use KVM on a Xen host, you  
could have Xen PV guests and KVM guests in parallel, easing migration  
to KVM for customers.

2) Alternative to HVM. That's how this came up from Gerd's mail. We do  
have KVM support in upstream qemu, but we don't have Xen HVM support.  
That way you could use the same binary for all your needs. Admittedly,  
it might make more sense to just implement HVM support :-).

Again, I just like talking to others about random ideas I have and  
this was one. I don't think it's worth it - IMHO it'd be more useful  
to create an in-kernel xen-like module that exposes Xen PV  
functionality, so you get all the PV benefits without the performance  
hit from full virtualization and duplication of code.

Alex

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

* Re: [PATCH 00/10] xen: pv domain support.
@ 2009-04-05 11:17           ` Alexander Graf
  0 siblings, 0 replies; 61+ messages in thread
From: Alexander Graf @ 2009-04-05 11:17 UTC (permalink / raw)
  To: Avi Kivity; +Cc: qemu-devel, xen-devel, Gerd Hoffmann, Laurent Vivier


On 05.04.2009, at 10:48, Avi Kivity wrote:

> Alexander Graf wrote:
>>
>> One idea I had for full virtualization in a Xen environment would  
>> be an PV vmenter/vmexit framework - either by implementing a  
>> completely new abstraction or simple traps for privileged  
>> operations like VMRUN.
>>
>> That way we could have a kvm that talks to xen for the VM,  
>> rendering kvm useful on Xen dom0s, giving people the best of both  
>> worlds.
>>
>> That was only one of the ideas that came up while talking to people  
>> why running kvm on xen isn't as easy as just recompiling :-). Would  
>> you think of such a thing as useful?
>>
>>
>
> Why would anyone want to do that?  If you've got Xen running, just  
> start up a Xen guest.

I'm not saying it's a great idea - that's why I didn't even consider  
to develop it yet :-).

Basically it would solve two problems:

1) Migration path. If you could already use KVM on a Xen host, you  
could have Xen PV guests and KVM guests in parallel, easing migration  
to KVM for customers.

2) Alternative to HVM. That's how this came up from Gerd's mail. We do  
have KVM support in upstream qemu, but we don't have Xen HVM support.  
That way you could use the same binary for all your needs. Admittedly,  
it might make more sense to just implement HVM support :-).

Again, I just like talking to others about random ideas I have and  
this was one. I don't think it's worth it - IMHO it'd be more useful  
to create an in-kernel xen-like module that exposes Xen PV  
functionality, so you get all the PV benefits without the performance  
hit from full virtualization and duplication of code.

Alex

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

* Re: [Qemu-devel] [PATCH 00/10] xen: pv domain support.
  2009-04-05 11:17           ` Alexander Graf
  (?)
@ 2009-04-05 11:37           ` Avi Kivity
  2009-04-05 12:10               ` Alexander Graf
  2009-04-06 13:56               ` Stefano Stabellini
  -1 siblings, 2 replies; 61+ messages in thread
From: Avi Kivity @ 2009-04-05 11:37 UTC (permalink / raw)
  To: Alexander Graf; +Cc: qemu-devel, xen-devel, Gerd Hoffmann, Laurent Vivier

Alexander Graf wrote:
>
> On 05.04.2009, at 10:48, Avi Kivity wrote:
>
>> Alexander Graf wrote:
>>>
>>> One idea I had for full virtualization in a Xen environment would be 
>>> an PV vmenter/vmexit framework - either by implementing a completely 
>>> new abstraction or simple traps for privileged operations like VMRUN.
>>>
>>> That way we could have a kvm that talks to xen for the VM, rendering 
>>> kvm useful on Xen dom0s, giving people the best of both worlds.
>>>
>>> That was only one of the ideas that came up while talking to people 
>>> why running kvm on xen isn't as easy as just recompiling :-). Would 
>>> you think of such a thing as useful?
>>>
>>>
>>
>> Why would anyone want to do that?  If you've got Xen running, just 
>> start up a Xen guest.
>
> I'm not saying it's a great idea - that's why I didn't even consider 
> to develop it yet :-).
>
> Basically it would solve two problems:
>
> 1) Migration path. If you could already use KVM on a Xen host, you 
> could have Xen PV guests and KVM guests in parallel, easing migration 
> to KVM for customers.

I like this, of course, but we have a path through Xenner.  Maybe this 
(kvm-on-xen) path will be easier to take.

>
> 2) Alternative to HVM. That's how this came up from Gerd's mail. We do 
> have KVM support in upstream qemu, but we don't have Xen HVM support. 
> That way you could use the same binary for all your needs. Admittedly, 
> it might make more sense to just implement HVM support :-).

I was under the impression that this is underway.

>
> Again, I just like talking to others about random ideas I have and 
> this was one. I don't think it's worth it - IMHO it'd be more useful 
> to create an in-kernel xen-like module that exposes Xen PV 
> functionality, so you get all the PV benefits without the performance 
> hit from full virtualization and duplication of code.
>

With npt/ept pv performance might be higher running under kvm+xenner 
than with software-only Xen by letting the guest kernel access 
pagetables directly.  Though Gerd had some issues with 64-bit guests 
IIRC, which is a pity since it's there that the pv performance hit is 
greatest.


-- 
error compiling committee.c: too many arguments to function

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

* Re: [Qemu-devel] [PATCH 00/10] xen: pv domain support.
  2009-04-05 11:37           ` [Qemu-devel] " Avi Kivity
@ 2009-04-05 12:10               ` Alexander Graf
  2009-04-06 13:56               ` Stefano Stabellini
  1 sibling, 0 replies; 61+ messages in thread
From: Alexander Graf @ 2009-04-05 12:10 UTC (permalink / raw)
  To: Avi Kivity; +Cc: qemu-devel, xen-devel, Gerd Hoffmann, Laurent Vivier


On 05.04.2009, at 13:37, Avi Kivity wrote:

> Alexander Graf wrote:
>>
>> On 05.04.2009, at 10:48, Avi Kivity wrote:
>>
>>> Alexander Graf wrote:
>>>>
>>>> One idea I had for full virtualization in a Xen environment would  
>>>> be an PV vmenter/vmexit framework - either by implementing a  
>>>> completely new abstraction or simple traps for privileged  
>>>> operations like VMRUN.
>>>>
>>>> That way we could have a kvm that talks to xen for the VM,  
>>>> rendering kvm useful on Xen dom0s, giving people the best of both  
>>>> worlds.
>>>>
>>>> That was only one of the ideas that came up while talking to  
>>>> people why running kvm on xen isn't as easy as just  
>>>> recompiling :-). Would you think of such a thing as useful?
>>>>
>>>>
>>>
>>> Why would anyone want to do that?  If you've got Xen running, just  
>>> start up a Xen guest.
>>
>> I'm not saying it's a great idea - that's why I didn't even  
>> consider to develop it yet :-).
>>
>> Basically it would solve two problems:
>>
>> 1) Migration path. If you could already use KVM on a Xen host, you  
>> could have Xen PV guests and KVM guests in parallel, easing  
>> migration to KVM for customers.
>
> I like this, of course, but we have a path through Xenner.  Maybe  
> this (kvm-on-xen) path will be easier to take.

Oh, I thought Xenner was semi on hold? Is it still actively developed?  
I thought Gerd's main goal for now was to get qemu-dm into upstream  
qemu for now.

>> 2) Alternative to HVM. That's how this came up from Gerd's mail. We  
>> do have KVM support in upstream qemu, but we don't have Xen HVM  
>> support. That way you could use the same binary for all your needs.  
>> Admittedly, it might make more sense to just implement HVM  
>> support :-).
>
> I was under the impression that this is underway.

Awesome :-).

>> Again, I just like talking to others about random ideas I have and  
>> this was one. I don't think it's worth it - IMHO it'd be more  
>> useful to create an in-kernel xen-like module that exposes Xen PV  
>> functionality, so you get all the PV benefits without the  
>> performance hit from full virtualization and duplication of code.
>>
>
> With npt/ept pv performance might be higher running under kvm+xenner  
> than with software-only Xen by letting the guest kernel access  
> pagetables directly.  Though Gerd had some issues with 64-bit guests  
> IIRC, which is a pity since it's there that the pv performance hit  
> is greatest.

Well that might be true, but I'm not fully convinced yet :-). Either  
way with "current" hardware (pre-Nehalem, pre-Barcelona) PV is still  
faster.
Also, FWIW IO performance on PV Xen is still way superior to KVM.  
Please correct me if I stand wrong there.

Alex

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

* Re: [PATCH 00/10] xen: pv domain support.
@ 2009-04-05 12:10               ` Alexander Graf
  0 siblings, 0 replies; 61+ messages in thread
From: Alexander Graf @ 2009-04-05 12:10 UTC (permalink / raw)
  To: Avi Kivity; +Cc: qemu-devel, xen-devel, Gerd Hoffmann, Laurent Vivier


On 05.04.2009, at 13:37, Avi Kivity wrote:

> Alexander Graf wrote:
>>
>> On 05.04.2009, at 10:48, Avi Kivity wrote:
>>
>>> Alexander Graf wrote:
>>>>
>>>> One idea I had for full virtualization in a Xen environment would  
>>>> be an PV vmenter/vmexit framework - either by implementing a  
>>>> completely new abstraction or simple traps for privileged  
>>>> operations like VMRUN.
>>>>
>>>> That way we could have a kvm that talks to xen for the VM,  
>>>> rendering kvm useful on Xen dom0s, giving people the best of both  
>>>> worlds.
>>>>
>>>> That was only one of the ideas that came up while talking to  
>>>> people why running kvm on xen isn't as easy as just  
>>>> recompiling :-). Would you think of such a thing as useful?
>>>>
>>>>
>>>
>>> Why would anyone want to do that?  If you've got Xen running, just  
>>> start up a Xen guest.
>>
>> I'm not saying it's a great idea - that's why I didn't even  
>> consider to develop it yet :-).
>>
>> Basically it would solve two problems:
>>
>> 1) Migration path. If you could already use KVM on a Xen host, you  
>> could have Xen PV guests and KVM guests in parallel, easing  
>> migration to KVM for customers.
>
> I like this, of course, but we have a path through Xenner.  Maybe  
> this (kvm-on-xen) path will be easier to take.

Oh, I thought Xenner was semi on hold? Is it still actively developed?  
I thought Gerd's main goal for now was to get qemu-dm into upstream  
qemu for now.

>> 2) Alternative to HVM. That's how this came up from Gerd's mail. We  
>> do have KVM support in upstream qemu, but we don't have Xen HVM  
>> support. That way you could use the same binary for all your needs.  
>> Admittedly, it might make more sense to just implement HVM  
>> support :-).
>
> I was under the impression that this is underway.

Awesome :-).

>> Again, I just like talking to others about random ideas I have and  
>> this was one. I don't think it's worth it - IMHO it'd be more  
>> useful to create an in-kernel xen-like module that exposes Xen PV  
>> functionality, so you get all the PV benefits without the  
>> performance hit from full virtualization and duplication of code.
>>
>
> With npt/ept pv performance might be higher running under kvm+xenner  
> than with software-only Xen by letting the guest kernel access  
> pagetables directly.  Though Gerd had some issues with 64-bit guests  
> IIRC, which is a pity since it's there that the pv performance hit  
> is greatest.

Well that might be true, but I'm not fully convinced yet :-). Either  
way with "current" hardware (pre-Nehalem, pre-Barcelona) PV is still  
faster.
Also, FWIW IO performance on PV Xen is still way superior to KVM.  
Please correct me if I stand wrong there.

Alex

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

* Re: [Qemu-devel] [PATCH 00/10] xen: pv domain support.
  2009-04-05 12:10               ` Alexander Graf
  (?)
@ 2009-04-05 12:33               ` Avi Kivity
  2009-04-06  7:39                 ` Gerd Hoffmann
  -1 siblings, 1 reply; 61+ messages in thread
From: Avi Kivity @ 2009-04-05 12:33 UTC (permalink / raw)
  To: Alexander Graf; +Cc: qemu-devel, xen-devel, Gerd Hoffmann, Laurent Vivier

Alexander Graf wrote:
>>>
>>> 1) Migration path. If you could already use KVM on a Xen host, you 
>>> could have Xen PV guests and KVM guests in parallel, easing 
>>> migration to KVM for customers.
>>
>> I like this, of course, but we have a path through Xenner.  Maybe 
>> this (kvm-on-xen) path will be easier to take.
>
> Oh, I thought Xenner was semi on hold? Is it still actively developed? 
> I thought Gerd's main goal for now was to get qemu-dm into upstream 
> qemu for now.

I understood that Xenner is the next thing on the list.

>> With npt/ept pv performance might be higher running under kvm+xenner 
>> than with software-only Xen by letting the guest kernel access 
>> pagetables directly.  Though Gerd had some issues with 64-bit guests 
>> IIRC, which is a pity since it's there that the pv performance hit is 
>> greatest.
>
> Well that might be true, but I'm not fully convinced yet :-). Either 
> way with "current" hardware (pre-Nehalem, pre-Barcelona) PV is still 
> faster.

Right, but every day this is becoming less important.

> Also, FWIW IO performance on PV Xen is still way superior to KVM. 
> Please correct me if I stand wrong there.

We still have some work some work to do on virtio, but bandwidth should 
be comparable.  And it has nothing to do with pv-vs-fv.

-- 
error compiling committee.c: too many arguments to function

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

* Re: [Qemu-devel] [PATCH 05/10] xen: add block device backend driver.
  2009-04-02 17:02   ` [Qemu-devel] " Christoph Hellwig
  2009-04-03 20:11     ` Gerd Hoffmann
@ 2009-04-05 13:49     ` Anthony Liguori
  2009-04-06 12:38       ` Christoph Hellwig
  2009-04-07 10:22     ` Gerd Hoffmann
  2 siblings, 1 reply; 61+ messages in thread
From: Anthony Liguori @ 2009-04-05 13:49 UTC (permalink / raw)
  To: qemu-devel; +Cc: xen-devel, Gerd Hoffmann

Christoph Hellwig wrote:
>
>
> We already have bdrv_aio_readv/writev which currently linearize the
> buffer underneath.  Hopefully Anthony will have commited the patch to
> implement the real one while I'm writing this, too :)
>   

Unless I missed it somehow, I'm still expecting another post from you to 
fix the use-after-free and Win32 issues I raised on the 3/29 posting.

Regards,

Anthony Liguori

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

* Re: [Qemu-devel] [PATCH 00/10] xen: pv domain support.
  2009-04-03 23:04       ` Alexander Graf
  (?)
  (?)
@ 2009-04-06  6:53       ` Gerd Hoffmann
  2009-04-06 20:44           ` Jeremy Fitzhardinge
  -1 siblings, 1 reply; 61+ messages in thread
From: Gerd Hoffmann @ 2009-04-06  6:53 UTC (permalink / raw)
  To: Alexander Graf; +Cc: xen-devel, Laurent Vivier, qemu-devel

Alexander Graf wrote:
> One idea I had for full virtualization in a Xen environment would be an
> PV vmenter/vmexit framework - either by implementing a completely new
> abstraction or simple traps for privileged operations like VMRUN.
>
> That way we could have a kvm that talks to xen for the VM, rendering kvm
> useful on Xen dom0s, giving people the best of both worlds.

Hmm.  I suspect xen's direct paging mode makes that quite intrusive as
the kvm mmu code would have to know about this extra p2m translation
step to get the shadow/ept/ntp tables right.  Given that this most
likely would be a odd and rarely tested use case I don't think this
would be a good idea ...

cheers,
  Gerd

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

* Re: [Qemu-devel] [PATCH 00/10] xen: pv domain support.
  2009-04-05 11:17           ` Alexander Graf
  (?)
  (?)
@ 2009-04-06  7:10           ` Gerd Hoffmann
  -1 siblings, 0 replies; 61+ messages in thread
From: Gerd Hoffmann @ 2009-04-06  7:10 UTC (permalink / raw)
  To: Alexander Graf; +Cc: qemu-devel, xen-devel, Avi Kivity, Laurent Vivier

Alexander Graf wrote:
> 1) Migration path. If you could already use KVM on a Xen host, you could
> have Xen PV guests and KVM guests in parallel, easing migration to KVM
> for customers.

I still plan to make xenner handle that use case.
You can also run xen inside kvm via nested svm.

> 2) Alternative to HVM. That's how this came up from Gerd's mail. We do
> have KVM support in upstream qemu, but we don't have Xen HVM support.
> That way you could use the same binary for all your needs. Admittedly,
> it might make more sense to just implement HVM support :-).

HVM is more difficuilt.  Xen considers the tools <-> hypervisor
interface private, i.e. it is a moving target.  For PV this isn't a big
issue as there is little reason to actually change something.  HVM
usually has quite a few changes from release to release though, due to
emulation changes/improvements and other reasons.

cheers,
  Gerd

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

* Re: [Qemu-devel] [PATCH 00/10] xen: pv domain support.
  2009-04-05 12:33               ` [Qemu-devel] " Avi Kivity
@ 2009-04-06  7:39                 ` Gerd Hoffmann
  0 siblings, 0 replies; 61+ messages in thread
From: Gerd Hoffmann @ 2009-04-06  7:39 UTC (permalink / raw)
  To: Avi Kivity; +Cc: qemu-devel, xen-devel, Alexander Graf, Laurent Vivier

Avi Kivity wrote:
> Alexander Graf wrote:
>> Oh, I thought Xenner was semi on hold? Is it still actively developed?
>> I thought Gerd's main goal for now was to get qemu-dm into upstream
>> qemu for now.
> 
> I understood that Xenner is the next thing on the list.

qemu-dm code is (largely) backend drivers, which are shared between xen
and xenner.  Thus this needs to be in first, before the xenner bits can
follow.  Now that this is mostly sorted I wanna un-stall the work on
merging xenner.

cheers,
  Gerd

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

* Re: [Qemu-devel] [PATCH 05/10] xen: add block device backend driver.
  2009-04-05 13:49     ` Anthony Liguori
@ 2009-04-06 12:38       ` Christoph Hellwig
  0 siblings, 0 replies; 61+ messages in thread
From: Christoph Hellwig @ 2009-04-06 12:38 UTC (permalink / raw)
  To: qemu-devel; +Cc: xen-devel, Gerd Hoffmann

On Sun, Apr 05, 2009 at 08:49:54AM -0500, Anthony Liguori wrote:
> Christoph Hellwig wrote:
> >
> >
> >We already have bdrv_aio_readv/writev which currently linearize the
> >buffer underneath.  Hopefully Anthony will have commited the patch to
> >implement the real one while I'm writing this, too :)
> >  
> 
> Unless I missed it somehow, I'm still expecting another post from you to 
> fix the use-after-free and Win32 issues I raised on the 3/29 posting.

I assumes you wanted to fix the use after free that we found inline, but
I'll resend the series now.  After your removal the patch doesn't touch
win32 code anymore and I used the mingw32 cross-compiler to verify that
it still builds (it doesn't link either with or without my patches,
though)

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

* Re: [Xen-devel] Re: [Qemu-devel] [PATCH 00/10] xen: pv domain support.
  2009-04-05 11:37           ` [Qemu-devel] " Avi Kivity
@ 2009-04-06 13:56               ` Stefano Stabellini
  2009-04-06 13:56               ` Stefano Stabellini
  1 sibling, 0 replies; 61+ messages in thread
From: Stefano Stabellini @ 2009-04-06 13:56 UTC (permalink / raw)
  To: Avi Kivity
  Cc: Laurent Vivier, xen-devel, Gerd Hoffmann, Alexander Graf, qemu-devel

Avi Kivity wrote:

>>> 2) Alternative to HVM. That's how this came up from Gerd's mail. We do 
>> have KVM support in upstream qemu, but we don't have Xen HVM support. 
>> That way you could use the same binary for all your needs. Admittedly, 
>> it might make more sense to just implement HVM support :-).
> 
> I was under the impression that this is underway.
> 

We certainly want to do it, we just haven't got the time yet.
After Gerd's patches get accepted I think it won't take too long to
create a similar patchqueue for hvm, the two tree are getting closer and
closer every month.

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

* Re: Re: [Qemu-devel] [PATCH 00/10] xen: pv domain support.
@ 2009-04-06 13:56               ` Stefano Stabellini
  0 siblings, 0 replies; 61+ messages in thread
From: Stefano Stabellini @ 2009-04-06 13:56 UTC (permalink / raw)
  To: Avi Kivity
  Cc: Laurent Vivier, xen-devel, Gerd Hoffmann, Alexander Graf, qemu-devel

Avi Kivity wrote:

>>> 2) Alternative to HVM. That's how this came up from Gerd's mail. We do 
>> have KVM support in upstream qemu, but we don't have Xen HVM support. 
>> That way you could use the same binary for all your needs. Admittedly, 
>> it might make more sense to just implement HVM support :-).
> 
> I was under the impression that this is underway.
> 

We certainly want to do it, we just haven't got the time yet.
After Gerd's patches get accepted I think it won't take too long to
create a similar patchqueue for hvm, the two tree are getting closer and
closer every month.

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

* Re: [Xen-devel] Re: [Qemu-devel] [PATCH 00/10] xen: pv domain support.
  2009-04-06  6:53       ` Gerd Hoffmann
@ 2009-04-06 20:44           ` Jeremy Fitzhardinge
  0 siblings, 0 replies; 61+ messages in thread
From: Jeremy Fitzhardinge @ 2009-04-06 20:44 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel, xen-devel, Alexander Graf, Laurent Vivier

Gerd Hoffmann wrote:
> Hmm.  I suspect xen's direct paging mode makes that quite intrusive as
> the kvm mmu code would have to know about this extra p2m translation
> step to get the shadow/ept/ntp tables right.  Given that this most
> likely would be a odd and rarely tested use case I don't think this
> would be a good idea ...
>   

That's mostly encapsulated in the normal pagetable manipulation 
routines, so if kvm can be convinced to use those to manage its shadow 
tables, it will all Just Work.  That doesn't work well with a non-PAE 
32-bit host with kvm's PAE shadow pagetables, but Xen doesn't support 
non-PAE anyway.

    J

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

* Re: Re: [Qemu-devel] [PATCH 00/10] xen: pv domain support.
@ 2009-04-06 20:44           ` Jeremy Fitzhardinge
  0 siblings, 0 replies; 61+ messages in thread
From: Jeremy Fitzhardinge @ 2009-04-06 20:44 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel, xen-devel, Alexander Graf, Laurent Vivier

Gerd Hoffmann wrote:
> Hmm.  I suspect xen's direct paging mode makes that quite intrusive as
> the kvm mmu code would have to know about this extra p2m translation
> step to get the shadow/ept/ntp tables right.  Given that this most
> likely would be a odd and rarely tested use case I don't think this
> would be a good idea ...
>   

That's mostly encapsulated in the normal pagetable manipulation 
routines, so if kvm can be convinced to use those to manage its shadow 
tables, it will all Just Work.  That doesn't work well with a non-PAE 
32-bit host with kvm's PAE shadow pagetables, but Xen doesn't support 
non-PAE anyway.

    J

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

* Re: [Qemu-devel] [PATCH 05/10] xen: add block device backend driver.
  2009-04-02 17:02   ` [Qemu-devel] " Christoph Hellwig
  2009-04-03 20:11     ` Gerd Hoffmann
  2009-04-05 13:49     ` Anthony Liguori
@ 2009-04-07 10:22     ` Gerd Hoffmann
  2009-04-07 15:51       ` Christoph Hellwig
  2 siblings, 1 reply; 61+ messages in thread
From: Gerd Hoffmann @ 2009-04-07 10:22 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: xen-devel, qemu-devel

   Hi,

> We already have bdrv_aio_readv/writev which currently linearize the
> buffer underneath.  Hopefully Anthony will have commited the patch to
> implement the real one while I'm writing this, too :)

Is there any specific reason to keep the nb_sectors argument for 
bdrv_aio_readv, other than cut&paste from the non-vectored versions?
I think it is superfluous now, it can be trivially calculated using 
iov->size.

cheers,
   Gerd

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

* Re: [Qemu-devel] [PATCH 05/10] xen: add block device backend driver.
  2009-04-07 10:22     ` Gerd Hoffmann
@ 2009-04-07 15:51       ` Christoph Hellwig
  0 siblings, 0 replies; 61+ messages in thread
From: Christoph Hellwig @ 2009-04-07 15:51 UTC (permalink / raw)
  To: qemu-devel; +Cc: xen-devel, Christoph Hellwig

On Tue, Apr 07, 2009 at 12:22:00PM +0200, Gerd Hoffmann wrote:
>   Hi,
> 
> >We already have bdrv_aio_readv/writev which currently linearize the
> >buffer underneath.  Hopefully Anthony will have commited the patch to
> >implement the real one while I'm writing this, too :)
> 
> Is there any specific reason to keep the nb_sectors argument for 
> bdrv_aio_readv, other than cut&paste from the non-vectored versions?
> I think it is superfluous now, it can be trivially calculated using 
> iov->size.

For the functions in block.c I want to keep them the same as they were
before, and for the methods I want to keep the signature the same as
the exported wrappers.

All this is going to change pretty soon I hope, we'll need another
argument to bdrv_aio_write for barrier writes, and I might switch to
a completely byte based interface for the aio requests with flags
in the block driver state for flagging the alignment restrictions.

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

* [Qemu-devel] [PATCH 01/10] xen: groundwork for xen support
  2009-04-21 12:19 [Qemu-devel] [PATCH 00/10] xen: pv domain support Gerd Hoffmann
@ 2009-04-21 12:19 ` Gerd Hoffmann
  0 siblings, 0 replies; 61+ messages in thread
From: Gerd Hoffmann @ 2009-04-21 12:19 UTC (permalink / raw)
  To: qemu-devel, xen-devel; +Cc: Gerd Hoffmann

- configure script and build system changes.
- wind up new machine type.
- add -xen-* command line options.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 Makefile.target       |    7 +++++
 configure             |   34 +++++++++++++++++++++++++++
 hw/boards.h           |    3 ++
 hw/xen.h              |   20 ++++++++++++++++
 hw/xen_machine_pv.c   |   60 +++++++++++++++++++++++++++++++++++++++++++++++++
 qemu-options.hx       |   11 +++++++++
 target-i386/machine.c |    3 ++
 vl.c                  |   12 +++++++++
 8 files changed, 150 insertions(+), 0 deletions(-)
 create mode 100644 hw/xen.h
 create mode 100644 hw/xen_machine_pv.c

diff --git a/Makefile.target b/Makefile.target
index b27696a..ab59af3 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -560,6 +560,13 @@ ifdef CONFIG_BLUEZ
 LIBS += $(CONFIG_BLUEZ_LIBS)
 endif
 
+# xen backend driver support
+XEN_OBJS := xen_machine_pv.o
+ifeq ($(CONFIG_XEN), yes)
+  OBJS += $(XEN_OBJS)
+  LIBS += $(XEN_LIBS)
+endif
+
 # SCSI layer
 OBJS+= lsi53c895a.o esp.o
 
diff --git a/configure b/configure
index 8bf44de..ec761ff 100755
--- a/configure
+++ b/configure
@@ -191,6 +191,7 @@ aix="no"
 blobs="yes"
 fdt="yes"
 sdl_x11="no"
+xen="yes"
 pkgversion=""
 
 # OS specific
@@ -421,6 +422,8 @@ for opt do
   ;;
   --disable-kqemu) kqemu="no"
   ;;
+  --disable-xen) xen="no"
+  ;;
   --disable-brlapi) brlapi="no"
   ;;
   --disable-bluez) bluez="no"
@@ -586,6 +589,7 @@ echo "                           Available drivers: $audio_possible_drivers"
 echo "  --audio-card-list=LIST   set list of emulated audio cards [$audio_card_list]"
 echo "                           Available cards: $audio_possible_cards"
 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-vnc-sasl       disable SASL encryption for VNC server"
@@ -802,6 +806,22 @@ else
 fi
 
 ##########################################
+# xen probe
+
+if test "$xen" = "yes" ; then
+cat > $TMPC <<EOF
+#include <xenctrl.h>
+#include <xs.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
@@ -1296,6 +1316,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" ] && \
@@ -1612,6 +1633,9 @@ if test "$bluez" = "yes" ; then
   echo "CONFIG_BLUEZ_LIBS=$bluez_libs" >> $config_mak
   echo "#define CONFIG_BLUEZ 1" >> $config_h
 fi
+if test "$xen" = "yes" ; then
+  echo "XEN_LIBS=-lxenstore -lxenctrl" >> $config_mak
+fi
 if test "$aio" = "yes" ; then
   echo "#define CONFIG_AIO 1" >> $config_h
   echo "CONFIG_AIO=yes" >> $config_mak
@@ -1777,6 +1801,11 @@ case "$target_cpu" in
       echo "KVM_CFLAGS=$kvm_cflags" >> $config_mak
       echo "#define CONFIG_KVM 1" >> $config_h
     fi
+    if test "$xen" = "yes" -a "$target_softmmu" = "yes";
+    then
+      echo "CONFIG_XEN=yes" >> $config_mak
+      echo "#define CONFIG_XEN 1" >> $config_h
+    fi
   ;;
   x86_64)
     echo "TARGET_ARCH=x86_64" >> $config_mak
@@ -1793,6 +1822,11 @@ case "$target_cpu" in
       echo "KVM_CFLAGS=$kvm_cflags" >> $config_mak
       echo "#define CONFIG_KVM 1" >> $config_h
     fi
+    if test "$xen" = "yes" -a "$target_softmmu" = "yes"
+    then
+      echo "CONFIG_XEN=yes" >> $config_mak
+      echo "#define CONFIG_XEN 1" >> $config_h
+    fi
   ;;
   alpha)
     echo "TARGET_ARCH=alpha" >> $config_mak
diff --git a/hw/boards.h b/hw/boards.h
index 7fada94..5611d2c 100644
--- a/hw/boards.h
+++ b/hw/boards.h
@@ -32,6 +32,9 @@ extern QEMUMachine axisdev88_machine;
 extern QEMUMachine pc_machine;
 extern QEMUMachine isapc_machine;
 
+/* xen_machine.c */
+extern QEMUMachine xenpv_machine;
+
 /* ppc.c */
 extern QEMUMachine prep_machine;
 extern QEMUMachine core99_machine;
diff --git a/hw/xen.h b/hw/xen.h
new file mode 100644
index 0000000..3c8da41
--- /dev/null
+++ b/hw/xen.h
@@ -0,0 +1,20 @@
+#ifndef QEMU_HW_XEN_H
+#define QEMU_HW_XEN_H 1
+/*
+ * public xen header
+ *   stuff needed outside xen-*.c, i.e. interfaces to qemu.
+ *   must not depend on any xen headers being present in
+ *   /usr/include/xen, so it can be included unconditionally.
+ */
+
+/* xen-machine.c */
+enum xen_mode {
+    XEN_EMULATE = 0,  // xen emulation, using xenner (default)
+    XEN_CREATE,       // create xen domain
+    XEN_ATTACH        // attach to xen domain created by xend
+};
+
+extern uint32_t xen_domid;
+extern enum xen_mode xen_mode;
+
+#endif /* QEMU_HW_XEN_H */
diff --git a/hw/xen_machine_pv.c b/hw/xen_machine_pv.c
new file mode 100644
index 0000000..f32ba7f
--- /dev/null
+++ b/hw/xen_machine_pv.c
@@ -0,0 +1,60 @@
+/*
+ * QEMU Xen PV Machine
+ *
+ * Copyright (c) 2007 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 "pc.h"
+#include "sysemu.h"
+#include "boards.h"
+#include "xen.h"
+
+uint32_t xen_domid;
+enum xen_mode xen_mode = XEN_EMULATE;
+
+static void xen_init_pv(ram_addr_t ram_size, int vga_ram_size,
+			const char *boot_device,
+			const char *kernel_filename,
+			const char *kernel_cmdline,
+			const char *initrd_filename,
+			const char *cpu_model)
+{
+    CPUState *env;
+
+    /* Initialize a dummy CPU */
+    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 = {
+    .name = "xenpv",
+    .desc = "Xen Para-virtualized PC",
+    .init = xen_init_pv,
+    .max_cpus = 1,
+};
diff --git a/qemu-options.hx b/qemu-options.hx
index 1d783e5..1f78021 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1333,6 +1333,17 @@ Enable KVM full virtualization support. This option is only available
 if KVM support is enabled when compiling.
 ETEXI
 
+#ifdef CONFIG_XEN
+DEF("xen-domid", HAS_ARG, QEMU_OPTION_xen_domid,
+    "-xen-domid id   specify xen guest domain id\n")
+DEF("xen-create", 0, QEMU_OPTION_xen_create,
+    "-xen-create     create domain using xen hypercalls, bypassing xend\n"
+    "                warning: should not be used when xend is in use\n")
+DEF("xen-attach", 0, QEMU_OPTION_xen_attach,
+    "-xen-attach     attach to existing xen domain\n"
+    "                xend will use this when starting qemu\n")
+#endif
+
 DEF("no-reboot", 0, QEMU_OPTION_no_reboot, \
     "-no-reboot      exit instead of rebooting\n")
 STEXI
diff --git a/target-i386/machine.c b/target-i386/machine.c
index 1cf49d5..1b0d36d 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 55a9bc5..b681775 100644
--- a/vl.c
+++ b/vl.c
@@ -139,6 +139,7 @@ int main(int argc, char **argv)
 #include "hw/baum.h"
 #include "hw/bt.h"
 #include "hw/smbios.h"
+#include "hw/xen.h"
 #include "bt-host.h"
 #include "net.h"
 #include "monitor.h"
@@ -4972,6 +4973,17 @@ int main(int argc, char **argv, char **envp)
                 run_as = optarg;
                 break;
 #endif
+#ifdef CONFIG_XEN
+            case QEMU_OPTION_xen_domid:
+                xen_domid = atoi(optarg);
+                break;
+            case QEMU_OPTION_xen_create:
+                xen_mode = XEN_CREATE;
+                break;
+            case QEMU_OPTION_xen_attach:
+                xen_mode = XEN_ATTACH;
+                break;
+#endif
             }
         }
     }
-- 
1.6.2.2

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

* [Qemu-devel] [PATCH 01/10] xen: groundwork for xen support
  2009-04-07 14:44 Gerd Hoffmann
@ 2009-04-07 14:44 ` Gerd Hoffmann
  0 siblings, 0 replies; 61+ messages in thread
From: Gerd Hoffmann @ 2009-04-07 14:44 UTC (permalink / raw)
  To: qemu-devel, xen-devel; +Cc: Gerd Hoffmann

- configure script and build system changes.
- wind up new machine type.
- add -xen-* command line options.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 Makefile.target       |    7 +++++
 configure             |   34 +++++++++++++++++++++++++++
 hw/boards.h           |    3 ++
 hw/xen.h              |   20 ++++++++++++++++
 hw/xen_machine_pv.c   |   61 +++++++++++++++++++++++++++++++++++++++++++++++++
 qemu-options.hx       |   11 +++++++++
 target-i386/machine.c |    3 ++
 vl.c                  |   12 +++++++++
 8 files changed, 151 insertions(+), 0 deletions(-)
 create mode 100644 hw/xen.h
 create mode 100644 hw/xen_machine_pv.c

diff --git a/Makefile.target b/Makefile.target
index b32d1af..1cad75e 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -557,6 +557,13 @@ ifdef CONFIG_BLUEZ
 LIBS += $(CONFIG_BLUEZ_LIBS)
 endif
 
+# xen backend driver support
+XEN_OBJS := xen_machine_pv.o
+ifeq ($(CONFIG_XEN), yes)
+  OBJS += $(XEN_OBJS)
+  LIBS += $(XEN_LIBS)
+endif
+
 # SCSI layer
 OBJS+= lsi53c895a.o esp.o
 
diff --git a/configure b/configure
index 15b7856..252d90c 100755
--- a/configure
+++ b/configure
@@ -190,6 +190,7 @@ aix="no"
 blobs="yes"
 fdt="yes"
 sdl_x11="no"
+xen="yes"
 
 # OS specific
 if check_define __linux__ ; then
@@ -409,6 +410,8 @@ for opt do
   ;;
   --disable-kqemu) kqemu="no"
   ;;
+  --disable-xen) xen="no"
+  ;;
   --disable-brlapi) brlapi="no"
   ;;
   --disable-bluez) bluez="no"
@@ -568,6 +571,7 @@ echo "                           Available drivers: $audio_possible_drivers"
 echo "  --audio-card-list=LIST   set list of emulated audio cards [$audio_card_list]"
 echo "                           Available cards: $audio_possible_cards"
 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-vnc-sasl       disable SASL encryption for VNC server"
@@ -781,6 +785,22 @@ else
 fi
 
 ##########################################
+# xen probe
+
+if test "$xen" = "yes" ; then
+cat > $TMPC <<EOF
+#include <xenctrl.h>
+#include <xs.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
@@ -1211,6 +1231,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" ] && \
@@ -1512,6 +1533,9 @@ if test "$bluez" = "yes" ; then
   echo "CONFIG_BLUEZ_LIBS=$bluez_libs" >> $config_mak
   echo "#define CONFIG_BLUEZ 1" >> $config_h
 fi
+if test "$xen" = "yes" ; then
+  echo "XEN_LIBS=-lxenstore -lxenctrl" >> $config_mak
+fi
 if test "$aio" = "yes" ; then
   echo "#define CONFIG_AIO 1" >> $config_h
   echo "CONFIG_AIO=yes" >> $config_mak
@@ -1673,6 +1697,11 @@ case "$target_cpu" in
       echo "KVM_CFLAGS=$kvm_cflags" >> $config_mak
       echo "#define CONFIG_KVM 1" >> $config_h
     fi
+    if test "$xen" = "yes" -a "$target_softmmu" = "yes";
+    then
+      echo "CONFIG_XEN=yes" >> $config_mak
+      echo "#define CONFIG_XEN 1" >> $config_h
+    fi
   ;;
   x86_64)
     echo "TARGET_ARCH=x86_64" >> $config_mak
@@ -1688,6 +1717,11 @@ case "$target_cpu" in
       echo "KVM_CFLAGS=$kvm_cflags" >> $config_mak
       echo "#define CONFIG_KVM 1" >> $config_h
     fi
+    if test "$xen" = "yes" -a "$target_softmmu" = "yes"
+    then
+      echo "CONFIG_XEN=yes" >> $config_mak
+      echo "#define CONFIG_XEN 1" >> $config_h
+    fi
   ;;
   alpha)
     echo "TARGET_ARCH=alpha" >> $config_mak
diff --git a/hw/boards.h b/hw/boards.h
index 1e18ba6..215ccdc 100644
--- a/hw/boards.h
+++ b/hw/boards.h
@@ -34,6 +34,9 @@ extern QEMUMachine axisdev88_machine;
 extern QEMUMachine pc_machine;
 extern QEMUMachine isapc_machine;
 
+/* xen_machine.c */
+extern QEMUMachine xenpv_machine;
+
 /* ppc.c */
 extern QEMUMachine prep_machine;
 extern QEMUMachine core99_machine;
diff --git a/hw/xen.h b/hw/xen.h
new file mode 100644
index 0000000..3c8da41
--- /dev/null
+++ b/hw/xen.h
@@ -0,0 +1,20 @@
+#ifndef QEMU_HW_XEN_H
+#define QEMU_HW_XEN_H 1
+/*
+ * public xen header
+ *   stuff needed outside xen-*.c, i.e. interfaces to qemu.
+ *   must not depend on any xen headers being present in
+ *   /usr/include/xen, so it can be included unconditionally.
+ */
+
+/* xen-machine.c */
+enum xen_mode {
+    XEN_EMULATE = 0,  // xen emulation, using xenner (default)
+    XEN_CREATE,       // create xen domain
+    XEN_ATTACH        // attach to xen domain created by xend
+};
+
+extern uint32_t xen_domid;
+extern enum xen_mode xen_mode;
+
+#endif /* QEMU_HW_XEN_H */
diff --git a/hw/xen_machine_pv.c b/hw/xen_machine_pv.c
new file mode 100644
index 0000000..081df0b
--- /dev/null
+++ b/hw/xen_machine_pv.c
@@ -0,0 +1,61 @@
+/*
+ * QEMU Xen PV Machine
+ *
+ * Copyright (c) 2007 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 "pc.h"
+#include "sysemu.h"
+#include "boards.h"
+#include "xen.h"
+
+uint32_t xen_domid;
+enum xen_mode xen_mode = XEN_EMULATE;
+
+static void xen_init_pv(ram_addr_t ram_size, int vga_ram_size,
+			const char *boot_device,
+			const char *kernel_filename,
+			const char *kernel_cmdline,
+			const char *initrd_filename,
+			const char *cpu_model)
+{
+    CPUState *env;
+
+    /* Initialize a dummy CPU */
+    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 = {
+    .name = "xenpv",
+    .desc = "Xen Para-virtualized PC",
+    .init = xen_init_pv,
+    .ram_require = (4 * 1024 * 1024) | RAMSIZE_FIXED,
+    .max_cpus = 1,
+};
diff --git a/qemu-options.hx b/qemu-options.hx
index c40ea1e..9fc0625 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1305,6 +1305,17 @@ Enable KVM full virtualization support. This option is only available
 if KVM support is enabled when compiling.
 ETEXI
 
+#ifdef CONFIG_XEN
+DEF("xen-domid", HAS_ARG, QEMU_OPTION_xen_domid,
+    "-xen-domid id   specify xen guest domain id\n")
+DEF("xen-create", 0, QEMU_OPTION_xen_create,
+    "-xen-create     create domain using xen hypercalls, bypassing xend\n"
+    "                warning: should not be used when xend is in use\n")
+DEF("xen-attach", 0, QEMU_OPTION_xen_attach,
+    "-xen-attach     attach to existing xen domain\n"
+    "                xend will use this when starting qemu\n")
+#endif
+
 DEF("no-reboot", 0, QEMU_OPTION_no_reboot, \
     "-no-reboot      exit instead of rebooting\n")
 STEXI
diff --git a/target-i386/machine.c b/target-i386/machine.c
index 1cf49d5..1b0d36d 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 4bd173f..889aaf6 100644
--- a/vl.c
+++ b/vl.c
@@ -138,6 +138,7 @@ int main(int argc, char **argv)
 #include "hw/isa.h"
 #include "hw/baum.h"
 #include "hw/bt.h"
+#include "hw/xen.h"
 #include "bt-host.h"
 #include "net.h"
 #include "monitor.h"
@@ -4949,6 +4950,17 @@ int main(int argc, char **argv, char **envp)
                 run_as = optarg;
                 break;
 #endif
+#ifdef CONFIG_XEN
+            case QEMU_OPTION_xen_domid:
+                xen_domid = atoi(optarg);
+                break;
+            case QEMU_OPTION_xen_create:
+                xen_mode = XEN_CREATE;
+                break;
+            case QEMU_OPTION_xen_attach:
+                xen_mode = XEN_ATTACH;
+                break;
+#endif
             }
         }
     }
-- 
1.6.2.2

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

end of thread, other threads:[~2009-04-21 12:20 UTC | newest]

Thread overview: 61+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-04-01 21:39 [Qemu-devel] [PATCH 00/10] xen: pv domain support Gerd Hoffmann
2009-04-01 21:39 ` Gerd Hoffmann
2009-04-01 21:39 ` [Qemu-devel] [PATCH 01/10] xen: groundwork for xen support Gerd Hoffmann
2009-04-01 21:39   ` Gerd Hoffmann
2009-04-02 16:37   ` [Qemu-devel] " Blue Swirl
2009-04-02 16:37     ` Blue Swirl
2009-04-03 19:58     ` [Qemu-devel] " Gerd Hoffmann
2009-04-01 21:39 ` [Qemu-devel] [PATCH 02/10] xen: backend driver core Gerd Hoffmann
2009-04-01 21:39   ` Gerd Hoffmann
2009-04-02 16:49   ` [Qemu-devel] " Blue Swirl
2009-04-02 16:49     ` Blue Swirl
2009-04-03 19:59     ` [Qemu-devel] " Gerd Hoffmann
2009-04-01 21:39 ` [Qemu-devel] [PATCH 03/10] xen: add console backend driver Gerd Hoffmann
2009-04-01 21:39   ` Gerd Hoffmann
2009-04-01 21:39 ` [Qemu-devel] [PATCH 04/10] xen: add framebuffer " Gerd Hoffmann
2009-04-01 21:39   ` Gerd Hoffmann
2009-04-02 16:57   ` [Qemu-devel] " Blue Swirl
2009-04-02 16:57     ` Blue Swirl
2009-04-01 21:39 ` [Qemu-devel] [PATCH 05/10] xen: add block device " Gerd Hoffmann
2009-04-01 21:39   ` Gerd Hoffmann
2009-04-02 17:02   ` [Qemu-devel] " Christoph Hellwig
2009-04-03 20:11     ` Gerd Hoffmann
2009-04-05 13:49     ` Anthony Liguori
2009-04-06 12:38       ` Christoph Hellwig
2009-04-07 10:22     ` Gerd Hoffmann
2009-04-07 15:51       ` Christoph Hellwig
2009-04-01 21:39 ` [Qemu-devel] [PATCH 06/10] xen: add net " Gerd Hoffmann
2009-04-01 21:39   ` Gerd Hoffmann
2009-04-01 21:39 ` [Qemu-devel] [PATCH 07/10] xen: blk & nic configuration via cmd line Gerd Hoffmann
2009-04-01 21:39   ` Gerd Hoffmann
2009-04-01 21:39 ` [Qemu-devel] [PATCH 08/10] xen: pv domain builder Gerd Hoffmann
2009-04-01 21:39   ` Gerd Hoffmann
2009-04-02 17:06   ` [Qemu-devel] " Blue Swirl
2009-04-02 17:06     ` Blue Swirl
2009-04-01 21:39 ` [Qemu-devel] [PATCH 09/10] simplify vga selection Gerd Hoffmann
2009-04-01 21:39   ` Gerd Hoffmann
2009-04-01 21:39 ` [Qemu-devel] [PATCH 10/10] xen: add -vga xenfb option, configure xenfb Gerd Hoffmann
2009-04-01 21:39   ` Gerd Hoffmann
2009-04-01 23:41 ` [Qemu-devel] [PATCH 00/10] xen: pv domain support Anthony Liguori
2009-04-02 15:32   ` Ian Jackson
2009-04-02 21:14 ` Laurent Vivier
2009-04-02 21:14   ` Laurent Vivier
2009-04-03 20:24   ` [Qemu-devel] " Gerd Hoffmann
2009-04-03 23:04     ` Alexander Graf
2009-04-03 23:04       ` Alexander Graf
2009-04-05  8:48       ` [Qemu-devel] " Avi Kivity
2009-04-05 11:17         ` Alexander Graf
2009-04-05 11:17           ` Alexander Graf
2009-04-05 11:37           ` [Qemu-devel] " Avi Kivity
2009-04-05 12:10             ` Alexander Graf
2009-04-05 12:10               ` Alexander Graf
2009-04-05 12:33               ` [Qemu-devel] " Avi Kivity
2009-04-06  7:39                 ` Gerd Hoffmann
2009-04-06 13:56             ` [Xen-devel] " Stefano Stabellini
2009-04-06 13:56               ` Stefano Stabellini
2009-04-06  7:10           ` Gerd Hoffmann
2009-04-06  6:53       ` Gerd Hoffmann
2009-04-06 20:44         ` [Xen-devel] " Jeremy Fitzhardinge
2009-04-06 20:44           ` Jeremy Fitzhardinge
2009-04-07 14:44 Gerd Hoffmann
2009-04-07 14:44 ` [Qemu-devel] [PATCH 01/10] xen: groundwork for xen support Gerd Hoffmann
2009-04-21 12:19 [Qemu-devel] [PATCH 00/10] xen: pv domain support Gerd Hoffmann
2009-04-21 12:19 ` [Qemu-devel] [PATCH 01/10] xen: groundwork for xen support Gerd Hoffmann

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.