summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--MAINTAINERS9
-rw-r--r--Makefile1
-rw-r--r--Makefile.objs6
-rw-r--r--Makefile.target2
-rw-r--r--QMP/qmp.py6
-rwxr-xr-xQMP/qom-get67
-rwxr-xr-xQMP/qom-list64
-rwxr-xr-xQMP/qom-set64
-rw-r--r--blockdev.c3
-rw-r--r--console.c26
-rw-r--r--console.h2
-rw-r--r--default-configs/i386-softmmu.mak1
-rw-r--r--default-configs/mips-softmmu.mak1
-rw-r--r--default-configs/mips64-softmmu.mak1
-rw-r--r--default-configs/mips64el-softmmu.mak1
-rw-r--r--default-configs/mipsel-softmmu.mak1
-rw-r--r--default-configs/x86_64-softmmu.mak1
-rw-r--r--hw/baum.c7
-rw-r--r--hw/baum.h2
-rw-r--r--hw/boards.h1
-rw-r--r--hw/jazz_led.c177
-rw-r--r--hw/mips.h3
-rw-r--r--hw/mips_jazz.c2
-rw-r--r--hw/msmouse.c5
-rw-r--r--hw/msmouse.h2
-rw-r--r--hw/pc.c56
-rw-r--r--hw/pc.h3
-rw-r--r--hw/pc_piix.c62
-rw-r--r--hw/pc_sysfw.c254
-rw-r--r--hw/pci.c15
-rw-r--r--hw/pci.h61
-rw-r--r--hw/pflash_cfi01.c44
-rw-r--r--hw/pflash_cfi02.c83
-rw-r--r--hw/qdev-properties.c186
-rw-r--r--hw/qxl-render.c12
-rw-r--r--hw/qxl.c109
-rw-r--r--hw/qxl.h4
-rw-r--r--include/qemu/object.h28
-rw-r--r--monitor.c9
-rw-r--r--qapi/qapi-visit-core.c51
-rw-r--r--qapi/qapi-visit-impl.h23
-rw-r--r--qapi/qmp-input-visitor.c39
-rw-r--r--qapi/qmp-output-visitor.c22
-rw-r--r--qapi/string-input-visitor.c138
-rw-r--r--qapi/string-input-visitor.h25
-rw-r--r--qapi/string-output-visitor.c89
-rw-r--r--qapi/string-output-visitor.h26
-rw-r--r--qemu-char.c140
-rw-r--r--qemu-config.c12
-rw-r--r--qemu-sockets.c55
-rw-r--r--qmp-commands.hx6
-rw-r--r--qom/object.c38
-rw-r--r--spice-qemu-char.c9
-rw-r--r--sysconfigs/target/target-x86_64.conf52
-rw-r--r--target-i386/cpuid.c72
-rw-r--r--test-string-input-visitor.c195
-rw-r--r--test-string-output-visitor.c188
-rw-r--r--tests/Makefile12
-rw-r--r--trace-events4
-rw-r--r--ui/qemu-spice.h9
-rw-r--r--ui/spice-core.c50
-rw-r--r--vl.c40
63 files changed, 1974 insertions, 704 deletions
diff --git a/.gitignore b/.gitignore
index f5aab2cb07..c72955aad1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -44,6 +44,8 @@ QMP/qmp-commands.txt
 test-coroutine
 test-qmp-input-visitor
 test-qmp-output-visitor
+test-string-input-visitor
+test-string-output-visitor
 fsdev/virtfs-proxy-helper.1
 fsdev/virtfs-proxy-helper.pod
 .gdbinit
diff --git a/MAINTAINERS b/MAINTAINERS
index 647c41363d..0b3b3d8dc6 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -420,11 +420,16 @@ F: hw/pci*
 F: hw/piix*
 
 SCSI
+M: Paolo Bonzini <pbonzini@redhat.com>
+S: Supported
+F: hw/virtio-scsi.*
+F: hw/scsi*
+T: git://github.com/bonzini/qemu.git scsi-next
+
+LSI53C895A
 M: Paul Brook <paul@codesourcery.com>
-M: Kevin Wolf <kwolf@redhat.com>
 S: Odd Fixes
 F: hw/lsi53c895a.c
-F: hw/scsi*
 
 USB
 M: Gerd Hoffmann <kraxel@redhat.com>
diff --git a/Makefile b/Makefile
index e66e885d1b..c67493e184 100644
--- a/Makefile
+++ b/Makefile
@@ -159,6 +159,7 @@ qemu-nbd$(EXESUF): qemu-nbd.o $(tools-obj-y) $(block-obj-y)
 qemu-io$(EXESUF): qemu-io.o cmd.o $(tools-obj-y) $(block-obj-y)
 
 qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o
+qemu-bridge-helper.o: $(GENERATED_HEADERS)
 
 fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/virtio-9p-marshal.o oslib-posix.o $(trace-obj-y)
 fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap
diff --git a/Makefile.objs b/Makefile.objs
index 391e524525..67ee3df828 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -250,6 +250,7 @@ hw-obj-$(CONFIG_PPCE500_PCI) += ppce500_pci.o
 # MIPS devices
 hw-obj-$(CONFIG_PIIX4) += piix4.o
 hw-obj-$(CONFIG_G364FB) += g364fb.o
+hw-obj-$(CONFIG_JAZZ_LED) += jazz_led.o
 
 # PCI watchdog devices
 hw-obj-$(CONFIG_PCI) += wdt_i6300esb.o
@@ -412,8 +413,9 @@ libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o
 ######################################################################
 # qapi
 
-qapi-nested-y = qapi-visit-core.o qmp-input-visitor.o qmp-output-visitor.o qapi-dealloc-visitor.o
-qapi-nested-y += qmp-registry.o qmp-dispatch.o
+qapi-nested-y = qapi-visit-core.o qapi-dealloc-visitor.o qmp-input-visitor.o
+qapi-nested-y += qmp-output-visitor.o qmp-registry.o qmp-dispatch.o
+qapi-nested-y += string-input-visitor.o string-output-visitor.o
 qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
 
 common-obj-y += qmp-marshal.o qapi-visit.o qapi-types.o $(qapi-obj-y)
diff --git a/Makefile.target b/Makefile.target
index eef4accb27..68a5641183 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -242,6 +242,7 @@ obj-i386-y += vmport.o
 obj-i386-y += pci-hotplug.o smbios.o wdt_ib700.o
 obj-i386-y += debugcon.o multiboot.o
 obj-i386-y += pc_piix.o
+obj-i386-y += pc_sysfw.o
 obj-i386-$(CONFIG_KVM) += kvm/clock.o kvm/apic.o kvm/i8259.o kvm/ioapic.o
 obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
 
@@ -300,7 +301,6 @@ obj-lm32-y += framebuffer.o
 
 obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
 obj-mips-y += mips_addr.o mips_timer.o mips_int.o
-obj-mips-y += jazz_led.o
 obj-mips-y += gt64xxx.o mc146818rtc.o
 obj-mips-$(CONFIG_FULONG) += bonito.o vt82c686.o mips_fulong2e.o
 
diff --git a/QMP/qmp.py b/QMP/qmp.py
index c7dbea076d..36ecc1dfae 100644
--- a/QMP/qmp.py
+++ b/QMP/qmp.py
@@ -128,6 +128,12 @@ class QEMUMonitorProtocol:
             qmp_cmd['id'] = id
         return self.cmd_obj(qmp_cmd)
 
+    def command(self, cmd, **kwds):
+        ret = self.cmd(cmd, kwds)
+        if ret.has_key('error'):
+            raise Exception(ret['error']['desc'])
+        return ret['return']
+
     def get_events(self, wait=False):
         """
         Get a list of available QMP events.
diff --git a/QMP/qom-get b/QMP/qom-get
new file mode 100755
index 0000000000..0172c69441
--- /dev/null
+++ b/QMP/qom-get
@@ -0,0 +1,67 @@
+#!/usr/bin/python
+##
+# QEMU Object Model test tools
+#
+# Copyright IBM, Corp. 2011
+#
+# Authors:
+#  Anthony Liguori   <aliguori@us.ibm.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or later.  See
+# the COPYING file in the top-level directory.
+##
+
+import sys
+import os
+from qmp import QEMUMonitorProtocol
+
+cmd, args = sys.argv[0], sys.argv[1:]
+socket_path = None
+path = None
+prop = None
+
+def usage():
+    return '''environment variables:
+    QMP_SOCKET=<path | addr:port>
+usage:
+    %s [-h] [-s <QMP socket path | addr:port>] <path>.<property>
+''' % cmd
+
+def usage_error(error_msg = "unspecified error"):
+    sys.stderr.write('%s\nERROR: %s\n' % (usage(), error_msg))
+    exit(1)
+
+if len(args) > 0:
+    if args[0] == "-h":
+        print usage()
+        exit(0);
+    elif args[0] == "-s":
+        try:
+            socket_path = args[1]
+        except:
+            usage_error("missing argument: QMP socket path or address");
+        args = args[2:]
+
+if not socket_path:
+    if os.environ.has_key('QMP_SOCKET'):
+        socket_path = os.environ['QMP_SOCKET']
+    else:
+        usage_error("no QMP socket path or address given");
+
+if len(args) > 0:
+    try:
+        path, prop = args[0].rsplit('.', 1)
+    except:
+        usage_error("invalid format for path/property/value")
+else:
+    usage_error("not enough arguments")
+
+srv = QEMUMonitorProtocol(socket_path)
+srv.connect()
+
+rsp = srv.command('qom-get', path=path, property=prop)
+if type(rsp) == dict:
+    for i in rsp.keys():
+        print '%s: %s' % (i, rsp[i])
+else:
+    print rsp
diff --git a/QMP/qom-list b/QMP/qom-list
new file mode 100755
index 0000000000..1e7cc6cb2d
--- /dev/null
+++ b/QMP/qom-list
@@ -0,0 +1,64 @@
+#!/usr/bin/python
+##
+# QEMU Object Model test tools
+#
+# Copyright IBM, Corp. 2011
+#
+# Authors:
+#  Anthony Liguori   <aliguori@us.ibm.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or later.  See
+# the COPYING file in the top-level directory.
+##
+
+import sys
+import os
+from qmp import QEMUMonitorProtocol
+
+cmd, args = sys.argv[0], sys.argv[1:]
+socket_path = None
+path = None
+prop = None
+
+def usage():
+    return '''environment variables:
+    QMP_SOCKET=<path | addr:port>
+usage:
+    %s [-h] [-s <QMP socket path | addr:port>] [<path>]
+''' % cmd
+
+def usage_error(error_msg = "unspecified error"):
+    sys.stderr.write('%s\nERROR: %s\n' % (usage(), error_msg))
+    exit(1)
+
+if len(args) > 0:
+    if args[0] == "-h":
+        print usage()
+        exit(0);
+    elif args[0] == "-s":
+        try:
+            socket_path = args[1]
+        except:
+            usage_error("missing argument: QMP socket path or address");
+        args = args[2:]
+
+if not socket_path:
+    if os.environ.has_key('QMP_SOCKET'):
+        socket_path = os.environ['QMP_SOCKET']
+    else:
+        usage_error("no QMP socket path or address given");
+
+srv = QEMUMonitorProtocol(socket_path)
+srv.connect()
+
+if len(args) == 0:
+    print '/'
+    sys.exit(0)
+
+for item in srv.command('qom-list', path=args[0]):
+    if item['type'].startswith('child<'):
+        print '%s/' % item['name']
+    elif item['type'].startswith('link<'):
+        print '@%s/' % item['name']
+    else:
+        print '%s' % item['name']
diff --git a/QMP/qom-set b/QMP/qom-set
new file mode 100755
index 0000000000..54ecfecc53
--- /dev/null
+++ b/QMP/qom-set
@@ -0,0 +1,64 @@
+#!/usr/bin/python
+##
+# QEMU Object Model test tools
+#
+# Copyright IBM, Corp. 2011
+#
+# Authors:
+#  Anthony Liguori   <aliguori@us.ibm.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or later.  See
+# the COPYING file in the top-level directory.
+##
+
+import sys
+import os
+from qmp import QEMUMonitorProtocol
+
+cmd, args = sys.argv[0], sys.argv[1:]
+socket_path = None
+path = None
+prop = None
+value = None
+
+def usage():
+    return '''environment variables:
+    QMP_SOCKET=<path | addr:port>
+usage:
+    %s [-h] [-s <QMP socket path | addr:port>] <path>.<property> <value>
+''' % cmd
+
+def usage_error(error_msg = "unspecified error"):
+    sys.stderr.write('%s\nERROR: %s\n' % (usage(), error_msg))
+    exit(1)
+
+if len(args) > 0:
+    if args[0] == "-h":
+        print usage()
+        exit(0);
+    elif args[0] == "-s":
+        try:
+            socket_path = args[1]
+        except:
+            usage_error("missing argument: QMP socket path or address");
+        args = args[2:]
+
+if not socket_path:
+    if os.environ.has_key('QMP_SOCKET'):
+        socket_path = os.environ['QMP_SOCKET']
+    else:
+        usage_error("no QMP socket path or address given");
+
+if len(args) > 1:
+    try:
+        path, prop = args[0].rsplit('.', 1)
+    except:
+        usage_error("invalid format for path/property/value")
+    value = args[1]
+else:
+    usage_error("not enough arguments")
+
+srv = QEMUMonitorProtocol(socket_path)
+srv.connect()
+
+print srv.command('qom-set', path=path, property=prop, value=sys.argv[2])
diff --git a/blockdev.c b/blockdev.c
index 7a6613a2d2..2c132a308b 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -595,7 +595,8 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
         /* CDROM is fine for any interface, don't check.  */
         ro = 1;
     } else if (ro == 1) {
-        if (type != IF_SCSI && type != IF_VIRTIO && type != IF_FLOPPY && type != IF_NONE) {
+        if (type != IF_SCSI && type != IF_VIRTIO && type != IF_FLOPPY &&
+            type != IF_NONE && type != IF_PFLASH) {
             error_report("readonly not supported by this bus type");
             goto err;
         }
diff --git a/console.c b/console.c
index 135394f6f6..744ef2d810 100644
--- a/console.c
+++ b/console.c
@@ -1441,9 +1441,6 @@ void console_color_init(DisplayState *ds)
     }
 }
 
-static int n_text_consoles;
-static CharDriverState *text_consoles[128];
-
 static void text_console_set_echo(CharDriverState *chr, bool echo)
 {
     TextConsole *s = chr->opaque;
@@ -1510,7 +1507,7 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
         chr->init(chr);
 }
 
-int text_console_init(QemuOpts *opts, CharDriverState **_chr)
+CharDriverState *text_console_init(QemuOpts *opts)
 {
     CharDriverState *chr;
     TextConsole *s;
@@ -1519,13 +1516,6 @@ int text_console_init(QemuOpts *opts, CharDriverState **_chr)
 
     chr = g_malloc0(sizeof(CharDriverState));
 
-    if (n_text_consoles == 128) {
-        fprintf(stderr, "Too many text consoles\n");
-        exit(1);
-    }
-    text_consoles[n_text_consoles] = chr;
-    n_text_consoles++;
-
     width = qemu_opt_get_number(opts, "width", 0);
     if (width == 0)
         width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
@@ -1542,7 +1532,7 @@ int text_console_init(QemuOpts *opts, CharDriverState **_chr)
 
     if (!s) {
         g_free(chr);
-        return -EBUSY;
+        return NULL;
     }
 
     s->chr = chr;
@@ -1550,20 +1540,18 @@ int text_console_init(QemuOpts *opts, CharDriverState **_chr)
     s->g_height = height;
     chr->opaque = s;
     chr->chr_set_echo = text_console_set_echo;
-
-    *_chr = chr;
-    return 0;
+    return chr;
 }
 
 void text_consoles_set_display(DisplayState *ds)
 {
     int i;
 
-    for (i = 0; i < n_text_consoles; i++) {
-        text_console_do_init(text_consoles[i], ds);
+    for (i = 0; i < nb_consoles; i++) {
+        if (consoles[i]->console_type != GRAPHIC_CONSOLE) {
+            text_console_do_init(consoles[i]->chr, ds);
+        }
     }
-
-    n_text_consoles = 0;
 }
 
 void qemu_console_resize(DisplayState *ds, int width, int height)
diff --git a/console.h b/console.h
index 6ba0d5ddf3..c33ffe0007 100644
--- a/console.h
+++ b/console.h
@@ -356,7 +356,7 @@ void vga_hw_text_update(console_ch_t *chardata);
 
 int is_graphic_console(void);
 int is_fixedsize_console(void);
-int text_console_init(QemuOpts *opts, CharDriverState **_chr);
+CharDriverState *text_console_init(QemuOpts *opts);
 void text_consoles_set_display(DisplayState *ds);
 void console_select(unsigned int index);
 void console_color_init(DisplayState *ds);
diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak
index 662348ef11..2c78175ae7 100644
--- a/default-configs/i386-softmmu.mak
+++ b/default-configs/i386-softmmu.mak
@@ -24,3 +24,4 @@ CONFIG_SOUND=y
 CONFIG_HPET=y
 CONFIG_APPLESMC=y
 CONFIG_I8259=y
+CONFIG_PFLASH_CFI01=y
diff --git a/default-configs/mips-softmmu.mak b/default-configs/mips-softmmu.mak
index 308d04aeab..a271b1c6da 100644
--- a/default-configs/mips-softmmu.mak
+++ b/default-configs/mips-softmmu.mak
@@ -30,3 +30,4 @@ CONFIG_MIPSNET=y
 CONFIG_PFLASH_CFI01=y
 CONFIG_G364FB=y
 CONFIG_I8259=y
+CONFIG_JAZZ_LED=y
diff --git a/default-configs/mips64-softmmu.mak b/default-configs/mips64-softmmu.mak
index f1b92da8a3..0510bb6a53 100644
--- a/default-configs/mips64-softmmu.mak
+++ b/default-configs/mips64-softmmu.mak
@@ -30,3 +30,4 @@ CONFIG_MIPSNET=y
 CONFIG_PFLASH_CFI01=y
 CONFIG_G364FB=y
 CONFIG_I8259=y
+CONFIG_JAZZ_LED=y
diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak
index 567396c84f..ed3bed3b8d 100644
--- a/default-configs/mips64el-softmmu.mak
+++ b/default-configs/mips64el-softmmu.mak
@@ -32,3 +32,4 @@ CONFIG_PFLASH_CFI01=y
 CONFIG_FULONG=y
 CONFIG_G364FB=y
 CONFIG_I8259=y
+CONFIG_JAZZ_LED=y
diff --git a/default-configs/mipsel-softmmu.mak b/default-configs/mipsel-softmmu.mak
index a8e421b151..fa3a2cacdd 100644
--- a/default-configs/mipsel-softmmu.mak
+++ b/default-configs/mipsel-softmmu.mak
@@ -30,3 +30,4 @@ CONFIG_MIPSNET=y
 CONFIG_PFLASH_CFI01=y
 CONFIG_G364FB=y
 CONFIG_I8259=y
+CONFIG_JAZZ_LED=y
diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak
index b445be2059..233a8564eb 100644
--- a/default-configs/x86_64-softmmu.mak
+++ b/default-configs/x86_64-softmmu.mak
@@ -24,3 +24,4 @@ CONFIG_SOUND=y
 CONFIG_HPET=y
 CONFIG_APPLESMC=y
 CONFIG_I8259=y
+CONFIG_PFLASH_CFI01=y
diff --git a/hw/baum.c b/hw/baum.c
index 86d780a617..3e94f84e51 100644
--- a/hw/baum.c
+++ b/hw/baum.c
@@ -562,7 +562,7 @@ static void baum_close(struct CharDriverState *chr)
     g_free(baum);
 }
 
-int chr_baum_init(QemuOpts *opts, CharDriverState **_chr)
+CharDriverState *chr_baum_init(QemuOpts *opts)
 {
     BaumDriverState *baum;
     CharDriverState *chr;
@@ -614,8 +614,7 @@ int chr_baum_init(QemuOpts *opts, CharDriverState **_chr)
 
     qemu_chr_generic_open(chr);
 
-    *_chr = chr;
-    return 0;
+    return chr;
 
 fail:
     qemu_free_timer(baum->cellCount_timer);
@@ -624,5 +623,5 @@ fail_handle:
     g_free(handle);
     g_free(chr);
     g_free(baum);
-    return -EIO;
+    return NULL;
 }
diff --git a/hw/baum.h b/hw/baum.h
index 3f28cc339a..8af710fa21 100644
--- a/hw/baum.h
+++ b/hw/baum.h
@@ -23,4 +23,4 @@
  */
 
 /* char device */
-int chr_baum_init(QemuOpts *opts, CharDriverState **_chr);
+CharDriverState *chr_baum_init(QemuOpts *opts);
diff --git a/hw/boards.h b/hw/boards.h
index f6d3784cf1..667177d76d 100644
--- a/hw/boards.h
+++ b/hw/boards.h
@@ -32,6 +32,7 @@ typedef struct QEMUMachine {
 } QEMUMachine;
 
 int qemu_register_machine(QEMUMachine *m);
+QEMUMachine *find_default_machine(void);
 
 extern QEMUMachine *current_machine;
 
diff --git a/hw/jazz_led.c b/hw/jazz_led.c
index f8a218252c..5d8040be30 100644
--- a/hw/jazz_led.c
+++ b/hw/jazz_led.c
@@ -1,7 +1,7 @@
 /*
  * QEMU JAZZ LED emulator.
  *
- * Copyright (c) 2007 Hervé Poussineau
+ * Copyright (c) 2007-2012 Herve Poussineau
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -22,131 +22,53 @@
  * THE SOFTWARE.
  */
 
-#include "hw.h"
-#include "mips.h"
 #include "console.h"
 #include "pixel_ops.h"
-
-//#define DEBUG_LED
-
-#ifdef DEBUG_LED
-#define DPRINTF(fmt, ...) \
-do { printf("jazz led: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while (0)
-#endif
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "jazz led ERROR: " fmt , ## __VA_ARGS__);} while (0)
+#include "trace.h"
+#include "sysbus.h"
 
 typedef enum {
     REDRAW_NONE = 0, REDRAW_SEGMENTS = 1, REDRAW_BACKGROUND = 2,
 } screen_state_t;
 
 typedef struct LedState {
+    SysBusDevice busdev;
     MemoryRegion iomem;
     uint8_t segments;
     DisplayState *ds;
     screen_state_t state;
 } LedState;
 
-static uint32_t led_readb(void *opaque, target_phys_addr_t addr)
+static uint64_t jazz_led_read(void *opaque, target_phys_addr_t addr,
+                              unsigned int size)
 {
     LedState *s = opaque;
-    uint32_t val;
-
-    switch (addr) {
-        case 0:
-            val = s->segments;
-            break;
-        default:
-            BADF("invalid read at [" TARGET_FMT_plx "]\n", addr);
-            val = 0;
-    }
+    uint8_t val;
 
-    DPRINTF("read addr=" TARGET_FMT_plx " val=0x%02x\n", addr, val);
+    val = s->segments;
+    trace_jazz_led_read(addr, val);
 
     return val;
 }
 
-static uint32_t led_readw(void *opaque, target_phys_addr_t addr)
-{
-    uint32_t v;
-#ifdef TARGET_WORDS_BIGENDIAN
-    v = led_readb(opaque, addr) << 8;
-    v |= led_readb(opaque, addr + 1);
-#else
-    v = led_readb(opaque, addr);
-    v |= led_readb(opaque, addr + 1) << 8;
-#endif
-    return v;
-}
-
-static uint32_t led_readl(void *opaque, target_phys_addr_t addr)
-{
-    uint32_t v;
-#ifdef TARGET_WORDS_BIGENDIAN
-    v = led_readb(opaque, addr) << 24;
-    v |= led_readb(opaque, addr + 1) << 16;
-    v |= led_readb(opaque, addr + 2) << 8;
-    v |= led_readb(opaque, addr + 3);
-#else
-    v = led_readb(opaque, addr);
-    v |= led_readb(opaque, addr + 1) << 8;
-    v |= led_readb(opaque, addr + 2) << 16;
-    v |= led_readb(opaque, addr + 3) << 24;
-#endif
-    return v;
-}
-
-static void led_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+static void jazz_led_write(void *opaque, target_phys_addr_t addr,
+                           uint64_t val, unsigned int size)
 {
     LedState *s = opaque;
+    uint8_t new_val = val & 0xff;
 
-    DPRINTF("write addr=" TARGET_FMT_plx " val=0x%02x\n", addr, val);
+    trace_jazz_led_write(addr, new_val);
 
-    switch (addr) {
-        case 0:
-            s->segments = val;
-            s->state |= REDRAW_SEGMENTS;
-            break;
-        default:
-            BADF("invalid write of 0x%08x at [" TARGET_FMT_plx "]\n", val, addr);
-            break;
-    }
-}
-
-static void led_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-#ifdef TARGET_WORDS_BIGENDIAN
-    led_writeb(opaque, addr, (val >> 8) & 0xff);
-    led_writeb(opaque, addr + 1, val & 0xff);
-#else
-    led_writeb(opaque, addr, val & 0xff);
-    led_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-#endif
-}
-
-static void led_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-#ifdef TARGET_WORDS_BIGENDIAN
-    led_writeb(opaque, addr, (val >> 24) & 0xff);
-    led_writeb(opaque, addr + 1, (val >> 16) & 0xff);
-    led_writeb(opaque, addr + 2, (val >> 8) & 0xff);
-    led_writeb(opaque, addr + 3, val & 0xff);
-#else
-    led_writeb(opaque, addr, val & 0xff);
-    led_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-    led_writeb(opaque, addr + 2, (val >> 16) & 0xff);
-    led_writeb(opaque, addr + 3, (val >> 24) & 0xff);
-#endif
+    s->segments = new_val;
+    s->state |= REDRAW_SEGMENTS;
 }
 
 static const MemoryRegionOps led_ops = {
-    .old_mmio = {
-        .read = { led_readb, led_readw, led_readl, },
-        .write = { led_writeb, led_writew, led_writel, },
-    },
+    .read = jazz_led_read,
+    .write = jazz_led_write,
     .endianness = DEVICE_NATIVE_ENDIAN,
+    .impl.min_access_size = 1,
+    .impl.max_access_size = 1,
 };
 
 /***********************************************************/
@@ -304,20 +226,71 @@ static void jazz_led_text_update(void *opaque, console_ch_t *chardata)
     dpy_update(s->ds, 0, 0, 2, 1);
 }
 
-void jazz_led_init(MemoryRegion *address_space, target_phys_addr_t base)
+static int jazz_led_post_load(void *opaque, int version_id)
 {
-    LedState *s;
+    /* force refresh */
+    jazz_led_invalidate_display(opaque);
+
+    return 0;
+}
 
-    s = g_malloc0(sizeof(LedState));
+static const VMStateDescription vmstate_jazz_led = {
+    .name = "jazz-led",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .post_load = jazz_led_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(segments, LedState),
+        VMSTATE_END_OF_LIST()
+    }
+};
 
-    s->state = REDRAW_SEGMENTS | REDRAW_BACKGROUND;
+static int jazz_led_init(SysBusDevice *dev)
+{
+    LedState *s = FROM_SYSBUS(LedState, dev);
 
     memory_region_init_io(&s->iomem, &led_ops, s, "led", 1);
-    memory_region_add_subregion(address_space, base, &s->iomem);
+    sysbus_init_mmio(dev, &s->iomem);
 
     s->ds = graphic_console_init(jazz_led_update_display,
                                  jazz_led_invalidate_display,
                                  jazz_led_screen_dump,
                                  jazz_led_text_update, s);
+
+    return 0;
+}
+
+static void jazz_led_reset(DeviceState *d)
+{
+    LedState *s = DO_UPCAST(LedState, busdev.qdev, d);
+
+    s->segments = 0;
+    s->state = REDRAW_SEGMENTS | REDRAW_BACKGROUND;
     qemu_console_resize(s->ds, 60, 80);
 }
+
+static void jazz_led_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = jazz_led_init;
+    dc->desc = "Jazz LED display",
+    dc->vmsd = &vmstate_jazz_led;
+    dc->reset = jazz_led_reset;
+}
+
+static TypeInfo jazz_led_info = {
+    .name          = "jazz-led",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(LedState),
+    .class_init    = jazz_led_class_init,
+};
+
+static void jazz_led_register(void)
+{
+    type_register_static(&jazz_led_info);
+}
+
+type_init(jazz_led_register);
diff --git a/hw/mips.h b/hw/mips.h
index 22156fce53..a7e6d4cc62 100644
--- a/hw/mips.h
+++ b/hw/mips.h
@@ -10,9 +10,6 @@ PCIBus *gt64120_register(qemu_irq *pic);
 /* bonito.c */
 PCIBus *bonito_init(qemu_irq *pic);
 
-/* jazz_led.c */
-void jazz_led_init(MemoryRegion *address_space, target_phys_addr_t base);
-
 /* rc4030.c */
 typedef struct rc4030DMAState *rc4030_dma;
 void rc4030_dma_memory_rw(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write);
diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c
index 65608dc644..2b4678e170 100644
--- a/hw/mips_jazz.c
+++ b/hw/mips_jazz.c
@@ -295,7 +295,7 @@ static void mips_jazz_init(MemoryRegion *address_space,
     sysbus_mmio_map(sysbus, 0, 0x80009000);
 
     /* LED indicator */
-    jazz_led_init(address_space, 0x8000f000);
+    sysbus_create_simple("jazz-led", 0x8000f000, NULL);
 }
 
 static
diff --git a/hw/msmouse.c b/hw/msmouse.c
index c3b57ea31c..9c492a4637 100644
--- a/hw/msmouse.c
+++ b/hw/msmouse.c
@@ -64,7 +64,7 @@ static void msmouse_chr_close (struct CharDriverState *chr)
     g_free (chr);
 }
 
-int qemu_chr_open_msmouse(QemuOpts *opts, CharDriverState **_chr)
+CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts)
 {
     CharDriverState *chr;
 
@@ -74,6 +74,5 @@ int qemu_chr_open_msmouse(QemuOpts *opts, CharDriverState **_chr)
 
     qemu_add_mouse_event_handler(msmouse_event, chr, 0, "QEMU Microsoft Mouse");
 
-    *_chr = chr;
-    return 0;
+    return chr;
 }
diff --git a/hw/msmouse.h b/hw/msmouse.h
index 8b853b35bf..456cb21424 100644
--- a/hw/msmouse.h
+++ b/hw/msmouse.h
@@ -1,2 +1,2 @@
 /* msmouse.c */
-int qemu_chr_open_msmouse(QemuOpts *opts, CharDriverState **_chr);
+CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts);
diff --git a/hw/pc.c b/hw/pc.c
index 57461291ef..b9f4bc72d7 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -60,10 +60,6 @@
 #define DPRINTF(fmt, ...)
 #endif
 
-#define BIOS_FILENAME "bios.bin"
-
-#define PC_MAX_BIOS_SIZE (4 * 1024 * 1024)
-
 /* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables.  */
 #define ACPI_DATA_SIZE       0x10000
 #define BIOS_CFG_IOPORT 0x510
@@ -990,11 +986,9 @@ void pc_memory_init(MemoryRegion *system_memory,
                     MemoryRegion *rom_memory,
                     MemoryRegion **ram_memory)
 {
-    char *filename;
-    int ret, linux_boot, i;
-    MemoryRegion *ram, *bios, *isa_bios, *option_rom_mr;
+    int linux_boot, i;
+    MemoryRegion *ram, *option_rom_mr;
     MemoryRegion *ram_below_4g, *ram_above_4g;
-    int bios_size, isa_bios_size;
     void *fw_cfg;
 
     linux_boot = (kernel_filename != NULL);
@@ -1020,44 +1014,9 @@ void pc_memory_init(MemoryRegion *system_memory,
                                     ram_above_4g);
     }
 
-    /* BIOS load */
-    if (bios_name == NULL)
-        bios_name = BIOS_FILENAME;
-    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
-    if (filename) {
-        bios_size = get_image_size(filename);
-    } else {
-        bios_size = -1;
-    }
-    if (bios_size <= 0 ||
-        (bios_size % 65536) != 0) {
-        goto bios_error;
-    }
-    bios = g_malloc(sizeof(*bios));
-    memory_region_init_ram(bios, "pc.bios", bios_size);
-    vmstate_register_ram_global(bios);
-    memory_region_set_readonly(bios, true);
-    ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size), -1);
-    if (ret != 0) {
-    bios_error:
-        fprintf(stderr, "qemu: could not load PC BIOS '%s'\n", bios_name);
-        exit(1);
-    }
-    if (filename) {
-        g_free(filename);
-    }
-    /* map the last 128KB of the BIOS in ISA space */
-    isa_bios_size = bios_size;
-    if (isa_bios_size > (128 * 1024))
-        isa_bios_size = 128 * 1024;
-    isa_bios = g_malloc(sizeof(*isa_bios));
-    memory_region_init_alias(isa_bios, "isa-bios", bios,
-                             bios_size - isa_bios_size, isa_bios_size);
-    memory_region_add_subregion_overlap(rom_memory,
-                                        0x100000 - isa_bios_size,
-                                        isa_bios,
-                                        1);
-    memory_region_set_readonly(isa_bios, true);
+
+    /* Initialize PC system firmware */
+    pc_system_firmware_init(rom_memory);
 
     option_rom_mr = g_malloc(sizeof(*option_rom_mr));
     memory_region_init_ram(option_rom_mr, "pc.rom", PC_ROM_SIZE);
@@ -1067,11 +1026,6 @@ void pc_memory_init(MemoryRegion *system_memory,
                                         option_rom_mr,
                                         1);
 
-    /* map all the bios at the top of memory */
-    memory_region_add_subregion(rom_memory,
-                                (uint32_t)(-bios_size),
-                                bios);
-
     fw_cfg = bochs_bios_init();
     rom_set_fw(fw_cfg);
 
diff --git a/hw/pc.h b/hw/pc.h
index 1b47bbdb0e..71f7df30aa 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -216,6 +216,9 @@ static inline bool isa_ne2000_init(ISABus *bus, int base, int irq, NICInfo *nd)
     return true;
 }
 
+/* pc_sysfw.c */
+void pc_system_firmware_init(MemoryRegion *rom_memory);
+
 /* e820 types */
 #define E820_RAM        1
 #define E820_RESERVED   2
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index 17f8d5d593..fe7a729472 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -371,8 +371,8 @@ static void pc_xen_hvm_init(ram_addr_t ram_size,
 }
 #endif
 
-static QEMUMachine pc_machine_v1_0 = {
-    .name = "pc-1.0",
+static QEMUMachine pc_machine_v1_1 = {
+    .name = "pc-1.1",
     .alias = "pc",
     .desc = "Standard PC",
     .init = pc_init_pci,
@@ -380,12 +380,34 @@ static QEMUMachine pc_machine_v1_0 = {
     .is_default = 1,
 };
 
+static QEMUMachine pc_machine_v1_0 = {
+    .name = "pc-1.0",
+    .desc = "Standard PC",
+    .init = pc_init_pci,
+    .max_cpus = 255,
+    .compat_props = (GlobalProperty[]) {
+        {
+            .driver   = "pc-sysfw",
+            .property = "rom_only",
+            .value    = stringify(1),
+        },
+        { /* end of list */ }
+    },
+};
+
 static QEMUMachine pc_machine_v0_15 = {
     .name = "pc-0.15",
     .desc = "Standard PC",
     .init = pc_init_pci,
     .max_cpus = 255,
-    .is_default = 1,
+    .compat_props = (GlobalProperty[]) {
+        {
+            .driver   = "pc-sysfw",
+            .property = "rom_only",
+            .value    = stringify(1),
+        },
+        { /* end of list */ }
+    },
 };
 
 static QEMUMachine pc_machine_v0_14 = {
@@ -419,6 +441,11 @@ static QEMUMachine pc_machine_v0_14 = {
             .property = "event_idx",
             .value    = "off",
         },
+        {
+            .driver   = "pc-sysfw",
+            .property = "rom_only",
+            .value    = stringify(1),
+        },
         { /* end of list */ }
     },
 };
@@ -466,6 +493,11 @@ static QEMUMachine pc_machine_v0_13 = {
             .property = "use_broken_id",
             .value    = stringify(1),
         },
+        {
+            .driver   = "pc-sysfw",
+            .property = "rom_only",
+            .value    = stringify(1),
+        },
         { /* end of list */ }
     },
 };
@@ -517,6 +549,11 @@ static QEMUMachine pc_machine_v0_12 = {
             .property = "use_broken_id",
             .value    = stringify(1),
         },
+        {
+            .driver   = "pc-sysfw",
+            .property = "rom_only",
+            .value    = stringify(1),
+        },
         { /* end of list */ }
     }
 };
@@ -576,6 +613,11 @@ static QEMUMachine pc_machine_v0_11 = {
             .property = "use_broken_id",
             .value    = stringify(1),
         },
+        {
+            .driver   = "pc-sysfw",
+            .property = "rom_only",
+            .value    = stringify(1),
+        },
         { /* end of list */ }
     }
 };
@@ -647,6 +689,11 @@ static QEMUMachine pc_machine_v0_10 = {
             .property = "use_broken_id",
             .value    = stringify(1),
         },
+        {
+            .driver   = "pc-sysfw",
+            .property = "rom_only",
+            .value    = stringify(1),
+        },
         { /* end of list */ }
     },
 };
@@ -656,6 +703,14 @@ static QEMUMachine isapc_machine = {
     .desc = "ISA-only PC",
     .init = pc_init_isa,
     .max_cpus = 1,
+    .compat_props = (GlobalProperty[]) {
+        {
+            .driver   = "pc-sysfw",
+            .property = "rom_only",
+            .value    = stringify(1),
+        },
+        { /* end of list */ }
+    },
 };
 
 #ifdef CONFIG_XEN
@@ -670,6 +725,7 @@ static QEMUMachine xenfv_machine = {
 
 static void pc_machine_init(void)
 {
+    qemu_register_machine(&pc_machine_v1_1);
     qemu_register_machine(&pc_machine_v1_0);
     qemu_register_machine(&pc_machine_v0_15);
     qemu_register_machine(&pc_machine_v0_14);
diff --git a/hw/pc_sysfw.c b/hw/pc_sysfw.c
new file mode 100644
index 0000000000..abf9004182
--- /dev/null
+++ b/hw/pc_sysfw.c
@@ -0,0 +1,254 @@
+/*
+ * QEMU PC System Firmware
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2011-2012 Intel Corporation
+ *
+ * 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 "sysbus.h"
+#include "hw.h"
+#include "pc.h"
+#include "hw/boards.h"
+#include "loader.h"
+#include "sysemu.h"
+#include "flash.h"
+#include "kvm.h"
+
+#define BIOS_FILENAME "bios.bin"
+
+typedef struct PcSysFwDevice {
+    SysBusDevice busdev;
+    uint8_t rom_only;
+} PcSysFwDevice;
+
+static void pc_isa_bios_init(MemoryRegion *rom_memory,
+                             MemoryRegion *flash_mem,
+                             int ram_size)
+{
+    int isa_bios_size;
+    MemoryRegion *isa_bios;
+    uint64_t flash_size;
+    void *flash_ptr, *isa_bios_ptr;
+
+    flash_size = memory_region_size(flash_mem);
+
+    /* map the last 128KB of the BIOS in ISA space */
+    isa_bios_size = flash_size;
+    if (isa_bios_size > (128 * 1024)) {
+        isa_bios_size = 128 * 1024;
+    }
+    isa_bios = g_malloc(sizeof(*isa_bios));
+    memory_region_init_ram(isa_bios, "isa-bios", isa_bios_size);
+    vmstate_register_ram_global(isa_bios);
+    memory_region_add_subregion_overlap(rom_memory,
+                                        0x100000 - isa_bios_size,
+                                        isa_bios,
+                                        1);
+
+    /* copy ISA rom image from top of flash memory */
+    flash_ptr = memory_region_get_ram_ptr(flash_mem);
+    isa_bios_ptr = memory_region_get_ram_ptr(isa_bios);
+    memcpy(isa_bios_ptr,
+           ((uint8_t*)flash_ptr) + (flash_size - isa_bios_size),
+           isa_bios_size);
+
+    memory_region_set_readonly(isa_bios, true);
+}
+
+static void pc_fw_add_pflash_drv(void)
+{
+    QemuOpts *opts;
+    QEMUMachine *machine;
+    char *filename;
+
+    if (bios_name == NULL) {
+        bios_name = BIOS_FILENAME;
+    }
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+
+    opts = drive_add(IF_PFLASH, -1, filename, "readonly=on");
+    if (opts == NULL) {
+      return;
+    }
+
+    machine = find_default_machine();
+    if (machine == NULL) {
+      return;
+    }
+
+    drive_init(opts, machine->use_scsi);
+}
+
+static void pc_system_flash_init(MemoryRegion *rom_memory,
+                                 DriveInfo *pflash_drv)
+{
+    BlockDriverState *bdrv;
+    int64_t size;
+    target_phys_addr_t phys_addr;
+    int sector_bits, sector_size;
+    pflash_t *system_flash;
+    MemoryRegion *flash_mem;
+
+    bdrv = pflash_drv->bdrv;
+    size = bdrv_getlength(pflash_drv->bdrv);
+    sector_bits = 12;
+    sector_size = 1 << sector_bits;
+
+    if ((size % sector_size) != 0) {
+        fprintf(stderr,
+                "qemu: PC system firmware (pflash) must be a multiple of 0x%x\n",
+                sector_size);
+        exit(1);
+    }
+
+    phys_addr = 0x100000000ULL - size;
+    system_flash = pflash_cfi01_register(phys_addr, NULL, "system.flash", size,
+                                         bdrv, sector_size, size >> sector_bits,
+                                         1, 0x0000, 0x0000, 0x0000, 0x0000, 0);
+    flash_mem = pflash_cfi01_get_memory(system_flash);
+
+    pc_isa_bios_init(rom_memory, flash_mem, size);
+}
+
+static void old_pc_system_rom_init(MemoryRegion *rom_memory)
+{
+    char *filename;
+    MemoryRegion *bios, *isa_bios;
+    int bios_size, isa_bios_size;
+    int ret;
+
+    /* BIOS load */
+    if (bios_name == NULL) {
+        bios_name = BIOS_FILENAME;
+    }
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+    if (filename) {
+        bios_size = get_image_size(filename);
+    } else {
+        bios_size = -1;
+    }
+    if (bios_size <= 0 ||
+        (bios_size % 65536) != 0) {
+        goto bios_error;
+    }
+    bios = g_malloc(sizeof(*bios));
+    memory_region_init_ram(bios, "pc.bios", bios_size);
+    vmstate_register_ram_global(bios);
+    memory_region_set_readonly(bios, true);
+    ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size), -1);
+    if (ret != 0) {
+    bios_error:
+        fprintf(stderr, "qemu: could not load PC BIOS '%s'\n", bios_name);
+        exit(1);
+    }
+    if (filename) {
+        g_free(filename);
+    }
+
+    /* map the last 128KB of the BIOS in ISA space */
+    isa_bios_size = bios_size;
+    if (isa_bios_size > (128 * 1024)) {
+        isa_bios_size = 128 * 1024;
+    }
+    isa_bios = g_malloc(sizeof(*isa_bios));
+    memory_region_init_alias(isa_bios, "isa-bios", bios,
+                             bios_size - isa_bios_size, isa_bios_size);
+    memory_region_add_subregion_overlap(rom_memory,
+                                        0x100000 - isa_bios_size,
+                                        isa_bios,
+                                        1);
+    memory_region_set_readonly(isa_bios, true);
+
+    /* map all the bios at the top of memory */
+    memory_region_add_subregion(rom_memory,
+                                (uint32_t)(-bios_size),
+                                bios);
+}
+
+void pc_system_firmware_init(MemoryRegion *rom_memory)
+{
+    DriveInfo *pflash_drv;
+    PcSysFwDevice *sysfw_dev;
+
+    sysfw_dev = (PcSysFwDevice*) qdev_create(NULL, "pc-sysfw");
+
+    if (sysfw_dev->rom_only) {
+        old_pc_system_rom_init(rom_memory);
+        return;
+    }
+
+    pflash_drv = drive_get(IF_PFLASH, 0, 0);
+
+    /* Currently KVM cannot execute from device memory.
+       Use old rom based firmware initialization for KVM. */
+    if (kvm_enabled()) {
+        if (pflash_drv != NULL) {
+            fprintf(stderr, "qemu: pflash cannot be used with kvm enabled\n");
+            exit(1);
+        } else {
+            sysfw_dev->rom_only = 1;
+            old_pc_system_rom_init(rom_memory);
+            return;
+        }
+    }
+
+    /* If a pflash drive is not found, then create one using
+       the bios filename. */
+    if (pflash_drv == NULL) {
+        pc_fw_add_pflash_drv();
+        pflash_drv = drive_get(IF_PFLASH, 0, 0);
+    }
+
+    if (pflash_drv != NULL) {
+        pc_system_flash_init(rom_memory, pflash_drv);
+    } else {
+        fprintf(stderr, "qemu: PC system firmware (pflash) not available\n");
+        exit(1);
+    }
+}
+
+static Property pcsysfw_properties[] = {
+    DEFINE_PROP_UINT8("rom_only", PcSysFwDevice, rom_only, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pcsysfw_class_init (ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS (klass);
+
+    dc->desc = "PC System Firmware";
+    dc->props = pcsysfw_properties;
+}
+
+static TypeInfo pcsysfw_info = {
+    .name          = "pc-sysfw",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof (PcSysFwDevice),
+    .class_init    = pcsysfw_class_init,
+};
+
+static void pcsysfw_register (void)
+{
+    type_register_static (&pcsysfw_info);
+}
+
+type_init (pcsysfw_register);
+
diff --git a/hw/pci.c b/hw/pci.c
index 678a8c1117..bf046bfcad 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -614,7 +614,7 @@ static void pci_init_w1cmask(PCIDevice *dev)
                  PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY);
 }
 
-static void pci_init_wmask_bridge(PCIDevice *d)
+static void pci_init_mask_bridge(PCIDevice *d)
 {
     /* PCI_PRIMARY_BUS, PCI_SECONDARY_BUS, PCI_SUBORDINATE_BUS and
        PCI_SEC_LETENCY_TIMER */
@@ -635,6 +635,14 @@ static void pci_init_wmask_bridge(PCIDevice *d)
     /* PCI_PREF_BASE_UPPER32 and PCI_PREF_LIMIT_UPPER32 */
     memset(d->wmask + PCI_PREF_BASE_UPPER32, 0xff, 8);
 
+    /* Supported memory and i/o types */
+    d->config[PCI_IO_BASE] |= PCI_IO_RANGE_TYPE_32;
+    d->config[PCI_IO_LIMIT] |= PCI_IO_RANGE_TYPE_32;
+    pci_word_test_and_set_mask(d->config + PCI_PREF_MEMORY_BASE,
+                               PCI_PREF_RANGE_TYPE_64);
+    pci_word_test_and_set_mask(d->config + PCI_PREF_MEMORY_LIMIT,
+                               PCI_PREF_RANGE_TYPE_64);
+
 /* TODO: add this define to pci_regs.h in linux and then in qemu. */
 #define  PCI_BRIDGE_CTL_VGA_16BIT	0x10	/* VGA 16-bit decode */
 #define  PCI_BRIDGE_CTL_DISCARD		0x100	/* Primary discard timer */
@@ -657,6 +665,9 @@ static void pci_init_wmask_bridge(PCIDevice *d)
      * completeness. */
     pci_set_word(d->w1cmask + PCI_BRIDGE_CONTROL,
                  PCI_BRIDGE_CTL_DISCARD_STATUS);
+    d->cmask[PCI_IO_BASE] |= PCI_IO_RANGE_TYPE_MASK;
+    pci_word_test_and_set_mask(d->cmask + PCI_PREF_MEMORY_BASE,
+                               PCI_PREF_RANGE_TYPE_MASK);
 }
 
 static int pci_init_multifunction(PCIBus *bus, PCIDevice *dev)
@@ -778,7 +789,7 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
     pci_init_wmask(pci_dev);
     pci_init_w1cmask(pci_dev);
     if (pc->is_bridge) {
-        pci_init_wmask_bridge(pci_dev);
+        pci_init_mask_bridge(pci_dev);
     }
     if (pci_init_multifunction(bus, pci_dev)) {
         pci_config_free(pci_dev);
diff --git a/hw/pci.h b/hw/pci.h
index ff4c12d452..4f19fdbd89 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -465,6 +465,67 @@ pci_quad_test_and_set_mask(uint8_t *config, uint64_t mask)
     return val & mask;
 }
 
+/* Access a register specified by a mask */
+static inline void
+pci_set_byte_by_mask(uint8_t *config, uint8_t mask, uint8_t reg)
+{
+    uint8_t val = pci_get_byte(config);
+    uint8_t rval = reg << (ffs(mask) - 1);
+    pci_set_byte(config, (~mask & val) | (mask & rval));
+}
+
+static inline uint8_t
+pci_get_byte_by_mask(uint8_t *config, uint8_t mask)
+{
+    uint8_t val = pci_get_byte(config);
+    return (val & mask) >> (ffs(mask) - 1);
+}
+
+static inline void
+pci_set_word_by_mask(uint8_t *config, uint16_t mask, uint16_t reg)
+{
+    uint16_t val = pci_get_word(config);
+    uint16_t rval = reg << (ffs(mask) - 1);
+    pci_set_word(config, (~mask & val) | (mask & rval));
+}
+
+static inline uint16_t
+pci_get_word_by_mask(uint8_t *config, uint16_t mask)
+{
+    uint16_t val = pci_get_word(config);
+    return (val & mask) >> (ffs(mask) - 1);
+}
+
+static inline void
+pci_set_long_by_mask(uint8_t *config, uint32_t mask, uint32_t reg)
+{
+    uint32_t val = pci_get_long(config);
+    uint32_t rval = reg << (ffs(mask) - 1);
+    pci_set_long(config, (~mask & val) | (mask & rval));
+}
+
+static inline uint32_t
+pci_get_long_by_mask(uint8_t *config, uint32_t mask)
+{
+    uint32_t val = pci_get_long(config);
+    return (val & mask) >> (ffs(mask) - 1);
+}
+
+static inline void
+pci_set_quad_by_mask(uint8_t *config, uint64_t mask, uint64_t reg)
+{
+    uint64_t val = pci_get_quad(config);
+    uint64_t rval = reg << (ffs(mask) - 1);
+    pci_set_quad(config, (~mask & val) | (mask & rval));
+}
+
+static inline uint64_t
+pci_get_quad_by_mask(uint8_t *config, uint64_t mask)
+{
+    uint64_t val = pci_get_quad(config);
+    return (val & mask) >> (ffs(mask) - 1);
+}
+
 PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction,
                                     const char *name);
 PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn,
diff --git a/hw/pflash_cfi01.c b/hw/pflash_cfi01.c
index ee0c3baab1..b03f623cb1 100644
--- a/hw/pflash_cfi01.c
+++ b/hw/pflash_cfi01.c
@@ -283,8 +283,12 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset,
                     TARGET_FMT_plx "\n",
                     __func__, offset, pfl->sector_len);
 
-            memset(p + offset, 0xff, pfl->sector_len);
-            pflash_update(pfl, offset, pfl->sector_len);
+            if (!pfl->ro) {
+                memset(p + offset, 0xff, pfl->sector_len);
+                pflash_update(pfl, offset, pfl->sector_len);
+            } else {
+                pfl->status |= 0x20; /* Block erase error */
+            }
             pfl->status |= 0x80; /* Ready! */
             break;
         case 0x50: /* Clear status bits */
@@ -323,8 +327,12 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset,
         case 0x10: /* Single Byte Program */
         case 0x40: /* Single Byte Program */
             DPRINTF("%s: Single Byte Program\n", __func__);
-            pflash_data_write(pfl, offset, value, width, be);
-            pflash_update(pfl, offset, width);
+            if (!pfl->ro) {
+                pflash_data_write(pfl, offset, value, width, be);
+                pflash_update(pfl, offset, width);
+            } else {
+                pfl->status |= 0x10; /* Programming error */
+            }
             pfl->status |= 0x80; /* Ready! */
             pfl->wcycle = 0;
         break;
@@ -372,7 +380,11 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset,
     case 2:
         switch (pfl->cmd) {
         case 0xe8: /* Block write */
-            pflash_data_write(pfl, offset, value, width, be);
+            if (!pfl->ro) {
+                pflash_data_write(pfl, offset, value, width, be);
+            } else {
+                pfl->status |= 0x10; /* Programming error */
+            }
 
             pfl->status |= 0x80;
 
@@ -382,8 +394,12 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset,
 
                 DPRINTF("%s: block write finished\n", __func__);
                 pfl->wcycle++;
-                /* Flush the entire write buffer onto backing storage.  */
-                pflash_update(pfl, offset & mask, pfl->writeblock_size);
+                if (!pfl->ro) {
+                    /* Flush the entire write buffer onto backing storage.  */
+                    pflash_update(pfl, offset & mask, pfl->writeblock_size);
+                } else {
+                    pfl->status |= 0x10; /* Programming error */
+                }
             }
 
             pfl->counter--;
@@ -607,13 +623,13 @@ pflash_t *pflash_cfi01_register(target_phys_addr_t base,
         }
         bdrv_attach_dev_nofail(pfl->bs, pfl);
     }
-#if 0 /* XXX: there should be a bit to set up read-only,
-       *      the same way the hardware does (with WP pin).
-       */
-    pfl->ro = 1;
-#else
-    pfl->ro = 0;
-#endif
+
+    if (pfl->bs) {
+        pfl->ro = bdrv_is_read_only(pfl->bs);
+    } else {
+        pfl->ro = 0;
+    }
+
     pfl->timer = qemu_new_timer_ns(vm_clock, pflash_timer, pfl);
     pfl->base = base;
     pfl->sector_len = sector_len;
diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c
index 2ca0fd4560..3e2002e4b3 100644
--- a/hw/pflash_cfi02.c
+++ b/hw/pflash_cfi02.c
@@ -330,35 +330,37 @@ static void pflash_write (pflash_t *pfl, target_phys_addr_t offset,
             DPRINTF("%s: write data offset " TARGET_FMT_plx " %08x %d\n",
                     __func__, offset, value, width);
             p = pfl->storage;
-            switch (width) {
-            case 1:
-                p[offset] &= value;
-                pflash_update(pfl, offset, 1);
-                break;
-            case 2:
-                if (be) {
-                    p[offset] &= value >> 8;
-                    p[offset + 1] &= value;
-                } else {
+            if (!pfl->ro) {
+                switch (width) {
+                case 1:
                     p[offset] &= value;
-                    p[offset + 1] &= value >> 8;
+                    pflash_update(pfl, offset, 1);
+                    break;
+                case 2:
+                    if (be) {
+                        p[offset] &= value >> 8;
+                        p[offset + 1] &= value;
+                    } else {
+                        p[offset] &= value;
+                        p[offset + 1] &= value >> 8;
+                    }
+                    pflash_update(pfl, offset, 2);
+                    break;
+                case 4:
+                    if (be) {
+                        p[offset] &= value >> 24;
+                        p[offset + 1] &= value >> 16;
+                        p[offset + 2] &= value >> 8;
+                        p[offset + 3] &= value;
+                    } else {
+                        p[offset] &= value;
+                        p[offset + 1] &= value >> 8;
+                        p[offset + 2] &= value >> 16;
+                        p[offset + 3] &= value >> 24;
+                    }
+                    pflash_update(pfl, offset, 4);
+                    break;
                 }
-                pflash_update(pfl, offset, 2);
-                break;
-            case 4:
-                if (be) {
-                    p[offset] &= value >> 24;
-                    p[offset + 1] &= value >> 16;
-                    p[offset + 2] &= value >> 8;
-                    p[offset + 3] &= value;
-                } else {
-                    p[offset] &= value;
-                    p[offset + 1] &= value >> 8;
-                    p[offset + 2] &= value >> 16;
-                    p[offset + 3] &= value >> 24;
-                }
-                pflash_update(pfl, offset, 4);
-                break;
             }
             pfl->status = 0x00 | ~(value & 0x80);
             /* Let's pretend write is immediate */
@@ -404,9 +406,11 @@ static void pflash_write (pflash_t *pfl, target_phys_addr_t offset,
             }
             /* Chip erase */
             DPRINTF("%s: start chip erase\n", __func__);
-            memset(pfl->storage, 0xFF, pfl->chip_len);
+            if (!pfl->ro) {
+                memset(pfl->storage, 0xFF, pfl->chip_len);
+                pflash_update(pfl, 0, pfl->chip_len);
+            }
             pfl->status = 0x00;
-            pflash_update(pfl, 0, pfl->chip_len);
             /* Let's wait 5 seconds before chip erase is done */
             qemu_mod_timer(pfl->timer,
                            qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() * 5));
@@ -417,8 +421,10 @@ static void pflash_write (pflash_t *pfl, target_phys_addr_t offset,
             offset &= ~(pfl->sector_len - 1);
             DPRINTF("%s: start sector erase at " TARGET_FMT_plx "\n", __func__,
                     offset);
-            memset(p + offset, 0xFF, pfl->sector_len);
-            pflash_update(pfl, offset, pfl->sector_len);
+            if (!pfl->ro) {
+                memset(p + offset, 0xFF, pfl->sector_len);
+                pflash_update(pfl, offset, pfl->sector_len);
+            }
             pfl->status = 0x00;
             /* Let's wait 1/2 second before sector erase is done */
             qemu_mod_timer(pfl->timer,
@@ -645,16 +651,17 @@ pflash_t *pflash_cfi02_register(target_phys_addr_t base,
         }
         bdrv_attach_dev_nofail(pfl->bs, pfl);
     }
+
     pflash_setup_mappings(pfl);
     pfl->rom_mode = 1;
     memory_region_add_subregion(get_system_memory(), pfl->base, &pfl->mem);
-#if 0 /* XXX: there should be a bit to set up read-only,
-       *      the same way the hardware does (with WP pin).
-       */
-    pfl->ro = 1;
-#else
-    pfl->ro = 0;
-#endif
+
+    if (pfl->bs) {
+        pfl->ro = bdrv_is_read_only(pfl->bs);
+    } else {
+        pfl->ro = 0;
+    }
+
     pfl->timer = qemu_new_timer_ns(vm_clock, pflash_timer, pfl);
     pfl->sector_len = sector_len;
     pfl->width = width;
diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index 7b74dd5beb..0423af1c31 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -27,16 +27,6 @@ static void bit_prop_set(DeviceState *dev, Property *props, bool val)
 }
 
 /* Bit */
-static int parse_bit(DeviceState *dev, Property *prop, const char *str)
-{
-    if (!strcasecmp(str, "on"))
-        bit_prop_set(dev, prop, true);
-    else if (!strcasecmp(str, "off"))
-        bit_prop_set(dev, prop, false);
-    else
-        return -EINVAL;
-    return 0;
-}
 
 static int print_bit(DeviceState *dev, Property *prop, char *dest, size_t len)
 {
@@ -79,7 +69,6 @@ static void set_bit(Object *obj, Visitor *v, void *opaque,
 PropertyInfo qdev_prop_bit = {
     .name  = "boolean",
     .legacy_name  = "on/off",
-    .parse = parse_bit,
     .print = print_bit,
     .get   = get_bit,
     .set   = set_bit,
@@ -87,26 +76,6 @@ PropertyInfo qdev_prop_bit = {
 
 /* --- 8bit integer --- */
 
-static int parse_uint8(DeviceState *dev, Property *prop, const char *str)
-{
-    uint8_t *ptr = qdev_get_prop_ptr(dev, prop);
-    char *end;
-
-    /* accept both hex and decimal */
-    *ptr = strtoul(str, &end, 0);
-    if ((*end != '\0') || (end == str)) {
-        return -EINVAL;
-    }
-
-    return 0;
-}
-
-static int print_uint8(DeviceState *dev, Property *prop, char *dest, size_t len)
-{
-    uint8_t *ptr = qdev_get_prop_ptr(dev, prop);
-    return snprintf(dest, len, "%" PRIu8, *ptr);
-}
-
 static void get_int8(Object *obj, Visitor *v, void *opaque,
                      const char *name, Error **errp)
 {
@@ -149,8 +118,6 @@ static void set_int8(Object *obj, Visitor *v, void *opaque,
 
 PropertyInfo qdev_prop_uint8 = {
     .name  = "uint8",
-    .parse = parse_uint8,
-    .print = print_uint8,
     .get   = get_int8,
     .set   = set_int8,
     .min   = 0,
@@ -164,6 +131,10 @@ static int parse_hex8(DeviceState *dev, Property *prop, const char *str)
     uint8_t *ptr = qdev_get_prop_ptr(dev, prop);
     char *end;
 
+    if (str[0] != '0' || str[1] != 'x') {
+        return -EINVAL;
+    }
+
     *ptr = strtoul(str, &end, 16);
     if ((*end != '\0') || (end == str)) {
         return -EINVAL;
@@ -191,26 +162,6 @@ PropertyInfo qdev_prop_hex8 = {
 
 /* --- 16bit integer --- */
 
-static int parse_uint16(DeviceState *dev, Property *prop, const char *str)
-{
-    uint16_t *ptr = qdev_get_prop_ptr(dev, prop);
-    char *end;
-
-    /* accept both hex and decimal */
-    *ptr = strtoul(str, &end, 0);
-    if ((*end != '\0') || (end == str)) {
-        return -EINVAL;
-    }
-
-    return 0;
-}
-
-static int print_uint16(DeviceState *dev, Property *prop, char *dest, size_t len)
-{
-    uint16_t *ptr = qdev_get_prop_ptr(dev, prop);
-    return snprintf(dest, len, "%" PRIu16, *ptr);
-}
-
 static void get_int16(Object *obj, Visitor *v, void *opaque,
                       const char *name, Error **errp)
 {
@@ -253,8 +204,6 @@ static void set_int16(Object *obj, Visitor *v, void *opaque,
 
 PropertyInfo qdev_prop_uint16 = {
     .name  = "uint16",
-    .parse = parse_uint16,
-    .print = print_uint16,
     .get   = get_int16,
     .set   = set_int16,
     .min   = 0,
@@ -263,26 +212,6 @@ PropertyInfo qdev_prop_uint16 = {
 
 /* --- 32bit integer --- */
 
-static int parse_uint32(DeviceState *dev, Property *prop, const char *str)
-{
-    uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
-    char *end;
-
-    /* accept both hex and decimal */
-    *ptr = strtoul(str, &end, 0);
-    if ((*end != '\0') || (end == str)) {
-        return -EINVAL;
-    }
-
-    return 0;
-}
-
-static int print_uint32(DeviceState *dev, Property *prop, char *dest, size_t len)
-{
-    uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
-    return snprintf(dest, len, "%" PRIu32, *ptr);
-}
-
 static void get_int32(Object *obj, Visitor *v, void *opaque,
                       const char *name, Error **errp)
 {
@@ -325,37 +254,14 @@ static void set_int32(Object *obj, Visitor *v, void *opaque,
 
 PropertyInfo qdev_prop_uint32 = {
     .name  = "uint32",
-    .parse = parse_uint32,
-    .print = print_uint32,
     .get   = get_int32,
     .set   = set_int32,
     .min   = 0,
     .max   = 0xFFFFFFFFULL,
 };
 
-static int parse_int32(DeviceState *dev, Property *prop, const char *str)
-{
-    int32_t *ptr = qdev_get_prop_ptr(dev, prop);
-    char *end;
-
-    *ptr = strtol(str, &end, 10);
-    if ((*end != '\0') || (end == str)) {
-        return -EINVAL;
-    }
-
-    return 0;
-}
-
-static int print_int32(DeviceState *dev, Property *prop, char *dest, size_t len)
-{
-    int32_t *ptr = qdev_get_prop_ptr(dev, prop);
-    return snprintf(dest, len, "%" PRId32, *ptr);
-}
-
 PropertyInfo qdev_prop_int32 = {
     .name  = "int32",
-    .parse = parse_int32,
-    .print = print_int32,
     .get   = get_int32,
     .set   = set_int32,
     .min   = -0x80000000LL,
@@ -369,6 +275,10 @@ static int parse_hex32(DeviceState *dev, Property *prop, const char *str)
     uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
     char *end;
 
+    if (str[0] != '0' || str[1] != 'x') {
+        return -EINVAL;
+    }
+
     *ptr = strtoul(str, &end, 16);
     if ((*end != '\0') || (end == str)) {
         return -EINVAL;
@@ -396,26 +306,6 @@ PropertyInfo qdev_prop_hex32 = {
 
 /* --- 64bit integer --- */
 
-static int parse_uint64(DeviceState *dev, Property *prop, const char *str)
-{
-    uint64_t *ptr = qdev_get_prop_ptr(dev, prop);
-    char *end;
-
-    /* accept both hex and decimal */
-    *ptr = strtoull(str, &end, 0);
-    if ((*end != '\0') || (end == str)) {
-        return -EINVAL;
-    }
-
-    return 0;
-}
-
-static int print_uint64(DeviceState *dev, Property *prop, char *dest, size_t len)
-{
-    uint64_t *ptr = qdev_get_prop_ptr(dev, prop);
-    return snprintf(dest, len, "%" PRIu64, *ptr);
-}
-
 static void get_int64(Object *obj, Visitor *v, void *opaque,
                       const char *name, Error **errp)
 {
@@ -443,8 +333,6 @@ static void set_int64(Object *obj, Visitor *v, void *opaque,
 
 PropertyInfo qdev_prop_uint64 = {
     .name  = "uint64",
-    .parse = parse_uint64,
-    .print = print_uint64,
     .get   = get_int64,
     .set   = set_int64,
 };
@@ -456,6 +344,10 @@ static int parse_hex64(DeviceState *dev, Property *prop, const char *str)
     uint64_t *ptr = qdev_get_prop_ptr(dev, prop);
     char *end;
 
+    if (str[0] != '0' || str[1] != 'x') {
+        return -EINVAL;
+    }
+
     *ptr = strtoull(str, &end, 16);
     if ((*end != '\0') || (end == str)) {
         return -EINVAL;
@@ -737,19 +629,6 @@ PropertyInfo qdev_prop_netdev = {
 
 /* --- vlan --- */
 
-static int parse_vlan(DeviceState *dev, Property *prop, const char *str)
-{
-    VLANState **ptr = qdev_get_prop_ptr(dev, prop);
-    int id;
-
-    if (sscanf(str, "%d", &id) != 1)
-        return -EINVAL;
-    *ptr = qemu_find_vlan(id, 1);
-    if (*ptr == NULL)
-        return -ENOENT;
-    return 0;
-}
-
 static int print_vlan(DeviceState *dev, Property *prop, char *dest, size_t len)
 {
     VLANState **ptr = qdev_get_prop_ptr(dev, prop);
@@ -808,7 +687,6 @@ static void set_vlan(Object *obj, Visitor *v, void *opaque,
 
 PropertyInfo qdev_prop_vlan = {
     .name  = "vlan",
-    .parse = parse_vlan,
     .print = print_vlan,
     .get   = get_vlan,
     .set   = set_vlan,
@@ -943,25 +821,40 @@ PropertyInfo qdev_prop_losttickpolicy = {
 /*
  * bus-local address, i.e. "$slot" or "$slot.$fn"
  */
-static int parse_pci_devfn(DeviceState *dev, Property *prop, const char *str)
+static void set_pci_devfn(Object *obj, Visitor *v, void *opaque,
+                          const char *name, Error **errp)
 {
+    DeviceState *dev = DEVICE(obj);
+    Property *prop = opaque;
     uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
     unsigned int slot, fn, n;
+    Error *local_err = NULL;
+    char *str = (char *)"";
+
+    if (dev->state != DEV_STATE_CREATED) {
+        error_set(errp, QERR_PERMISSION_DENIED);
+        return;
+    }
+
+    visit_type_str(v, &str, name, &local_err);
+    if (local_err) {
+        return set_int32(obj, v, opaque, name, errp);
+    }
 
     if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) {
         fn = 0;
         if (sscanf(str, "%x%n", &slot, &n) != 1) {
-            return -EINVAL;
+            goto invalid;
         }
     }
-    if (str[n] != '\0')
-        return -EINVAL;
-    if (fn > 7)
-        return -EINVAL;
-    if (slot > 31)
-        return -EINVAL;
+    if (str[n] != '\0' || fn > 7 || slot > 31) {
+        goto invalid;
+    }
     *ptr = slot << 3 | fn;
-    return 0;
+    return;
+
+invalid:
+    error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
 }
 
 static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t len)
@@ -978,10 +871,9 @@ static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t
 PropertyInfo qdev_prop_pci_devfn = {
     .name  = "int32",
     .legacy_name  = "pci-devfn",
-    .parse = parse_pci_devfn,
     .print = print_pci_devfn,
     .get   = get_int32,
-    .set   = set_int32,
+    .set   = set_pci_devfn,
     /* FIXME: this should be -1...255, but the address is stored
      * into an uint32_t rather than int32_t.
      */
@@ -1054,9 +946,9 @@ int qdev_prop_parse(DeviceState *dev, const char *name, const char *value)
 
     legacy_name = g_strdup_printf("legacy-%s", name);
     if (object_property_get_type(OBJECT(dev), legacy_name, NULL)) {
-        object_property_set_str(OBJECT(dev), value, legacy_name, &err);
+        object_property_parse(OBJECT(dev), value, legacy_name, &err);
     } else {
-        object_property_set_str(OBJECT(dev), value, name, &err);
+        object_property_parse(OBJECT(dev), value, name, &err);
     }
     g_free(legacy_name);
 
diff --git a/hw/qxl-render.c b/hw/qxl-render.c
index 133d09324c..708414376e 100644
--- a/hw/qxl-render.c
+++ b/hw/qxl-render.c
@@ -121,19 +121,17 @@ void qxl_render_update(PCIQXLDevice *qxl)
         dpy_resize(vga->ds);
     }
 
-    if (!qxl->guest_primary.commands) {
-        return;
-    }
-    qxl->guest_primary.commands = 0;
-
     update.left   = 0;
     update.right  = qxl->guest_primary.surface.width;
     update.top    = 0;
     update.bottom = qxl->guest_primary.surface.height;
 
     memset(dirty, 0, sizeof(dirty));
-    qxl_spice_update_area(qxl, 0, &update,
-                          dirty, ARRAY_SIZE(dirty), 1, QXL_SYNC);
+    if (runstate_is_running() && qxl->guest_primary.commands) {
+        qxl->guest_primary.commands = 0;
+        qxl_spice_update_area(qxl, 0, &update,
+                              dirty, ARRAY_SIZE(dirty), 1, QXL_SYNC);
+    }
     if (redraw) {
         memset(dirty, 0, sizeof(dirty));
         dirty[0] = update;
diff --git a/hw/qxl.c b/hw/qxl.c
index ac69125f27..87ad49ad8b 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -625,7 +625,7 @@ static void interface_release_resource(QXLInstance *sin,
 
     if (ext.group_id == MEMSLOT_GROUP_HOST) {
         /* host group -> vga mode update request */
-        qemu_spice_destroy_update(&qxl->ssd, (void*)ext.info->id);
+        qemu_spice_destroy_update(&qxl->ssd, (void *)(intptr_t)ext.info->id);
         return;
     }
 
@@ -748,7 +748,8 @@ static void interface_async_complete(QXLInstance *sin, uint64_t cookie)
     qxl->current_async = QXL_UNDEFINED_IO;
     qemu_mutex_unlock(&qxl->async_lock);
 
-    dprint(qxl, 2, "async_complete: %d (%ld) done\n", current_async, cookie);
+    dprint(qxl, 2, "async_complete: %d (%" PRId64 ") done\n",
+           current_async, cookie);
     switch (current_async) {
     case QXL_IO_CREATE_PRIMARY_ASYNC:
         qxl_create_guest_primary_complete(qxl);
@@ -1006,7 +1007,7 @@ static void qxl_reset_surfaces(PCIQXLDevice *d)
     qxl_spice_destroy_surfaces(d, QXL_SYNC);
 }
 
-/* called from spice server thread context only */
+/* can be also called from spice server thread context */
 void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id)
 {
     uint64_t phys   = le64_to_cpu(pqxl);
@@ -1015,7 +1016,7 @@ void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id)
 
     switch (group_id) {
     case MEMSLOT_GROUP_HOST:
-        return (void*)offset;
+        return (void *)(intptr_t)offset;
     case MEMSLOT_GROUP_GUEST:
         PANIC_ON(slot >= NUM_MEMSLOTS);
         PANIC_ON(!qxl->guest_slots[slot].active);
@@ -1465,6 +1466,46 @@ static void qxl_hw_text_update(void *opaque, console_ch_t *chardata)
     }
 }
 
+static void qxl_dirty_surfaces(PCIQXLDevice *qxl)
+{
+    intptr_t vram_start;
+    int i;
+
+    if (qxl->mode != QXL_MODE_NATIVE && qxl->mode != QXL_MODE_COMPAT) {
+        return;
+    }
+
+    /* dirty the primary surface */
+    qxl_set_dirty(&qxl->vga.vram, qxl->shadow_rom.draw_area_offset,
+                  qxl->shadow_rom.surface0_area_size);
+
+    vram_start =  (intptr_t)memory_region_get_ram_ptr(&qxl->vram_bar);
+
+    /* dirty the off-screen surfaces */
+    for (i = 0; i < NUM_SURFACES; i++) {
+        QXLSurfaceCmd *cmd;
+        intptr_t surface_offset;
+        int surface_size;
+
+        if (qxl->guest_surfaces.cmds[i] == 0) {
+            continue;
+        }
+
+        cmd = qxl_phys2virt(qxl, qxl->guest_surfaces.cmds[i],
+                            MEMSLOT_GROUP_GUEST);
+        assert(cmd->type == QXL_SURFACE_CMD_CREATE);
+        surface_offset = (intptr_t)qxl_phys2virt(qxl,
+                                                 cmd->u.surface_create.data,
+                                                 MEMSLOT_GROUP_GUEST);
+        surface_offset -= vram_start;
+        surface_size = cmd->u.surface_create.height *
+                       abs(cmd->u.surface_create.stride);
+        dprint(qxl, 3, "%s: dirty surface %d, offset %d, size %d\n", __func__,
+               i, (int)surface_offset, surface_size);
+        qxl_set_dirty(&qxl->vram_bar, surface_offset, surface_size);
+    }
+}
+
 static void qxl_vm_change_state_handler(void *opaque, int running,
                                         RunState state)
 {
@@ -1478,14 +1519,9 @@ static void qxl_vm_change_state_handler(void *opaque, int running,
          * called
          */
          qxl_update_irq(qxl);
-    } else if (qxl->mode == QXL_MODE_NATIVE) {
-        /* dirty all vram (which holds surfaces) and devram (primary surface)
-         * to make sure they are saved */
-        /* FIXME #1: should go out during "live" stage */
-        /* FIXME #2: we only need to save the areas which are actually used */
-        qxl_set_dirty(&qxl->vram_bar, 0, qxl->vram_size);
-        qxl_set_dirty(&qxl->vga.vram, qxl->shadow_rom.draw_area_offset,
-                      qxl->shadow_rom.surface0_area_size);
+    } else {
+        /* make sure surfaces are saved before migration */
+        qxl_dirty_surfaces(qxl);
     }
 }
 
@@ -1518,6 +1554,31 @@ static DisplayChangeListener display_listener = {
     .dpy_refresh = display_refresh,
 };
 
+static void qxl_init_ramsize(PCIQXLDevice *qxl, uint32_t ram_min_mb)
+{
+    /* vga ram (bar 0) */
+    if (qxl->ram_size_mb != -1) {
+        qxl->vga.vram_size = qxl->ram_size_mb * 1024 * 1024;
+    }
+    if (qxl->vga.vram_size < ram_min_mb * 1024 * 1024) {
+        qxl->vga.vram_size = ram_min_mb * 1024 * 1024;
+    }
+
+    /* vram (surfaces, bar 1) */
+    if (qxl->vram_size_mb != -1) {
+        qxl->vram_size = qxl->vram_size_mb * 1024 * 1024;
+    }
+    if (qxl->vram_size < 4096) {
+        qxl->vram_size = 4096;
+    }
+    if (qxl->revision == 1) {
+        qxl->vram_size = 4096;
+    }
+
+    qxl->vga.vram_size = msb_mask(qxl->vga.vram_size * 2 - 1);
+    qxl->vram_size = msb_mask(qxl->vram_size * 2 - 1);
+}
+
 static int qxl_init_common(PCIQXLDevice *qxl)
 {
     uint8_t* config = qxl->pci.config;
@@ -1556,13 +1617,6 @@ static int qxl_init_common(PCIQXLDevice *qxl)
     init_qxl_rom(qxl);
     init_qxl_ram(qxl);
 
-    if (qxl->vram_size < 16 * 1024 * 1024) {
-        qxl->vram_size = 16 * 1024 * 1024;
-    }
-    if (qxl->revision == 1) {
-        qxl->vram_size = 4096;
-    }
-    qxl->vram_size = msb_mask(qxl->vram_size * 2 - 1);
     memory_region_init_ram(&qxl->vram_bar, "qxl.vram", qxl->vram_size);
     vmstate_register_ram(&qxl->vram_bar, &qxl->pci.qdev);
 
@@ -1605,15 +1659,11 @@ static int qxl_init_primary(PCIDevice *dev)
 {
     PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev);
     VGACommonState *vga = &qxl->vga;
-    ram_addr_t ram_size = msb_mask(qxl->vga.vram_size * 2 - 1);
     PortioList *qxl_vga_port_list = g_new(PortioList, 1);
 
     qxl->id = 0;
-
-    if (ram_size < 32 * 1024 * 1024) {
-        ram_size = 32 * 1024 * 1024;
-    }
-    vga_common_init(vga, ram_size);
+    qxl_init_ramsize(qxl, 32);
+    vga_common_init(vga, qxl->vga.vram_size);
     vga_init(vga, pci_address_space(dev), pci_address_space_io(dev), false);
     portio_list_init(qxl_vga_port_list, qxl_vga_portio_list, vga, "vga");
     portio_list_add(qxl_vga_port_list, pci_address_space_io(dev), 0x3b0);
@@ -1632,14 +1682,9 @@ static int qxl_init_secondary(PCIDevice *dev)
 {
     static int device_id = 1;
     PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev);
-    ram_addr_t ram_size = msb_mask(qxl->vga.vram_size * 2 - 1);
 
     qxl->id = device_id++;
-
-    if (ram_size < 16 * 1024 * 1024) {
-        ram_size = 16 * 1024 * 1024;
-    }
-    qxl->vga.vram_size = ram_size;
+    qxl_init_ramsize(qxl, 16);
     memory_region_init_ram(&qxl->vga.vram, "qxl.vgavram", qxl->vga.vram_size);
     vmstate_register_ram(&qxl->vga.vram, &qxl->pci.qdev);
     qxl->vga.vram_ptr = memory_region_get_ram_ptr(&qxl->vga.vram);
@@ -1821,6 +1866,8 @@ static Property qxl_properties[] = {
         DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0),
         DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0),
         DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0),
+        DEFINE_PROP_UINT32("ram_size_mb",  PCIQXLDevice, ram_size_mb, -1),
+        DEFINE_PROP_UINT32("vram_size_mb", PCIQXLDevice, vram_size_mb, -1),
         DEFINE_PROP_END_OF_LIST(),
 };
 
diff --git a/hw/qxl.h b/hw/qxl.h
index 766aa6d68e..d0629916ad 100644
--- a/hw/qxl.h
+++ b/hw/qxl.h
@@ -89,6 +89,10 @@ typedef struct PCIQXLDevice {
 
     /* io bar */
     MemoryRegion       io_bar;
+
+    /* user-friendly properties (in megabytes) */
+    uint32_t          ram_size_mb;
+    uint32_t          vram_size_mb;
 } PCIQXLDevice;
 
 #define PANIC_ON(x) if ((x)) {                         \
diff --git a/include/qemu/object.h b/include/qemu/object.h
index 5179c0cf5a..69e4b7b282 100644
--- a/include/qemu/object.h
+++ b/include/qemu/object.h
@@ -730,6 +730,30 @@ void object_property_set(Object *obj, struct Visitor *v, const char *name,
                          struct Error **errp);
 
 /**
+ * object_property_parse:
+ * @obj: the object
+ * @string: the string that will be used to parse the property value.
+ * @name: the name of the property
+ * @errp: returns an error if this function fails
+ *
+ * Parses a string and writes the result into a property of an object.
+ */
+void object_property_parse(Object *obj, const char *string,
+                           const char *name, struct Error **errp);
+
+/**
+ * object_property_print:
+ * @obj: the object
+ * @name: the name of the property
+ * @errp: returns an error if this function fails
+ *
+ * Returns a string representation of the value of the property.  The
+ * caller shall free the string.
+ */
+char *object_property_print(Object *obj, const char *name,
+                            struct Error **errp);
+
+/**
  * object_property_get_type:
  * @obj: the object
  * @name: the name of the property
@@ -813,6 +837,10 @@ Object *object_resolve_path_type(const char *path, const char *typename,
  *
  * There is no way for a child to determine what its parent is.  It is not
  * a bidirectional relationship.  This is by design.
+ *
+ * The value of a child property as a C string will be the child object's
+ * canonical path. It can be retrieved using object_property_get_str().
+ * The child object itself can be retrieved using object_property_get_link().
  */
 void object_property_add_child(Object *obj, const char *name,
                                Object *child, struct Error **errp);
diff --git a/monitor.c b/monitor.c
index aadbdcbf33..0d4daadf42 100644
--- a/monitor.c
+++ b/monitor.c
@@ -823,13 +823,18 @@ static int add_graphics_client(Monitor *mon, const QDict *qdict, QObject **ret_d
     CharDriverState *s;
 
     if (strcmp(protocol, "spice") == 0) {
+        int fd = monitor_get_fd(mon, fdname);
+        int skipauth = qdict_get_try_bool(qdict, "skipauth", 0);
+        int tls = qdict_get_try_bool(qdict, "tls", 0);
         if (!using_spice) {
             /* correct one? spice isn't a device ,,, */
             qerror_report(QERR_DEVICE_NOT_ACTIVE, "spice");
             return -1;
         }
-	qerror_report(QERR_ADD_CLIENT_FAILED);
-	return -1;
+        if (qemu_spice_display_add_client(fd, skipauth, tls) < 0) {
+            close(fd);
+        }
+        return 0;
 #ifdef CONFIG_VNC
     } else if (strcmp(protocol, "vnc") == 0) {
 	int fd = monitor_get_fd(mon, fdname);
diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c
index ddef3eda12..a4e088c9fc 100644
--- a/qapi/qapi-visit-core.c
+++ b/qapi/qapi-visit-core.c
@@ -12,6 +12,7 @@
  */
 
 #include "qapi/qapi-visit-core.h"
+#include "qapi/qapi-visit-impl.h"
 
 void visit_start_handle(Visitor *v, void **obj, const char *kind,
                         const char *name, Error **errp)
@@ -116,3 +117,53 @@ void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp)
         v->type_number(v, obj, name, errp);
     }
 }
+
+void output_type_enum(Visitor *v, int *obj, const char *strings[],
+                      const char *kind, const char *name,
+                      Error **errp)
+{
+    int i = 0;
+    int value = *obj;
+    char *enum_str;
+
+    assert(strings);
+    while (strings[i++] != NULL);
+    if (value < 0 || value >= i - 1) {
+        error_set(errp, QERR_INVALID_PARAMETER, name ? name : "null");
+        return;
+    }
+
+    enum_str = (char *)strings[value];
+    visit_type_str(v, &enum_str, name, errp);
+}
+
+void input_type_enum(Visitor *v, int *obj, const char *strings[],
+                     const char *kind, const char *name,
+                     Error **errp)
+{
+    int64_t value = 0;
+    char *enum_str;
+
+    assert(strings);
+
+    visit_type_str(v, &enum_str, name, errp);
+    if (error_is_set(errp)) {
+        return;
+    }
+
+    while (strings[value] != NULL) {
+        if (strcmp(strings[value], enum_str) == 0) {
+            break;
+        }
+        value++;
+    }
+
+    if (strings[value] == NULL) {
+        error_set(errp, QERR_INVALID_PARAMETER, name ? name : "null");
+        g_free(enum_str);
+        return;
+    }
+
+    g_free(enum_str);
+    *obj = value;
+}
diff --git a/qapi/qapi-visit-impl.h b/qapi/qapi-visit-impl.h
new file mode 100644
index 0000000000..0f3a1898fe
--- /dev/null
+++ b/qapi/qapi-visit-impl.h
@@ -0,0 +1,23 @@
+/*
+ * Core Definitions for QAPI Visitor implementations
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * Author: Paolo Bonizni <pbonzini@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+#ifndef QAPI_VISITOR_IMPL_H
+#define QAPI_VISITOR_IMPL_H
+
+#include "qapi/qapi-types-core.h"
+#include "qapi/qapi-visit-core.h"
+
+void input_type_enum(Visitor *v, int *obj, const char *strings[],
+                     const char *kind, const char *name, Error **errp);
+void output_type_enum(Visitor *v, int *obj, const char *strings[],
+                      const char *kind, const char *name, Error **errp);
+
+#endif
diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c
index c78022bb87..e6b6152e08 100644
--- a/qapi/qmp-input-visitor.c
+++ b/qapi/qmp-input-visitor.c
@@ -12,6 +12,7 @@
  */
 
 #include "qmp-input-visitor.h"
+#include "qapi/qapi-visit-impl.h"
 #include "qemu-queue.h"
 #include "qemu-common.h"
 #include "qemu-objects.h"
@@ -217,37 +218,6 @@ static void qmp_input_type_number(Visitor *v, double *obj, const char *name,
     *obj = qfloat_get_double(qobject_to_qfloat(qobj));
 }
 
-static void qmp_input_type_enum(Visitor *v, int *obj, const char *strings[],
-                                const char *kind, const char *name,
-                                Error **errp)
-{
-    int64_t value = 0;
-    char *enum_str;
-
-    assert(strings);
-
-    qmp_input_type_str(v, &enum_str, name, errp);
-    if (error_is_set(errp)) {
-        return;
-    }
-
-    while (strings[value] != NULL) {
-        if (strcmp(strings[value], enum_str) == 0) {
-            break;
-        }
-        value++;
-    }
-
-    if (strings[value] == NULL) {
-        error_set(errp, QERR_INVALID_PARAMETER, name ? name : "null");
-        g_free(enum_str);
-        return;
-    }
-
-    g_free(enum_str);
-    *obj = value;
-}
-
 static void qmp_input_start_optional(Visitor *v, bool *present,
                                      const char *name, Error **errp)
 {
@@ -262,10 +232,6 @@ static void qmp_input_start_optional(Visitor *v, bool *present,
     *present = true;
 }
 
-static void qmp_input_end_optional(Visitor *v, Error **errp)
-{
-}
-
 Visitor *qmp_input_get_visitor(QmpInputVisitor *v)
 {
     return &v->visitor;
@@ -288,13 +254,12 @@ QmpInputVisitor *qmp_input_visitor_new(QObject *obj)
     v->visitor.start_list = qmp_input_start_list;
     v->visitor.next_list = qmp_input_next_list;
     v->visitor.end_list = qmp_input_end_list;
-    v->visitor.type_enum = qmp_input_type_enum;
+    v->visitor.type_enum = input_type_enum;
     v->visitor.type_int = qmp_input_type_int;
     v->visitor.type_bool = qmp_input_type_bool;
     v->visitor.type_str = qmp_input_type_str;
     v->visitor.type_number = qmp_input_type_number;
     v->visitor.start_optional = qmp_input_start_optional;
-    v->visitor.end_optional = qmp_input_end_optional;
 
     v->obj = obj;
     qobject_incref(v->obj);
diff --git a/qapi/qmp-output-visitor.c b/qapi/qmp-output-visitor.c
index f76d0159cd..e0697b0d0f 100644
--- a/qapi/qmp-output-visitor.c
+++ b/qapi/qmp-output-visitor.c
@@ -12,6 +12,7 @@
  */
 
 #include "qmp-output-visitor.h"
+#include "qapi/qapi-visit-impl.h"
 #include "qemu-queue.h"
 #include "qemu-common.h"
 #include "qemu-objects.h"
@@ -180,25 +181,6 @@ static void qmp_output_type_number(Visitor *v, double *obj, const char *name,
     qmp_output_add(qov, name, qfloat_from_double(*obj));
 }
 
-static void qmp_output_type_enum(Visitor *v, int *obj, const char *strings[],
-                                 const char *kind, const char *name,
-                                 Error **errp)
-{
-    int i = 0;
-    int value = *obj;
-    char *enum_str;
-
-    assert(strings);
-    while (strings[i++] != NULL);
-    if (value < 0 || value >= i - 1) {
-        error_set(errp, QERR_INVALID_PARAMETER, name ? name : "null");
-        return;
-    }
-
-    enum_str = (char *)strings[value];
-    qmp_output_type_str(v, &enum_str, name, errp);
-}
-
 QObject *qmp_output_get_qobject(QmpOutputVisitor *qov)
 {
     QObject *obj = qmp_output_first(qov);
@@ -239,7 +221,7 @@ QmpOutputVisitor *qmp_output_visitor_new(void)
     v->visitor.start_list = qmp_output_start_list;
     v->visitor.next_list = qmp_output_next_list;
     v->visitor.end_list = qmp_output_end_list;
-    v->visitor.type_enum = qmp_output_type_enum;
+    v->visitor.type_enum = output_type_enum;
     v->visitor.type_int = qmp_output_type_int;
     v->visitor.type_bool = qmp_output_type_bool;
     v->visitor.type_str = qmp_output_type_str;
diff --git a/qapi/string-input-visitor.c b/qapi/string-input-visitor.c
new file mode 100644
index 0000000000..497eb9a60a
--- /dev/null
+++ b/qapi/string-input-visitor.c
@@ -0,0 +1,138 @@
+/*
+ * String parsing visitor
+ *
+ * Copyright Red Hat, Inc. 2012
+ *
+ * Author: Paolo Bonzini <pbonzini@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "string-input-visitor.h"
+#include "qapi/qapi-visit-impl.h"
+#include "qerror.h"
+
+struct StringInputVisitor
+{
+    Visitor visitor;
+    const char *string;
+};
+
+static void parse_type_int(Visitor *v, int64_t *obj, const char *name,
+                           Error **errp)
+{
+    StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
+    char *endp = (char *) siv->string;
+    long long val;
+
+    errno = 0;
+    if (siv->string) {
+        val = strtoll(siv->string, &endp, 0);
+    }
+    if (!siv->string || errno || endp == siv->string || *endp) {
+        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
+                  "integer");
+        return;
+    }
+
+    *obj = val;
+}
+
+static void parse_type_bool(Visitor *v, bool *obj, const char *name,
+                            Error **errp)
+{
+    StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
+
+    if (siv->string) {
+        if (!strcasecmp(siv->string, "on") ||
+            !strcasecmp(siv->string, "yes") ||
+            !strcasecmp(siv->string, "true")) {
+            *obj = true;
+            return;
+        }
+        if (!strcasecmp(siv->string, "off") ||
+            !strcasecmp(siv->string, "no") ||
+            !strcasecmp(siv->string, "false")) {
+            *obj = false;
+            return;
+        }
+    }
+
+    error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
+              "boolean");
+}
+
+static void parse_type_str(Visitor *v, char **obj, const char *name,
+                           Error **errp)
+{
+    StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
+    if (siv->string) {
+        *obj = g_strdup(siv->string);
+    } else {
+        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
+                  "string");
+    }
+}
+
+static void parse_type_number(Visitor *v, double *obj, const char *name,
+                              Error **errp)
+{
+    StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
+    char *endp = (char *) siv->string;
+    double val;
+
+    errno = 0;
+    if (siv->string) {
+        val = strtod(siv->string, &endp);
+    }
+    if (!siv->string || errno || endp == siv->string || *endp) {
+        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
+                  "number");
+        return;
+    }
+
+    *obj = val;
+}
+
+static void parse_start_optional(Visitor *v, bool *present,
+                                 const char *name, Error **errp)
+{
+    StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
+
+    if (!siv->string) {
+        *present = false;
+        return;
+    }
+
+    *present = true;
+}
+
+Visitor *string_input_get_visitor(StringInputVisitor *v)
+{
+    return &v->visitor;
+}
+
+void string_input_visitor_cleanup(StringInputVisitor *v)
+{
+    g_free(v);
+}
+
+StringInputVisitor *string_input_visitor_new(const char *str)
+{
+    StringInputVisitor *v;
+
+    v = g_malloc0(sizeof(*v));
+
+    v->visitor.type_enum = input_type_enum;
+    v->visitor.type_int = parse_type_int;
+    v->visitor.type_bool = parse_type_bool;
+    v->visitor.type_str = parse_type_str;
+    v->visitor.type_number = parse_type_number;
+    v->visitor.start_optional = parse_start_optional;
+
+    v->string = str;
+    return v;
+}
diff --git a/qapi/string-input-visitor.h b/qapi/string-input-visitor.h
new file mode 100644
index 0000000000..d269d42cef
--- /dev/null
+++ b/qapi/string-input-visitor.h
@@ -0,0 +1,25 @@
+/*
+ * String parsing Visitor
+ *
+ * Copyright Red Hat, Inc. 2012
+ *
+ * Author: Paolo Bonzini <pbonzini@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef STRING_INPUT_VISITOR_H
+#define STRING_INPUT_VISITOR_H
+
+#include "qapi-visit-core.h"
+
+typedef struct StringInputVisitor StringInputVisitor;
+
+StringInputVisitor *string_input_visitor_new(const char *str);
+void string_input_visitor_cleanup(StringInputVisitor *v);
+
+Visitor *string_input_get_visitor(StringInputVisitor *v);
+
+#endif
diff --git a/qapi/string-output-visitor.c b/qapi/string-output-visitor.c
new file mode 100644
index 0000000000..92b0305212
--- /dev/null
+++ b/qapi/string-output-visitor.c
@@ -0,0 +1,89 @@
+/*
+ * String printing Visitor
+ *
+ * Copyright Red Hat, Inc. 2012
+ *
+ * Author: Paolo Bonzini <pbonzini@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "string-output-visitor.h"
+#include "qapi/qapi-visit-impl.h"
+#include "qerror.h"
+
+struct StringOutputVisitor
+{
+    Visitor visitor;
+    char *string;
+};
+
+static void string_output_set(StringOutputVisitor *sov, char *string)
+{
+    g_free(sov->string);
+    sov->string = string;
+}
+
+static void print_type_int(Visitor *v, int64_t *obj, const char *name,
+                           Error **errp)
+{
+    StringOutputVisitor *sov = DO_UPCAST(StringOutputVisitor, visitor, v);
+    string_output_set(sov, g_strdup_printf("%lld", (long long) *obj));
+}
+
+static void print_type_bool(Visitor *v, bool *obj, const char *name,
+                            Error **errp)
+{
+    StringOutputVisitor *sov = DO_UPCAST(StringOutputVisitor, visitor, v);
+    string_output_set(sov, g_strdup(*obj ? "true" : "false"));
+}
+
+static void print_type_str(Visitor *v, char **obj, const char *name,
+                           Error **errp)
+{
+    StringOutputVisitor *sov = DO_UPCAST(StringOutputVisitor, visitor, v);
+    string_output_set(sov, g_strdup(*obj ? *obj : ""));
+}
+
+static void print_type_number(Visitor *v, double *obj, const char *name,
+                              Error **errp)
+{
+    StringOutputVisitor *sov = DO_UPCAST(StringOutputVisitor, visitor, v);
+    string_output_set(sov, g_strdup_printf("%g", *obj));
+}
+
+char *string_output_get_string(StringOutputVisitor *sov)
+{
+    char *string = sov->string;
+    sov->string = NULL;
+    return string;
+}
+
+Visitor *string_output_get_visitor(StringOutputVisitor *sov)
+{
+    return &sov->visitor;
+}
+
+void string_output_visitor_cleanup(StringOutputVisitor *sov)
+{
+    g_free(sov->string);
+    g_free(sov);
+}
+
+StringOutputVisitor *string_output_visitor_new(void)
+{
+    StringOutputVisitor *v;
+
+    v = g_malloc0(sizeof(*v));
+
+    v->visitor.type_enum = output_type_enum;
+    v->visitor.type_int = print_type_int;
+    v->visitor.type_bool = print_type_bool;
+    v->visitor.type_str = print_type_str;
+    v->visitor.type_number = print_type_number;
+
+    return v;
+}
diff --git a/qapi/string-output-visitor.h b/qapi/string-output-visitor.h
new file mode 100644
index 0000000000..8868454110
--- /dev/null
+++ b/qapi/string-output-visitor.h
@@ -0,0 +1,26 @@
+/*
+ * String printing Visitor
+ *
+ * Copyright Red Hat, Inc. 2012
+ *
+ * Author: Paolo Bonzini <pbonzini@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef STRING_OUTPUT_VISITOR_H
+#define STRING_OUTPUT_VISITOR_H
+
+#include "qapi-visit-core.h"
+
+typedef struct StringOutputVisitor StringOutputVisitor;
+
+StringOutputVisitor *string_output_visitor_new(void);
+void string_output_visitor_cleanup(StringOutputVisitor *v);
+
+char *string_output_get_string(StringOutputVisitor *v);
+Visitor *string_output_get_visitor(StringOutputVisitor *v);
+
+#endif
diff --git a/qemu-char.c b/qemu-char.c
index b1d80dd24e..bb9e3f50a8 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -218,15 +218,13 @@ static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
     return len;
 }
 
-static int qemu_chr_open_null(QemuOpts *opts, CharDriverState **_chr)
+static CharDriverState *qemu_chr_open_null(QemuOpts *opts)
 {
     CharDriverState *chr;
 
     chr = g_malloc0(sizeof(CharDriverState));
     chr->chr_write = null_chr_write;
-
-    *_chr= chr;
-    return 0;
+    return chr;
 }
 
 /* MUX driver for serial I/O splitting */
@@ -636,21 +634,19 @@ static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out)
     return chr;
 }
 
-static int qemu_chr_open_file_out(QemuOpts *opts, CharDriverState **_chr)
+static CharDriverState *qemu_chr_open_file_out(QemuOpts *opts)
 {
     int fd_out;
 
     TFR(fd_out = qemu_open(qemu_opt_get(opts, "path"),
                       O_WRONLY | O_TRUNC | O_CREAT | O_BINARY, 0666));
     if (fd_out < 0) {
-        return -errno;
+        return NULL;
     }
-
-    *_chr = qemu_chr_open_fd(-1, fd_out);
-    return 0;
+    return qemu_chr_open_fd(-1, fd_out);
 }
 
-static int qemu_chr_open_pipe(QemuOpts *opts, CharDriverState **_chr)
+static CharDriverState *qemu_chr_open_pipe(QemuOpts *opts)
 {
     int fd_in, fd_out;
     char filename_in[256], filename_out[256];
@@ -658,7 +654,7 @@ static int qemu_chr_open_pipe(QemuOpts *opts, CharDriverState **_chr)
 
     if (filename == NULL) {
         fprintf(stderr, "chardev: pipe: no filename given\n");
-        return -EINVAL;
+        return NULL;
     }
 
     snprintf(filename_in, 256, "%s.in", filename);
@@ -672,12 +668,10 @@ static int qemu_chr_open_pipe(QemuOpts *opts, CharDriverState **_chr)
 	    close(fd_out);
         TFR(fd_in = fd_out = qemu_open(filename, O_RDWR | O_BINARY));
         if (fd_in < 0) {
-            return -errno;
+            return NULL;
         }
     }
-
-    *_chr = qemu_chr_open_fd(fd_in, fd_out);
-    return 0;
+    return qemu_chr_open_fd(fd_in, fd_out);
 }
 
 
@@ -768,14 +762,13 @@ static void qemu_chr_close_stdio(struct CharDriverState *chr)
     fd_chr_close(chr);
 }
 
-static int qemu_chr_open_stdio(QemuOpts *opts, CharDriverState **_chr)
+static CharDriverState *qemu_chr_open_stdio(QemuOpts *opts)
 {
     CharDriverState *chr;
 
     if (stdio_nb_clients >= STDIO_MAX_CLIENTS) {
-        return -EBUSY;
+        return NULL;
     }
-
     if (stdio_nb_clients == 0) {
         old_fd0_flags = fcntl(0, F_GETFL);
         tcgetattr (0, &oldtty);
@@ -792,8 +785,7 @@ static int qemu_chr_open_stdio(QemuOpts *opts, CharDriverState **_chr)
                                            display_type != DT_NOGRAPHIC);
     qemu_chr_fe_set_echo(chr, false);
 
-    *_chr = chr;
-    return 0;
+    return chr;
 }
 
 #ifdef __sun__
@@ -980,7 +972,7 @@ static void pty_chr_close(struct CharDriverState *chr)
     qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
-static int qemu_chr_open_pty(QemuOpts *opts, CharDriverState **_chr)
+static CharDriverState *qemu_chr_open_pty(QemuOpts *opts)
 {
     CharDriverState *chr;
     PtyCharDriver *s;
@@ -995,7 +987,7 @@ static int qemu_chr_open_pty(QemuOpts *opts, CharDriverState **_chr)
 #endif
 
     if (openpty(&master_fd, &slave_fd, pty_name, NULL, NULL) < 0) {
-        return -errno;
+        return NULL;
     }
 
     /* Set raw attributes on the pty. */
@@ -1021,8 +1013,7 @@ static int qemu_chr_open_pty(QemuOpts *opts, CharDriverState **_chr)
     s->fd = master_fd;
     s->timer = qemu_new_timer_ms(rt_clock, pty_chr_timer, chr);
 
-    *_chr = chr;
-    return 0;
+    return chr;
 }
 
 static void tty_serial_init(int fd, int speed,
@@ -1223,7 +1214,7 @@ static void qemu_chr_close_tty(CharDriverState *chr)
     }
 }
 
-static int qemu_chr_open_tty(QemuOpts *opts, CharDriverState **_chr)
+static CharDriverState *qemu_chr_open_tty(QemuOpts *opts)
 {
     const char *filename = qemu_opt_get(opts, "path");
     CharDriverState *chr;
@@ -1231,20 +1222,18 @@ static int qemu_chr_open_tty(QemuOpts *opts, CharDriverState **_chr)
 
     TFR(fd = qemu_open(filename, O_RDWR | O_NONBLOCK));
     if (fd < 0) {
-        return -errno;
+        return NULL;
     }
     tty_serial_init(fd, 115200, 'N', 8, 1);
     chr = qemu_chr_open_fd(fd, fd);
     chr->chr_ioctl = tty_serial_ioctl;
     chr->chr_close = qemu_chr_close_tty;
-
-    *_chr = chr;
-    return 0;
+    return chr;
 }
 #else  /* ! __linux__ && ! __sun__ */
-static int qemu_chr_open_pty(QemuOpts *opts, CharDriverState **_chr)
+static CharDriverState *qemu_chr_open_pty(QemuOpts *opts)
 {
-    return -ENOTSUP;
+    return NULL;
 }
 #endif /* __linux__ || __sun__ */
 
@@ -1358,21 +1347,21 @@ static void pp_close(CharDriverState *chr)
     qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
-static int qemu_chr_open_pp(QemuOpts *opts, CharDriverState **_chr)
+static CharDriverState *qemu_chr_open_pp(QemuOpts *opts)
 {
     const char *filename = qemu_opt_get(opts, "path");
     CharDriverState *chr;
     ParallelCharDriver *drv;
     int fd;
 
-    TFR(fd = open(filename, O_RDWR));
+    TFR(fd = qemu_open(filename, O_RDWR));
     if (fd < 0) {
-        return -errno;
+        return NULL;
     }
 
     if (ioctl(fd, PPCLAIM) < 0) {
         close(fd);
-        return -errno;
+        return NULL;
     }
 
     drv = g_malloc0(sizeof(ParallelCharDriver));
@@ -1387,8 +1376,7 @@ static int qemu_chr_open_pp(QemuOpts *opts, CharDriverState **_chr)
 
     qemu_chr_generic_open(chr);
 
-    *_chr = chr;
-    return 0;
+    return chr;
 }
 #endif /* __linux__ */
 
@@ -1430,7 +1418,7 @@ static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
     return 0;
 }
 
-static int qemu_chr_open_pp(QemuOpts *opts, CharDriverState **_chr)
+static CharDriverState *qemu_chr_open_pp(QemuOpts *opts)
 {
     const char *filename = qemu_opt_get(opts, "path");
     CharDriverState *chr;
@@ -1438,16 +1426,14 @@ static int qemu_chr_open_pp(QemuOpts *opts, CharDriverState **_chr)
 
     fd = qemu_open(filename, O_RDWR);
     if (fd < 0) {
-        return -errno;
+        return NULL;
     }
 
     chr = g_malloc0(sizeof(CharDriverState));
     chr->opaque = (void *)(intptr_t)fd;
     chr->chr_write = null_chr_write;
     chr->chr_ioctl = pp_ioctl;
-
-    *_chr = chr;
-    return 0;
+    return chr;
 }
 #endif
 
@@ -1663,7 +1649,7 @@ static int win_chr_poll(void *opaque)
     return 0;
 }
 
-static int qemu_chr_open_win(QemuOpts *opts, CharDriverState **_chr)
+static CharDriverState *qemu_chr_open_win(QemuOpts *opts)
 {
     const char *filename = qemu_opt_get(opts, "path");
     CharDriverState *chr;
@@ -1678,12 +1664,10 @@ static int qemu_chr_open_win(QemuOpts *opts, CharDriverState **_chr)
     if (win_chr_init(chr, filename) < 0) {
         g_free(s);
         g_free(chr);
-        return -EIO;
+        return NULL;
     }
     qemu_chr_generic_open(chr);
-
-    *_chr = chr;
-    return 0;
+    return chr;
 }
 
 static int win_chr_pipe_poll(void *opaque)
@@ -1765,7 +1749,7 @@ static int win_chr_pipe_init(CharDriverState *chr, const char *filename)
 }
 
 
-static int qemu_chr_open_win_pipe(QemuOpts *opts, CharDriverState **_chr)
+static CharDriverState *qemu_chr_open_win_pipe(QemuOpts *opts)
 {
     const char *filename = qemu_opt_get(opts, "path");
     CharDriverState *chr;
@@ -1780,15 +1764,13 @@ static int qemu_chr_open_win_pipe(QemuOpts *opts, CharDriverState **_chr)
     if (win_chr_pipe_init(chr, filename) < 0) {
         g_free(s);
         g_free(chr);
-        return -EIO;
+        return NULL;
     }
     qemu_chr_generic_open(chr);
-
-    *_chr = chr;
-    return 0;
+    return chr;
 }
 
-static int qemu_chr_open_win_file(HANDLE fd_out, CharDriverState **pchr)
+static CharDriverState *qemu_chr_open_win_file(HANDLE fd_out)
 {
     CharDriverState *chr;
     WinCharState *s;
@@ -1799,16 +1781,15 @@ static int qemu_chr_open_win_file(HANDLE fd_out, CharDriverState **pchr)
     chr->opaque = s;
     chr->chr_write = win_chr_write;
     qemu_chr_generic_open(chr);
-    *pchr = chr;
-    return 0;
+    return chr;
 }
 
-static int qemu_chr_open_win_con(QemuOpts *opts, CharDriverState **chr)
+static CharDriverState *qemu_chr_open_win_con(QemuOpts *opts)
 {
-    return qemu_chr_open_win_file(GetStdHandle(STD_OUTPUT_HANDLE), chr);
+    return qemu_chr_open_win_file(GetStdHandle(STD_OUTPUT_HANDLE));
 }
 
-static int qemu_chr_open_win_file_out(QemuOpts *opts, CharDriverState **_chr)
+static CharDriverState *qemu_chr_open_win_file_out(QemuOpts *opts)
 {
     const char *file_out = qemu_opt_get(opts, "path");
     HANDLE fd_out;
@@ -1816,10 +1797,10 @@ static int qemu_chr_open_win_file_out(QemuOpts *opts, CharDriverState **_chr)
     fd_out = CreateFile(file_out, GENERIC_WRITE, FILE_SHARE_READ, NULL,
                         OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
     if (fd_out == INVALID_HANDLE_VALUE) {
-        return -EIO;
+        return NULL;
     }
 
-    return qemu_chr_open_win_file(fd_out, _chr);
+    return qemu_chr_open_win_file(fd_out);
 }
 
 static int win_stdio_write(CharDriverState *chr, const uint8_t *buf, int len)
@@ -1960,7 +1941,7 @@ static void win_stdio_close(CharDriverState *chr)
     stdio_nb_clients--;
 }
 
-static int qemu_chr_open_win_stdio(QemuOpts *opts, CharDriverState **_chr)
+static CharDriverState *qemu_chr_open_win_stdio(QemuOpts *opts)
 {
     CharDriverState   *chr;
     WinStdioCharState *stdio;
@@ -1969,7 +1950,7 @@ static int qemu_chr_open_win_stdio(QemuOpts *opts, CharDriverState **_chr)
 
     if (stdio_nb_clients >= STDIO_MAX_CLIENTS
         || ((display_type != DT_NOGRAPHIC) && (stdio_nb_clients != 0))) {
-        return -EIO;
+        return NULL;
     }
 
     chr   = g_malloc0(sizeof(CharDriverState));
@@ -2028,9 +2009,7 @@ static int qemu_chr_open_win_stdio(QemuOpts *opts, CharDriverState **_chr)
     chr->chr_set_echo = qemu_chr_set_echo_win_stdio;
     qemu_chr_fe_set_echo(chr, false);
 
-    *_chr = chr;
-
-    return 0;
+    return chr;
 }
 #endif /* !_WIN32 */
 
@@ -2111,12 +2090,11 @@ static void udp_chr_close(CharDriverState *chr)
     qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
-static int qemu_chr_open_udp(QemuOpts *opts, CharDriverState **_chr)
+static CharDriverState *qemu_chr_open_udp(QemuOpts *opts)
 {
     CharDriverState *chr = NULL;
     NetCharDriver *s = NULL;
     int fd = -1;
-    int ret;
 
     chr = g_malloc0(sizeof(CharDriverState));
     s = g_malloc0(sizeof(NetCharDriver));
@@ -2124,7 +2102,6 @@ static int qemu_chr_open_udp(QemuOpts *opts, CharDriverState **_chr)
     fd = inet_dgram_opts(opts);
     if (fd < 0) {
         fprintf(stderr, "inet_dgram_opts failed\n");
-        ret = -errno;
         goto return_err;
     }
 
@@ -2135,9 +2112,7 @@ static int qemu_chr_open_udp(QemuOpts *opts, CharDriverState **_chr)
     chr->chr_write = udp_chr_write;
     chr->chr_update_read_handler = udp_chr_update_read_handler;
     chr->chr_close = udp_chr_close;
-
-    *_chr = chr;
-    return 0;
+    return chr;
 
 return_err:
     g_free(chr);
@@ -2145,7 +2120,7 @@ return_err:
     if (fd >= 0) {
         closesocket(fd);
     }
-    return ret;
+    return NULL;
 }
 
 /***********************************************************/
@@ -2436,7 +2411,7 @@ static void tcp_chr_close(CharDriverState *chr)
     qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
-static int qemu_chr_open_socket(QemuOpts *opts, CharDriverState **_chr)
+static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
 {
     CharDriverState *chr = NULL;
     TCPCharDriver *s = NULL;
@@ -2446,7 +2421,6 @@ static int qemu_chr_open_socket(QemuOpts *opts, CharDriverState **_chr)
     int do_nodelay;
     int is_unix;
     int is_telnet;
-    int ret;
 
     is_listen      = qemu_opt_get_bool(opts, "server", 0);
     is_waitconnect = qemu_opt_get_bool(opts, "wait", 1);
@@ -2473,7 +2447,6 @@ static int qemu_chr_open_socket(QemuOpts *opts, CharDriverState **_chr)
         }
     }
     if (fd < 0) {
-        ret = -errno;
         goto fail;
     }
 
@@ -2528,16 +2501,14 @@ static int qemu_chr_open_socket(QemuOpts *opts, CharDriverState **_chr)
         tcp_chr_accept(chr);
         socket_set_nonblock(s->listen_fd);
     }
-
-    *_chr = chr;
-    return 0;
+    return chr;
 
  fail:
     if (fd >= 0)
         closesocket(fd);
     g_free(s);
     g_free(chr);
-    return ret;
+    return NULL;
 }
 
 /***********************************************************/
@@ -2730,7 +2701,7 @@ fail:
 
 static const struct {
     const char *name;
-    int (*open)(QemuOpts *opts, CharDriverState **chr);
+    CharDriverState *(*open)(QemuOpts *opts);
 } backend_table[] = {
     { .name = "null",      .open = qemu_chr_open_null },
     { .name = "socket",    .open = qemu_chr_open_socket },
@@ -2771,7 +2742,6 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
 {
     CharDriverState *chr;
     int i;
-    int ret;
 
     if (qemu_opts_id(opts) == NULL) {
         fprintf(stderr, "chardev: no id specified\n");
@@ -2793,10 +2763,10 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
         return NULL;
     }
 
-    ret = backend_table[i].open(opts, &chr);
-    if (ret < 0) {
-        fprintf(stderr, "chardev: opening backend \"%s\" failed: %s\n",
-                qemu_opt_get(opts, "backend"), strerror(-ret));
+    chr = backend_table[i].open(opts);
+    if (!chr) {
+        fprintf(stderr, "chardev: opening backend \"%s\" failed\n",
+                qemu_opt_get(opts, "backend"));
         return NULL;
     }
 
diff --git a/qemu-config.c b/qemu-config.c
index c9763e0b93..7d9da787c7 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -566,6 +566,18 @@ static QemuOptsList qemu_machine_opts = {
             .name = "kvm_shadow_mem",
             .type = QEMU_OPT_SIZE,
             .help = "KVM shadow MMU size",
+        }, {
+            .name = "kernel",
+            .type = QEMU_OPT_STRING,
+            .help = "Linux kernel image file",
+        }, {
+            .name = "initrd",
+            .type = QEMU_OPT_STRING,
+            .help = "Linux initial ramdisk file",
+        }, {
+            .name = "append",
+            .type = QEMU_OPT_STRING,
+            .help = "Linux kernel command line",
         },
         { /* End of list */ }
     },
diff --git a/qemu-sockets.c b/qemu-sockets.c
index 61b2247077..6bcb8e3e0f 100644
--- a/qemu-sockets.c
+++ b/qemu-sockets.c
@@ -26,7 +26,6 @@
 # define AI_ADDRCONFIG 0
 #endif
 
-static int sockets_debug = 0;
 static const int on=1, off=0;
 
 /* used temporarely until all users are converted to QemuOpts */
@@ -101,21 +100,6 @@ const char *inet_strfamily(int family)
     return "unknown";
 }
 
-static void inet_print_addrinfo(const char *tag, struct addrinfo *res)
-{
-    struct addrinfo *e;
-    char uaddr[INET6_ADDRSTRLEN+1];
-    char uport[33];
-
-    for (e = res; e != NULL; e = e->ai_next) {
-        getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen,
-                    uaddr,INET6_ADDRSTRLEN,uport,32,
-                    NI_NUMERICHOST | NI_NUMERICSERV);
-        fprintf(stderr,"%s: getaddrinfo: family %s, host %s, port %s\n",
-                tag, inet_strfamily(e->ai_family), uaddr, uport);
-    }
-}
-
 int inet_listen_opts(QemuOpts *opts, int port_offset)
 {
     struct addrinfo ai,*res,*e;
@@ -123,7 +107,7 @@ int inet_listen_opts(QemuOpts *opts, int port_offset)
     char port[33];
     char uaddr[INET6_ADDRSTRLEN+1];
     char uport[33];
-    int slisten,rc,to,try_next;
+    int slisten, rc, to, port_min, port_max, p;
 
     memset(&ai,0, sizeof(ai));
     ai.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
@@ -153,8 +137,6 @@ int inet_listen_opts(QemuOpts *opts, int port_offset)
                 gai_strerror(rc));
         return -1;
     }
-    if (sockets_debug)
-        inet_print_addrinfo(__FUNCTION__, res);
 
     /* create socket + bind */
     for (e = res; e != NULL; e = e->ai_next) {
@@ -177,23 +159,18 @@ int inet_listen_opts(QemuOpts *opts, int port_offset)
         }
 #endif
 
-        for (;;) {
+        port_min = inet_getport(e);
+        port_max = to ? to + port_offset : port_min;
+        for (p = port_min; p <= port_max; p++) {
+            inet_setport(e, p);
             if (bind(slisten, e->ai_addr, e->ai_addrlen) == 0) {
-                if (sockets_debug)
-                    fprintf(stderr,"%s: bind(%s,%s,%d): OK\n", __FUNCTION__,
-                        inet_strfamily(e->ai_family), uaddr, inet_getport(e));
                 goto listen;
             }
-            try_next = to && (inet_getport(e) <= to + port_offset);
-            if (!try_next || sockets_debug)
+            if (p == port_max) {
                 fprintf(stderr,"%s: bind(%s,%s,%d): %s\n", __FUNCTION__,
                         inet_strfamily(e->ai_family), uaddr, inet_getport(e),
                         strerror(errno));
-            if (try_next) {
-                inet_setport(e, inet_getport(e) + 1);
-                continue;
             }
-            break;
         }
         closesocket(slisten);
     }
@@ -249,8 +226,6 @@ int inet_connect_opts(QemuOpts *opts)
                 gai_strerror(rc));
 	return -1;
     }
-    if (sockets_debug)
-        inet_print_addrinfo(__FUNCTION__, res);
 
     for (e = res; e != NULL; e = e->ai_next) {
         if (getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen,
@@ -269,17 +244,13 @@ int inet_connect_opts(QemuOpts *opts)
 
         /* connect to peer */
         if (connect(sock,e->ai_addr,e->ai_addrlen) < 0) {
-            if (sockets_debug || NULL == e->ai_next)
+            if (NULL == e->ai_next)
                 fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__,
                         inet_strfamily(e->ai_family),
                         e->ai_canonname, uaddr, uport, strerror(errno));
             closesocket(sock);
             continue;
         }
-        if (sockets_debug)
-            fprintf(stderr, "%s: connect(%s,%s,%s,%s): OK\n", __FUNCTION__,
-                    inet_strfamily(e->ai_family),
-                    e->ai_canonname, uaddr, uport);
         freeaddrinfo(res);
         return sock;
     }
@@ -322,10 +293,6 @@ int inet_dgram_opts(QemuOpts *opts)
                 gai_strerror(rc));
 	return -1;
     }
-    if (sockets_debug) {
-        fprintf(stderr, "%s: peer (%s:%s)\n", __FUNCTION__, addr, port);
-        inet_print_addrinfo(__FUNCTION__, peer);
-    }
 
     /* lookup local addr */
     memset(&ai,0, sizeof(ai));
@@ -346,10 +313,6 @@ int inet_dgram_opts(QemuOpts *opts)
                 gai_strerror(rc));
         return -1;
     }
-    if (sockets_debug) {
-        fprintf(stderr, "%s: local (%s:%s)\n", __FUNCTION__, addr, port);
-        inet_print_addrinfo(__FUNCTION__, local);
-    }
 
     /* create socket */
     sock = qemu_socket(peer->ai_family, peer->ai_socktype, peer->ai_protocol);
@@ -541,8 +504,6 @@ int unix_listen_opts(QemuOpts *opts)
         goto err;
     }
 
-    if (sockets_debug)
-        fprintf(stderr, "bind(unix:%s): OK\n", un.sun_path);
     return sock;
 
 err:
@@ -576,8 +537,6 @@ int unix_connect_opts(QemuOpts *opts)
 	return -1;
     }
 
-    if (sockets_debug)
-        fprintf(stderr, "connect(unix:%s): OK\n", path);
     return sock;
 }
 
diff --git a/qmp-commands.hx b/qmp-commands.hx
index b5e2ab8574..dee95f1d67 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -910,8 +910,8 @@ EQMP
 
     {
         .name       = "add_client",
-        .args_type  = "protocol:s,fdname:s,skipauth:b?",
-        .params     = "protocol fdname skipauth",
+        .args_type  = "protocol:s,fdname:s,skipauth:b?,tls:b?",
+        .params     = "protocol fdname skipauth tls",
         .help       = "add a graphics client",
         .user_print = monitor_user_noop,
         .mhandler.cmd_new = add_graphics_client,
@@ -927,6 +927,8 @@ Arguments:
 
 - "protocol": protocol name (json-string)
 - "fdname": file descriptor name (json-string)
+- "skipauth": whether to skip authentication (json-bool, optional)
+- "tls": whether to perform TLS (json-bool, optional)
 
 Example:
 
diff --git a/qom/object.c b/qom/object.c
index 0cbd9bb004..aa037d299f 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -13,6 +13,8 @@
 #include "qemu/object.h"
 #include "qemu-common.h"
 #include "qapi/qapi-visit-core.h"
+#include "qapi/string-input-visitor.h"
+#include "qapi/string-output-visitor.h"
 
 /* TODO: replace QObject with a simpler visitor to avoid a dependency
  * of the QOM core on QObject?  */
@@ -262,7 +264,7 @@ void object_initialize_with_type(void *data, TypeImpl *type)
     Object *obj = data;
 
     g_assert(type != NULL);
-    g_assert(type->instance_size >= sizeof(ObjectClass));
+    g_assert(type->instance_size >= sizeof(Object));
 
     type_class_init(type);
     g_assert(type->abstract == false);
@@ -782,6 +784,29 @@ int64_t object_property_get_int(Object *obj, const char *name,
     return retval;
 }
 
+void object_property_parse(Object *obj, const char *string,
+                           const char *name, Error **errp)
+{
+    StringInputVisitor *mi;
+    mi = string_input_visitor_new(string);
+    object_property_set(obj, string_input_get_visitor(mi), name, errp);
+
+    string_input_visitor_cleanup(mi);
+}
+
+char *object_property_print(Object *obj, const char *name,
+                            Error **errp)
+{
+    StringOutputVisitor *mo;
+    char *string;
+
+    mo = string_output_visitor_new();
+    object_property_get(obj, string_output_get_visitor(mo), name, NULL);
+    string = string_output_get_string(mo);
+    string_output_visitor_cleanup(mo);
+    return string;
+}
+
 const char *object_property_get_type(Object *obj, const char *name, Error **errp)
 {
     ObjectProperty *prop = object_property_find(obj, name);
@@ -867,6 +892,7 @@ static void object_set_link_property(Object *obj, Visitor *v, void *opaque,
                                      const char *name, Error **errp)
 {
     Object **child = opaque;
+    Object *old_target;
     bool ambiguous = false;
     const char *type;
     char *path;
@@ -876,10 +902,8 @@ static void object_set_link_property(Object *obj, Visitor *v, void *opaque,
 
     visit_type_str(v, &path, name, errp);
 
-    if (*child) {
-        object_unref(*child);
-        *child = NULL;
-    }
+    old_target = *child;
+    *child = NULL;
 
     if (strcmp(path, "") != 0) {
         Object *target;
@@ -905,6 +929,10 @@ static void object_set_link_property(Object *obj, Visitor *v, void *opaque,
     }
 
     g_free(path);
+
+    if (old_target != NULL) {
+        object_unref(old_target);
+    }
 }
 
 void object_property_add_link(Object *obj, const char *name,
diff --git a/spice-qemu-char.c b/spice-qemu-char.c
index 7e8eaa9fd8..1e735ffd09 100644
--- a/spice-qemu-char.c
+++ b/spice-qemu-char.c
@@ -188,7 +188,7 @@ static void print_allowed_subtypes(void)
     fprintf(stderr, "\n");
 }
 
-int qemu_chr_open_spice(QemuOpts *opts, CharDriverState **_chr)
+CharDriverState *qemu_chr_open_spice(QemuOpts *opts)
 {
     CharDriverState *chr;
     SpiceCharDriver *s;
@@ -200,7 +200,7 @@ int qemu_chr_open_spice(QemuOpts *opts, CharDriverState **_chr)
     if (name == NULL) {
         fprintf(stderr, "spice-qemu-char: missing name parameter\n");
         print_allowed_subtypes();
-        return -EINVAL;
+        return NULL;
     }
     for(;*psubtype != NULL; ++psubtype) {
         if (strcmp(name, *psubtype) == 0) {
@@ -211,7 +211,7 @@ int qemu_chr_open_spice(QemuOpts *opts, CharDriverState **_chr)
     if (subtype == NULL) {
         fprintf(stderr, "spice-qemu-char: unsupported name\n");
         print_allowed_subtypes();
-        return -EINVAL;
+        return NULL;
     }
 
     chr = g_malloc0(sizeof(CharDriverState));
@@ -233,6 +233,5 @@ int qemu_chr_open_spice(QemuOpts *opts, CharDriverState **_chr)
     }
 #endif
 
-    *_chr = chr;
-    return 0;
+    return chr;
 }
diff --git a/sysconfigs/target/target-x86_64.conf b/sysconfigs/target/target-x86_64.conf
index 43ad282b5c..d0503804c2 100644
--- a/sysconfigs/target/target-x86_64.conf
+++ b/sysconfigs/target/target-x86_64.conf
@@ -7,9 +7,9 @@
    family = "6"
    model = "2"
    stepping = "3"
-   feature_edx = "sse2 sse fxsr mmx pat cmov pge sep apic cx8 mce pae msr tsc pse de fpu    mtrr clflush mca pse36"
-   feature_ecx = "sse3 ssse3"
-   extfeature_edx = "fxsr mmx pat cmov pge apic cx8 mce pae msr tsc pse de fpu    lm syscall nx"
+   feature_edx = "sse2 sse fxsr mmx clflush pse36 pat cmov mca pge mtrr sep apic cx8 mce pae msr tsc pse de fpu"
+   feature_ecx = "ssse3 sse3"
+   extfeature_edx = "i64 xd syscall"
    extfeature_ecx = "lahf_lm"
    xlevel = "0x8000000A"
    model_id = "Intel Celeron_4x0 (Conroe/Merom Class Core 2)"
@@ -21,9 +21,9 @@
    family = "6"
    model = "2"
    stepping = "3"
-   feature_edx = "sse2 sse fxsr mmx pat cmov pge sep apic cx8 mce pae msr tsc pse de fpu    mtrr clflush mca pse36"
-   feature_ecx = "sse3 cx16 ssse3 sse4.1"
-   extfeature_edx = "fxsr mmx pat cmov pge apic cx8 mce pae msr tsc pse de fpu    lm syscall nx"
+   feature_edx = "sse2 sse fxsr mmx clflush pse36 pat cmov mca pge mtrr sep apic cx8 mce pae msr tsc pse de fpu"
+   feature_ecx = "sse4.1 cx16 ssse3 sse3"
+   extfeature_edx = "i64 xd syscall"
    extfeature_ecx = "lahf_lm"
    xlevel = "0x8000000A"
    model_id = "Intel Core 2 Duo P9xxx (Penryn Class Core 2)"
@@ -35,24 +35,38 @@
    family = "6"
    model = "2"
    stepping = "3"
-   feature_edx = "sse2 sse fxsr mmx pat cmov pge sep apic cx8 mce pae msr tsc pse de fpu    mtrr clflush mca pse36"
-   feature_ecx = "sse3 cx16 ssse3 sse4.1 sse4.2 popcnt"
-   extfeature_edx = "fxsr mmx pat cmov pge apic cx8 mce pae msr tsc pse de fpu    lm syscall nx"
+   feature_edx = "sse2 sse fxsr mmx clflush pse36 pat cmov mca pge mtrr sep apic cx8 mce pae msr tsc pse de fpu"
+   feature_ecx = "popcnt sse4.2 sse4.1 cx16 ssse3 sse3"
+   extfeature_edx = "i64 syscall xd"
    extfeature_ecx = "lahf_lm"
    xlevel = "0x8000000A"
    model_id = "Intel Core i7 9xx (Nehalem Class Core i7)"
 
 [cpudef]
+   name = "Westmere"
+   level = "11"
+   vendor = "GenuineIntel"
+   family = "6"
+   model = "44"
+   stepping = "1"
+   feature_edx = "sse2 sse fxsr mmx clflush pse36 pat cmov mca pge mtrr sep apic cx8 mce pae msr tsc pse de fpu"
+   feature_ecx = "aes popcnt sse4.2 sse4.1 cx16 ssse3 sse3"
+   extfeature_edx = "i64 syscall xd"
+   extfeature_ecx = "lahf_lm"
+   xlevel = "0x8000000A"
+   model_id = "Westmere E56xx/L56xx/X56xx (Nehalem-C)"
+
+[cpudef]
    name = "Opteron_G1"
    level = "5"
    vendor = "AuthenticAMD"
    family = "15"
    model = "6"
    stepping = "1"
-   feature_edx = "sse2 sse fxsr mmx pat cmov pge sep apic cx8 mce pae msr tsc pse de fpu    mtrr clflush mca pse36"
+   feature_edx = "sse2 sse fxsr mmx clflush pse36 pat cmov mca pge mtrr sep apic cx8 mce pae msr tsc pse de fpu"
    feature_ecx = "sse3"
-   extfeature_edx = "fxsr mmx pat cmov pge apic cx8 mce pae msr tsc pse de fpu    lm syscall nx"
-#   extfeature_ecx = ""
+   extfeature_edx = "lm fxsr mmx nx pse36 pat cmov mca pge mtrr syscall apic cx8 mce pae msr tsc pse de fpu"
+   extfeature_ecx = " "
    xlevel = "0x80000008"
    model_id = "AMD Opteron 240 (Gen 1 Class Opteron)"
 
@@ -63,9 +77,9 @@
    family = "15"
    model = "6"
    stepping = "1"
-   feature_edx = "sse2 sse fxsr mmx pat cmov pge sep apic cx8 mce pae msr tsc pse de fpu    mtrr clflush mca pse36"
-   feature_ecx = "sse3 cx16"
-   extfeature_edx = "fxsr mmx pat cmov pge apic cx8 mce pae msr tsc pse de fpu    lm syscall nx rdtscp"
+   feature_edx = "sse2 sse fxsr mmx clflush pse36 pat cmov mca pge mtrr sep apic cx8 mce pae msr tsc pse de fpu"
+   feature_ecx = "cx16 sse3"
+   extfeature_edx = "lm rdtscp fxsr mmx nx pse36 pat cmov mca pge mtrr syscall apic cx8 mce pae msr tsc pse de fpu"
    extfeature_ecx = "svm lahf_lm"
    xlevel = "0x80000008"
    model_id = "AMD Opteron 22xx (Gen 2 Class Opteron)"
@@ -77,10 +91,10 @@
    family = "15"
    model = "6"
    stepping = "1"
-   feature_edx = "sse2 sse fxsr mmx pat cmov pge sep apic cx8 mce pae msr tsc pse de fpu    mtrr clflush mca pse36"
-   feature_ecx = "sse3 cx16 monitor popcnt"
-   extfeature_edx = "fxsr mmx pat cmov pge apic cx8 mce pae msr tsc pse de fpu    lm syscall nx rdtscp"
-   extfeature_ecx = "svm sse4a  abm misalignsse lahf_lm"
+   feature_edx = "sse2 sse fxsr mmx clflush pse36 pat cmov mca pge mtrr sep apic cx8 mce pae msr tsc pse de fpu"
+   feature_ecx = "popcnt cx16 monitor sse3"
+   extfeature_edx = "lm rdtscp fxsr mmx nx pse36 pat cmov mca pge mtrr syscall apic cx8 mce pae msr tsc pse de fpu"
+   extfeature_ecx = "misalignsse sse4a abm svm lahf_lm"
    xlevel = "0x80000008"
    model_id = "AMD Opteron 23xx (Gen 3 Class Opteron)"
 
diff --git a/target-i386/cpuid.c b/target-i386/cpuid.c
index b9bfeaff70..c2edb646fe 100644
--- a/target-i386/cpuid.c
+++ b/target-i386/cpuid.c
@@ -44,7 +44,7 @@ static const char *feature_name[] = {
     "ht" /* Intel htt */, "tm", "ia64", "pbe",
 };
 static const char *ext_feature_name[] = {
-    "pni|sse3" /* Intel,AMD sse3 */, "pclmuldq", "dtes64", "monitor",
+    "pni|sse3" /* Intel,AMD sse3 */, "pclmulqdq|pclmuldq", "dtes64", "monitor",
     "ds_cpl", "vmx", "smx", "est",
     "tm2", "ssse3", "cid", NULL,
     "fma", "cx16", "xtpr", "pdcm",
@@ -59,9 +59,9 @@ static const char *ext2_feature_name[] = {
     "cx8" /* AMD CMPXCHG8B */, "apic", NULL, "syscall",
     "mtrr", "pge", "mca", "cmov",
     "pat", "pse36", NULL, NULL /* Linux mp */,
-    "nx" /* Intel xd */, NULL, "mmxext", "mmx",
-    "fxsr", "fxsr_opt" /* AMD ffxsr */, "pdpe1gb" /* AMD Page1GB */, "rdtscp",
-    NULL, "lm" /* Intel 64 */, "3dnowext", "3dnow",
+    "nx|xd", NULL, "mmxext", "mmx",
+    "fxsr", "fxsr_opt|ffxsr", "pdpe1gb" /* AMD Page1GB */, "rdtscp",
+    NULL, "lm|i64", "3dnowext", "3dnow",
 };
 static const char *ext3_feature_name[] = {
     "lahf_lm" /* AMD LahfSahf */, "cmp_legacy", "svm", "extapic" /* AMD ExtApicSpace */,
@@ -597,6 +597,46 @@ static int check_features_against_host(x86_def_t *guest_def)
     return rv;
 }
 
+static void x86_cpuid_version_set_family(CPUX86State *env, int family)
+{
+    env->cpuid_version &= ~0xff00f00;
+    if (family > 0x0f) {
+        env->cpuid_version |= 0xf00 | ((family - 0x0f) << 20);
+    } else {
+        env->cpuid_version |= family << 8;
+    }
+}
+
+static void x86_cpuid_version_set_model(CPUX86State *env, int model)
+{
+    env->cpuid_version &= ~0xf00f0;
+    env->cpuid_version |= ((model & 0xf) << 4) | ((model >> 4) << 16);
+}
+
+static void x86_cpuid_version_set_stepping(CPUX86State *env, int stepping)
+{
+    env->cpuid_version &= ~0xf;
+    env->cpuid_version |= stepping & 0xf;
+}
+
+static void x86_cpuid_set_model_id(CPUX86State *env, const char *model_id)
+{
+    int c, len, i;
+
+    if (model_id == NULL) {
+        model_id = "";
+    }
+    len = strlen(model_id);
+    for (i = 0; i < 48; i++) {
+        if (i >= len) {
+            c = '\0';
+        } else {
+            c = (uint8_t)model_id[i];
+        }
+        env->cpuid_model[i >> 2] |= c << (8 * (i & 3));
+    }
+}
+
 static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
 {
     unsigned int i;
@@ -883,12 +923,9 @@ int cpu_x86_register (CPUX86State *env, const char *cpu_model)
     }
     env->cpuid_vendor_override = def->vendor_override;
     env->cpuid_level = def->level;
-    if (def->family > 0x0f)
-        env->cpuid_version = 0xf00 | ((def->family - 0x0f) << 20);
-    else
-        env->cpuid_version = def->family << 8;
-    env->cpuid_version |= ((def->model & 0xf) << 4) | ((def->model >> 4) << 16);
-    env->cpuid_version |= def->stepping;
+    x86_cpuid_version_set_family(env, def->family);
+    x86_cpuid_version_set_model(env, def->model);
+    x86_cpuid_version_set_stepping(env, def->stepping);
     env->cpuid_features = def->features;
     env->cpuid_ext_features = def->ext_features;
     env->cpuid_ext2_features = def->ext2_features;
@@ -910,20 +947,7 @@ int cpu_x86_register (CPUX86State *env, const char *cpu_model)
         env->cpuid_ext3_features &= TCG_EXT3_FEATURES;
         env->cpuid_svm_features &= TCG_SVM_FEATURES;
     }
-    {
-        const char *model_id = def->model_id;
-        int c, len, i;
-        if (!model_id)
-            model_id = "";
-        len = strlen(model_id);
-        for(i = 0; i < 48; i++) {
-            if (i >= len)
-                c = '\0';
-            else
-                c = (uint8_t)model_id[i];
-            env->cpuid_model[i >> 2] |= c << (8 * (i & 3));
-        }
-    }
+    x86_cpuid_set_model_id(env, def->model_id);
     return 0;
 }
 
diff --git a/test-string-input-visitor.c b/test-string-input-visitor.c
new file mode 100644
index 0000000000..5370e32041
--- /dev/null
+++ b/test-string-input-visitor.c
@@ -0,0 +1,195 @@
+/*
+ * String Input Visitor unit-tests.
+ *
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * Authors:
+ *  Paolo Bonzini <pbonzini@redhat.com> (based on test-qmp-input-visitor)
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <glib.h>
+#include <stdarg.h>
+
+#include "qapi/string-input-visitor.h"
+#include "test-qapi-types.h"
+#include "test-qapi-visit.h"
+#include "qemu-objects.h"
+
+typedef struct TestInputVisitorData {
+    StringInputVisitor *siv;
+} TestInputVisitorData;
+
+static void visitor_input_teardown(TestInputVisitorData *data,
+                                   const void *unused)
+{
+    if (data->siv) {
+        string_input_visitor_cleanup(data->siv);
+        data->siv = NULL;
+    }
+}
+
+/* This is provided instead of a test setup function so that the JSON
+   string used by the tests are kept in the test functions (and not
+   int main()) */
+static
+Visitor *visitor_input_test_init(TestInputVisitorData *data,
+                                 const char *string)
+{
+    Visitor *v;
+
+    data->siv = string_input_visitor_new(string);
+    g_assert(data->siv != NULL);
+
+    v = string_input_get_visitor(data->siv);
+    g_assert(v != NULL);
+
+    return v;
+}
+
+static void test_visitor_in_int(TestInputVisitorData *data,
+                                const void *unused)
+{
+    int64_t res = 0, value = -42;
+    Error *errp = NULL;
+    Visitor *v;
+
+    v = visitor_input_test_init(data, "-42");
+
+    visit_type_int(v, &res, NULL, &errp);
+    g_assert(!error_is_set(&errp));
+    g_assert_cmpint(res, ==, value);
+}
+
+static void test_visitor_in_bool(TestInputVisitorData *data,
+                                 const void *unused)
+{
+    Error *errp = NULL;
+    bool res = false;
+    Visitor *v;
+
+    v = visitor_input_test_init(data, "true");
+
+    visit_type_bool(v, &res, NULL, &errp);
+    g_assert(!error_is_set(&errp));
+    g_assert_cmpint(res, ==, true);
+    visitor_input_teardown(data, unused);
+
+    v = visitor_input_test_init(data, "yes");
+
+    visit_type_bool(v, &res, NULL, &errp);
+    g_assert(!error_is_set(&errp));
+    g_assert_cmpint(res, ==, true);
+    visitor_input_teardown(data, unused);
+
+    v = visitor_input_test_init(data, "on");
+
+    visit_type_bool(v, &res, NULL, &errp);
+    g_assert(!error_is_set(&errp));
+    g_assert_cmpint(res, ==, true);
+    visitor_input_teardown(data, unused);
+
+    v = visitor_input_test_init(data, "false");
+
+    visit_type_bool(v, &res, NULL, &errp);
+    g_assert(!error_is_set(&errp));
+    g_assert_cmpint(res, ==, false);
+    visitor_input_teardown(data, unused);
+
+    v = visitor_input_test_init(data, "no");
+
+    visit_type_bool(v, &res, NULL, &errp);
+    g_assert(!error_is_set(&errp));
+    g_assert_cmpint(res, ==, false);
+    visitor_input_teardown(data, unused);
+
+    v = visitor_input_test_init(data, "off");
+
+    visit_type_bool(v, &res, NULL, &errp);
+    g_assert(!error_is_set(&errp));
+    g_assert_cmpint(res, ==, false);
+}
+
+static void test_visitor_in_number(TestInputVisitorData *data,
+                                   const void *unused)
+{
+    double res = 0, value = 3.14;
+    Error *errp = NULL;
+    Visitor *v;
+
+    v = visitor_input_test_init(data, "3.14");
+
+    visit_type_number(v, &res, NULL, &errp);
+    g_assert(!error_is_set(&errp));
+    g_assert_cmpfloat(res, ==, value);
+}
+
+static void test_visitor_in_string(TestInputVisitorData *data,
+                                   const void *unused)
+{
+    char *res = NULL, *value = (char *) "Q E M U";
+    Error *errp = NULL;
+    Visitor *v;
+
+    v = visitor_input_test_init(data, value);
+
+    visit_type_str(v, &res, NULL, &errp);
+    g_assert(!error_is_set(&errp));
+    g_assert_cmpstr(res, ==, value);
+
+    g_free(res);
+}
+
+static void test_visitor_in_enum(TestInputVisitorData *data,
+                                 const void *unused)
+{
+    Error *errp = NULL;
+    Visitor *v;
+    EnumOne i;
+
+    for (i = 0; EnumOne_lookup[i]; i++) {
+        EnumOne res = -1;
+
+        v = visitor_input_test_init(data, EnumOne_lookup[i]);
+
+        visit_type_EnumOne(v, &res, NULL, &errp);
+        g_assert(!error_is_set(&errp));
+        g_assert_cmpint(i, ==, res);
+
+        visitor_input_teardown(data, NULL);
+    }
+
+    data->siv = NULL;
+}
+
+static void input_visitor_test_add(const char *testpath,
+                                   TestInputVisitorData *data,
+                                   void (*test_func)(TestInputVisitorData *data, const void *user_data))
+{
+    g_test_add(testpath, TestInputVisitorData, data, NULL, test_func,
+               visitor_input_teardown);
+}
+
+int main(int argc, char **argv)
+{
+    TestInputVisitorData in_visitor_data;
+
+    g_test_init(&argc, &argv, NULL);
+
+    input_visitor_test_add("/string-visitor/input/int",
+                           &in_visitor_data, test_visitor_in_int);
+    input_visitor_test_add("/string-visitor/input/bool",
+                           &in_visitor_data, test_visitor_in_bool);
+    input_visitor_test_add("/string-visitor/input/number",
+                           &in_visitor_data, test_visitor_in_number);
+    input_visitor_test_add("/string-visitor/input/string",
+                            &in_visitor_data, test_visitor_in_string);
+    input_visitor_test_add("/string-visitor/input/enum",
+                            &in_visitor_data, test_visitor_in_enum);
+
+    g_test_run();
+
+    return 0;
+}
diff --git a/test-string-output-visitor.c b/test-string-output-visitor.c
new file mode 100644
index 0000000000..22909b84ef
--- /dev/null
+++ b/test-string-output-visitor.c
@@ -0,0 +1,188 @@
+/*
+ * String Output Visitor unit-tests.
+ *
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * Authors:
+ *  Paolo Bonzini <pbonzini@redhat.com> (based on test-qmp-output-visitor)
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <glib.h>
+
+#include "qapi/string-output-visitor.h"
+#include "test-qapi-types.h"
+#include "test-qapi-visit.h"
+#include "qemu-objects.h"
+
+typedef struct TestOutputVisitorData {
+    StringOutputVisitor *sov;
+    Visitor *ov;
+} TestOutputVisitorData;
+
+static void visitor_output_setup(TestOutputVisitorData *data,
+                                 const void *unused)
+{
+    data->sov = string_output_visitor_new();
+    g_assert(data->sov != NULL);
+
+    data->ov = string_output_get_visitor(data->sov);
+    g_assert(data->ov != NULL);
+}
+
+static void visitor_output_teardown(TestOutputVisitorData *data,
+                                    const void *unused)
+{
+    string_output_visitor_cleanup(data->sov);
+    data->sov = NULL;
+    data->ov = NULL;
+}
+
+static void test_visitor_out_int(TestOutputVisitorData *data,
+                                 const void *unused)
+{
+    int64_t value = -42;
+    Error *errp = NULL;
+    char *str;
+
+    visit_type_int(data->ov, &value, NULL, &errp);
+    g_assert(error_is_set(&errp) == 0);
+
+    str = string_output_get_string(data->sov);
+    g_assert(str != NULL);
+    g_assert_cmpstr(str, ==, "-42");
+    g_free(str);
+}
+
+static void test_visitor_out_bool(TestOutputVisitorData *data,
+                                  const void *unused)
+{
+    Error *errp = NULL;
+    bool value = true;
+    char *str;
+
+    visit_type_bool(data->ov, &value, NULL, &errp);
+    g_assert(error_is_set(&errp) == 0);
+
+    str = string_output_get_string(data->sov);
+    g_assert(str != NULL);
+    g_assert_cmpstr(str, ==, "true");
+    g_free(str);
+}
+
+static void test_visitor_out_number(TestOutputVisitorData *data,
+                                    const void *unused)
+{
+    double value = 3.14;
+    Error *errp = NULL;
+    char *str;
+
+    visit_type_number(data->ov, &value, NULL, &errp);
+    g_assert(error_is_set(&errp) == 0);
+
+    str = string_output_get_string(data->sov);
+    g_assert(str != NULL);
+    g_assert_cmpstr(str, ==, "3.14");
+    g_free(str);
+}
+
+static void test_visitor_out_string(TestOutputVisitorData *data,
+                                    const void *unused)
+{
+    char *string = (char *) "Q E M U";
+    Error *errp = NULL;
+    char *str;
+
+    visit_type_str(data->ov, &string, NULL, &errp);
+    g_assert(error_is_set(&errp) == 0);
+
+    str = string_output_get_string(data->sov);
+    g_assert(str != NULL);
+    g_assert_cmpstr(str, ==, string);
+    g_free(str);
+}
+
+static void test_visitor_out_no_string(TestOutputVisitorData *data,
+                                       const void *unused)
+{
+    char *string = NULL;
+    Error *errp = NULL;
+    char *str;
+
+    /* A null string should return "" */
+    visit_type_str(data->ov, &string, NULL, &errp);
+    g_assert(error_is_set(&errp) == 0);
+
+    str = string_output_get_string(data->sov);
+    g_assert(str != NULL);
+    g_assert_cmpstr(str, ==, "");
+    g_free(str);
+}
+
+static void test_visitor_out_enum(TestOutputVisitorData *data,
+                                  const void *unused)
+{
+    Error *errp = NULL;
+    char *str;
+    EnumOne i;
+
+    for (i = 0; i < ENUM_ONE_MAX; i++) {
+        visit_type_EnumOne(data->ov, &i, "unused", &errp);
+        g_assert(!error_is_set(&errp));
+
+        str = string_output_get_string(data->sov);
+        g_assert(str != NULL);
+        g_assert_cmpstr(str, ==, EnumOne_lookup[i]);
+	g_free(str);
+    }
+}
+
+static void test_visitor_out_enum_errors(TestOutputVisitorData *data,
+                                         const void *unused)
+{
+    EnumOne i, bad_values[] = { ENUM_ONE_MAX, -1 };
+    Error *errp;
+
+    for (i = 0; i < ARRAY_SIZE(bad_values) ; i++) {
+        errp = NULL;
+        visit_type_EnumOne(data->ov, &bad_values[i], "unused", &errp);
+        g_assert(error_is_set(&errp) == true);
+        error_free(errp);
+    }
+}
+
+static void output_visitor_test_add(const char *testpath,
+                                    TestOutputVisitorData *data,
+                                    void (*test_func)(TestOutputVisitorData *data, const void *user_data))
+{
+    g_test_add(testpath, TestOutputVisitorData, data, visitor_output_setup,
+               test_func, visitor_output_teardown);
+}
+
+int main(int argc, char **argv)
+{
+    TestOutputVisitorData out_visitor_data;
+
+    g_test_init(&argc, &argv, NULL);
+
+    output_visitor_test_add("/string-visitor/output/int",
+                            &out_visitor_data, test_visitor_out_int);
+    output_visitor_test_add("/string-visitor/output/bool",
+                            &out_visitor_data, test_visitor_out_bool);
+    output_visitor_test_add("/string-visitor/output/number",
+                            &out_visitor_data, test_visitor_out_number);
+    output_visitor_test_add("/string-visitor/output/string",
+                            &out_visitor_data, test_visitor_out_string);
+    output_visitor_test_add("/string-visitor/output/no-string",
+                            &out_visitor_data, test_visitor_out_no_string);
+    output_visitor_test_add("/string-visitor/output/enum",
+                            &out_visitor_data, test_visitor_out_enum);
+    output_visitor_test_add("/string-visitor/output/enum-errors",
+                            &out_visitor_data, test_visitor_out_enum_errors);
+
+    g_test_run();
+
+    return 0;
+}
diff --git a/tests/Makefile b/tests/Makefile
index 55e8eb0ad5..74b29dc076 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -1,6 +1,6 @@
 CHECKS = check-qdict check-qfloat check-qint check-qstring check-qlist
 CHECKS += check-qjson test-qmp-output-visitor test-qmp-input-visitor
-CHECKS += test-coroutine
+CHECKS += test-string-input-visitor test-string-output-visitor test-coroutine
 
 check-qint.o check-qstring.o check-qdict.o check-qlist.o check-qfloat.o check-qjson.o test-coroutine.o: $(GENERATED_HEADERS)
 
@@ -12,7 +12,9 @@ check-qfloat: check-qfloat.o qfloat.o $(tools-obj-y)
 check-qjson: check-qjson.o $(qobject-obj-y) $(tools-obj-y)
 test-coroutine: test-coroutine.o qemu-timer-common.o async.o $(coroutine-obj-y) $(tools-obj-y)
 
-test-qmp-input-visitor.o test-qmp-output-visitor.o test-qmp-commands.o qemu-ga$(EXESUF): QEMU_CFLAGS += -I $(qapi-dir)
+test-qmp-input-visitor.o test-qmp-output-visitor.o \
+test-string-input-visitor.o test-string-output-visitor.o \
+	test-qmp-commands.o qemu-ga$(EXESUF): QEMU_CFLAGS += -I $(qapi-dir)
 
 $(qapi-dir)/test-qapi-types.c $(qapi-dir)/test-qapi-types.h :\
 $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py
@@ -25,6 +27,12 @@ $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-commands.py
 	    $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -o "$(qapi-dir)" -p "test-" < $<, "  GEN   $@")
 
 
+test-string-output-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y)
+test-string-output-visitor: test-string-output-visitor.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
+
+test-string-input-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y)
+test-string-input-visitor: test-string-input-visitor.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
+
 test-qmp-output-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y)
 test-qmp-output-visitor: test-qmp-output-visitor.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
 
diff --git a/trace-events b/trace-events
index 9b26ce2304..e918ff61fd 100644
--- a/trace-events
+++ b/trace-events
@@ -141,6 +141,10 @@ ecc_mem_readl_ecr1(uint32_t ret) "Read event count 2 %08x"
 ecc_diag_mem_writeb(uint64_t addr, uint32_t val) "Write diagnostic %"PRId64" = %02x"
 ecc_diag_mem_readb(uint64_t addr, uint32_t ret) "Read diagnostic %"PRId64"= %02x"
 
+# hw/jazz-led.c
+jazz_led_read(uint64_t addr, uint8_t val) "read addr=0x%"PRIx64": 0x%x"
+jazz_led_write(uint64_t addr, uint8_t new) "write addr=0x%"PRIx64": 0x%x"
+
 # hw/lance.c
 lance_mem_readw(uint64_t addr, uint32_t ret) "addr=%"PRIx64"val=0x%04x"
 lance_mem_writew(uint64_t addr, uint32_t val) "addr=%"PRIx64"val=0x%04x"
diff --git a/ui/qemu-spice.h b/ui/qemu-spice.h
index c35b29c1f6..3299da87d6 100644
--- a/ui/qemu-spice.h
+++ b/ui/qemu-spice.h
@@ -33,6 +33,7 @@ void qemu_spice_init(void);
 void qemu_spice_input_init(void);
 void qemu_spice_audio_init(void);
 void qemu_spice_display_init(DisplayState *ds);
+int qemu_spice_display_add_client(int csock, int skipauth, int tls);
 int qemu_spice_add_interface(SpiceBaseInstance *sin);
 int qemu_spice_set_passwd(const char *passwd,
                           bool fail_if_connected, bool disconnect_if_connected);
@@ -44,7 +45,7 @@ int qemu_spice_migrate_info(const char *hostname, int port, int tls_port,
 void do_info_spice_print(Monitor *mon, const QObject *data);
 void do_info_spice(Monitor *mon, QObject **ret_data);
 
-int qemu_chr_open_spice(QemuOpts *opts, CharDriverState **_chr);
+CharDriverState *qemu_chr_open_spice(QemuOpts *opts);
 
 #else  /* CONFIG_SPICE */
 #include "monitor.h"
@@ -68,6 +69,12 @@ static inline int qemu_spice_migrate_info(const char *h, int p, int t,
     return -1;
 }
 
+static inline int qemu_spice_display_add_client(int csock, int skipauth,
+                                                int tls)
+{
+    return -1;
+}
+
 #endif /* CONFIG_SPICE */
 
 #endif /* QEMU_SPICE_H */
diff --git a/ui/spice-core.c b/ui/spice-core.c
index b4629f895b..1308a3d886 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -220,10 +220,23 @@ static void channel_event(int event, SpiceChannelEventInfo *info)
     }
 
     client = qdict_new();
-    add_addr_info(client, &info->paddr, info->plen);
-
     server = qdict_new();
-    add_addr_info(server, &info->laddr, info->llen);
+
+#ifdef SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT
+    if (info->flags & SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT) {
+        add_addr_info(client, (struct sockaddr *)&info->paddr_ext,
+                      info->plen_ext);
+        add_addr_info(server, (struct sockaddr *)&info->laddr_ext,
+                      info->llen_ext);
+    } else {
+        fprintf(stderr, "spice: %s, extended address is expected\n",
+                        __func__);
+#endif
+        add_addr_info(client, &info->paddr, info->plen);
+        add_addr_info(server, &info->laddr, info->llen);
+#ifdef SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT
+    }
+#endif
 
     if (event == SPICE_CHANNEL_EVENT_INITIALIZED) {
         qdict_put(server, "auth", qstring_from_str(auth));
@@ -376,16 +389,30 @@ static SpiceChannelList *qmp_query_spice_channels(void)
     QTAILQ_FOREACH(item, &channel_list, link) {
         SpiceChannelList *chan;
         char host[NI_MAXHOST], port[NI_MAXSERV];
+        struct sockaddr *paddr;
+        socklen_t plen;
 
         chan = g_malloc0(sizeof(*chan));
         chan->value = g_malloc0(sizeof(*chan->value));
 
-        getnameinfo(&item->info->paddr, item->info->plen,
+#ifdef SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT
+        if (item->info->flags & SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT) {
+            paddr = (struct sockaddr *)&item->info->paddr_ext;
+            plen = item->info->plen_ext;
+        } else {
+#endif
+            paddr = &item->info->paddr;
+            plen = item->info->plen;
+#ifdef SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT
+        }
+#endif
+
+        getnameinfo(paddr, plen,
                     host, sizeof(host), port, sizeof(port),
                     NI_NUMERICHOST | NI_NUMERICSERV);
         chan->value->host = g_strdup(host);
         chan->value->port = g_strdup(port);
-        chan->value->family = g_strdup(inet_strfamily(item->info->paddr.sa_family));
+        chan->value->family = g_strdup(inet_strfamily(paddr->sa_family));
 
         chan->value->connection_id = item->info->connection_id;
         chan->value->channel_type = item->info->type;
@@ -747,6 +774,19 @@ int qemu_spice_set_pw_expire(time_t expires)
     return qemu_spice_set_ticket(false, false);
 }
 
+int qemu_spice_display_add_client(int csock, int skipauth, int tls)
+{
+#if SPICE_SERVER_VERSION >= 0x000a01
+    if (tls) {
+        return spice_server_add_ssl_client(spice_server, csock, skipauth);
+    } else {
+        return spice_server_add_client(spice_server, csock, skipauth);
+    }
+#else
+    return -1;
+#endif
+}
+
 static void spice_register_config(void)
 {
     qemu_add_opts(&qemu_spice_opts);
diff --git a/vl.c b/vl.c
index d8a521afe2..641df593cb 100644
--- a/vl.c
+++ b/vl.c
@@ -1187,7 +1187,7 @@ static QEMUMachine *find_machine(const char *name)
     return NULL;
 }
 
-static QEMUMachine *find_default_machine(void)
+QEMUMachine *find_default_machine(void)
 {
     QEMUMachine *m;
 
@@ -1857,8 +1857,10 @@ struct device_config {
         DEV_PARALLEL,  /* -parallel      */
         DEV_VIRTCON,   /* -virtioconsole */
         DEV_DEBUGCON,  /* -debugcon */
+        DEV_GDB,       /* -gdb, -s */
     } type;
     const char *cmdline;
+    Location loc;
     QTAILQ_ENTRY(device_config) next;
 };
 QTAILQ_HEAD(, device_config) device_configs = QTAILQ_HEAD_INITIALIZER(device_configs);
@@ -1870,6 +1872,7 @@ static void add_device_config(int type, const char *cmdline)
     conf = g_malloc0(sizeof(*conf));
     conf->type = type;
     conf->cmdline = cmdline;
+    loc_save(&conf->loc);
     QTAILQ_INSERT_TAIL(&device_configs, conf, next);
 }
 
@@ -1881,7 +1884,9 @@ static int foreach_device_config(int type, int (*func)(const char *cmdline))
     QTAILQ_FOREACH(conf, &device_configs, next) {
         if (conf->type != type)
             continue;
+        loc_push_restore(&conf->loc);
         rc = func(conf->cmdline);
+        loc_pop(&conf->loc);
         if (0 != rc)
             return rc;
     }
@@ -2178,7 +2183,6 @@ int qemu_init_main_loop(void)
 
 int main(int argc, char **argv, char **envp)
 {
-    const char *gdbstub_dev = NULL;
     int i;
     int snapshot, linux_boot;
     const char *icount_option = NULL;
@@ -2238,11 +2242,8 @@ int main(int argc, char **argv, char **envp)
     module_call_init(MODULE_INIT_MACHINE);
     machine = find_default_machine();
     cpu_model = NULL;
-    initrd_filename = NULL;
     ram_size = 0;
     snapshot = 0;
-    kernel_filename = NULL;
-    kernel_cmdline = "";
     cyls = heads = secs = 0;
     translation = BIOS_ATA_TRANSLATION_AUTO;
 
@@ -2318,9 +2319,6 @@ int main(int argc, char **argv, char **envp)
                     cpu_model = optarg;
                 }
                 break;
-            case QEMU_OPTION_initrd:
-                initrd_filename = optarg;
-                break;
             case QEMU_OPTION_hda:
                 {
                     char buf[256];
@@ -2451,10 +2449,13 @@ int main(int argc, char **argv, char **envp)
                 }
                 break;
             case QEMU_OPTION_kernel:
-                kernel_filename = optarg;
+                qemu_opts_set(qemu_find_opts("machine"), 0, "kernel", optarg);
+                break;
+            case QEMU_OPTION_initrd:
+                qemu_opts_set(qemu_find_opts("machine"), 0, "initrd", optarg);
                 break;
             case QEMU_OPTION_append:
-                kernel_cmdline = optarg;
+                qemu_opts_set(qemu_find_opts("machine"), 0, "append", optarg);
                 break;
             case QEMU_OPTION_cdrom:
                 drive_add(IF_DEFAULT, 2, optarg, CDROM_OPTS);
@@ -2606,10 +2607,10 @@ int main(int argc, char **argv, char **envp)
                 log_file = optarg;
                 break;
             case QEMU_OPTION_s:
-                gdbstub_dev = "tcp::" DEFAULT_GDBSTUB_PORT;
+                add_device_config(DEV_GDB, "tcp::" DEFAULT_GDBSTUB_PORT);
                 break;
             case QEMU_OPTION_gdb:
-                gdbstub_dev = optarg;
+                add_device_config(DEV_GDB, optarg);
                 break;
             case QEMU_OPTION_L:
                 data_dir = optarg;
@@ -3249,6 +3250,17 @@ int main(int argc, char **argv, char **envp)
         fprintf(stderr, "qemu_init_main_loop failed\n");
         exit(1);
     }
+
+    kernel_filename = qemu_opt_get(qemu_opts_find(qemu_find_opts("machine"),
+                                                  0), "kernel");
+    initrd_filename = qemu_opt_get(qemu_opts_find(qemu_find_opts("machine"),
+                                                  0), "initrd");
+    kernel_cmdline = qemu_opt_get(qemu_opts_find(qemu_find_opts("machine"),
+                                                 0), "append");
+    if (!kernel_cmdline) {
+        kernel_cmdline = "";
+    }
+
     linux_boot = (kernel_filename != NULL);
 
     if (!linux_boot && *kernel_cmdline != '\0') {
@@ -3488,9 +3500,7 @@ int main(int argc, char **argv, char **envp)
     }
     text_consoles_set_display(ds);
 
-    if (gdbstub_dev && gdbserver_start(gdbstub_dev) < 0) {
-        fprintf(stderr, "qemu: could not open gdbserver on device '%s'\n",
-                gdbstub_dev);
+    if (foreach_device_config(DEV_GDB, gdbserver_start) < 0) {
         exit(1);
     }