Merge remote branch 'qemu-kvm/uq/master' into staging
diff --git a/Makefile b/Makefile
index c72a059..c6629d6 100644
--- a/Makefile
+++ b/Makefile
@@ -191,7 +191,11 @@
 	$(INSTALL_DATA) qemu-nbd.8 "$(DESTDIR)$(mandir)/man8"
 endif
 
-install: all $(if $(BUILD_DOCS),install-doc)
+install-sysconfig:
+	$(INSTALL_DIR) "$(sysconfdir)/qemu"
+	$(INSTALL_DATA) sysconfigs/target/target-x86_64.conf "$(sysconfdir)/qemu"
+
+install: all $(if $(BUILD_DOCS),install-doc) install-sysconfig
 	$(INSTALL_DIR) "$(DESTDIR)$(bindir)"
 ifneq ($(TOOLS),)
 	$(INSTALL_PROG) $(STRIP_OPT) $(TOOLS) "$(DESTDIR)$(bindir)"
diff --git a/Makefile.target b/Makefile.target
index f498574..4c4d397 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -173,6 +173,7 @@
 # virtio has to be here due to weird dependency between PCI and virtio-net.
 # need to fix this properly
 obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-pci.o virtio-serial-bus.o
+obj-y += rwhandler.o
 obj-$(CONFIG_KVM) += kvm.o kvm-all.o
 obj-$(CONFIG_ISA_MMIO) += isa_mmio.o
 LIBS+=-lz
diff --git a/block.c b/block.c
index af56ea7..31d1ba4 100644
--- a/block.c
+++ b/block.c
@@ -363,6 +363,7 @@
     bs->is_temporary = 0;
     bs->encrypted = 0;
     bs->valid_key = 0;
+    bs->open_flags = flags;
     /* buffer_alignment defaulted to 512, drivers can change this value */
     bs->buffer_alignment = 512;
 
@@ -450,8 +451,6 @@
     if (flags & (BDRV_O_CACHE_WB|BDRV_O_NOCACHE))
         bs->enable_write_cache = 1;
 
-    bs->read_only = (flags & BDRV_O_RDWR) == 0;
-
     /*
      * Clear flags that are internal to the block layer before opening the
      * image.
@@ -472,6 +471,7 @@
         goto free_and_fail;
     }
 
+    bs->keep_read_only = bs->read_only = !(open_flags & BDRV_O_RDWR);
     if (drv->bdrv_getlength) {
         bs->total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
     }
@@ -488,13 +488,22 @@
                      filename, bs->backing_file);
         if (bs->backing_format[0] != '\0')
             back_drv = bdrv_find_format(bs->backing_format);
+
+        /* backing files always opened read-only */
+        open_flags &= ~BDRV_O_RDWR;
+        
         ret = bdrv_open2(bs->backing_hd, backing_filename, open_flags,
                          back_drv);
-        bs->backing_hd->read_only =  (open_flags & BDRV_O_RDWR) == 0;
         if (ret < 0) {
             bdrv_close(bs);
             return ret;
         }
+        if (bs->is_temporary) {
+            bs->backing_hd->keep_read_only = !(flags & BDRV_O_RDWR);
+        } else {
+            /* base image inherits from "parent" */
+            bs->backing_hd->keep_read_only = bs->keep_read_only;
+        }
     }
 
     if (!bdrv_key_required(bs)) {
@@ -570,19 +579,48 @@
 {
     BlockDriver *drv = bs->drv;
     int64_t i, total_sectors;
-    int n, j;
-    int ret = 0;
+    int n, j, ro, open_flags;
+    int ret = 0, rw_ret = 0;
     unsigned char sector[512];
+    char filename[1024];
+    BlockDriverState *bs_rw, *bs_ro;
 
     if (!drv)
         return -ENOMEDIUM;
-
-    if (bs->read_only) {
-	return -EACCES;
+    
+    if (!bs->backing_hd) {
+        return -ENOTSUP;
     }
 
-    if (!bs->backing_hd) {
-	return -ENOTSUP;
+    if (bs->backing_hd->keep_read_only) {
+        return -EACCES;
+    }
+    
+    ro = bs->backing_hd->read_only;
+    strncpy(filename, bs->backing_hd->filename, sizeof(filename));
+    open_flags =  bs->backing_hd->open_flags;
+
+    if (ro) {
+        /* re-open as RW */
+        bdrv_delete(bs->backing_hd);
+        bs->backing_hd = NULL;
+        bs_rw = bdrv_new("");
+        rw_ret = bdrv_open2(bs_rw, filename, open_flags | BDRV_O_RDWR, NULL);
+        if (rw_ret < 0) {
+            bdrv_delete(bs_rw);
+            /* try to re-open read-only */
+            bs_ro = bdrv_new("");
+            ret = bdrv_open2(bs_ro, filename, open_flags & ~BDRV_O_RDWR, NULL);
+            if (ret < 0) {
+                bdrv_delete(bs_ro);
+                /* drive not functional anymore */
+                bs->drv = NULL;
+                return ret;
+            }
+            bs->backing_hd = bs_ro;
+            return rw_ret;
+        }
+        bs->backing_hd = bs_rw;
     }
 
     total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
@@ -590,11 +628,13 @@
         if (drv->bdrv_is_allocated(bs, i, 65536, &n)) {
             for(j = 0; j < n; j++) {
                 if (bdrv_read(bs, i, sector, 1) != 0) {
-                    return -EIO;
+                    ret = -EIO;
+                    goto ro_cleanup;
                 }
 
                 if (bdrv_write(bs->backing_hd, i, sector, 1) != 0) {
-                    return -EIO;
+                    ret = -EIO;
+                    goto ro_cleanup;
                 }
                 i++;
 	    }
@@ -614,6 +654,25 @@
      */
     if (bs->backing_hd)
         bdrv_flush(bs->backing_hd);
+
+ro_cleanup:
+
+    if (ro) {
+        /* re-open as RO */
+        bdrv_delete(bs->backing_hd);
+        bs->backing_hd = NULL;
+        bs_ro = bdrv_new("");
+        ret = bdrv_open2(bs_ro, filename, open_flags & ~BDRV_O_RDWR, NULL);
+        if (ret < 0) {
+            bdrv_delete(bs_ro);
+            /* drive not functional anymore */
+            bs->drv = NULL;
+            return ret;
+        }
+        bs->backing_hd = bs_ro;
+        bs->backing_hd->keep_read_only = 0;
+    }
+
     return ret;
 }
 
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 3501a94..b13b693 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -750,12 +750,15 @@
     while (i < nb_clusters) {
         i += count_contiguous_clusters(nb_clusters - i, s->cluster_size,
                 &l2_table[l2_index], i, 0);
-
-        if(be64_to_cpu(l2_table[l2_index + i]))
+        if ((i >= nb_clusters) || be64_to_cpu(l2_table[l2_index + i])) {
             break;
+        }
 
         i += count_contiguous_free_clusters(nb_clusters - i,
                 &l2_table[l2_index + i]);
+        if (i >= nb_clusters) {
+            break;
+        }
 
         cluster_offset = be64_to_cpu(l2_table[l2_index + i]);
 
@@ -763,6 +766,7 @@
                 (cluster_offset & QCOW_OFLAG_COMPRESSED))
             break;
     }
+    assert(i <= nb_clusters);
     nb_clusters = i;
 
     /*
diff --git a/block_int.h b/block_int.h
index 930a5a4..50e1a0b 100644
--- a/block_int.h
+++ b/block_int.h
@@ -130,6 +130,8 @@
     int64_t total_sectors; /* if we are reading a disk image, give its
                               size in sectors */
     int read_only; /* if true, the media is read only */
+    int keep_read_only; /* if true, the media was requested to stay read only */
+    int open_flags; /* flags used to open the file, re-used for re-open */
     int removable; /* if true, the media can be removed */
     int locked;    /* if true, the media cannot temporarily be ejected */
     int encrypted; /* if true, the media is encrypted */
diff --git a/bswap.h b/bswap.h
index 4558704..aace9b7 100644
--- a/bswap.h
+++ b/bswap.h
@@ -214,4 +214,10 @@
 #undef le_bswaps
 #undef be_bswaps
 
+/* len must be one of 1, 2, 4 */
+static inline uint32_t qemu_bswap_len(uint32_t value, int len)
+{
+    return bswap32(value) >> (32 - 8 * len);
+}
+
 #endif /* BSWAP_H */
diff --git a/cache-utils.c b/cache-utils.c
index 45d62c9..8bbd680 100644
--- a/cache-utils.c
+++ b/cache-utils.c
@@ -57,6 +57,27 @@
 }
 #endif
 
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+static void ppc_init_cacheline_sizes(void)
+{
+    size_t len = 4;
+    unsigned cacheline;
+
+    if (sysctlbyname ("machdep.cacheline_size", &cacheline, &len, NULL, 0)) {
+        fprintf(stderr, "sysctlbyname machdep.cacheline_size failed: %s\n",
+                strerror(errno));
+        exit(1);
+    }
+
+    qemu_cache_conf.dcache_bsize = cacheline;
+    qemu_cache_conf.icache_bsize = cacheline;
+}
+#endif    
+
 #ifdef __linux__
 void qemu_cache_utils_init(char **envp)
 {
diff --git a/configure b/configure
index 0a84b0e..8eb5f5b 100755
--- a/configure
+++ b/configure
@@ -266,6 +266,7 @@
 
 gprof="no"
 debug_tcg="no"
+debug_mon="no"
 debug="no"
 strip_opt="yes"
 bigendian="no"
@@ -440,6 +441,8 @@
 if test "$mingw32" = "yes" ; then
   EXESUF=".exe"
   QEMU_CFLAGS="-DWIN32_LEAN_AND_MEAN -DWINVER=0x501 $QEMU_CFLAGS"
+  # enable C99/POSIX format strings (needs mingw32-runtime 3.15 or later)
+  QEMU_CFLAGS="-D__USE_MINGW_ANSI_STDIO=1 $QEMU_CFLAGS"
   LIBS="-lwinmm -lws2_32 -liphlpapi $LIBS"
 fi
 
@@ -514,9 +517,14 @@
   ;;
   --disable-debug-tcg) debug_tcg="no"
   ;;
+  --enable-debug-mon) debug_mon="yes"
+  ;;
+  --disable-debug-mon) debug_mon="no"
+  ;;
   --enable-debug)
       # Enable debugging options that aren't excessively noisy
       debug_tcg="yes"
+      debug_mon="yes"
       debug="yes"
       strip_opt="no"
   ;;
@@ -1918,6 +1926,7 @@
 echo "host big endian   $bigendian"
 echo "target list       $target_list"
 echo "tcg debug enabled $debug_tcg"
+echo "Mon debug enabled $debug_mon"
 echo "gprof enabled     $gprof"
 echo "sparse enabled    $sparse"
 echo "strip binaries    $strip_opt"
@@ -1995,6 +2004,9 @@
 if test "$debug_tcg" = "yes" ; then
   echo "CONFIG_DEBUG_TCG=y" >> $config_host_mak
 fi
+if test "$debug_mon" = "yes" ; then
+  echo "CONFIG_DEBUG_MONITOR=y" >> $config_host_mak
+fi
 if test "$debug" = "yes" ; then
   echo "CONFIG_DEBUG_EXEC=y" >> $config_host_mak
 fi
diff --git a/console.c b/console.c
index 8086bd6..8bcd00b 100644
--- a/console.c
+++ b/console.c
@@ -154,6 +154,7 @@
     QEMUTimer *kbd_timer;
 };
 
+static DisplayState *display_state;
 static TextConsole *active_console;
 static TextConsole *consoles[MAX_CONSOLES];
 static int nb_consoles = 0;
@@ -1265,6 +1266,117 @@
     return s;
 }
 
+static DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
+{
+    DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
+
+    surface->width = width;
+    surface->height = height;
+    surface->linesize = width * 4;
+    surface->pf = qemu_default_pixelformat(32);
+#ifdef HOST_WORDS_BIGENDIAN
+    surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
+#else
+    surface->flags = QEMU_ALLOCATED_FLAG;
+#endif
+    surface->data = (uint8_t*) qemu_mallocz(surface->linesize * surface->height);
+
+    return surface;
+}
+
+static DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
+                                          int width, int height)
+{
+    surface->width = width;
+    surface->height = height;
+    surface->linesize = width * 4;
+    surface->pf = qemu_default_pixelformat(32);
+    if (surface->flags & QEMU_ALLOCATED_FLAG)
+        surface->data = (uint8_t*) qemu_realloc(surface->data, surface->linesize * surface->height);
+    else
+        surface->data = (uint8_t*) qemu_malloc(surface->linesize * surface->height);
+#ifdef HOST_WORDS_BIGENDIAN
+    surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
+#else
+    surface->flags = QEMU_ALLOCATED_FLAG;
+#endif
+
+    return surface;
+}
+
+DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
+                                              int linesize, uint8_t *data)
+{
+    DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
+
+    surface->width = width;
+    surface->height = height;
+    surface->linesize = linesize;
+    surface->pf = qemu_default_pixelformat(bpp);
+#ifdef HOST_WORDS_BIGENDIAN
+    surface->flags = QEMU_BIG_ENDIAN_FLAG;
+#endif
+    surface->data = data;
+
+    return surface;
+}
+
+static void defaultallocator_free_displaysurface(DisplaySurface *surface)
+{
+    if (surface == NULL)
+        return;
+    if (surface->flags & QEMU_ALLOCATED_FLAG)
+        qemu_free(surface->data);
+    qemu_free(surface);
+}
+
+static struct DisplayAllocator default_allocator = {
+    defaultallocator_create_displaysurface,
+    defaultallocator_resize_displaysurface,
+    defaultallocator_free_displaysurface
+};
+
+static void dumb_display_init(void)
+{
+    DisplayState *ds = qemu_mallocz(sizeof(DisplayState));
+    ds->allocator = &default_allocator;
+    ds->surface = qemu_create_displaysurface(ds, 640, 480);
+    register_displaystate(ds);
+}
+
+/***********************************************************/
+/* register display */
+
+void register_displaystate(DisplayState *ds)
+{
+    DisplayState **s;
+    s = &display_state;
+    while (*s != NULL)
+        s = &(*s)->next;
+    ds->next = NULL;
+    *s = ds;
+}
+
+DisplayState *get_displaystate(void)
+{
+    if (!display_state) {
+        dumb_display_init ();
+    }
+    return display_state;
+}
+
+DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da)
+{
+    if(ds->allocator ==  &default_allocator) {
+        DisplaySurface *surf;
+        surf = da->create_displaysurface(ds_get_width(ds), ds_get_height(ds));
+        defaultallocator_free_displaysurface(ds->surface);
+        ds->surface = surf;
+        ds->allocator = da;
+    }
+    return ds->allocator;
+}
+
 DisplayState *graphic_console_init(vga_hw_update_ptr update,
                                    vga_hw_invalidate_ptr invalidate,
                                    vga_hw_screen_dump_ptr screen_dump,
@@ -1559,67 +1671,3 @@
     }
     return pf;
 }
-
-DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
-{
-    DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
-
-    surface->width = width;
-    surface->height = height;
-    surface->linesize = width * 4;
-    surface->pf = qemu_default_pixelformat(32);
-#ifdef HOST_WORDS_BIGENDIAN
-    surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
-#else
-    surface->flags = QEMU_ALLOCATED_FLAG;
-#endif
-    surface->data = (uint8_t*) qemu_mallocz(surface->linesize * surface->height);
-
-    return surface;
-}
-
-DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
-                                          int width, int height)
-{
-    surface->width = width;
-    surface->height = height;
-    surface->linesize = width * 4;
-    surface->pf = qemu_default_pixelformat(32);
-    if (surface->flags & QEMU_ALLOCATED_FLAG)
-        surface->data = (uint8_t*) qemu_realloc(surface->data, surface->linesize * surface->height);
-    else
-        surface->data = (uint8_t*) qemu_malloc(surface->linesize * surface->height);
-#ifdef HOST_WORDS_BIGENDIAN
-    surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
-#else
-    surface->flags = QEMU_ALLOCATED_FLAG;
-#endif
-
-    return surface;
-}
-
-DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
-                                              int linesize, uint8_t *data)
-{
-    DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
-
-    surface->width = width;
-    surface->height = height;
-    surface->linesize = linesize;
-    surface->pf = qemu_default_pixelformat(bpp);
-#ifdef HOST_WORDS_BIGENDIAN
-    surface->flags = QEMU_BIG_ENDIAN_FLAG;
-#endif
-    surface->data = data;
-
-    return surface;
-}
-
-void defaultallocator_free_displaysurface(DisplaySurface *surface)
-{
-    if (surface == NULL)
-        return;
-    if (surface->flags & QEMU_ALLOCATED_FLAG)
-        qemu_free(surface->data);
-    qemu_free(surface);
-}
diff --git a/console.h b/console.h
index dfc8ae4..916859d 100644
--- a/console.h
+++ b/console.h
@@ -144,11 +144,7 @@
 PixelFormat qemu_different_endianness_pixelformat(int bpp);
 PixelFormat qemu_default_pixelformat(int bpp);
 
-extern struct DisplayAllocator default_allocator;
 DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da);
-DisplaySurface* defaultallocator_create_displaysurface(int width, int height);
-DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface, int width, int height);
-void defaultallocator_free_displaysurface(DisplaySurface *surface);
 
 static inline DisplaySurface* qemu_create_displaysurface(DisplayState *ds, int width, int height)
 {
diff --git a/cpu-exec.c b/cpu-exec.c
index 4029ea2..184bdde 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -210,8 +210,7 @@
 
 int cpu_exec(CPUState *env1)
 {
-#define DECLARE_HOST_REGS 1
-#include "hostregs_helper.h"
+    host_reg_t saved_env_reg;
     int ret, interrupt_request;
     TranslationBlock *tb;
     uint8_t *tc_ptr;
@@ -222,9 +221,12 @@
 
     cpu_single_env = env1;
 
-    /* first we save global registers */
-#define SAVE_HOST_REGS 1
-#include "hostregs_helper.h"
+    /* the access to env below is actually saving the global register's
+       value, so that files not including target-xyz/exec.h are free to
+       use it.  */
+    QEMU_BUILD_BUG_ON (sizeof (saved_env_reg) != sizeof (env));
+    saved_env_reg = (host_reg_t) env;
+    asm("");
     env = env1;
 
 #if defined(TARGET_I386)
@@ -671,7 +673,8 @@
 #endif
 
     /* restore global registers */
-#include "hostregs_helper.h"
+    asm("");
+    env = (void *) saved_env_reg;
 
     /* fail safe : never use cpu_single_env outside cpu_exec() */
     cpu_single_env = NULL;
@@ -923,6 +926,20 @@
 # define TRAP_sig(context)			REG_sig(trap, context)
 #endif /* linux */
 
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#include <ucontext.h>
+# define IAR_sig(context)		((context)->uc_mcontext.mc_srr0)
+# define MSR_sig(context)		((context)->uc_mcontext.mc_srr1)
+# define CTR_sig(context)		((context)->uc_mcontext.mc_ctr)
+# define XER_sig(context)		((context)->uc_mcontext.mc_xer)
+# define LR_sig(context)		((context)->uc_mcontext.mc_lr)
+# define CR_sig(context)		((context)->uc_mcontext.mc_cr)
+/* Exception Registers access */
+# define DAR_sig(context)		((context)->uc_mcontext.mc_dar)
+# define DSISR_sig(context)		((context)->uc_mcontext.mc_dsisr)
+# define TRAP_sig(context)		((context)->uc_mcontext.mc_exc)
+#endif /* __FreeBSD__|| __FreeBSD_kernel__ */
+
 #ifdef __APPLE__
 # include <sys/ucontext.h>
 typedef struct ucontext SIGCONTEXT;
@@ -952,7 +969,11 @@
                        void *puc)
 {
     siginfo_t *info = pinfo;
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+    ucontext_t *uc = puc;
+#else
     struct ucontext *uc = puc;
+#endif
     unsigned long pc;
     int is_write;
 
diff --git a/gdbstub.c b/gdbstub.c
index 80477be..91c5f68 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1249,10 +1249,46 @@
 
 #define NUM_CORE_REGS 49
 
+static int
+read_register_crisv10(CPUState *env, uint8_t *mem_buf, int n)
+{
+    if (n < 15) {
+        GET_REG32(env->regs[n]);
+    }
+
+    if (n == 15) {
+        GET_REG32(env->pc);
+    }
+
+    if (n < 32) {
+        switch (n) {
+        case 16:
+            GET_REG8(env->pregs[n - 16]);
+            break;
+        case 17:
+            GET_REG8(env->pregs[n - 16]);
+            break;
+        case 20:
+        case 21:
+            GET_REG16(env->pregs[n - 16]);
+            break;
+        default:
+            if (n >= 23) {
+                GET_REG32(env->pregs[n - 16]);
+            }
+            break;
+        }
+    }
+    return 0;
+}
+
 static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
 {
     uint8_t srs;
 
+    if (env->pregs[PR_VR] < 32)
+        return read_register_crisv10(env, mem_buf, n);
+
     srs = env->pregs[PR_SRS];
     if (n < 16) {
 	GET_REG32(env->regs[n]);
diff --git a/hostregs_helper.h b/hostregs_helper.h
deleted file mode 100644
index 3a0bece..0000000
--- a/hostregs_helper.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- *  Save/restore host registers.
- *
- *  Copyright (c) 2007 CodeSourcery
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-/* The GCC global register variable extension is used to reserve some
-   host registers for use by generated code.  However only the core parts of
-   the translation engine are compiled with these settings.  We must manually
-   save/restore these registers when called from regular code.
-   It is not sufficient to save/restore T0 et. al. as these may be declared
-   with a datatype smaller than the actual register.  */
-
-#if defined(DECLARE_HOST_REGS)
-
-#define DO_REG(REG)					\
-    register host_reg_t reg_AREG##REG asm(AREG##REG);	\
-    volatile host_reg_t saved_AREG##REG;
-
-#elif defined(SAVE_HOST_REGS)
-
-#define DO_REG(REG)					\
-    __asm__ __volatile__ ("" : "=r" (reg_AREG##REG));	\
-    saved_AREG##REG = reg_AREG##REG;
-
-#else
-
-#define DO_REG(REG)                                     \
-    reg_AREG##REG = saved_AREG##REG;		        \
-    __asm__ __volatile__ ("" : : "r" (reg_AREG##REG));
-
-#endif
-
-#ifdef AREG0
-DO_REG(0)
-#endif
-
-#ifdef AREG1
-DO_REG(1)
-#endif
-
-#ifdef AREG2
-DO_REG(2)
-#endif
-
-#undef SAVE_HOST_REGS
-#undef DECLARE_HOST_REGS
-#undef DO_REG
diff --git a/hw/apb_pci.c b/hw/apb_pci.c
index ebfcd41..324e74e 100644
--- a/hw/apb_pci.c
+++ b/hw/apb_pci.c
@@ -29,6 +29,7 @@
 #include "sysbus.h"
 #include "pci.h"
 #include "pci_host.h"
+#include "rwhandler.h"
 #include "apb_pci.h"
 
 /* debug APB */
@@ -65,6 +66,7 @@
 typedef struct APBState {
     SysBusDevice busdev;
     PCIHostState host_state;
+    ReadWriteHandler pci_config_handler;
     uint32_t iommu[4];
     uint32_t pci_control[16];
     uint32_t pci_irq_map[8];
@@ -183,82 +185,28 @@
     &apb_config_readl,
 };
 
-static void apb_pci_config_write(APBState *s, target_phys_addr_t addr,
+static void apb_pci_config_write(ReadWriteHandler *h, pcibus_t addr,
                                  uint32_t val, int size)
 {
+    APBState *s = container_of(h, APBState, pci_config_handler);
+
+    val = qemu_bswap_len(val, size);
     APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %x\n", __func__, addr, val);
-    pci_data_write(s->host_state.bus, (addr & 0x00ffffff) | (1u << 31), val,
-                   size);
+    pci_data_write(s->host_state.bus, addr, val, size);
 }
 
-static uint32_t apb_pci_config_read(APBState *s, target_phys_addr_t addr,
+static uint32_t apb_pci_config_read(ReadWriteHandler *h, pcibus_t addr,
                                     int size)
 {
     uint32_t ret;
+    APBState *s = container_of(h, APBState, pci_config_handler);
 
-    ret = pci_data_read(s->host_state.bus, (addr & 0x00ffffff) | (1u << 31),
-                        size);
+    ret = pci_data_read(s->host_state.bus, addr, size);
+    ret = qemu_bswap_len(ret, size);
     APB_DPRINTF("%s: addr " TARGET_FMT_lx " -> %x\n", __func__, addr, ret);
     return ret;
 }
 
-static void apb_pci_config_writel(void *opaque, target_phys_addr_t addr,
-                                  uint32_t val)
-{
-    APBState *s = opaque;
-
-    apb_pci_config_write(s, addr, bswap32(val), 4);
-}
-
-static void apb_pci_config_writew(void *opaque, target_phys_addr_t addr,
-                                  uint32_t val)
-{
-    APBState *s = opaque;
-
-    apb_pci_config_write(s, addr, bswap16(val), 2);
-}
-
-static void apb_pci_config_writeb(void *opaque, target_phys_addr_t addr,
-                                  uint32_t val)
-{
-    APBState *s = opaque;
-
-    apb_pci_config_write(s, addr, val, 1);
-}
-
-static uint32_t apb_pci_config_readl(void *opaque, target_phys_addr_t addr)
-{
-    APBState *s = opaque;
-
-    return bswap32(apb_pci_config_read(s, addr, 4));
-}
-
-static uint32_t apb_pci_config_readw(void *opaque, target_phys_addr_t addr)
-{
-    APBState *s = opaque;
-
-    return bswap16(apb_pci_config_read(s, addr, 2));
-}
-
-static uint32_t apb_pci_config_readb(void *opaque, target_phys_addr_t addr)
-{
-    APBState *s = opaque;
-
-    return apb_pci_config_read(s, addr, 1);
-}
-
-static CPUWriteMemoryFunc * const apb_pci_config_writes[] = {
-    &apb_pci_config_writeb,
-    &apb_pci_config_writew,
-    &apb_pci_config_writel,
-};
-
-static CPUReadMemoryFunc * const apb_pci_config_reads[] = {
-    &apb_pci_config_readb,
-    &apb_pci_config_readw,
-    &apb_pci_config_readl,
-};
-
 static void pci_apb_iowriteb (void *opaque, target_phys_addr_t addr,
                                   uint32_t val)
 {
@@ -455,8 +403,10 @@
                                           pci_apb_iowrite, s);
     sysbus_init_mmio(dev, 0x10000ULL, pci_ioport);
     /* pci_config */
-    pci_config = cpu_register_io_memory(apb_pci_config_reads,
-                                        apb_pci_config_writes, s);
+    s->pci_config_handler.read = apb_pci_config_read;
+    s->pci_config_handler.write = apb_pci_config_write;
+    pci_config = cpu_register_io_memory_simple(&s->pci_config_handler);
+    assert(pci_config >= 0);
     sysbus_init_mmio(dev, 0x1000000ULL, pci_config);
     /* mem_data */
     pci_mem_data = pci_host_data_register_mmio(&s->host_state);
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 37a5151..2e0971d 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -2650,6 +2650,7 @@
         s->unit = i;
         s->drive_serial = drive_serial++;
         s->io_buffer = qemu_blockalign(s->bs, IDE_DMA_BUF_SECTORS*512 + 4);
+        s->io_buffer_total_len = IDE_DMA_BUF_SECTORS*512 + 4;
         s->smart_selftest_data = qemu_blockalign(s->bs, 512);
         s->sector_write_timer = qemu_new_timer(vm_clock,
                                                ide_sector_write_timer_cb, s);
@@ -2684,6 +2685,25 @@
     return s->identify_set != 0;
 }
 
+static EndTransferFunc* transfer_end_table[] = {
+        ide_sector_read,
+        ide_sector_write,
+        ide_transfer_stop,
+        ide_atapi_cmd_reply_end,
+        ide_atapi_cmd,
+};
+
+static int transfer_end_table_idx(EndTransferFunc *fn)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(transfer_end_table); i++)
+        if (transfer_end_table[i] == fn)
+            return i;
+
+    return -1;
+}
+
 static int ide_drive_post_load(void *opaque, int version_id)
 {
     IDEState *s = opaque;
@@ -2694,14 +2714,45 @@
             s->cdrom_changed = 1;
         }
     }
+
+    if (s->cur_io_buffer_len) {
+        s->end_transfer_func = transfer_end_table[s->end_transfer_fn_idx];
+        s->data_ptr = s->io_buffer + s->cur_io_buffer_offset;
+        s->data_end = s->data_ptr + s->cur_io_buffer_len;
+    }
+        
     return 0;
 }
 
+static void ide_drive_pre_save(void *opaque)
+{
+    IDEState *s = opaque;
+    int idx;
+
+    s->cur_io_buffer_len = 0;
+
+    if (!(s->status & DRQ_STAT))
+        return;
+
+    s->cur_io_buffer_offset = s->data_ptr - s->io_buffer;
+    s->cur_io_buffer_len = s->data_end - s->data_ptr;
+
+    idx = transfer_end_table_idx(s->end_transfer_func);
+    if (idx == -1) {
+        fprintf(stderr, "%s: invalid end_transfer_func for DRQ_STAT\n",
+                        __func__);
+        s->end_transfer_fn_idx = 2;
+    } else {
+        s->end_transfer_fn_idx = idx;
+    }
+}
+
 const VMStateDescription vmstate_ide_drive = {
     .name = "ide_drive",
-    .version_id = 3,
+    .version_id = 4,
     .minimum_version_id = 0,
     .minimum_version_id_old = 0,
+    .pre_save = ide_drive_pre_save,
     .post_load = ide_drive_post_load,
     .fields      = (VMStateField []) {
         VMSTATE_INT32(mult_sectors, IDEState),
@@ -2724,7 +2775,14 @@
         VMSTATE_UINT8(sense_key, IDEState),
         VMSTATE_UINT8(asc, IDEState),
         VMSTATE_UINT8_V(cdrom_changed, IDEState, 3),
-        /* XXX: if a transfer is pending, we do not save it yet */
+        VMSTATE_INT32_V(req_nb_sectors, IDEState, 4),
+        VMSTATE_VARRAY_INT32(io_buffer, IDEState, io_buffer_total_len, 4,
+			     vmstate_info_uint8, uint8_t),
+        VMSTATE_INT32_V(cur_io_buffer_offset, IDEState, 4),
+        VMSTATE_INT32_V(cur_io_buffer_len, IDEState, 4),
+        VMSTATE_UINT8_V(end_transfer_fn_idx, IDEState, 4),
+        VMSTATE_INT32_V(elementary_transfer_size, IDEState, 4),
+        VMSTATE_INT32_V(packet_transfer_size, IDEState, 4),
         VMSTATE_END_OF_LIST()
     }
 };
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index 9945993..027029e 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -419,6 +419,11 @@
     uint8_t *data_ptr;
     uint8_t *data_end;
     uint8_t *io_buffer;
+    /* PIO save/restore */
+    int32_t io_buffer_total_len;
+    int cur_io_buffer_offset;
+    int cur_io_buffer_len;
+    uint8_t end_transfer_fn_idx;
     QEMUTimer *sector_write_timer; /* only used for win2k install hack */
     uint32_t irq_count; /* counts IRQs when using win2k install hack */
     /* CF-ATA extended error */
diff --git a/hw/mac_dbdma.c b/hw/mac_dbdma.c
index 8ec3d99..8f94c35 100644
--- a/hw/mac_dbdma.c
+++ b/hw/mac_dbdma.c
@@ -402,7 +402,9 @@
     ch->io.dma_end = dbdma_end;
     ch->io.is_dma_out = 1;
     ch->processing = 1;
-    ch->rw(&ch->io);
+    if (ch->rw) {
+        ch->rw(&ch->io);
+    }
 }
 
 static void start_input(DBDMA_channel *ch, int key, uint32_t addr,
@@ -425,7 +427,9 @@
     ch->io.dma_end = dbdma_end;
     ch->io.is_dma_out = 0;
     ch->processing = 1;
-    ch->rw(&ch->io);
+    if (ch->rw) {
+        ch->rw(&ch->io);
+    }
 }
 
 static void load_word(DBDMA_channel *ch, int key, uint32_t addr,
@@ -688,7 +692,7 @@
 
     if (status & ACTIVE)
         qemu_bh_schedule(dbdma_bh);
-    if (status & FLUSH)
+    if ((status & FLUSH) && ch->flush)
         ch->flush(&ch->io);
 }
 
diff --git a/hw/pc.c b/hw/pc.c
index 6fbe98b..4f6a522 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -59,6 +59,7 @@
 #define FW_CFG_ACPI_TABLES (FW_CFG_ARCH_LOCAL + 0)
 #define FW_CFG_SMBIOS_ENTRIES (FW_CFG_ARCH_LOCAL + 1)
 #define FW_CFG_IRQ0_OVERRIDE (FW_CFG_ARCH_LOCAL + 2)
+#define FW_CFG_E820_TABLE (FW_CFG_ARCH_LOCAL + 3)
 
 #define MAX_IDE_BUS 2
 
@@ -67,6 +68,21 @@
 static PITState *pit;
 static PCII440FXState *i440fx_state;
 
+#define E820_NR_ENTRIES		16
+
+struct e820_entry {
+    uint64_t address;
+    uint64_t length;
+    uint32_t type;
+};
+
+struct e820_table {
+    uint32_t count;
+    struct e820_entry entry[E820_NR_ENTRIES];
+};
+
+static struct e820_table e820_table;
+
 typedef struct isa_irq_state {
     qemu_irq *i8259;
     qemu_irq *ioapic;
@@ -435,6 +451,23 @@
     }
 }
 
+int e820_add_entry(uint64_t address, uint64_t length, uint32_t type)
+{
+    int index = e820_table.count;
+    struct e820_entry *entry;
+
+    if (index >= E820_NR_ENTRIES)
+        return -EBUSY;
+    entry = &e820_table.entry[index];
+
+    entry->address = address;
+    entry->length = length;
+    entry->type = type;
+
+    e820_table.count++;
+    return e820_table.count;
+}
+
 static void *bochs_bios_init(void)
 {
     void *fw_cfg;
@@ -466,6 +499,8 @@
     if (smbios_table)
         fw_cfg_add_bytes(fw_cfg, FW_CFG_SMBIOS_ENTRIES,
                          smbios_table, smbios_len);
+    fw_cfg_add_bytes(fw_cfg, FW_CFG_E820_TABLE, (uint8_t *)&e820_table,
+                     sizeof(struct e820_table));
 
     /* allocate memory for the NUMA channel: one (64bit) word for the number
      * of nodes, one word for each VCPU->node and one word for each node to
@@ -1052,7 +1087,7 @@
 }
 
 static QEMUMachine pc_machine = {
-    .name = "pc-0.12",
+    .name = "pc-0.13",
     .alias = "pc",
     .desc = "Standard PC",
     .init = pc_init_pci,
@@ -1060,6 +1095,25 @@
     .is_default = 1,
 };
 
+static QEMUMachine pc_machine_v0_12 = {
+    .name = "pc-0.12",
+    .desc = "Standard PC",
+    .init = pc_init_pci,
+    .max_cpus = 255,
+    .compat_props = (GlobalProperty[]) {
+        {
+            .driver   = "virtio-serial-pci",
+            .property = "max_nr_ports",
+            .value    = stringify(1),
+        },{
+            .driver   = "virtio-serial-pci",
+            .property = "vectors",
+            .value    = stringify(0),
+        },
+        { /* end of list */ }
+    }
+};
+
 static QEMUMachine pc_machine_v0_11 = {
     .name = "pc-0.11",
     .desc = "Standard PC, qemu 0.11",
@@ -1071,6 +1125,14 @@
             .property = "vectors",
             .value    = stringify(0),
         },{
+            .driver   = "virtio-serial-pci",
+            .property = "max_nr_ports",
+            .value    = stringify(1),
+        },{
+            .driver   = "virtio-serial-pci",
+            .property = "vectors",
+            .value    = stringify(0),
+        },{
             .driver   = "ide-drive",
             .property = "ver",
             .value    = "0.11",
@@ -1102,6 +1164,14 @@
             .property = "class",
             .value    = stringify(PCI_CLASS_DISPLAY_OTHER),
         },{
+            .driver   = "virtio-serial-pci",
+            .property = "max_nr_ports",
+            .value    = stringify(1),
+        },{
+            .driver   = "virtio-serial-pci",
+            .property = "vectors",
+            .value    = stringify(0),
+        },{
             .driver   = "virtio-net-pci",
             .property = "vectors",
             .value    = stringify(0),
@@ -1136,6 +1206,7 @@
 static void pc_machine_init(void)
 {
     qemu_register_machine(&pc_machine);
+    qemu_register_machine(&pc_machine_v0_12);
     qemu_register_machine(&pc_machine_v0_11);
     qemu_register_machine(&pc_machine_v0_10);
     qemu_register_machine(&isapc_machine);
diff --git a/hw/pc.h b/hw/pc.h
index 03ffc91..92f8563 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -150,4 +150,14 @@
 void isa_ne2000_init(int base, int irq, NICInfo *nd);
 
 int cpu_is_bsp(CPUState *env);
+
+/* e820 types */
+#define E820_RAM        1
+#define E820_RESERVED   2
+#define E820_ACPI       3
+#define E820_NVS        4
+#define E820_UNUSABLE   5
+
+int e820_add_entry(uint64_t, uint64_t, uint32_t);
+
 #endif
diff --git a/hw/pci-hotplug.c b/hw/pci-hotplug.c
index 0fb96f0..bd82c6a 100644
--- a/hw/pci-hotplug.c
+++ b/hw/pci-hotplug.c
@@ -254,7 +254,7 @@
  *
  * { "domain": 0, "bus": 0, "slot": 5, "function": 0 }
  */
-void pci_device_hot_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
+int pci_device_hot_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {
     PCIDevice *dev = NULL;
     const char *pci_addr = qdict_get_str(qdict, "pci_addr");
@@ -273,43 +273,49 @@
     if (!strcmp(pci_addr, "auto"))
         pci_addr = NULL;
 
-    if (strcmp(type, "nic") == 0)
+    if (strcmp(type, "nic") == 0) {
         dev = qemu_pci_hot_add_nic(mon, pci_addr, opts);
-    else if (strcmp(type, "storage") == 0)
+    } else if (strcmp(type, "storage") == 0) {
         dev = qemu_pci_hot_add_storage(mon, pci_addr, opts);
-    else
+    } else {
         monitor_printf(mon, "invalid type: %s\n", type);
+        return -1;
+    }
 
     if (dev) {
         *ret_data =
         qobject_from_jsonf("{ 'domain': 0, 'bus': %d, 'slot': %d, "
                            "'function': %d }", pci_bus_num(dev->bus),
                            PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
-    } else
+    } else {
         monitor_printf(mon, "failed to add %s\n", opts);
+        return -1;
+    }
+
+    return 0;
 }
 #endif
 
-void pci_device_hot_remove(Monitor *mon, const char *pci_addr)
+int pci_device_hot_remove(Monitor *mon, const char *pci_addr)
 {
     PCIDevice *d;
     int dom, bus;
     unsigned slot;
 
     if (pci_read_devaddr(mon, pci_addr, &dom, &bus, &slot)) {
-        return;
+        return -1;
     }
 
     d = pci_find_device(pci_find_root_bus(0), bus, slot, 0);
     if (!d) {
         monitor_printf(mon, "slot %d empty\n", slot);
-        return;
+        return -1;
     }
-    qdev_unplug(&d->qdev);
+    return qdev_unplug(&d->qdev);
 }
 
-void do_pci_device_hot_remove(Monitor *mon, const QDict *qdict,
-                              QObject **ret_data)
+int do_pci_device_hot_remove(Monitor *mon, const QDict *qdict,
+                             QObject **ret_data)
 {
-    pci_device_hot_remove(mon, qdict_get_str(qdict, "pci_addr"));
+    return pci_device_hot_remove(mon, qdict_get_str(qdict, "pci_addr"));
 }
diff --git a/hw/pci.h b/hw/pci.h
index 8b511d2..37ebdc4 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -70,7 +70,6 @@
 #define PCI_DEVICE_ID_VIRTIO_BALLOON     0x1002
 #define PCI_DEVICE_ID_VIRTIO_CONSOLE     0x1003
 
-typedef uint64_t pcibus_t;
 #define FMT_PCIBUS                      PRIx64
 
 typedef void PCIConfigWriteFunc(PCIDevice *pci_dev,
diff --git a/hw/pci_host.c b/hw/pci_host.c
index 6289ead..b15d5fa 100644
--- a/hw/pci_host.c
+++ b/hw/pci_host.c
@@ -79,152 +79,120 @@
     return val;
 }
 
-static void pci_host_config_writel(void *opaque, target_phys_addr_t addr,
-                                   uint32_t val)
+static void pci_host_config_write(ReadWriteHandler *handler,
+                                  pcibus_t addr, uint32_t val, int len)
 {
-    PCIHostState *s = opaque;
+    PCIHostState *s = container_of(handler, PCIHostState, conf_handler);
 
+    PCI_DPRINTF("%s addr %" FMT_PCIBUS " %d val %"PRIx32"\n",
+                __func__, addr, len, val);
 #ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap32(val);
+    val = qemu_bswap_len(val, len);
 #endif
-    PCI_DPRINTF("%s addr " TARGET_FMT_plx " val %"PRIx32"\n",
-                __func__, addr, val);
     s->config_reg = val;
 }
 
-static uint32_t pci_host_config_readl(void *opaque, target_phys_addr_t addr)
+static uint32_t pci_host_config_read(ReadWriteHandler *handler,
+                                            pcibus_t addr, int len)
 {
-    PCIHostState *s = opaque;
+    PCIHostState *s = container_of(handler, PCIHostState, conf_handler);
     uint32_t val = s->config_reg;
-
 #ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap32(val);
+    val = qemu_bswap_len(val, len);
 #endif
-    PCI_DPRINTF("%s addr " TARGET_FMT_plx " val %"PRIx32"\n",
-                __func__, addr, val);
+    PCI_DPRINTF("%s addr %" FMT_PCIBUS " len %d val %"PRIx32"\n",
+                __func__, addr, len, val);
     return val;
 }
 
-static CPUWriteMemoryFunc * const pci_host_config_write[] = {
-    &pci_host_config_writel,
-    &pci_host_config_writel,
-    &pci_host_config_writel,
-};
+static void pci_host_config_write_noswap(ReadWriteHandler *handler,
+                                         pcibus_t addr, uint32_t val, int len)
+{
+    PCIHostState *s = container_of(handler, PCIHostState, conf_noswap_handler);
 
-static CPUReadMemoryFunc * const pci_host_config_read[] = {
-    &pci_host_config_readl,
-    &pci_host_config_readl,
-    &pci_host_config_readl,
-};
+    PCI_DPRINTF("%s addr %" FMT_PCIBUS " %d val %"PRIx32"\n",
+                __func__, addr, len, val);
+    s->config_reg = val;
+}
+
+static uint32_t pci_host_config_read_noswap(ReadWriteHandler *handler,
+                                            pcibus_t addr, int len)
+{
+    PCIHostState *s = container_of(handler, PCIHostState, conf_noswap_handler);
+    uint32_t val = s->config_reg;
+
+    PCI_DPRINTF("%s addr %" FMT_PCIBUS " len %d val %"PRIx32"\n",
+                __func__, addr, len, val);
+    return val;
+}
+
+static void pci_host_data_write(ReadWriteHandler *handler,
+                                pcibus_t addr, uint32_t val, int len)
+{
+    PCIHostState *s = container_of(handler, PCIHostState, data_handler);
+#ifdef TARGET_WORDS_BIGENDIAN
+    val = qemu_bswap_len(val, len);
+#endif
+    PCI_DPRINTF("write addr %" FMT_PCIBUS " len %d val %x\n",
+                addr, len, val);
+    if (s->config_reg & (1u << 31))
+        pci_data_write(s->bus, s->config_reg | (addr & 3), val, len);
+}
+
+static uint32_t pci_host_data_read(ReadWriteHandler *handler,
+                                   pcibus_t addr, int len)
+{
+    PCIHostState *s = container_of(handler, PCIHostState, data_handler);
+    uint32_t val;
+    if (!(s->config_reg & (1 << 31)))
+        return 0xffffffff;
+    val = pci_data_read(s->bus, s->config_reg | (addr & 3), len);
+    PCI_DPRINTF("read addr %" FMT_PCIBUS " len %d val %x\n",
+                addr, len, val);
+#ifdef TARGET_WORDS_BIGENDIAN
+    val = qemu_bswap_len(val, len);
+#endif
+    return val;
+}
+
+static void pci_host_init(PCIHostState *s)
+{
+    s->conf_handler.write = pci_host_config_write;
+    s->conf_handler.read = pci_host_config_read;
+    s->conf_noswap_handler.write = pci_host_config_write_noswap;
+    s->conf_noswap_handler.read = pci_host_config_read_noswap;
+    s->data_handler.write = pci_host_data_write;
+    s->data_handler.read = pci_host_data_read;
+}
 
 int pci_host_conf_register_mmio(PCIHostState *s)
 {
-    return cpu_register_io_memory(pci_host_config_read,
-                                  pci_host_config_write, s);
+    pci_host_init(s);
+    return cpu_register_io_memory_simple(&s->conf_handler);
 }
 
-static void pci_host_config_writel_noswap(void *opaque,
-                                          target_phys_addr_t addr,
-                                          uint32_t val)
-{
-    PCIHostState *s = opaque;
-
-    PCI_DPRINTF("%s addr " TARGET_FMT_plx " val %"PRIx32"\n",
-                __func__, addr, val);
-    s->config_reg = val;
-}
-
-static uint32_t pci_host_config_readl_noswap(void *opaque,
-                                             target_phys_addr_t addr)
-{
-    PCIHostState *s = opaque;
-    uint32_t val = s->config_reg;
-
-    PCI_DPRINTF("%s addr " TARGET_FMT_plx " val %"PRIx32"\n",
-                __func__, addr, val);
-    return val;
-}
-
-static CPUWriteMemoryFunc * const pci_host_config_write_noswap[] = {
-    &pci_host_config_writel_noswap,
-    &pci_host_config_writel_noswap,
-    &pci_host_config_writel_noswap,
-};
-
-static CPUReadMemoryFunc * const pci_host_config_read_noswap[] = {
-    &pci_host_config_readl_noswap,
-    &pci_host_config_readl_noswap,
-    &pci_host_config_readl_noswap,
-};
-
 int pci_host_conf_register_mmio_noswap(PCIHostState *s)
 {
-    return cpu_register_io_memory(pci_host_config_read_noswap,
-                                  pci_host_config_write_noswap, s);
-}
-
-static void pci_host_config_writel_ioport(void *opaque,
-                                          uint32_t addr, uint32_t val)
-{
-    PCIHostState *s = opaque;
-
-    PCI_DPRINTF("%s addr %"PRIx32 " val %"PRIx32"\n", __func__, addr, val);
-    s->config_reg = val;
-}
-
-static uint32_t pci_host_config_readl_ioport(void *opaque, uint32_t addr)
-{
-    PCIHostState *s = opaque;
-    uint32_t val = s->config_reg;
-
-    PCI_DPRINTF("%s addr %"PRIx32" val %"PRIx32"\n", __func__, addr, val);
-    return val;
+    pci_host_init(s);
+    return cpu_register_io_memory_simple(&s->conf_noswap_handler);
 }
 
 void pci_host_conf_register_ioport(pio_addr_t ioport, PCIHostState *s)
 {
-    register_ioport_write(ioport, 4, 4, pci_host_config_writel_ioport, s);
-    register_ioport_read(ioport, 4, 4, pci_host_config_readl_ioport, s);
+    pci_host_init(s);
+    register_ioport_simple(&s->conf_noswap_handler, ioport, 4, 4);
 }
 
-#define PCI_ADDR_T      target_phys_addr_t
-#define PCI_HOST_SUFFIX _mmio
-
-#include "pci_host_template.h"
-
-static CPUWriteMemoryFunc * const pci_host_data_write_mmio[] = {
-    pci_host_data_writeb_mmio,
-    pci_host_data_writew_mmio,
-    pci_host_data_writel_mmio,
-};
-
-static CPUReadMemoryFunc * const pci_host_data_read_mmio[] = {
-    pci_host_data_readb_mmio,
-    pci_host_data_readw_mmio,
-    pci_host_data_readl_mmio,
-};
-
 int pci_host_data_register_mmio(PCIHostState *s)
 {
-    return cpu_register_io_memory(pci_host_data_read_mmio,
-                                  pci_host_data_write_mmio,
-                                  s);
+    pci_host_init(s);
+    return cpu_register_io_memory_simple(&s->data_handler);
 }
 
-#undef PCI_ADDR_T
-#undef PCI_HOST_SUFFIX
-
-#define PCI_ADDR_T      uint32_t
-#define PCI_HOST_SUFFIX _ioport
-
-#include "pci_host_template.h"
-
 void pci_host_data_register_ioport(pio_addr_t ioport, PCIHostState *s)
 {
-    register_ioport_write(ioport, 4, 1, pci_host_data_writeb_ioport, s);
-    register_ioport_write(ioport, 4, 2, pci_host_data_writew_ioport, s);
-    register_ioport_write(ioport, 4, 4, pci_host_data_writel_ioport, s);
-    register_ioport_read(ioport, 4, 1, pci_host_data_readb_ioport, s);
-    register_ioport_read(ioport, 4, 2, pci_host_data_readw_ioport, s);
-    register_ioport_read(ioport, 4, 4, pci_host_data_readl_ioport, s);
+    pci_host_init(s);
+    register_ioport_simple(&s->data_handler, ioport, 4, 1);
+    register_ioport_simple(&s->data_handler, ioport, 4, 2);
+    register_ioport_simple(&s->data_handler, ioport, 4, 4);
 }
diff --git a/hw/pci_host.h b/hw/pci_host.h
index a006687..5ff6443 100644
--- a/hw/pci_host.h
+++ b/hw/pci_host.h
@@ -29,9 +29,13 @@
 #define PCI_HOST_H
 
 #include "sysbus.h"
+#include "rwhandler.h"
 
 struct PCIHostState {
     SysBusDevice busdev;
+    ReadWriteHandler conf_noswap_handler;
+    ReadWriteHandler conf_handler;
+    ReadWriteHandler data_handler;
     uint32_t config_reg;
     PCIBus *bus;
 };
diff --git a/hw/pci_host_template.h b/hw/pci_host_template.h
deleted file mode 100644
index 11e6c88..0000000
--- a/hw/pci_host_template.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * QEMU Common PCI Host bridge configuration data space access routines.
- *
- * Copyright (c) 2006 Fabrice Bellard
- *
- * 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.
- */
-
-/* Worker routines for a PCI host controller that uses an {address,data}
-   register pair to access PCI configuration space.  */
-
-static void glue(pci_host_data_writeb, PCI_HOST_SUFFIX)(
-    void* opaque, PCI_ADDR_T addr, uint32_t val)
-{
-    PCIHostState *s = opaque;
-
-    PCI_DPRINTF("writeb addr " TARGET_FMT_plx " val %x\n",
-                (target_phys_addr_t)addr, val);
-    if (s->config_reg & (1u << 31))
-        pci_data_write(s->bus, s->config_reg | (addr & 3), val, 1);
-}
-
-static void glue(pci_host_data_writew, PCI_HOST_SUFFIX)(
-    void* opaque, PCI_ADDR_T addr, uint32_t val)
-{
-    PCIHostState *s = opaque;
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap16(val);
-#endif
-    PCI_DPRINTF("writew addr " TARGET_FMT_plx " val %x\n",
-                (target_phys_addr_t)addr, val);
-    if (s->config_reg & (1u << 31))
-        pci_data_write(s->bus, s->config_reg | (addr & 3), val, 2);
-}
-
-static void glue(pci_host_data_writel, PCI_HOST_SUFFIX)(
-    void* opaque, PCI_ADDR_T addr, uint32_t val)
-{
-    PCIHostState *s = opaque;
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap32(val);
-#endif
-    PCI_DPRINTF("writel addr " TARGET_FMT_plx " val %x\n",
-                (target_phys_addr_t)addr, val);
-    if (s->config_reg & (1u << 31))
-        pci_data_write(s->bus, s->config_reg, val, 4);
-}
-
-static uint32_t glue(pci_host_data_readb, PCI_HOST_SUFFIX)(
-    void* opaque, PCI_ADDR_T addr)
-{
-    PCIHostState *s = opaque;
-    uint32_t val;
-
-    if (!(s->config_reg & (1 << 31)))
-        return 0xff;
-    val = pci_data_read(s->bus, s->config_reg | (addr & 3), 1);
-    PCI_DPRINTF("readb addr " TARGET_FMT_plx " val %x\n",
-                (target_phys_addr_t)addr, val);
-    return val;
-}
-
-static uint32_t glue(pci_host_data_readw, PCI_HOST_SUFFIX)(
-    void* opaque, PCI_ADDR_T addr)
-{
-    PCIHostState *s = opaque;
-    uint32_t val;
-    if (!(s->config_reg & (1 << 31)))
-        return 0xffff;
-    val = pci_data_read(s->bus, s->config_reg | (addr & 3), 2);
-    PCI_DPRINTF("readw addr " TARGET_FMT_plx " val %x\n",
-                (target_phys_addr_t)addr, val);
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap16(val);
-#endif
-    return val;
-}
-
-static uint32_t glue(pci_host_data_readl, PCI_HOST_SUFFIX)(
-    void* opaque, PCI_ADDR_T addr)
-{
-    PCIHostState *s = opaque;
-    uint32_t val;
-    if (!(s->config_reg & (1 << 31)))
-        return 0xffffffff;
-    val = pci_data_read(s->bus, s->config_reg | (addr & 3), 4);
-    PCI_DPRINTF("readl addr " TARGET_FMT_plx " val %x\n",
-                (target_phys_addr_t)addr, val);
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap32(val);
-#endif
-    return val;
-}
diff --git a/hw/pci_ids.h b/hw/pci_ids.h
index 63379c2..fe7a121 100644
--- a/hw/pci_ids.h
+++ b/hw/pci_ids.h
@@ -63,6 +63,7 @@
 
 #define PCI_VENDOR_ID_APPLE              0x106b
 #define PCI_DEVICE_ID_APPLE_UNI_N_AGP    0x0020
+#define PCI_DEVICE_ID_APPLE_U3_AGP       0x004b
 
 #define PCI_VENDOR_ID_SUN                0x108e
 #define PCI_DEVICE_ID_SUN_EBUS           0x1000
diff --git a/hw/pl181.c b/hw/pl181.c
index 7282053..1924053 100644
--- a/hw/pl181.c
+++ b/hw/pl181.c
@@ -182,39 +182,40 @@
 static void pl181_fifo_run(pl181_state *s)
 {
     uint32_t bits;
-    uint32_t value;
+    uint32_t value = 0;
     int n;
-    int limit;
     int is_read;
 
     is_read = (s->datactrl & PL181_DATA_DIRECTION) != 0;
     if (s->datacnt != 0 && (!is_read || sd_data_ready(s->card))
             && !s->linux_hack) {
-        limit = is_read ? PL181_FIFO_LEN : 0;
-        n = 0;
-        value = 0;
-        while (s->datacnt && s->fifo_len != limit) {
-            if (is_read) {
+        if (is_read) {
+            n = 0;
+            while (s->datacnt && s->fifo_len < PL181_FIFO_LEN) {
                 value |= (uint32_t)sd_read_data(s->card) << (n * 8);
+                s->datacnt--;
                 n++;
                 if (n == 4) {
                     pl181_fifo_push(s, value);
-                    value = 0;
                     n = 0;
+                    value = 0;
                 }
-            } else {
+            }
+            if (n != 0) {
+                pl181_fifo_push(s, value);
+            }
+        } else { /* write */
+            n = 0;
+            while (s->datacnt > 0 && (s->fifo_len > 0 || n > 0)) {
                 if (n == 0) {
                     value = pl181_fifo_pop(s);
                     n = 4;
                 }
+                n--;
+                s->datacnt--;
                 sd_write_data(s->card, value & 0xff);
                 value >>= 8;
-                n--;
             }
-            s->datacnt--;
-        }
-        if (n && is_read) {
-            pl181_fifo_push(s, value);
         }
     }
     s->status &= ~(PL181_STATUS_RX_FIFO | PL181_STATUS_TX_FIFO);
diff --git a/hw/ppc.h b/hw/ppc.h
index bbf3a98..de13092 100644
--- a/hw/ppc.h
+++ b/hw/ppc.h
@@ -40,10 +40,12 @@
     ARCH_PREP = 0,
     ARCH_MAC99,
     ARCH_HEATHROW,
+    ARCH_MAC99_U3,
 };
 
 #define FW_CFG_PPC_WIDTH	(FW_CFG_ARCH_LOCAL + 0x00)
 #define FW_CFG_PPC_HEIGHT	(FW_CFG_ARCH_LOCAL + 0x01)
 #define FW_CFG_PPC_DEPTH	(FW_CFG_ARCH_LOCAL + 0x02)
+#define FW_CFG_PPC_TBFREQ	(FW_CFG_ARCH_LOCAL + 0x03)
 
 #define PPC_SERIAL_MM_BAUDBASE 399193
diff --git a/hw/ppc_mac.h b/hw/ppc_mac.h
index a04dffe..89f96bb 100644
--- a/hw/ppc_mac.h
+++ b/hw/ppc_mac.h
@@ -58,6 +58,7 @@
 
 /* UniNorth PCI */
 PCIBus *pci_pmac_init(qemu_irq *pic);
+PCIBus *pci_pmac_u3_init(qemu_irq *pic);
 
 /* Mac NVRAM */
 typedef struct MacIONVRAMState MacIONVRAMState;
diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c
index a4c714a..bc86c85 100644
--- a/hw/ppc_newworld.c
+++ b/hw/ppc_newworld.c
@@ -21,6 +21,30 @@
  * 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.
+ *
+ * PCI bus layout on a real G5 (U3 based):
+ *
+ * 0000:f0:0b.0 Host bridge [0600]: Apple Computer Inc. U3 AGP [106b:004b]
+ * 0000:f0:10.0 VGA compatible controller [0300]: ATI Technologies Inc RV350 AP [Radeon 9600] [1002:4150]
+ * 0001:00:00.0 Host bridge [0600]: Apple Computer Inc. CPC945 HT Bridge [106b:004a]
+ * 0001:00:01.0 PCI bridge [0604]: Advanced Micro Devices [AMD] AMD-8131 PCI-X Bridge [1022:7450] (rev 12)
+ * 0001:00:02.0 PCI bridge [0604]: Advanced Micro Devices [AMD] AMD-8131 PCI-X Bridge [1022:7450] (rev 12)
+ * 0001:00:03.0 PCI bridge [0604]: Apple Computer Inc. K2 HT-PCI Bridge [106b:0045]
+ * 0001:00:04.0 PCI bridge [0604]: Apple Computer Inc. K2 HT-PCI Bridge [106b:0046]
+ * 0001:00:05.0 PCI bridge [0604]: Apple Computer Inc. K2 HT-PCI Bridge [106b:0047]
+ * 0001:00:06.0 PCI bridge [0604]: Apple Computer Inc. K2 HT-PCI Bridge [106b:0048]
+ * 0001:00:07.0 PCI bridge [0604]: Apple Computer Inc. K2 HT-PCI Bridge [106b:0049]
+ * 0001:01:07.0 Class [ff00]: Apple Computer Inc. K2 KeyLargo Mac/IO [106b:0041] (rev 20)
+ * 0001:01:08.0 USB Controller [0c03]: Apple Computer Inc. K2 KeyLargo USB [106b:0040]
+ * 0001:01:09.0 USB Controller [0c03]: Apple Computer Inc. K2 KeyLargo USB [106b:0040]
+ * 0001:02:0b.0 USB Controller [0c03]: NEC Corporation USB [1033:0035] (rev 43)
+ * 0001:02:0b.1 USB Controller [0c03]: NEC Corporation USB [1033:0035] (rev 43)
+ * 0001:02:0b.2 USB Controller [0c03]: NEC Corporation USB 2.0 [1033:00e0] (rev 04)
+ * 0001:03:0d.0 Class [ff00]: Apple Computer Inc. K2 ATA/100 [106b:0043]
+ * 0001:03:0e.0 FireWire (IEEE 1394) [0c00]: Apple Computer Inc. K2 FireWire [106b:0042]
+ * 0001:04:0f.0 Ethernet controller [0200]: Apple Computer Inc. K2 GMAC (Sun GEM) [106b:004c]
+ * 0001:05:0c.0 IDE interface [0101]: Broadcom K2 SATA [1166:0240]
+ *
  */
 #include "hw.h"
 #include "ppc.h"
@@ -40,6 +64,8 @@
 #include "loader.h"
 #include "elf.h"
 #include "kvm.h"
+#include "kvm_ppc.h"
+#include "hw/usb.h"
 
 #define MAX_IDE_BUS 2
 #define VGA_BIOS_SIZE 65536
@@ -109,11 +135,13 @@
     int nvram_mem_index;
     int vga_bios_size, bios_size;
     int pic_mem_index, dbdma_mem_index, cuda_mem_index, escc_mem_index;
+    int ide_mem_index[3];
     int ppc_boot_device;
     DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
     void *fw_cfg;
     void *dbdma;
     uint8_t *vga_bios_ptr;
+    int machine_arch;
 
     linux_boot = (kernel_filename != NULL);
 
@@ -317,7 +345,14 @@
         }
     }
     pic = openpic_init(NULL, &pic_mem_index, smp_cpus, openpic_irqs, NULL);
-    pci_bus = pci_pmac_init(pic);
+    if (PPC_INPUT(env) == PPC_FLAGS_INPUT_970) {
+        /* 970 gets a U3 bus */
+        pci_bus = pci_pmac_u3_init(pic);
+        machine_arch = ARCH_MAC99_U3;
+    } else {
+        pci_bus = pci_pmac_init(pic);
+        machine_arch = ARCH_MAC99;
+    }
     /* init basic PC hardware */
     pci_vga_init(pci_bus, vga_bios_offset, vga_bios_size);
 
@@ -331,27 +366,41 @@
         fprintf(stderr, "qemu: too many IDE bus\n");
         exit(1);
     }
-    for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) {
-        hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
-    }
     dbdma = DBDMA_init(&dbdma_mem_index);
-    pci_cmd646_ide_init(pci_bus, hd, 0);
+
+    /* We only emulate 2 out of 3 IDE controllers for now */
+    ide_mem_index[0] = -1;
+    hd[0] = drive_get(IF_IDE, 0, 0);
+    hd[1] = drive_get(IF_IDE, 0, 1);
+    ide_mem_index[1] = pmac_ide_init(hd, pic[0x0d], dbdma, 0x16, pic[0x02]);
+    hd[0] = drive_get(IF_IDE, 1, 0);
+    hd[1] = drive_get(IF_IDE, 1, 1);
+    ide_mem_index[2] = pmac_ide_init(hd, pic[0x0e], dbdma, 0x1a, pic[0x02]);
 
     /* cuda also initialize ADB */
+    if (machine_arch == ARCH_MAC99_U3) {
+        usb_enabled = 1;
+    }
     cuda_init(&cuda_mem_index, pic[0x19]);
 
     adb_kbd_init(&adb_bus);
     adb_mouse_init(&adb_bus);
 
-
     macio_init(pci_bus, PCI_DEVICE_ID_APPLE_UNI_N_KEYL, 0, pic_mem_index,
-               dbdma_mem_index, cuda_mem_index, NULL, 0, NULL,
+               dbdma_mem_index, cuda_mem_index, NULL, 3, ide_mem_index,
                escc_mem_index);
 
     if (usb_enabled) {
         usb_ohci_init_pci(pci_bus, -1);
     }
 
+    /* U3 needs to use USB for input because Linux doesn't support via-cuda
+       on PPC64 */
+    if (machine_arch == ARCH_MAC99_U3) {
+        usbdevice_create("keyboard");
+        usbdevice_create("mouse");
+    }
+
     if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8)
         graphic_depth = 15;
 
@@ -364,7 +413,7 @@
     fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2);
     fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
     fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
-    fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, ARCH_MAC99);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, machine_arch);
     fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_base);
     fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
     if (kernel_cmdline) {
@@ -381,6 +430,14 @@
     fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_HEIGHT, graphic_height);
     fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_DEPTH, graphic_depth);
 
+    if (kvm_enabled()) {
+#ifdef CONFIG_KVM
+        fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, kvmppc_get_tbfreq());
+#endif
+    } else {
+        fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, get_ticks_per_sec());
+    }
+
     qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
 }
 
diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c
index 7ccc6a1..04a7835 100644
--- a/hw/ppc_oldworld.c
+++ b/hw/ppc_oldworld.c
@@ -40,6 +40,7 @@
 #include "loader.h"
 #include "elf.h"
 #include "kvm.h"
+#include "kvm_ppc.h"
 
 #define MAX_IDE_BUS 2
 #define VGA_BIOS_SIZE 65536
@@ -401,6 +402,14 @@
     fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_HEIGHT, graphic_height);
     fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_DEPTH, graphic_depth);
 
+    if (kvm_enabled()) {
+#ifdef CONFIG_KVM
+        fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, kvmppc_get_tbfreq());
+#endif
+    } else {
+        fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, get_ticks_per_sec());
+    }
+
     qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
 }
 
diff --git a/hw/qdev.c b/hw/qdev.c
index 539b5a2..d0052d4 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -749,8 +749,11 @@
 
     opts = qemu_opts_parse(&qemu_device_opts,
                            qdict_get_str(qdict, "config"), "driver");
-    if (opts && !qdev_device_help(opts))
-        qdev_device_add(opts);
+    if (opts) {
+        if (qdev_device_help(opts) || qdev_device_add(opts) == NULL) {
+            qemu_opts_del(opts);
+        }
+    }
 }
 
 void do_device_del(Monitor *mon, const QDict *qdict)
diff --git a/hw/serial.c b/hw/serial.c
index e7538ac..df67383 100644
--- a/hw/serial.c
+++ b/hw/serial.c
@@ -169,11 +169,19 @@
 {
     SerialFIFO *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo;
 
-    f->data[f->head++] = chr;
+    /* Receive overruns do not overwrite FIFO contents. */
+    if (fifo == XMIT_FIFO || f->count < UART_FIFO_LENGTH) {
 
-    if (f->head == UART_FIFO_LENGTH)
-        f->head = 0;
-    f->count++;
+        f->data[f->head++] = chr;
+
+        if (f->head == UART_FIFO_LENGTH)
+            f->head = 0;
+    }
+
+    if (f->count < UART_FIFO_LENGTH)
+        f->count++;
+    else if (fifo == RECV_FIFO)
+        s->lsr |= UART_LSR_OE;
 
     return 1;
 }
@@ -533,8 +541,10 @@
         break;
     case 2:
         ret = s->iir;
+        if (ret & UART_IIR_THRI) {
             s->thr_ipending = 0;
-        serial_update_irq(s);
+            serial_update_irq(s);
+        }
         break;
     case 3:
         ret = s->lcr;
@@ -544,9 +554,9 @@
         break;
     case 5:
         ret = s->lsr;
-        /* Clear break interrupt */
-        if (s->lsr & UART_LSR_BI) {
-            s->lsr &= ~UART_LSR_BI;
+        /* Clear break and overrun interrupts */
+        if (s->lsr & (UART_LSR_BI|UART_LSR_OE)) {
+            s->lsr &= ~(UART_LSR_BI|UART_LSR_OE);
             serial_update_irq(s);
         }
         break;
@@ -629,6 +639,8 @@
         /* call the timeout receive callback in 4 char transmit time */
         qemu_mod_timer(s->fifo_timeout_timer, qemu_get_clock (vm_clock) + s->char_transmit_time * 4);
     } else {
+        if (s->lsr & UART_LSR_DR)
+            s->lsr |= UART_LSR_OE;
         s->rbr = buf[0];
         s->lsr |= UART_LSR_DR;
     }
diff --git a/hw/unin_pci.c b/hw/unin_pci.c
index 19eb5e0..7bdf430 100644
--- a/hw/unin_pci.c
+++ b/hw/unin_pci.c
@@ -36,22 +36,31 @@
 #define UNIN_DPRINTF(fmt, ...)
 #endif
 
+static const int unin_irq_line[] = { 0x1b, 0x1c, 0x1d, 0x1e };
+
 typedef struct UNINState {
     SysBusDevice busdev;
     PCIHostState host_state;
+    ReadWriteHandler data_handler;
 } UNINState;
 
-/* Don't know if this matches real hardware, but it agrees with OHW.  */
 static int pci_unin_map_irq(PCIDevice *pci_dev, int irq_num)
 {
-    return (irq_num + (pci_dev->devfn >> 3)) & 3;
+    int retval;
+    int devfn = pci_dev->devfn & 0x00FFFFFF;
+
+    retval = (((devfn >> 11) & 0x1F) + irq_num) & 3;
+
+    return retval;
 }
 
 static void pci_unin_set_irq(void *opaque, int irq_num, int level)
 {
     qemu_irq *pic = opaque;
 
-    qemu_set_irq(pic[irq_num + 8], level);
+    UNIN_DPRINTF("%s: setting INT %d = %d\n", __func__,
+                 unin_irq_line[irq_num], level);
+    qemu_set_irq(pic[unin_irq_line[irq_num]], level);
 }
 
 static void pci_unin_save(QEMUFile* f, void *opaque)
@@ -75,6 +84,68 @@
 {
 }
 
+static uint32_t unin_get_config_reg(uint32_t reg, uint32_t addr)
+{
+    uint32_t retval;
+
+    if (reg & (1u << 31)) {
+        /* XXX OpenBIOS compatibility hack */
+        retval = reg | (addr & 3);
+    } else if (reg & 1) {
+        /* CFA1 style */
+        retval = (reg & ~7u) | (addr & 7);
+    } else {
+        uint32_t slot, func;
+
+        /* Grab CFA0 style values */
+        slot = ffs(reg & 0xfffff800) - 1;
+        func = (reg >> 8) & 7;
+
+        /* ... and then convert them to x86 format */
+        /* config pointer */
+        retval = (reg & (0xff - 7)) | (addr & 7);
+        /* slot */
+        retval |= slot << 11;
+        /* fn */
+        retval |= func << 8;
+    }
+
+
+    UNIN_DPRINTF("Converted config space accessor %08x/%08x -> %08x\n",
+                 reg, addr, retval);
+
+    return retval;
+}
+
+static void unin_data_write(ReadWriteHandler *handler,
+                            pcibus_t addr, uint32_t val, int len)
+{
+    UNINState *s = container_of(handler, UNINState, data_handler);
+#ifdef TARGET_WORDS_BIGENDIAN
+    val = qemu_bswap_len(val, len);
+#endif
+    UNIN_DPRINTF("write addr %" FMT_PCIBUS " len %d val %x\n", addr, len, val);
+    pci_data_write(s->host_state.bus,
+                   unin_get_config_reg(s->host_state.config_reg, addr),
+                   val, len);
+}
+
+static uint32_t unin_data_read(ReadWriteHandler *handler,
+                               pcibus_t addr, int len)
+{
+    UNINState *s = container_of(handler, UNINState, data_handler);
+    uint32_t val;
+
+    val = pci_data_read(s->host_state.bus,
+                        unin_get_config_reg(s->host_state.config_reg, addr),
+                        len);
+    UNIN_DPRINTF("read addr %" FMT_PCIBUS " len %d val %x\n", addr, len, val);
+#ifdef TARGET_WORDS_BIGENDIAN
+    val = qemu_bswap_len(val, len);
+#endif
+    return val;
+}
+
 static int pci_unin_main_init_device(SysBusDevice *dev)
 {
     UNINState *s;
@@ -85,7 +156,9 @@
     s = FROM_SYSBUS(UNINState, dev);
 
     pci_mem_config = pci_host_conf_register_mmio(&s->host_state);
-    pci_mem_data = pci_host_data_register_mmio(&s->host_state);
+    s->data_handler.read = unin_data_read;
+    s->data_handler.write = unin_data_write;
+    pci_mem_data = cpu_register_io_memory_simple(&s->data_handler);
     sysbus_init_mmio(dev, 0x1000, pci_mem_config);
     sysbus_init_mmio(dev, 0x1000, pci_mem_data);
 
@@ -94,6 +167,27 @@
     return 0;
 }
 
+static int pci_u3_agp_init_device(SysBusDevice *dev)
+{
+    UNINState *s;
+    int pci_mem_config, pci_mem_data;
+
+    /* Uninorth U3 AGP bus */
+    s = FROM_SYSBUS(UNINState, dev);
+
+    pci_mem_config = pci_host_conf_register_mmio(&s->host_state);
+    s->data_handler.read = unin_data_read;
+    s->data_handler.write = unin_data_write;
+    pci_mem_data = cpu_register_io_memory_simple(&s->data_handler);
+    sysbus_init_mmio(dev, 0x1000, pci_mem_config);
+    sysbus_init_mmio(dev, 0x1000, pci_mem_data);
+
+    register_savevm("uninorth", 0, 1, pci_unin_save, pci_unin_load, &s->host_state);
+    qemu_register_reset(pci_unin_reset, &s->host_state);
+
+    return 0;
+}
+
 static int pci_unin_agp_init_device(SysBusDevice *dev)
 {
     UNINState *s;
@@ -175,6 +269,31 @@
     return d->host_state.bus;
 }
 
+PCIBus *pci_pmac_u3_init(qemu_irq *pic)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    UNINState *d;
+
+    /* Uninorth AGP bus */
+
+    dev = qdev_create(NULL, "u3-agp");
+    qdev_init_nofail(dev);
+    s = sysbus_from_qdev(dev);
+    d = FROM_SYSBUS(UNINState, s);
+
+    d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
+                                         pci_unin_set_irq, pci_unin_map_irq,
+                                         pic, 11 << 3, 4);
+
+    sysbus_mmio_map(s, 0, 0xf0800000);
+    sysbus_mmio_map(s, 1, 0xf0c00000);
+
+    pci_create_simple(d->host_state.bus, 11 << 3, "u3-agp");
+
+    return d->host_state.bus;
+}
+
 static int unin_main_pci_host_init(PCIDevice *d)
 {
     pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_APPLE);
@@ -201,6 +320,21 @@
     return 0;
 }
 
+static int u3_agp_pci_host_init(PCIDevice *d)
+{
+    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_APPLE);
+    pci_config_set_device_id(d->config, PCI_DEVICE_ID_APPLE_U3_AGP);
+    /* revision */
+    d->config[0x08] = 0x00;
+    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
+    /* cache line size */
+    d->config[0x0C] = 0x08;
+    /* latency timer */
+    d->config[0x0D] = 0x10;
+    d->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL;
+    return 0;
+}
+
 static int unin_internal_pci_host_init(PCIDevice *d)
 {
     pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_APPLE);
@@ -220,6 +354,12 @@
     .init      = unin_main_pci_host_init,
 };
 
+static PCIDeviceInfo u3_agp_pci_host_info = {
+    .qdev.name = "u3-agp",
+    .qdev.size = sizeof(PCIDevice),
+    .init      = u3_agp_pci_host_init,
+};
+
 static PCIDeviceInfo unin_agp_pci_host_info = {
     .qdev.name = "uni-north-agp",
     .qdev.size = sizeof(PCIDevice),
@@ -237,6 +377,9 @@
     sysbus_register_dev("uni-north", sizeof(UNINState),
                         pci_unin_main_init_device);
     pci_qdev_register(&unin_main_pci_host_info);
+    sysbus_register_dev("u3-agp", sizeof(UNINState),
+                        pci_u3_agp_init_device);
+    pci_qdev_register(&u3_agp_pci_host_info);
     sysbus_register_dev("uni-north-agp", sizeof(UNINState),
                         pci_unin_agp_init_device);
     pci_qdev_register(&unin_agp_pci_host_info);
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index 4f320d7..bf456bb 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -66,6 +66,7 @@
     int kind;
     int protocol;
     uint8_t idle;
+    int64_t next_idle_clock;
     int changed;
     void *datain_opaque;
     void (*datain)(void *);
@@ -630,6 +631,11 @@
     s->protocol = 1;
 }
 
+static void usb_hid_set_next_idle(USBHIDState *s, int64_t curtime)
+{
+    s->next_idle_clock = curtime + (get_ticks_per_sec() * s->idle * 4) / 1000;
+}
+
 static int usb_hid_handle_control(USBDevice *dev, int request, int value,
                                   int index, int length, uint8_t *data)
 {
@@ -795,6 +801,7 @@
         break;
     case SET_IDLE:
         s->idle = (uint8_t) (value >> 8);
+        usb_hid_set_next_idle(s, qemu_get_clock(vm_clock));
         ret = 0;
         break;
     default:
@@ -813,9 +820,10 @@
     switch(p->pid) {
     case USB_TOKEN_IN:
         if (p->devep == 1) {
-            /* TODO: Implement finite idle delays.  */
-            if (!(s->changed || s->idle))
+            int64_t curtime = qemu_get_clock(vm_clock);
+            if (!s->changed && (!s->idle || s->next_idle_clock - curtime > 0))
                 return USB_RET_NAK;
+            usb_hid_set_next_idle(s, curtime);
             s->changed = 0;
             if (s->kind == USB_MOUSE)
                 ret = usb_mouse_poll(s, p->data, p->len);
diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c
index 153c651..7048fb8 100644
--- a/hw/versatile_pci.c
+++ b/hw/versatile_pci.c
@@ -147,14 +147,10 @@
     pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_XILINX);
     /* Both boards have the same device ID.  Oh well.  */
     pci_config_set_device_id(d->config, PCI_DEVICE_ID_XILINX_XC2VP30);
-    d->config[0x04] = 0x00;
-    d->config[0x05] = 0x00;
-    d->config[0x06] = 0x20;
-    d->config[0x07] = 0x02;
-    d->config[0x08] = 0x00; // revision
-    d->config[0x09] = 0x00; // programming i/f
+    pci_set_word(d->config + PCI_STATUS,
+		 PCI_STATUS_66MHZ | PCI_STATUS_DEVSEL_MEDIUM);
     pci_config_set_class(d->config, PCI_CLASS_PROCESSOR_CO);
-    d->config[0x0D] = 0x10; // latency_timer
+    pci_set_byte(d->config + PCI_LATENCY_TIMER, 0x10);
     return 0;
 }
 
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index f3373ae..bcd40f7 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -500,8 +500,8 @@
     if (!vdev) {
         return -1;
     }
-    vdev->nvectors = proxy->nvectors ? proxy->nvectors
-                                     : proxy->max_virtserial_ports + 1;
+    vdev->nvectors = proxy->nvectors == -1 ? proxy->max_virtserial_ports + 1
+                                           : proxy->nvectors;
     virtio_init_pci(proxy, vdev,
                     PCI_VENDOR_ID_REDHAT_QUMRANET,
                     PCI_DEVICE_ID_VIRTIO_CONSOLE,
@@ -585,7 +585,7 @@
         .init      = virtio_serial_init_pci,
         .exit      = virtio_exit_pci,
         .qdev.props = (Property[]) {
-            DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 0),
+            DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, -1),
             DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
             DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
             DEFINE_PROP_UINT32("max_ports", VirtIOPCIProxy, max_virtserial_ports,
diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
index ab456ea..d0e0219 100644
--- a/hw/virtio-serial-bus.c
+++ b/hw/virtio-serial-bus.c
@@ -335,8 +335,10 @@
 
 static uint32_t get_features(VirtIODevice *vdev, uint32_t features)
 {
-    features |= (1 << VIRTIO_CONSOLE_F_MULTIPORT);
-
+    VirtIOSerial *vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
+    if (vser->bus->max_nr_ports > 1) {
+        features |= (1 << VIRTIO_CONSOLE_F_MULTIPORT);
+    }
     return features;
 }
 
diff --git a/linux-user/main.c b/linux-user/main.c
index a0d8ce7..1189dda 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -2553,6 +2553,10 @@
     }
 
     cpu_model = NULL;
+#if defined(cpudef_setup)
+    cpudef_setup(); /* parse cpu definitions in target config file (TBD) */
+#endif
+
     optind = 1;
     for(;;) {
         if (optind >= argc)
@@ -2624,8 +2628,8 @@
             cpu_model = argv[optind++];
             if (cpu_model == NULL || strcmp(cpu_model, "?") == 0) {
 /* XXX: implement xxx_cpu_list for targets that still miss it */
-#if defined(cpu_list)
-                    cpu_list(stdout, &fprintf);
+#if defined(cpu_list_id)
+                cpu_list_id(stdout, &fprintf, "");
 #endif
                 exit(1);
             }
diff --git a/linux-user/strace.c b/linux-user/strace.c
index 6090dcc..d77053b 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -1252,8 +1252,10 @@
 
     int cmd = (int)tswap32(tflag);
 #ifdef FUTEX_PRIVATE_FLAG
-    if (cmd == FUTEX_PRIVATE_FLAG)
+    if (cmd & FUTEX_PRIVATE_FLAG) {
         gemu_log("FUTEX_PRIVATE_FLAG|");
+        cmd &= ~FUTEX_PRIVATE_FLAG;
+    }
 #endif
     print_op(FUTEX_WAIT)
     print_op(FUTEX_WAKE)
diff --git a/migration.c b/migration.c
index 2320c5f..05f6cc5 100644
--- a/migration.c
+++ b/migration.c
@@ -54,7 +54,7 @@
         fprintf(stderr, "unknown migration protocol: %s\n", uri);
 }
 
-void do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data)
+int do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {
     MigrationState *s = NULL;
     const char *p;
@@ -64,49 +64,56 @@
     if (current_migration &&
         current_migration->get_status(current_migration) == MIG_STATE_ACTIVE) {
         monitor_printf(mon, "migration already in progress\n");
-        return;
+        return -1;
     }
 
-    if (strstart(uri, "tcp:", &p))
+    if (strstart(uri, "tcp:", &p)) {
         s = tcp_start_outgoing_migration(mon, p, max_throttle, detach,
                                          (int)qdict_get_int(qdict, "blk"), 
                                          (int)qdict_get_int(qdict, "inc"));
 #if !defined(WIN32)
-    else if (strstart(uri, "exec:", &p))
+    } else if (strstart(uri, "exec:", &p)) {
         s = exec_start_outgoing_migration(mon, p, max_throttle, detach,
                                           (int)qdict_get_int(qdict, "blk"), 
                                           (int)qdict_get_int(qdict, "inc"));
-    else if (strstart(uri, "unix:", &p))
+    } else if (strstart(uri, "unix:", &p)) {
         s = unix_start_outgoing_migration(mon, p, max_throttle, detach,
 					  (int)qdict_get_int(qdict, "blk"), 
                                           (int)qdict_get_int(qdict, "inc"));
-    else if (strstart(uri, "fd:", &p))
+    } else if (strstart(uri, "fd:", &p)) {
         s = fd_start_outgoing_migration(mon, p, max_throttle, detach, 
                                         (int)qdict_get_int(qdict, "blk"), 
                                         (int)qdict_get_int(qdict, "inc"));
 #endif
-    else
+    } else {
         monitor_printf(mon, "unknown migration protocol: %s\n", uri);
-
-    if (s == NULL)
-        monitor_printf(mon, "migration failed\n");
-    else {
-        if (current_migration)
-            current_migration->release(current_migration);
-
-        current_migration = s;
+        return -1;
     }
+
+    if (s == NULL) {
+        monitor_printf(mon, "migration failed\n");
+        return -1;
+    }
+
+    if (current_migration) {
+        current_migration->release(current_migration);
+    }
+
+    current_migration = s;
+    return 0;
 }
 
-void do_migrate_cancel(Monitor *mon, const QDict *qdict, QObject **ret_data)
+int do_migrate_cancel(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {
     MigrationState *s = current_migration;
 
     if (s)
         s->cancel(s);
+
+    return 0;
 }
 
-void do_migrate_set_speed(Monitor *mon, const QDict *qdict, QObject **ret_data)
+int do_migrate_set_speed(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {
     double d;
     FdMigrationState *s;
@@ -119,6 +126,8 @@
     if (s && s->file) {
         qemu_file_set_rate_limit(s->file, max_throttle);
     }
+
+    return 0;
 }
 
 /* amount of nanoseconds we are willing to wait for migration to be down.
@@ -132,14 +141,16 @@
     return max_downtime;
 }
 
-void do_migrate_set_downtime(Monitor *mon, const QDict *qdict,
-                             QObject **ret_data)
+int do_migrate_set_downtime(Monitor *mon, const QDict *qdict,
+                            QObject **ret_data)
 {
     double d;
 
     d = qdict_get_double(qdict, "value") * 1e9;
     d = MAX(0, MIN(UINT64_MAX, d));
     max_downtime = (uint64_t)d;
+
+    return 0;
 }
 
 static void migrate_print_status(Monitor *mon, const char *name,
diff --git a/migration.h b/migration.h
index 65572c1..385423f 100644
--- a/migration.h
+++ b/migration.h
@@ -52,16 +52,16 @@
 
 void qemu_start_incoming_migration(const char *uri);
 
-void do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data);
+int do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data);
 
-void do_migrate_cancel(Monitor *mon, const QDict *qdict, QObject **ret_data);
+int do_migrate_cancel(Monitor *mon, const QDict *qdict, QObject **ret_data);
 
-void do_migrate_set_speed(Monitor *mon, const QDict *qdict, QObject **ret_data);
+int do_migrate_set_speed(Monitor *mon, const QDict *qdict, QObject **ret_data);
 
 uint64_t migrate_max_downtime(void);
 
-void do_migrate_set_downtime(Monitor *mon, const QDict *qdict,
-                             QObject **ret_data);
+int do_migrate_set_downtime(Monitor *mon, const QDict *qdict,
+                            QObject **ret_data);
 
 void do_info_migrate_print(Monitor *mon, const QObject *data);
 
diff --git a/monitor.c b/monitor.c
index ae125b8..b1a6edc 100644
--- a/monitor.c
+++ b/monitor.c
@@ -103,7 +103,7 @@
         void (*info_new)(Monitor *mon, QObject **ret_data);
         int  (*info_async)(Monitor *mon, MonitorCompletion *cb, void *opaque);
         void (*cmd)(Monitor *mon, const QDict *qdict);
-        void (*cmd_new)(Monitor *mon, const QDict *params, QObject **ret_data);
+        int  (*cmd_new)(Monitor *mon, const QDict *params, QObject **ret_data);
         int  (*cmd_async)(Monitor *mon, const QDict *params,
                           MonitorCompletion *cb, void *opaque);
     } mhandler;
@@ -120,7 +120,6 @@
 
 typedef struct MonitorControl {
     QObject *id;
-    int print_enabled;
     JSONMessageParser parser;
     int command_mode;
 } MonitorControl;
@@ -138,11 +137,41 @@
     CPUState *mon_cpu;
     BlockDriverCompletionFunc *password_completion_cb;
     void *password_opaque;
+#ifdef CONFIG_DEBUG_MONITOR
+    int print_calls_nr;
+#endif
     QError *error;
     QLIST_HEAD(,mon_fd_t) fds;
     QLIST_ENTRY(Monitor) entry;
 };
 
+#ifdef CONFIG_DEBUG_MONITOR
+#define MON_DEBUG(fmt, ...) do {    \
+    fprintf(stderr, "Monitor: ");       \
+    fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+
+static inline void mon_print_count_inc(Monitor *mon)
+{
+    mon->print_calls_nr++;
+}
+
+static inline void mon_print_count_init(Monitor *mon)
+{
+    mon->print_calls_nr = 0;
+}
+
+static inline int mon_print_count_get(const Monitor *mon)
+{
+    return mon->print_calls_nr;
+}
+
+#else /* !CONFIG_DEBUG_MONITOR */
+#define MON_DEBUG(fmt, ...) do { } while (0)
+static inline void mon_print_count_inc(Monitor *mon) { }
+static inline void mon_print_count_init(Monitor *mon) { }
+static inline int mon_print_count_get(const Monitor *mon) { return 0; }
+#endif /* CONFIG_DEBUG_MONITOR */
+
 static QLIST_HEAD(mon_list, Monitor) mon_list;
 
 static const mon_cmd_t mon_cmds[];
@@ -218,16 +247,19 @@
 
 void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
 {
+    char buf[4096];
+
     if (!mon)
         return;
 
-    if (mon->mc && !mon->mc->print_enabled) {
-        qemu_error_new(QERR_UNDEFINED_ERROR);
-    } else {
-        char buf[4096];
-        vsnprintf(buf, sizeof(buf), fmt, ap);
-        monitor_puts(mon, buf);
+    mon_print_count_inc(mon);
+
+    if (monitor_ctrl_mode(mon)) {
+        return;
     }
+
+    vsnprintf(buf, sizeof(buf), fmt, ap);
+    monitor_puts(mon, buf);
 }
 
 void monitor_printf(Monitor *mon, const char *fmt, ...)
@@ -298,9 +330,8 @@
     json = qobject_to_json(data);
     assert(json != NULL);
 
-    mon->mc->print_enabled = 1;
-    monitor_printf(mon, "%s\n", qstring_get_str(json));
-    mon->mc->print_enabled = 0;
+    qstring_append_chr(json, '\n');
+    monitor_puts(mon, qstring_get_str(json));
 
     QDECREF(json);
 }
@@ -416,13 +447,15 @@
     QDECREF(qmp);
 }
 
-static void do_qmp_capabilities(Monitor *mon, const QDict *params,
-                                QObject **ret_data)
+static int do_qmp_capabilities(Monitor *mon, const QDict *params,
+                               QObject **ret_data)
 {
     /* Will setup QMP capabilities in the future */
     if (monitor_ctrl_mode(mon)) {
         mon->mc->command_mode = 1;
     }
+
+    return 0;
 }
 
 static int compare_cmd(const char *name, const char *list)
@@ -553,7 +586,7 @@
     }
 }
 
-static void do_info(Monitor *mon, const QDict *qdict, QObject **ret_data)
+static int do_info(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {
     const mon_cmd_t *cmd;
     const char *item = qdict_get_try_str(qdict, "item");
@@ -571,7 +604,7 @@
     if (cmd->name == NULL) {
         if (monitor_ctrl_mode(mon)) {
             qemu_error_new(QERR_COMMAND_NOT_FOUND, item);
-            return;
+            return -1;
         }
         goto help;
     }
@@ -603,15 +636,17 @@
         if (monitor_ctrl_mode(mon)) {
             /* handler not converted yet */
             qemu_error_new(QERR_COMMAND_NOT_FOUND, item);
+            return -1;
         } else {
             cmd->mhandler.info(mon);
         }
     }
 
-    return;
+    return 0;
 
 help:
     help_cmd(mon, "info");
+    return 0;
 }
 
 static void do_info_version_print(Monitor *mon, const QObject *data)
@@ -918,11 +953,14 @@
     *ret_data = QOBJECT(cpu_list);
 }
 
-static void do_cpu_set(Monitor *mon, const QDict *qdict, QObject **ret_data)
+static int do_cpu_set(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {
     int index = qdict_get_int(qdict, "index");
-    if (mon_set_cpu(index) < 0)
+    if (mon_set_cpu(index) < 0) {
         qemu_error_new(QERR_INVALID_PARAMETER, "index");
+        return -1;
+    }
+    return 0;
 }
 
 static void do_info_jit(Monitor *mon)
@@ -961,9 +999,10 @@
 /**
  * do_quit(): Quit QEMU execution
  */
-static void do_quit(Monitor *mon, const QDict *qdict, QObject **ret_data)
+static int do_quit(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {
     exit(0);
+    return 0;
 }
 
 static int eject_device(Monitor *mon, BlockDriverState *bs, int force)
@@ -985,7 +1024,7 @@
     return 0;
 }
 
-static void do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data)
+static int do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {
     BlockDriverState *bs;
     int force = qdict_get_int(qdict, "force");
@@ -994,12 +1033,12 @@
     bs = bdrv_find(filename);
     if (!bs) {
         qemu_error_new(QERR_DEVICE_NOT_FOUND, filename);
-        return;
+        return -1;
     }
-    eject_device(mon, bs, force);
+    return eject_device(mon, bs, force);
 }
 
-static void do_block_set_passwd(Monitor *mon, const QDict *qdict,
+static int do_block_set_passwd(Monitor *mon, const QDict *qdict,
                                 QObject **ret_data)
 {
     BlockDriverState *bs;
@@ -1007,16 +1046,19 @@
     bs = bdrv_find(qdict_get_str(qdict, "device"));
     if (!bs) {
         qemu_error_new(QERR_DEVICE_NOT_FOUND, qdict_get_str(qdict, "device"));
-        return;
+        return -1;
     }
 
     if (bdrv_set_key(bs, qdict_get_str(qdict, "password")) < 0) {
         qemu_error_new(QERR_INVALID_PASSWORD);
+        return -1;
     }
+
+    return 0;
 }
 
-static void do_change_block(Monitor *mon, const char *device,
-                            const char *filename, const char *fmt)
+static int do_change_block(Monitor *mon, const char *device,
+                           const char *filename, const char *fmt)
 {
     BlockDriverState *bs;
     BlockDriver *drv = NULL;
@@ -1024,26 +1066,32 @@
     bs = bdrv_find(device);
     if (!bs) {
         qemu_error_new(QERR_DEVICE_NOT_FOUND, device);
-        return;
+        return -1;
     }
     if (fmt) {
         drv = bdrv_find_whitelisted_format(fmt);
         if (!drv) {
             qemu_error_new(QERR_INVALID_BLOCK_FORMAT, fmt);
-            return;
+            return -1;
         }
     }
-    if (eject_device(mon, bs, 0) < 0)
-        return;
-    bdrv_open2(bs, filename, BDRV_O_RDWR, drv);
-    monitor_read_bdrv_key_start(mon, bs, NULL, NULL);
+    if (eject_device(mon, bs, 0) < 0) {
+        return -1;
+    }
+    if (bdrv_open2(bs, filename, BDRV_O_RDWR, drv) < 0) {
+        return -1;
+    }
+    return monitor_read_bdrv_key_start(mon, bs, NULL, NULL);
 }
 
-static void change_vnc_password(const char *password)
+static int change_vnc_password(const char *password)
 {
-    if (vnc_display_password(NULL, password) < 0)
+    if (vnc_display_password(NULL, password) < 0) {
         qemu_error_new(QERR_SET_PASSWD_FAILED);
+        return -1;
+    }
 
+    return 0;
 }
 
 static void change_vnc_password_cb(Monitor *mon, const char *password,
@@ -1053,7 +1101,7 @@
     monitor_read_command(mon, 1);
 }
 
-static void do_change_vnc(Monitor *mon, const char *target, const char *arg)
+static int do_change_vnc(Monitor *mon, const char *target, const char *arg)
 {
     if (strcmp(target, "passwd") == 0 ||
         strcmp(target, "password") == 0) {
@@ -1061,29 +1109,37 @@
             char password[9];
             strncpy(password, arg, sizeof(password));
             password[sizeof(password) - 1] = '\0';
-            change_vnc_password(password);
+            return change_vnc_password(password);
         } else {
-            monitor_read_password(mon, change_vnc_password_cb, NULL);
+            return monitor_read_password(mon, change_vnc_password_cb, NULL);
         }
     } else {
-        if (vnc_display_open(NULL, target) < 0)
+        if (vnc_display_open(NULL, target) < 0) {
             qemu_error_new(QERR_VNC_SERVER_FAILED, target);
+            return -1;
+        }
     }
+
+    return 0;
 }
 
 /**
  * do_change(): Change a removable medium, or VNC configuration
  */
-static void do_change(Monitor *mon, const QDict *qdict, QObject **ret_data)
+static int do_change(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {
     const char *device = qdict_get_str(qdict, "device");
     const char *target = qdict_get_str(qdict, "target");
     const char *arg = qdict_get_try_str(qdict, "arg");
+    int ret;
+
     if (strcmp(device, "vnc") == 0) {
-        do_change_vnc(mon, target, arg);
+        ret = do_change_vnc(mon, target, arg);
     } else {
-        do_change_block(mon, device, target, arg);
+        ret = do_change_block(mon, device, target, arg);
     }
+
+    return ret;
 }
 
 static void do_screen_dump(Monitor *mon, const QDict *qdict)
@@ -1128,9 +1184,10 @@
 /**
  * do_stop(): Stop VM execution
  */
-static void do_stop(Monitor *mon, const QDict *qdict, QObject **ret_data)
+static int do_stop(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {
     vm_stop(EXCP_INTERRUPT);
+    return 0;
 }
 
 static void encrypted_bdrv_it(void *opaque, BlockDriverState *bs);
@@ -1143,14 +1200,18 @@
 /**
  * do_cont(): Resume emulation.
  */
-static void do_cont(Monitor *mon, const QDict *qdict, QObject **ret_data)
+static int do_cont(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {
     struct bdrv_iterate_context context = { mon, 0 };
 
     bdrv_iterate(encrypted_bdrv_it, &context);
     /* only resume the vm if all keys are set and valid */
-    if (!context.err)
+    if (!context.err) {
         vm_start();
+        return 0;
+    } else {
+        return -1;
+    }
 }
 
 static void bdrv_key_cb(void *opaque, int err)
@@ -1413,7 +1474,7 @@
     monitor_printf(mon, "\n");
 }
 
-static void do_memory_save(Monitor *mon, const QDict *qdict, QObject **ret_data)
+static int do_memory_save(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {
     FILE *f;
     uint32_t size = qdict_get_int(qdict, "size");
@@ -1422,13 +1483,14 @@
     uint32_t l;
     CPUState *env;
     uint8_t buf[1024];
+    int ret = -1;
 
     env = mon_get_cpu();
 
     f = fopen(filename, "wb");
     if (!f) {
         qemu_error_new(QERR_OPEN_FILE_FAILED, filename);
-        return;
+        return -1;
     }
     while (size != 0) {
         l = sizeof(buf);
@@ -1442,11 +1504,15 @@
         addr += l;
         size -= l;
     }
+
+    ret = 0;
+
 exit:
     fclose(f);
+    return ret;
 }
 
-static void do_physical_memory_save(Monitor *mon, const QDict *qdict,
+static int do_physical_memory_save(Monitor *mon, const QDict *qdict,
                                     QObject **ret_data)
 {
     FILE *f;
@@ -1455,11 +1521,12 @@
     uint32_t size = qdict_get_int(qdict, "size");
     const char *filename = qdict_get_str(qdict, "filename");
     target_phys_addr_t addr = qdict_get_int(qdict, "val");
+    int ret = -1;
 
     f = fopen(filename, "wb");
     if (!f) {
         qemu_error_new(QERR_OPEN_FILE_FAILED, filename);
-        return;
+        return -1;
     }
     while (size != 0) {
         l = sizeof(buf);
@@ -1474,8 +1541,12 @@
         addr += l;
         size -= l;
     }
+
+    ret = 0;
+
 exit:
     fclose(f);
+    return ret;
 }
 
 static void do_sum(Monitor *mon, const QDict *qdict)
@@ -1828,19 +1899,21 @@
 /**
  * do_system_reset(): Issue a machine reset
  */
-static void do_system_reset(Monitor *mon, const QDict *qdict,
-                            QObject **ret_data)
+static int do_system_reset(Monitor *mon, const QDict *qdict,
+                           QObject **ret_data)
 {
     qemu_system_reset_request();
+    return 0;
 }
 
 /**
  * do_system_powerdown(): Issue a machine powerdown
  */
-static void do_system_powerdown(Monitor *mon, const QDict *qdict,
-                                QObject **ret_data)
+static int do_system_powerdown(Monitor *mon, const QDict *qdict,
+                               QObject **ret_data)
 {
     qemu_system_powerdown_request();
+    return 0;
 }
 
 #if defined(TARGET_I386)
@@ -2236,6 +2309,7 @@
         return -1;
     }
 
+    cb(opaque, NULL);
     return 0;
 }
 
@@ -2386,7 +2460,7 @@
 }
 #endif
 
-static void do_getfd(Monitor *mon, const QDict *qdict, QObject **ret_data)
+static int do_getfd(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {
     const char *fdname = qdict_get_str(qdict, "fdname");
     mon_fd_t *monfd;
@@ -2395,12 +2469,12 @@
     fd = qemu_chr_get_msgfd(mon->chr);
     if (fd == -1) {
         qemu_error_new(QERR_FD_NOT_SUPPLIED);
-        return;
+        return -1;
     }
 
     if (qemu_isdigit(fdname[0])) {
         qemu_error_new(QERR_INVALID_PARAMETER, "fdname");
-        return;
+        return -1;
     }
 
     fd = dup(fd);
@@ -2409,7 +2483,7 @@
             qemu_error_new(QERR_TOO_MANY_FILES);
         else
             qemu_error_new(QERR_UNDEFINED_ERROR);
-        return;
+        return -1;
     }
 
     QLIST_FOREACH(monfd, &mon->fds, next) {
@@ -2419,7 +2493,7 @@
 
         close(monfd->fd);
         monfd->fd = fd;
-        return;
+        return 0;
     }
 
     monfd = qemu_mallocz(sizeof(mon_fd_t));
@@ -2427,9 +2501,10 @@
     monfd->fd = fd;
 
     QLIST_INSERT_HEAD(&mon->fds, monfd, next);
+    return 0;
 }
 
-static void do_closefd(Monitor *mon, const QDict *qdict, QObject **ret_data)
+static int do_closefd(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {
     const char *fdname = qdict_get_str(qdict, "fdname");
     mon_fd_t *monfd;
@@ -2443,10 +2518,11 @@
         close(monfd->fd);
         qemu_free(monfd->name);
         qemu_free(monfd);
-        return;
+        return 0;
     }
 
     qemu_error_new(QERR_FD_NOT_FOUND, fdname);
+    return -1;
 }
 
 static void do_loadvm(Monitor *mon, const QDict *qdict)
@@ -3796,12 +3872,59 @@
     return 0;
 }
 
+static void handler_audit(Monitor *mon, const mon_cmd_t *cmd, int ret)
+{
+    if (ret && !monitor_has_error(mon)) {
+        /*
+         * If it returns failure, it must have passed on error.
+         *
+         * Action: Report an internal error to the client if in QMP.
+         */
+        if (monitor_ctrl_mode(mon)) {
+            qemu_error_new(QERR_UNDEFINED_ERROR);
+        }
+        MON_DEBUG("command '%s' returned failure but did not pass an error\n",
+                  cmd->name);
+    }
+
+#ifdef CONFIG_DEBUG_MONITOR
+    if (!ret && monitor_has_error(mon)) {
+        /*
+         * If it returns success, it must not have passed an error.
+         *
+         * Action: Report the passed error to the client.
+         */
+        MON_DEBUG("command '%s' returned success but passed an error\n",
+                  cmd->name);
+    }
+
+    if (mon_print_count_get(mon) > 0 && strcmp(cmd->name, "info") != 0) {
+        /*
+         * Handlers should not call Monitor print functions.
+         *
+         * Action: Ignore them in QMP.
+         *
+         * (XXX: we don't check any 'info' or 'query' command here
+         * because the user print function _is_ called by do_info(), hence
+         * we will trigger this check. This problem will go away when we
+         * make 'query' commands real and kill do_info())
+         */
+        MON_DEBUG("command '%s' called print functions %d time(s)\n",
+                  cmd->name, mon_print_count_get(mon));
+    }
+#endif
+}
+
 static void monitor_call_handler(Monitor *mon, const mon_cmd_t *cmd,
                                  const QDict *params)
 {
+    int ret;
     QObject *data = NULL;
 
-    cmd->mhandler.cmd_new(mon, params, &data);
+    mon_print_count_init(mon);
+
+    ret = cmd->mhandler.cmd_new(mon, params, &data);
+    handler_audit(mon, cmd, ret);
 
     if (is_async_return(data)) {
         /*
@@ -4519,21 +4642,21 @@
     monitor_read_command(mon, 1);
 }
 
-void monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
-                                 BlockDriverCompletionFunc *completion_cb,
-                                 void *opaque)
+int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
+                                BlockDriverCompletionFunc *completion_cb,
+                                void *opaque)
 {
     int err;
 
     if (!bdrv_key_required(bs)) {
         if (completion_cb)
             completion_cb(opaque, 0);
-        return;
+        return 0;
     }
 
     if (monitor_ctrl_mode(mon)) {
         qemu_error_new(QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs));
-        return;
+        return -1;
     }
 
     monitor_printf(mon, "%s (%s) is encrypted.\n", bdrv_get_device_name(bs),
@@ -4546,6 +4669,8 @@
 
     if (err && completion_cb)
         completion_cb(opaque, err);
+
+    return err;
 }
 
 typedef struct QemuErrorSink QemuErrorSink;
@@ -4636,7 +4761,8 @@
         if (!qemu_error_sink->mon->error) {
             qemu_error_sink->mon->error = qerror;
         } else {
-            /* XXX: warn the programmer */
+            MON_DEBUG("Additional error report at %s:%d\n", qerror->file,
+                      qerror->linenr);
             QDECREF(qerror);
         }
         break;
diff --git a/monitor.h b/monitor.h
index e35f1e4..fc09505 100644
--- a/monitor.h
+++ b/monitor.h
@@ -33,9 +33,9 @@
 int monitor_suspend(Monitor *mon);
 void monitor_resume(Monitor *mon);
 
-void monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
-                                 BlockDriverCompletionFunc *completion_cb,
-                                 void *opaque);
+int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
+                                BlockDriverCompletionFunc *completion_cb,
+                                void *opaque);
 
 int monitor_get_fd(Monitor *mon, const char *fdname);
 
diff --git a/net.c b/net.c
index 8e951ca..a1bf49f 100644
--- a/net.c
+++ b/net.c
@@ -812,9 +812,6 @@
     }
 
     nd->used = 1;
-    if (vlan) {
-        nd->vlan->nb_guest_devs++;
-    }
     nb_nics++;
 
     return idx;
@@ -843,7 +840,7 @@
 /* magic number, but compiler will warn if too small */
 #define NET_MAX_DESC 20
 
-static struct {
+static const struct {
     const char *type;
     net_client_init_func init;
     QemuOptDesc desc[NET_MAX_DESC];
@@ -1128,20 +1125,6 @@
     return -1;
 }
 
-void net_client_uninit(NICInfo *nd)
-{
-    if (nd->vlan) {
-        nd->vlan->nb_guest_devs--;
-    }
-    nb_nics--;
-
-    qemu_free(nd->model);
-    qemu_free(nd->name);
-    qemu_free(nd->devaddr);
-
-    nd->used = 0;
-}
-
 static int net_host_check_device(const char *device)
 {
     int i;
@@ -1227,16 +1210,23 @@
 void do_info_network(Monitor *mon)
 {
     VLANState *vlan;
+    VLANClientState *vc;
 
     QTAILQ_FOREACH(vlan, &vlans, next) {
-        VLANClientState *vc;
-
         monitor_printf(mon, "VLAN %d devices:\n", vlan->id);
 
         QTAILQ_FOREACH(vc, &vlan->clients, next) {
             monitor_printf(mon, "  %s: %s\n", vc->name, vc->info_str);
         }
     }
+    monitor_printf(mon, "Devices not on any VLAN:\n");
+    QTAILQ_FOREACH(vc, &non_vlan_clients, next) {
+        monitor_printf(mon, "  %s: %s", vc->name, vc->info_str);
+        if (vc->peer) {
+            monitor_printf(mon, " peer=%s", vc->peer->name);
+        }
+        monitor_printf(mon, "\n");
+    }
 }
 
 void do_set_link(Monitor *mon, const QDict *qdict)
@@ -1253,6 +1243,7 @@
             }
         }
     }
+    vc = qemu_find_netdev(name);
 done:
 
     if (!vc) {
@@ -1289,20 +1280,41 @@
     }
 }
 
-static void net_check_clients(void)
+void net_check_clients(void)
 {
     VLANState *vlan;
+    VLANClientState *vc;
+    int has_nic = 0, has_host_dev = 0;
 
     QTAILQ_FOREACH(vlan, &vlans, next) {
-        if (vlan->nb_guest_devs == 0 && vlan->nb_host_devs == 0)
-            continue;
-        if (vlan->nb_guest_devs == 0)
+        QTAILQ_FOREACH(vc, &vlan->clients, next) {
+            switch (vc->info->type) {
+            case NET_CLIENT_TYPE_NIC:
+                has_nic = 1;
+                break;
+            case NET_CLIENT_TYPE_SLIRP:
+            case NET_CLIENT_TYPE_TAP:
+            case NET_CLIENT_TYPE_SOCKET:
+            case NET_CLIENT_TYPE_VDE:
+                has_host_dev = 1;
+                break;
+            default: ;
+            }
+        }
+        if (has_host_dev && !has_nic)
             fprintf(stderr, "Warning: vlan %d with no nics\n", vlan->id);
-        if (vlan->nb_host_devs == 0)
+        if (has_nic && !has_host_dev)
             fprintf(stderr,
                     "Warning: vlan %d is not connected to host network\n",
                     vlan->id);
     }
+    QTAILQ_FOREACH(vc, &non_vlan_clients, next) {
+        if (!vc->peer) {
+            fprintf(stderr, "Warning: %s %s has no peer\n",
+                    vc->info->type == NET_CLIENT_TYPE_NIC ? "nic" : "netdev",
+                    vc->name);
+        }
+    }
 }
 
 static int net_init_client(QemuOpts *opts, void *dummy)
@@ -1337,8 +1349,6 @@
         return -1;
     }
 
-    net_check_clients();
-
     return 0;
 }
 
diff --git a/net.h b/net.h
index 116bb80..33a1eaf 100644
--- a/net.h
+++ b/net.h
@@ -79,7 +79,6 @@
     int id;
     QTAILQ_HEAD(, VLANClientState) clients;
     QTAILQ_ENTRY(VLANState) next;
-    unsigned int nb_guest_devs, nb_host_devs;
     NetQueue *send_queue;
 };
 
@@ -163,9 +162,9 @@
 extern const char *legacy_bootp_filename;
 
 int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev);
-void net_client_uninit(NICInfo *nd);
 int net_client_parse(QemuOptsList *opts_list, const char *str);
 int net_init_clients(void);
+void net_check_clients(void);
 void net_cleanup(void);
 void net_set_boot_mask(int boot_mask);
 void net_host_device_add(Monitor *mon, const QDict *qdict);
diff --git a/net/slirp.c b/net/slirp.c
index 361899b..317cca7 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -738,10 +738,6 @@
         qemu_free(config);
     }
 
-    if (ret != -1 && vlan) {
-        vlan->nb_host_devs++;
-    }
-
     qemu_free(vnet);
 
     return ret;
diff --git a/net/socket.c b/net/socket.c
index 5533737..442a9c7 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -569,9 +569,5 @@
         return -1;
     }
 
-    if (vlan) {
-        vlan->nb_host_devs++;
-    }
-
     return 0;
 }
diff --git a/net/tap-win32.c b/net/tap-win32.c
index b717c17..8370c80 100644
--- a/net/tap-win32.c
+++ b/net/tap-win32.c
@@ -714,10 +714,6 @@
         return -1;
     }
 
-    if (vlan) {
-        vlan->nb_host_devs++;
-    }
-
     return 0;
 }
 
diff --git a/net/tap.c b/net/tap.c
index d3492de..7a7320c 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -449,9 +449,5 @@
         }
     }
 
-    if (vlan) {
-        vlan->nb_host_devs++;
-    }
-
     return 0;
 }
diff --git a/net/vde.c b/net/vde.c
index 42b4633..0b46fa6 100644
--- a/net/vde.c
+++ b/net/vde.c
@@ -127,9 +127,5 @@
         return -1;
     }
 
-    if (vlan) {
-        vlan->nb_host_devs++;
-    }
-
     return 0;
 }
diff --git a/pc-bios/README b/pc-bios/README
index 0570922..ee68723 100644
--- a/pc-bios/README
+++ b/pc-bios/README
@@ -14,8 +14,8 @@
 - OpenBIOS (http://www.openbios.org/) is a free (GPL v2) portable
   firmware implementation. The goal is to implement a 100% IEEE
   1275-1994 (referred to as Open Firmware) compliant firmware.
-  The included images for PowerPC (for 32 and 64 bit PPC CPUs) are built from
-  OpenBIOS SVN revision 640, Sparc64 images from r665 and Sparc32 from r666.
+  The included images for PowerPC (for 32 and 64 bit PPC CPUs),
+  Sparc32 and Sparc64 are built from OpenBIOS SVN revision 683.
 
 - The PXE roms come from Rom-o-Matic gPXE 0.9.9 with BANNER_TIMEOUT=0
 
diff --git a/pc-bios/openbios-ppc b/pc-bios/openbios-ppc
index 1bcfed3..b82ce2c 100644
--- a/pc-bios/openbios-ppc
+++ b/pc-bios/openbios-ppc
Binary files differ
diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32
index aafb041..4f2f45f 100644
--- a/pc-bios/openbios-sparc32
+++ b/pc-bios/openbios-sparc32
Binary files differ
diff --git a/pc-bios/openbios-sparc64 b/pc-bios/openbios-sparc64
index 437d246..632f938 100644
--- a/pc-bios/openbios-sparc64
+++ b/pc-bios/openbios-sparc64
Binary files differ
diff --git a/qemu-char.c b/qemu-char.c
index 75dbf66..4169492 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -1173,6 +1173,22 @@
     return 0;
 }
 
+static void qemu_chr_close_tty(CharDriverState *chr)
+{
+    FDCharDriver *s = chr->opaque;
+    int fd = -1;
+
+    if (s) {
+        fd = s->fd_in;
+    }
+
+    fd_chr_close(chr);
+
+    if (fd >= 0) {
+        close(fd);
+    }
+}
+
 static CharDriverState *qemu_chr_open_tty(QemuOpts *opts)
 {
     const char *filename = qemu_opt_get(opts, "path");
@@ -1190,6 +1206,7 @@
         return NULL;
     }
     chr->chr_ioctl = tty_serial_ioctl;
+    chr->chr_close = qemu_chr_close_tty;
     return chr;
 }
 #else  /* ! __linux__ && ! __sun__ */
diff --git a/qemu-common.h b/qemu-common.h
index c941006..805be1a 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -11,6 +11,8 @@
 #define QEMU_WARN_UNUSED_RESULT
 #endif
 
+#define QEMU_BUILD_BUG_ON(x) typedef char __build_bug_on__##__LINE__[(x)?-1:1];
+
 /* Hack around the mess dyngen-exec.h causes: We need QEMU_NORETURN in files that
    cannot include the following headers without conflicts. This condition has
    to be removed once dyngen is gone. */
@@ -226,6 +228,8 @@
 typedef struct DeviceState DeviceState;
 typedef struct SSIBus SSIBus;
 
+typedef uint64_t pcibus_t;
+
 /* CPU save/load.  */
 void cpu_save(QEMUFile *f, void *opaque);
 int cpu_load(QEMUFile *f, void *opaque, int version_id);
diff --git a/qemu-config.c b/qemu-config.c
index c3203c8..246fae6 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -242,6 +242,54 @@
     },
 };
 
+QemuOptsList qemu_cpudef_opts = {
+    .name = "cpudef",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_cpudef_opts.head),
+    .desc = {
+        {
+            .name = "name",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "level",
+            .type = QEMU_OPT_NUMBER,
+        },{
+            .name = "vendor",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "family",
+            .type = QEMU_OPT_NUMBER,
+        },{
+            .name = "model",
+            .type = QEMU_OPT_NUMBER,
+        },{
+            .name = "stepping",
+            .type = QEMU_OPT_NUMBER,
+        },{
+            .name = "feature_edx",      /* cpuid 0000_0001.edx */
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "feature_ecx",      /* cpuid 0000_0001.ecx */
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "extfeature_edx",   /* cpuid 8000_0001.edx */
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "extfeature_ecx",   /* cpuid 8000_0001.ecx */
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "xlevel",
+            .type = QEMU_OPT_NUMBER,
+        },{
+            .name = "model_id",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "vendor_override",
+            .type = QEMU_OPT_NUMBER,
+        },
+        { /* end of list */ }
+    },
+};
+
 static QemuOptsList *lists[] = {
     &qemu_drive_opts,
     &qemu_chardev_opts,
@@ -251,6 +299,7 @@
     &qemu_rtc_opts,
     &qemu_global_opts,
     &qemu_mon_opts,
+    &qemu_cpudef_opts,
     NULL,
 };
 
diff --git a/qemu-config.h b/qemu-config.h
index dd89ae4..b335c42 100644
--- a/qemu-config.h
+++ b/qemu-config.h
@@ -9,6 +9,7 @@
 extern QemuOptsList qemu_rtc_opts;
 extern QemuOptsList qemu_global_opts;
 extern QemuOptsList qemu_mon_opts;
+extern QemuOptsList qemu_cpudef_opts;
 
 int qemu_set_option(const char *str);
 int qemu_global_option(const char *str);
diff --git a/qemu-img.c b/qemu-img.c
index 0db8d4f..0c9f2d4 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -1168,7 +1168,7 @@
         if (bdrv_open2(bs_new_backing, out_baseimg, BRDV_O_FLAGS | BDRV_O_RDWR,
             new_backing_drv))
         {
-            error("Could not open new backing file '%s'", backing_name);
+            error("Could not open new backing file '%s'", out_baseimg);
             return -1;
         }
     }
@@ -1224,7 +1224,7 @@
                 int pnum;
 
                 if (compare_sectors(buf_old + written * 512,
-                    buf_new + written * 512, n, &pnum))
+                    buf_new + written * 512, n - written, &pnum))
                 {
                     ret = bdrv_write(bs, sector + written,
                         buf_old + written * 512, pnum);
diff --git a/qemu-option.c b/qemu-option.c
index a52a4c4..de40bff 100644
--- a/qemu-option.c
+++ b/qemu-option.c
@@ -470,7 +470,7 @@
     const char   *name;
     const char   *str;
 
-    QemuOptDesc  *desc;
+    const QemuOptDesc *desc;
     union {
         int      boolean;
         uint64_t uint;
@@ -565,7 +565,7 @@
 int qemu_opt_set(QemuOpts *opts, const char *name, const char *value)
 {
     QemuOpt *opt;
-    QemuOptDesc *desc = opts->list->desc;
+    const QemuOptDesc *desc = opts->list->desc;
     int i;
 
     for (i = 0; desc[i].name != NULL; i++) {
@@ -777,7 +777,7 @@
 /* Validate parsed opts against descriptions where no
  * descriptions were provided in the QemuOptsList.
  */
-int qemu_opts_validate(QemuOpts *opts, QemuOptDesc *desc)
+int qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc)
 {
     QemuOpt *opt;
 
diff --git a/qemu-option.h b/qemu-option.h
index 666b666..f3f1de7 100644
--- a/qemu-option.h
+++ b/qemu-option.h
@@ -115,7 +115,7 @@
                   const char *name, const char *value);
 const char *qemu_opts_id(QemuOpts *opts);
 void qemu_opts_del(QemuOpts *opts);
-int qemu_opts_validate(QemuOpts *opts, QemuOptDesc *desc);
+int qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc);
 int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname);
 QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params, const char *firstname);
 
diff --git a/rwhandler.c b/rwhandler.c
new file mode 100644
index 0000000..1f9b6db
--- /dev/null
+++ b/rwhandler.c
@@ -0,0 +1,87 @@
+#include "rwhandler.h"
+#include "ioport.h"
+#include "cpu-all.h"
+
+#define RWHANDLER_WRITE(name, len, type) \
+static void name(void *opaque, type addr, uint32_t value) \
+{\
+    struct ReadWriteHandler *handler = opaque;\
+    handler->write(handler, addr, value, len);\
+}
+
+#define RWHANDLER_READ(name, len, type) \
+static uint32_t name(void *opaque, type addr) \
+{ \
+    struct ReadWriteHandler *handler = opaque; \
+    return handler->read(handler, addr, len); \
+}
+
+RWHANDLER_WRITE(cpu_io_memory_simple_writeb, 1, target_phys_addr_t);
+RWHANDLER_READ(cpu_io_memory_simple_readb, 1, target_phys_addr_t);
+RWHANDLER_WRITE(cpu_io_memory_simple_writew, 2, target_phys_addr_t);
+RWHANDLER_READ(cpu_io_memory_simple_readw, 2, target_phys_addr_t);
+RWHANDLER_WRITE(cpu_io_memory_simple_writel, 4, target_phys_addr_t);
+RWHANDLER_READ(cpu_io_memory_simple_readl, 4, target_phys_addr_t);
+
+static CPUWriteMemoryFunc * const cpu_io_memory_simple_write[] = {
+    &cpu_io_memory_simple_writeb,
+    &cpu_io_memory_simple_writew,
+    &cpu_io_memory_simple_writel,
+};
+
+static CPUReadMemoryFunc * const cpu_io_memory_simple_read[] = {
+    &cpu_io_memory_simple_readb,
+    &cpu_io_memory_simple_readw,
+    &cpu_io_memory_simple_readl,
+};
+
+int cpu_register_io_memory_simple(struct ReadWriteHandler *handler)
+{
+    if (!handler->read || !handler->write) {
+        return -1;
+    }
+    return cpu_register_io_memory(cpu_io_memory_simple_read,
+                                  cpu_io_memory_simple_write,
+                                  handler);
+}
+
+RWHANDLER_WRITE(ioport_simple_writeb, 1, uint32_t);
+RWHANDLER_READ(ioport_simple_readb, 1, uint32_t);
+RWHANDLER_WRITE(ioport_simple_writew, 2, uint32_t);
+RWHANDLER_READ(ioport_simple_readw, 2, uint32_t);
+RWHANDLER_WRITE(ioport_simple_writel, 4, uint32_t);
+RWHANDLER_READ(ioport_simple_readl, 4, uint32_t);
+
+int register_ioport_simple(ReadWriteHandler* handler,
+                           pio_addr_t start, int length, int size)
+{
+    IOPortWriteFunc *write;
+    IOPortReadFunc *read;
+    int r;
+    switch (size) {
+    case 1:
+        write = ioport_simple_writeb;
+        read = ioport_simple_readb;
+        break;
+    case 2:
+        write = ioport_simple_writew;
+        read = ioport_simple_readw;
+        break;
+    default:
+        write = ioport_simple_writel;
+        read = ioport_simple_readl;
+    }
+    if (handler->write) {
+        r = register_ioport_write(start, length, size, write, handler);
+        if (r < 0) {
+            return r;
+        }
+    }
+    if (handler->read) {
+        r = register_ioport_read(start, length, size, read, handler);
+        if (r < 0) {
+            return r;
+        }
+    }
+    return 0;
+}
diff --git a/rwhandler.h b/rwhandler.h
new file mode 100644
index 0000000..bc11849
--- /dev/null
+++ b/rwhandler.h
@@ -0,0 +1,27 @@
+#ifndef READ_WRITE_HANDLER_H
+#define READ_WRITE_HANDLER_H
+
+#include "qemu-common.h"
+#include "ioport.h"
+
+typedef struct ReadWriteHandler ReadWriteHandler;
+
+/* len is guaranteed to be one of 1, 2 or 4, addr is guaranteed to fit in an
+ * appropriate type (io/memory/etc). They do not need to be range checked. */
+typedef void WriteHandlerFunc(ReadWriteHandler *, pcibus_t addr,
+                              uint32_t value, int len);
+typedef uint32_t ReadHandlerFunc(ReadWriteHandler *, pcibus_t addr, int len);
+
+struct ReadWriteHandler {
+    WriteHandlerFunc *write;
+    ReadHandlerFunc *read;
+};
+
+/* Helpers for when we want to use a single routine with length. */
+/* CPU memory handler: both read and write must be present. */
+int cpu_register_io_memory_simple(ReadWriteHandler *);
+/* io port handler: can supply only read or write handlers. */
+int register_ioport_simple(ReadWriteHandler *,
+                           pio_addr_t start, int length, int size);
+
+#endif
diff --git a/sdl.c b/sdl.c
index cf27ad2..a9b4323 100644
--- a/sdl.c
+++ b/sdl.c
@@ -872,10 +872,6 @@
     da->resize_displaysurface = sdl_resize_displaysurface;
     da->free_displaysurface = sdl_free_displaysurface;
     if (register_displayallocator(ds, da) == da) {
-        DisplaySurface *surf;
-        surf = sdl_create_displaysurface(ds_get_width(ds), ds_get_height(ds));
-        defaultallocator_free_displaysurface(ds->surface);
-        ds->surface = surf;
         dpy_resize(ds);
     }
 
diff --git a/sysconfigs/target/target-x86_64.conf b/sysconfigs/target/target-x86_64.conf
new file mode 100644
index 0000000..43ad282
--- /dev/null
+++ b/sysconfigs/target/target-x86_64.conf
@@ -0,0 +1,86 @@
+# x86 CPU MODELS
+
+[cpudef]
+   name = "Conroe"
+   level = "2"
+   vendor = "GenuineIntel"
+   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"
+   extfeature_ecx = "lahf_lm"
+   xlevel = "0x8000000A"
+   model_id = "Intel Celeron_4x0 (Conroe/Merom Class Core 2)"
+
+[cpudef]
+   name = "Penryn"
+   level = "2"
+   vendor = "GenuineIntel"
+   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"
+   extfeature_ecx = "lahf_lm"
+   xlevel = "0x8000000A"
+   model_id = "Intel Core 2 Duo P9xxx (Penryn Class Core 2)"
+
+[cpudef]
+   name = "Nehalem"
+   level = "2"
+   vendor = "GenuineIntel"
+   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"
+   extfeature_ecx = "lahf_lm"
+   xlevel = "0x8000000A"
+   model_id = "Intel Core i7 9xx (Nehalem Class Core i7)"
+
+[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_ecx = "sse3"
+   extfeature_edx = "fxsr mmx pat cmov pge apic cx8 mce pae msr tsc pse de fpu    lm syscall nx"
+#   extfeature_ecx = ""
+   xlevel = "0x80000008"
+   model_id = "AMD Opteron 240 (Gen 1 Class Opteron)"
+
+[cpudef]
+   name = "Opteron_G2"
+   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_ecx = "sse3 cx16"
+   extfeature_edx = "fxsr mmx pat cmov pge apic cx8 mce pae msr tsc pse de fpu    lm syscall nx rdtscp"
+   extfeature_ecx = "svm lahf_lm"
+   xlevel = "0x80000008"
+   model_id = "AMD Opteron 22xx (Gen 2 Class Opteron)"
+
+[cpudef]
+   name = "Opteron_G3"
+   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_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"
+   xlevel = "0x80000008"
+   model_id = "AMD Opteron 23xx (Gen 3 Class Opteron)"
+
diff --git a/sysemu.h b/sysemu.h
index 9c3b281..8ba618e 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -213,11 +213,11 @@
 
 /* pci-hotplug */
 void pci_device_hot_add_print(Monitor *mon, const QObject *data);
-void pci_device_hot_add(Monitor *mon, const QDict *qdict, QObject **ret_data);
+int pci_device_hot_add(Monitor *mon, const QDict *qdict, QObject **ret_data);
 void drive_hot_add(Monitor *mon, const QDict *qdict);
-void pci_device_hot_remove(Monitor *mon, const char *pci_addr);
-void do_pci_device_hot_remove(Monitor *mon, const QDict *qdict,
-                              QObject **ret_data);
+int pci_device_hot_remove(Monitor *mon, const char *pci_addr);
+int do_pci_device_hot_remove(Monitor *mon, const QDict *qdict,
+                             QObject **ret_data);
 
 /* serial ports */
 
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 27001e8..6f40084 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -824,11 +824,10 @@
     env->spsr = cpsr_read(env);
     /* Clear IT bits.  */
     env->condexec_bits = 0;
-    /* Switch to the new mode, and switch to Arm mode.  */
-    /* ??? Thumb interrupt handlers not implemented.  */
+    /* Switch to the new mode, and to the correct instruction set.  */
     env->uncached_cpsr = (env->uncached_cpsr & ~CPSR_M) | new_mode;
     env->uncached_cpsr |= mask;
-    env->thumb = 0;
+    env->thumb = (env->cp15.c1_sys & (1 << 30)) != 0;
     env->regs[14] = env->regs[15] + offset;
     env->regs[15] = addr;
     env->interrupt_request |= CPU_INTERRUPT_EXITTB;
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 786c329..8b3b12d 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -8001,8 +8001,16 @@
                         gen_bx(s, tmp);
                         break;
                     case 5: /* Exception return.  */
-                        /* Unpredictable in user mode.  */
-                        goto illegal_op;
+                        if (IS_USER(s)) {
+                            goto illegal_op;
+                        }
+                        if (rn != 14 || rd != 15) {
+                            goto illegal_op;
+                        }
+                        tmp = load_reg(s, rn);
+                        tcg_gen_subi_i32(tmp, tmp, insn & 0xff);
+                        gen_exception_return(s, tmp);
+                        break;
                     case 6: /* mrs cpsr.  */
                         tmp = new_tmp();
                         if (IS_M(env)) {
@@ -8898,7 +8906,7 @@
                     shift = CPSR_A | CPSR_I | CPSR_F;
                 else
                     shift = 0;
-                gen_set_psr_im(s, shift, 0, ((insn & 7) << 6) & shift);
+                gen_set_psr_im(s, ((insn & 7) << 6), 0, shift);
             }
             break;
 
diff --git a/target-cris/translate_v10.c b/target-cris/translate_v10.c
index 9a29c51..9abf1a8 100644
--- a/target-cris/translate_v10.c
+++ b/target-cris/translate_v10.c
@@ -1187,6 +1187,10 @@
         dc->cpustate_changed = 1;
     }
 
+    /* CRISv10 locks out interrupts on dslots.  */
+    if (dc->delayed_branch == 2) {
+        cris_lock_irq(dc);
+    }
     return insn_len;
 }
 
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 216b00e..ef7d951 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -723,8 +723,10 @@
 CPUX86State *cpu_x86_init(const char *cpu_model);
 int cpu_x86_exec(CPUX86State *s);
 void cpu_x86_close(CPUX86State *s);
-void x86_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt,
-                                                 ...));
+void x86_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+                   const char *optarg);
+void x86_cpudef_setup(void);
+
 int cpu_get_pic_interrupt(CPUX86State *s);
 /* MSDOS compatibility mode FPU exception support */
 void cpu_set_ferr(CPUX86State *s);
@@ -876,7 +878,8 @@
 #define cpu_exec cpu_x86_exec
 #define cpu_gen_code cpu_x86_gen_code
 #define cpu_signal_handler cpu_x86_signal_handler
-#define cpu_list x86_cpu_list
+#define cpu_list_id x86_cpu_list
+#define cpudef_setup	x86_cpudef_setup
 
 #define CPU_SAVE_VERSION 11
 
diff --git a/target-i386/helper.c b/target-i386/helper.c
index 70762bb..7cda864 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -29,33 +29,52 @@
 #include "kvm.h"
 
 //#define DEBUG_MMU
+#include "qemu-option.h"
+#include "qemu-config.h"
 
 /* feature flags taken from "Intel Processor Identification and the CPUID
- * Instruction" and AMD's "CPUID Specification". In cases of disagreement
- * about feature names, the Linux name is used. */
+ * Instruction" and AMD's "CPUID Specification".  In cases of disagreement
+ * between feature naming conventions, aliases may be added.
+ */
 static const char *feature_name[] = {
-    "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
-    "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
-    "pat", "pse36", "pn" /* Intel psn */, "clflush" /* Intel clfsh */, NULL, "ds" /* Intel dts */, "acpi", "mmx",
-    "fxsr", "sse", "sse2", "ss", "ht" /* Intel htt */, "tm", "ia64", "pbe",
+    "fpu", "vme", "de", "pse",
+    "tsc", "msr", "pae", "mce",
+    "cx8", "apic", NULL, "sep",
+    "mtrr", "pge", "mca", "cmov",
+    "pat", "pse36", "pn" /* Intel psn */, "clflush" /* Intel clfsh */,
+    NULL, "ds" /* Intel dts */, "acpi", "mmx",
+    "fxsr", "sse", "sse2", "ss",
+    "ht" /* Intel htt */, "tm", "ia64", "pbe",
 };
 static const char *ext_feature_name[] = {
-    "pni" /* Intel,AMD sse3 */, NULL, NULL, "monitor", "ds_cpl", "vmx", NULL /* Linux smx */, "est",
-    "tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL,
-    NULL, NULL, "dca", NULL, NULL, NULL, NULL, "popcnt",
-    NULL, NULL, NULL, NULL, NULL, NULL, NULL, "hypervisor",
+    "pni|sse3" /* Intel,AMD sse3 */, NULL, NULL, "monitor",
+    "ds_cpl", "vmx", NULL /* Linux smx */, "est",
+    "tm2", "ssse3", "cid", NULL,
+    NULL, "cx16", "xtpr", NULL,
+    NULL, NULL, "dca", "sse4.1|sse4_1",
+    "sse4.2|sse4_2", "x2apic", NULL, "popcnt",
+    NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, "hypervisor",
 };
 static const char *ext2_feature_name[] = {
-    "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
-    "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",
+    "fpu", "vme", "de", "pse",
+    "tsc", "msr", "pae", "mce",
+    "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",
 };
 static const char *ext3_feature_name[] = {
-    "lahf_lm" /* AMD LahfSahf */, "cmp_legacy", "svm", "extapic" /* AMD ExtApicSpace */, "cr8legacy" /* AMD AltMovCr8 */, "abm", "sse4a", "misalignsse",
-    "3dnowprefetch", "osvw", NULL /* Linux ibs */, NULL, "skinit", "wdt", NULL, NULL,
-    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+    "lahf_lm" /* AMD LahfSahf */, "cmp_legacy", "svm", "extapic" /* AMD ExtApicSpace */,
+    "cr8legacy" /* AMD AltMovCr8 */, "abm", "sse4a", "misalignsse",
+    "3dnowprefetch", "osvw", NULL /* Linux ibs */, NULL,
+    "skinit", "wdt", NULL, NULL,
+    NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL,
 };
 
 static const char *kvm_feature_name[] = {
@@ -65,47 +84,99 @@
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 };
 
+/* collects per-function cpuid data
+ */
+typedef struct model_features_t {
+    uint32_t *guest_feat;
+    uint32_t *host_feat;
+    uint32_t check_feat;
+    const char **flag_names;
+    uint32_t cpuid;
+    } model_features_t;
+
+int check_cpuid = 0;
+int enforce_cpuid = 0;
+
+static void host_cpuid(uint32_t function, uint32_t count, uint32_t *eax,
+                       uint32_t *ebx, uint32_t *ecx, uint32_t *edx);
+
+#define iswhite(c) ((c) && ((c) <= ' ' || '~' < (c)))
+
+/* general substring compare of *[s1..e1) and *[s2..e2).  sx is start of
+ * a substring.  ex if !NULL points to the first char after a substring,
+ * otherwise the string is assumed to sized by a terminating nul.
+ * Return lexical ordering of *s1:*s2.
+ */
+static int sstrcmp(const char *s1, const char *e1, const char *s2,
+    const char *e2)
+{
+    for (;;) {
+        if (!*s1 || !*s2 || *s1 != *s2)
+            return (*s1 - *s2);
+        ++s1, ++s2;
+        if (s1 == e1 && s2 == e2)
+            return (0);
+        else if (s1 == e1)
+            return (*s2);
+        else if (s2 == e2)
+            return (*s1);
+    }
+}
+
+/* compare *[s..e) to *altstr.  *altstr may be a simple string or multiple
+ * '|' delimited (possibly empty) strings in which case search for a match
+ * within the alternatives proceeds left to right.  Return 0 for success,
+ * non-zero otherwise.
+ */
+static int altcmp(const char *s, const char *e, const char *altstr)
+{
+    const char *p, *q;
+
+    for (q = p = altstr; ; ) {
+        while (*p && *p != '|')
+            ++p;
+        if ((q == p && !*s) || (q != p && !sstrcmp(s, e, q, p)))
+            return (0);
+        if (!*p)
+            return (1);
+        else
+            q = ++p;
+    }
+}
+
+/* search featureset for flag *[s..e), if found set corresponding bit in
+ * *pval and return success, otherwise return zero
+ */
+static int lookup_feature(uint32_t *pval, const char *s, const char *e,
+    const char **featureset)
+{
+    uint32_t mask;
+    const char **ppc;
+
+    for (mask = 1, ppc = featureset; mask; mask <<= 1, ++ppc)
+        if (*ppc && !altcmp(s, e, *ppc)) {
+            *pval |= mask;
+            break;
+        }
+    return (mask ? 1 : 0);
+}
+
 static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features,
                                     uint32_t *ext_features,
                                     uint32_t *ext2_features,
                                     uint32_t *ext3_features,
                                     uint32_t *kvm_features)
 {
-    int i;
-    int found = 0;
-
-    for ( i = 0 ; i < 32 ; i++ )
-        if (feature_name[i] && !strcmp (flagname, feature_name[i])) {
-            *features |= 1 << i;
-            found = 1;
-        }
-    for ( i = 0 ; i < 32 ; i++ )
-        if (ext_feature_name[i] && !strcmp (flagname, ext_feature_name[i])) {
-            *ext_features |= 1 << i;
-            found = 1;
-        }
-    for ( i = 0 ; i < 32 ; i++ )
-        if (ext2_feature_name[i] && !strcmp (flagname, ext2_feature_name[i])) {
-            *ext2_features |= 1 << i;
-            found = 1;
-        }
-    for ( i = 0 ; i < 32 ; i++ )
-        if (ext3_feature_name[i] && !strcmp (flagname, ext3_feature_name[i])) {
-            *ext3_features |= 1 << i;
-            found = 1;
-        }
-    for ( i = 0 ; i < 32 ; i++ )
-        if (kvm_feature_name[i] && !strcmp (flagname, kvm_feature_name[i])) {
-            *kvm_features |= 1 << i;
-            found = 1;
-        }
-
-    if (!found) {
-        fprintf(stderr, "CPU feature %s not found\n", flagname);
-    }
+    if (!lookup_feature(features, flagname, NULL, feature_name) &&
+        !lookup_feature(ext_features, flagname, NULL, ext_feature_name) &&
+        !lookup_feature(ext2_features, flagname, NULL, ext2_feature_name) &&
+        !lookup_feature(ext3_features, flagname, NULL, ext3_feature_name) &&
+        !lookup_feature(kvm_features, flagname, NULL, kvm_feature_name))
+            fprintf(stderr, "CPU feature %s not found\n", flagname);
 }
 
 typedef struct x86_def_t {
+    struct x86_def_t *next;
     const char *name;
     uint32_t level;
     uint32_t vendor1, vendor2, vendor3;
@@ -116,6 +187,7 @@
     uint32_t xlevel;
     char model_id[48];
     int vendor_override;
+    uint32_t flags;
 } x86_def_t;
 
 #define I486_FEATURES (CPUID_FP87 | CPUID_VME | CPUID_PSE)
@@ -129,7 +201,14 @@
           CPUID_MSR | CPUID_MCE | CPUID_CX8 | CPUID_PGE | CPUID_CMOV | \
           CPUID_PAT | CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | \
           CPUID_PAE | CPUID_SEP | CPUID_APIC)
-static x86_def_t x86_defs[] = {
+
+/* maintains list of cpu model definitions
+ */
+static x86_def_t *x86_defs = {NULL};
+
+/* built-in cpu model definitions (deprecated)
+ */
+static x86_def_t builtin_x86_defs[] = {
 #ifdef TARGET_X86_64
     {
         .name = "qemu64",
@@ -334,9 +413,6 @@
     },
 };
 
-static void host_cpuid(uint32_t function, uint32_t count, uint32_t *eax,
-                               uint32_t *ebx, uint32_t *ecx, uint32_t *edx);
-
 static int cpu_x86_fill_model_id(char *str)
 {
     uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
@@ -382,6 +458,51 @@
     return 0;
 }
 
+static int unavailable_host_feature(struct model_features_t *f, uint32_t mask)
+{
+    int i;
+
+    for (i = 0; i < 32; ++i)
+        if (1 << i & mask) {
+            fprintf(stderr, "warning: host cpuid %04x_%04x lacks requested"
+                " flag '%s' [0x%08x]\n",
+                f->cpuid >> 16, f->cpuid & 0xffff,
+                f->flag_names[i] ? f->flag_names[i] : "[reserved]", mask);
+            break;
+        }
+    return 0;
+}
+
+/* best effort attempt to inform user requested cpu flags aren't making
+ * their way to the guest.  Note: ft[].check_feat ideally should be
+ * specified via a guest_def field to suppress report of extraneous flags.
+ */
+static int check_features_against_host(x86_def_t *guest_def)
+{
+    x86_def_t host_def;
+    uint32_t mask;
+    int rv, i;
+    struct model_features_t ft[] = {
+        {&guest_def->features, &host_def.features,
+            ~0, feature_name, 0x00000000},
+        {&guest_def->ext_features, &host_def.ext_features,
+            ~CPUID_EXT_HYPERVISOR, ext_feature_name, 0x00000001},
+        {&guest_def->ext2_features, &host_def.ext2_features,
+            ~PPRO_FEATURES, ext2_feature_name, 0x80000000},
+        {&guest_def->ext3_features, &host_def.ext3_features,
+            ~CPUID_EXT3_SVM, ext3_feature_name, 0x80000001}};
+
+    cpu_x86_fill_host(&host_def);
+    for (rv = 0, i = 0; i < sizeof (ft) / sizeof (ft[0]); ++i)
+        for (mask = 1; mask; mask <<= 1)
+            if (ft[i].check_feat & mask && *ft[i].guest_feat & mask &&
+                !(*ft[i].host_feat & mask)) {
+                    unavailable_host_feature(&ft[i], mask);
+                    rv = 1;
+                }
+    return rv;
+}
+
 static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
 {
     unsigned int i;
@@ -393,13 +514,9 @@
     uint32_t minus_features = 0, minus_ext_features = 0, minus_ext2_features = 0, minus_ext3_features = 0, minus_kvm_features = 0;
     uint32_t numvalue;
 
-    def = NULL;
-    for (i = 0; i < ARRAY_SIZE(x86_defs); i++) {
-        if (strcmp(name, x86_defs[i].name) == 0) {
-            def = &x86_defs[i];
+    for (def = x86_defs; def; def = def->next)
+        if (!strcmp(name, def->name))
             break;
-        }
-    }
     if (kvm_enabled() && strcmp(name, "host") == 0) {
         cpu_x86_fill_host(x86_cpu_def);
     } else if (!def) {
@@ -488,6 +605,10 @@
                 fprintf(stderr, "unrecognized feature %s\n", featurestr);
                 goto error;
             }
+        } else if (!strcmp(featurestr, "check")) {
+            check_cpuid = 1;
+        } else if (!strcmp(featurestr, "enforce")) {
+            check_cpuid = enforce_cpuid = 1;
         } else {
             fprintf(stderr, "feature string `%s' not in format (+feature|-feature|feature=xyz)\n", featurestr);
             goto error;
@@ -504,6 +625,10 @@
     x86_cpu_def->ext2_features &= ~minus_ext2_features;
     x86_cpu_def->ext3_features &= ~minus_ext3_features;
     x86_cpu_def->kvm_features &= ~minus_kvm_features;
+    if (check_cpuid) {
+        if (check_features_against_host(x86_cpu_def) && enforce_cpuid)
+            goto error;
+    }
     free(s);
     return 0;
 
@@ -512,12 +637,97 @@
     return -1;
 }
 
-void x86_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
+/* generate a composite string into buf of all cpuid names in featureset
+ * selected by fbits.  indicate truncation at bufsize in the event of overflow.
+ * if flags, suppress names undefined in featureset.
+ */
+static void listflags(char *buf, int bufsize, uint32_t fbits,
+    const char **featureset, uint32_t flags)
 {
-    unsigned int i;
+    const char **p = &featureset[31];
+    char *q, *b, bit;
+    int nc;
 
-    for (i = 0; i < ARRAY_SIZE(x86_defs); i++)
-        (*cpu_fprintf)(f, "x86 %16s\n", x86_defs[i].name);
+    b = 4 <= bufsize ? buf + (bufsize -= 3) - 1 : NULL;
+    *buf = '\0';
+    for (q = buf, bit = 31; fbits && bufsize; --p, fbits &= ~(1 << bit), --bit)
+        if (fbits & 1 << bit && (*p || !flags)) {
+            if (*p)
+                nc = snprintf(q, bufsize, "%s%s", q == buf ? "" : " ", *p);
+            else
+                nc = snprintf(q, bufsize, "%s[%d]", q == buf ? "" : " ", bit);
+            if (bufsize <= nc) {
+                if (b)
+                    sprintf(b, "...");
+                return;
+            }
+            q += nc;
+            bufsize -= nc;
+        }
+}
+
+/* generate CPU information:
+ * -?        list model names
+ * -?model   list model names/IDs
+ * -?dump    output all model (x86_def_t) data
+ * -?cpuid   list all recognized cpuid flag names
+ */ 
+void x86_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+                  const char *optarg)
+{
+    unsigned char model = !strcmp("?model", optarg);
+    unsigned char dump = !strcmp("?dump", optarg);
+    unsigned char cpuid = !strcmp("?cpuid", optarg);
+    x86_def_t *def;
+    char buf[256];
+
+    if (cpuid) {
+        (*cpu_fprintf)(f, "Recognized CPUID flags:\n");
+        listflags(buf, sizeof (buf), (uint32_t)~0, feature_name, 1);
+        (*cpu_fprintf)(f, "  f_edx: %s\n", buf);
+        listflags(buf, sizeof (buf), (uint32_t)~0, ext_feature_name, 1);
+        (*cpu_fprintf)(f, "  f_ecx: %s\n", buf);
+        listflags(buf, sizeof (buf), (uint32_t)~0, ext2_feature_name, 1);
+        (*cpu_fprintf)(f, "  extf_edx: %s\n", buf);
+        listflags(buf, sizeof (buf), (uint32_t)~0, ext3_feature_name, 1);
+        (*cpu_fprintf)(f, "  extf_ecx: %s\n", buf);
+        return;
+    }
+    for (def = x86_defs; def; def = def->next) {
+        snprintf(buf, sizeof (buf), def->flags ? "[%s]": "%s", def->name);
+        if (model || dump) {
+            (*cpu_fprintf)(f, "x86 %16s  %-48s\n", buf, def->model_id);
+        } else {
+            (*cpu_fprintf)(f, "x86 %16s\n", buf);
+        }
+        if (dump) {
+            memcpy(buf, &def->vendor1, sizeof (def->vendor1));
+            memcpy(buf + 4, &def->vendor2, sizeof (def->vendor2));
+            memcpy(buf + 8, &def->vendor3, sizeof (def->vendor3));
+            buf[12] = '\0';
+            (*cpu_fprintf)(f,
+                "  family %d model %d stepping %d level %d xlevel 0x%x"
+                " vendor \"%s\"\n",
+                def->family, def->model, def->stepping, def->level,
+                def->xlevel, buf);
+            listflags(buf, sizeof (buf), def->features, feature_name, 0);
+            (*cpu_fprintf)(f, "  feature_edx %08x (%s)\n", def->features,
+                buf);
+            listflags(buf, sizeof (buf), def->ext_features, ext_feature_name,
+                0);
+            (*cpu_fprintf)(f, "  feature_ecx %08x (%s)\n", def->ext_features,
+                buf);
+            listflags(buf, sizeof (buf), def->ext2_features, ext2_feature_name,
+                0);
+            (*cpu_fprintf)(f, "  extfeature_edx %08x (%s)\n",
+                def->ext2_features, buf);
+            listflags(buf, sizeof (buf), def->ext3_features, ext3_feature_name,
+                0);
+            (*cpu_fprintf)(f, "  extfeature_ecx %08x (%s)\n",
+                def->ext3_features, buf);
+            (*cpu_fprintf)(f, "\n");
+        }
+    }
 }
 
 static int cpu_x86_register (CPUX86State *env, const char *cpu_model)
@@ -566,6 +776,128 @@
     return 0;
 }
 
+#if !defined(CONFIG_LINUX_USER)
+/* copy vendor id string to 32 bit register, nul pad as needed
+ */
+static void cpyid(const char *s, uint32_t *id)
+{
+    char *d = (char *)id;
+    char i;
+
+    for (i = sizeof (*id); i--; )
+        *d++ = *s ? *s++ : '\0';
+}
+
+/* interpret radix and convert from string to arbitrary scalar,
+ * otherwise flag failure
+ */
+#define setscalar(pval, str, perr)                      \
+{                                                       \
+    char *pend;                                         \
+    unsigned long ul;                                   \
+                                                        \
+    ul = strtoul(str, &pend, 0);                        \
+    *str && !*pend ? (*pval = ul) : (*perr = 1);        \
+}
+
+/* map cpuid options to feature bits, otherwise return failure
+ * (option tags in *str are delimited by whitespace)
+ */
+static void setfeatures(uint32_t *pval, const char *str,
+    const char **featureset, int *perr)
+{
+    const char *p, *q;
+
+    for (q = p = str; *p || *q; q = p) {
+        while (iswhite(*p))
+            q = ++p; 
+        while (*p && !iswhite(*p))
+            ++p;
+        if (!*q && !*p)
+            return;
+        if (!lookup_feature(pval, q, p, featureset)) {
+            fprintf(stderr, "error: feature \"%.*s\" not available in set\n",
+                (int)(p - q), q);
+            *perr = 1;
+            return;
+        }
+    }
+}
+
+/* map config file options to x86_def_t form
+ */
+static int cpudef_setfield(const char *name, const char *str, void *opaque)
+{
+    x86_def_t *def = opaque;
+    int err = 0;
+
+    if (!strcmp(name, "name")) {
+        def->name = strdup(str);
+    } else if (!strcmp(name, "model_id")) {
+        strncpy(def->model_id, str, sizeof (def->model_id));
+    } else if (!strcmp(name, "level")) {
+        setscalar(&def->level, str, &err)
+    } else if (!strcmp(name, "vendor")) {
+        cpyid(&str[0], &def->vendor1);
+        cpyid(&str[4], &def->vendor2);
+        cpyid(&str[8], &def->vendor3);
+    } else if (!strcmp(name, "family")) {
+        setscalar(&def->family, str, &err)
+    } else if (!strcmp(name, "model")) {
+        setscalar(&def->model, str, &err)
+    } else if (!strcmp(name, "stepping")) {
+        setscalar(&def->stepping, str, &err)
+    } else if (!strcmp(name, "feature_edx")) {
+        setfeatures(&def->features, str, feature_name, &err);
+    } else if (!strcmp(name, "feature_ecx")) {
+        setfeatures(&def->ext_features, str, ext_feature_name, &err);
+    } else if (!strcmp(name, "extfeature_edx")) {
+        setfeatures(&def->ext2_features, str, ext2_feature_name, &err);
+    } else if (!strcmp(name, "extfeature_ecx")) {
+        setfeatures(&def->ext3_features, str, ext3_feature_name, &err);
+    } else if (!strcmp(name, "xlevel")) {
+        setscalar(&def->xlevel, str, &err)
+    } else {
+        fprintf(stderr, "error: unknown option [%s = %s]\n", name, str);
+        return (1);
+    }
+    if (err) {
+        fprintf(stderr, "error: bad option value [%s = %s]\n", name, str);
+        return (1);
+    }
+    return (0);
+}
+
+/* register config file entry as x86_def_t
+ */
+static int cpudef_register(QemuOpts *opts, void *opaque)
+{
+    x86_def_t *def = qemu_mallocz(sizeof (x86_def_t));
+
+    qemu_opt_foreach(opts, cpudef_setfield, def, 1);
+    def->next = x86_defs;
+    x86_defs = def;
+    return (0);
+}
+#endif	/* !CONFIG_LINUX_USER */
+
+/* register "cpudef" models defined in configuration file.  Here we first
+ * preload any built-in definitions
+ */
+void x86_cpudef_setup(void)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); ++i) {
+        builtin_x86_defs[i].next = x86_defs;
+        builtin_x86_defs[i].flags = 1;
+        x86_defs = &builtin_x86_defs[i];
+    }
+#if !defined(CONFIG_LINUX_USER)
+    qemu_opts_foreach(&qemu_cpudef_opts, cpudef_register, NULL, 0);
+#endif
+}
+
 /* NOTE: must be called outside the CPU execute loop */
 void cpu_reset(CPUX86State *env)
 {
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 5d9aecc..6b741ba 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -24,6 +24,7 @@
 #include "cpu.h"
 #include "gdbstub.h"
 #include "host-utils.h"
+#include "hw/pc.h"
 
 #ifdef CONFIG_KVM_PARA
 #include <linux/kvm_para.h>
@@ -359,6 +360,13 @@
      * as unavaible memory.  FIXME, need to ensure the e820 map deals with
      * this?
      */
+    /*
+     * Tell fw_cfg to notify the BIOS to reserve the range.
+     */
+    if (e820_add_entry(0xfffbc000, 0x4000, E820_RESERVED) < 0) {
+        perror("e820_add_entry() table is full");
+        exit(1);
+    }
     return kvm_vm_ioctl(s, KVM_SET_TSS_ADDR, 0xfffbd000);
 }
                     
diff --git a/target-m68k/exec.h b/target-m68k/exec.h
index 1267bb6..ece9aa0 100644
--- a/target-m68k/exec.h
+++ b/target-m68k/exec.h
@@ -20,10 +20,6 @@
 #include "dyngen-exec.h"
 
 register struct CPUM68KState *env asm(AREG0);
-/* This is only used for tb lookup.  */
-register uint32_t T0 asm(AREG1);
-/* ??? We don't use T1, but common code expects it to exist  */
-#define T1 env->t1
 
 #include "cpu.h"
 #include "exec-all.h"
diff --git a/target-microblaze/op_helper.c b/target-microblaze/op_helper.c
index af89dcf..8a9cea2 100644
--- a/target-microblaze/op_helper.c
+++ b/target-microblaze/op_helper.c
@@ -251,6 +251,12 @@
                           int is_asi, int size)
 {
     CPUState *saved_env;
+
+    if (!cpu_single_env) {
+        /* XXX: ???   */
+        return;
+    }
+
     /* XXX: hack to restore env in all cases, even if not called from
        generated code */
     saved_env = env;
diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c
index 583f09d..ca54e2c 100644
--- a/target-microblaze/translate.c
+++ b/target-microblaze/translate.c
@@ -993,6 +993,7 @@
 static void dec_br(DisasContext *dc)
 {
     unsigned int dslot, link, abs;
+    int mem_index = cpu_mmu_index(dc->env);
 
     dslot = dc->ir & (1 << 20);
     abs = dc->ir & (1 << 19);
@@ -1016,11 +1017,19 @@
     if (abs) {
         tcg_gen_movi_tl(env_btaken, 1);
         tcg_gen_mov_tl(env_btarget, *(dec_alu_op_b(dc)));
-        if (link && !(dc->tb_flags & IMM_FLAG)
-            && (dc->imm == 8 || dc->imm == 0x18))
-            t_gen_raise_exception(dc, EXCP_BREAK);
-        if (dc->imm == 0)
-            t_gen_raise_exception(dc, EXCP_DEBUG);
+        if (link && !dslot) {
+            if (!(dc->tb_flags & IMM_FLAG) && (dc->imm == 8 || dc->imm == 0x18))
+                t_gen_raise_exception(dc, EXCP_BREAK);
+            if (dc->imm == 0) {
+                if ((dc->tb_flags & MSR_EE_FLAG) && mem_index == MMU_USER_IDX) {
+                    tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
+                    t_gen_raise_exception(dc, EXCP_HW_EXCP);
+                    return;
+                }
+
+                t_gen_raise_exception(dc, EXCP_DEBUG);
+            }
+        }
     } else {
         if (!dc->type_b || (dc->tb_flags & IMM_FLAG)) {
             tcg_gen_movi_tl(env_btaken, 1);
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index a4fae31..cd1c9fe 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -736,14 +736,13 @@
                     PRIx32 "\n", __func__, n, slb->tmp64, slb->tmp);
         if (slb_is_valid(slb)) {
             /* SLB entry is valid */
+            mask = 0xFFFFFFFFF0000000ULL;
             if (slb->tmp & 0x8) {
-                /* 1 TB Segment */
-                mask = 0xFFFF000000000000ULL;
+                /* 16 MB PTEs */
                 if (target_page_bits)
-                    *target_page_bits = 24; // XXX 16M pages?
+                    *target_page_bits = 24;
             } else {
-                /* 256MB Segment */
-                mask = 0xFFFFFFFFF0000000ULL;
+                /* 4 KB PTEs */
                 if (target_page_bits)
                     *target_page_bits = TARGET_PAGE_BITS;
             }
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index 0424a78..8ad0037 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -37,6 +37,22 @@
     do { } while (0)
 #endif
 
+/* XXX For some odd reason we sometimes hang inside KVM forever. I'd guess it's
+ *     a race condition where we actually have a level triggered interrupt, but
+ *     the infrastructure can't expose that yet, so the guest ACKs it, goes to
+ *     sleep and never gets notified that there's still an interrupt pending.
+ *
+ *     As a quick workaround, let's just wake up every 500 ms. That way we can
+ *     assure that we're always reinjecting interrupts in time.
+ */
+static QEMUTimer *idle_timer;
+
+static void do_nothing(void *opaque)
+{
+    qemu_mod_timer(idle_timer, qemu_get_clock(vm_clock) +
+                   (get_ticks_per_sec() / 2));
+}
+
 int kvm_arch_init(KVMState *s, int smp_cpus)
 {
     return 0;
@@ -173,6 +189,12 @@
     int r;
     unsigned irq;
 
+    if (!idle_timer) {
+        idle_timer = qemu_new_timer(vm_clock, do_nothing, NULL);
+        qemu_mod_timer(idle_timer, qemu_get_clock(vm_clock) +
+                       (get_ticks_per_sec() / 2));
+    }
+
     /* PowerPC Qemu tracks the various core input pins (interrupt, critical
      * interrupt, reset, etc) in PPC-specific env->irq_input_state. */
     if (run->ready_for_interrupt_injection &&
@@ -252,3 +274,50 @@
     return ret;
 }
 
+static int read_cpuinfo(const char *field, char *value, int len)
+{
+    FILE *f;
+    int ret = -1;
+    int field_len = strlen(field);
+    char line[512];
+
+    f = fopen("/proc/cpuinfo", "r");
+    if (!f) {
+        return -1;
+    }
+
+    do {
+        if(!fgets(line, sizeof(line), f)) {
+            break;
+        }
+        if (!strncmp(line, field, field_len)) {
+            strncpy(value, line, len);
+            ret = 0;
+            break;
+        }
+    } while(*line);
+
+    fclose(f);
+
+    return ret;
+}
+
+uint32_t kvmppc_get_tbfreq(void)
+{
+    char line[512];
+    char *ns;
+    uint32_t retval = get_ticks_per_sec();
+
+    if (read_cpuinfo("timebase", line, sizeof(line))) {
+        return retval;
+    }
+
+    if (!(ns = strchr(line, ':'))) {
+        return retval;
+    }
+
+    ns++;
+
+    retval = atoi(ns);
+    return retval;
+}
diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h
index 3792ef7..e8d66e8 100644
--- a/target-ppc/kvm_ppc.h
+++ b/target-ppc/kvm_ppc.h
@@ -14,4 +14,6 @@
 int kvmppc_read_host_property(const char *node_path, const char *prop,
                                      void *val, size_t len);
 
+uint32_t kvmppc_get_tbfreq(void);
+
 #endif /* __KVM_PPC_H__ */
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 7e9f0cf..b7d2a32 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -1663,27 +1663,27 @@
 #ifdef TARGET_SPARC64
 static inline void gen_load_trap_state_at_tl(TCGv_ptr r_tsptr, TCGv_ptr cpu_env)
 {
-    TCGv r_tl = tcg_temp_new();
+    TCGv_i32 r_tl = tcg_temp_new_i32();
 
     /* load env->tl into r_tl */
-    {
-        TCGv_i32 r_tl_tmp = tcg_temp_new_i32();
-        tcg_gen_ld_i32(r_tl_tmp, cpu_env, offsetof(CPUSPARCState, tl));
-        tcg_gen_ext_i32_tl(r_tl, r_tl_tmp);
-        tcg_temp_free_i32(r_tl_tmp);
-    }
+    tcg_gen_ld_i32(r_tl, cpu_env, offsetof(CPUSPARCState, tl));
 
     /* tl = [0 ... MAXTL_MASK] where MAXTL_MASK must be power of 2 */
-    tcg_gen_andi_tl(r_tl, r_tl, MAXTL_MASK);
+    tcg_gen_andi_i32(r_tl, r_tl, MAXTL_MASK);
 
     /* calculate offset to current trap state from env->ts, reuse r_tl */
-    tcg_gen_muli_tl(r_tl, r_tl, sizeof (trap_state));
+    tcg_gen_muli_i32(r_tl, r_tl, sizeof (trap_state));
     tcg_gen_addi_ptr(r_tsptr, cpu_env, offsetof(CPUState, ts));
 
     /* tsptr = env->ts[env->tl & MAXTL_MASK] */
-    tcg_gen_add_ptr(r_tsptr, r_tsptr, r_tl);
+    {
+        TCGv_ptr r_tl_tmp = tcg_temp_new_ptr();
+        tcg_gen_ext_i32_ptr(r_tl_tmp, r_tl);
+        tcg_gen_add_ptr(r_tsptr, r_tsptr, r_tl_tmp);
+        tcg_temp_free_i32(r_tl_tmp);
+    }
 
-    tcg_temp_free(r_tl);
+    tcg_temp_free_i32(r_tl);
 }
 #endif
 
diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h
index 71e1ec5..5eac7bf 100644
--- a/tcg/arm/tcg-target.h
+++ b/tcg/arm/tcg-target.h
@@ -63,6 +63,20 @@
 #define TCG_TARGET_STACK_ALIGN		8
 #define TCG_TARGET_CALL_STACK_OFFSET	0
 
+/* optional instructions */
+// #define TCG_TARGET_HAS_div_i32
+// #define TCG_TARGET_HAS_rot_i32
+// #define TCG_TARGET_HAS_ext8s_i32
+// #define TCG_TARGET_HAS_ext16s_i32
+// #define TCG_TARGET_HAS_ext8u_i32
+// #define TCG_TARGET_HAS_ext16u_i32
+// #define TCG_TARGET_HAS_bswap16_i32
+// #define TCG_TARGET_HAS_bswap32_i32
+// #define TCG_TARGET_HAS_not_i32
+// #define TCG_TARGET_HAS_neg_i32
+// #define TCG_TARGET_HAS_andc_i32
+// #define TCG_TARGET_HAS_orc_i32
+
 #define TCG_TARGET_HAS_GUEST_BASE
 
 enum {
diff --git a/tcg/hppa/tcg-target.c b/tcg/hppa/tcg-target.c
index ddce60c..4677971 100644
--- a/tcg/hppa/tcg-target.c
+++ b/tcg/hppa/tcg-target.c
@@ -936,7 +936,6 @@
     { INDEX_op_qemu_ld16u, { "r", "L", "L" } },
     { INDEX_op_qemu_ld16s, { "r", "L", "L" } },
     { INDEX_op_qemu_ld32u, { "r", "L", "L" } },
-    { INDEX_op_qemu_ld32s, { "r", "L", "L" } },
     { INDEX_op_qemu_ld64, { "r", "r", "L", "L" } },
 
     { INDEX_op_qemu_st8, { "L", "L", "L" } },
diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h
index 69227c3..f97034c 100644
--- a/tcg/i386/tcg-target.h
+++ b/tcg/i386/tcg-target.h
@@ -45,15 +45,17 @@
 #define TCG_TARGET_CALL_STACK_OFFSET 0
 
 /* optional instructions */
+#define TCG_TARGET_HAS_rot_i32
+#define TCG_TARGET_HAS_ext8s_i32
+#define TCG_TARGET_HAS_ext16s_i32
+#define TCG_TARGET_HAS_ext8u_i32
+#define TCG_TARGET_HAS_ext16u_i32
 #define TCG_TARGET_HAS_bswap16_i32
 #define TCG_TARGET_HAS_bswap32_i32
 #define TCG_TARGET_HAS_neg_i32
 #define TCG_TARGET_HAS_not_i32
-#define TCG_TARGET_HAS_ext8s_i32
-#define TCG_TARGET_HAS_ext16s_i32
-#define TCG_TARGET_HAS_rot_i32
-#define TCG_TARGET_HAS_ext8u_i32
-#define TCG_TARGET_HAS_ext16u_i32
+// #define TCG_TARGET_HAS_andc_i32
+// #define TCG_TARGET_HAS_orc_i32
 
 #define TCG_TARGET_HAS_GUEST_BASE
 
diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h
index 46760a5..377b0c8 100644
--- a/tcg/mips/tcg-target.h
+++ b/tcg/mips/tcg-target.h
@@ -80,11 +80,13 @@
 /* optional instructions */
 #define TCG_TARGET_HAS_div_i32
 #define TCG_TARGET_HAS_not_i32
+#undef TCG_TARGET_HAS_rot_i32
 #undef TCG_TARGET_HAS_ext8s_i32
 #undef TCG_TARGET_HAS_ext16s_i32
 #undef TCG_TARGET_HAS_bswap32_i32
 #undef TCG_TARGET_HAS_bswap16_i32
-#undef TCG_TARGET_HAS_rot_i32
+#undef TCG_TARGET_HAS_andc_i32
+#undef TCG_TARGET_HAS_orc_i32
 
 /* optional instructions automatically implemented */
 #undef TCG_TARGET_HAS_neg_i32      /* sub  rd, zero, rt   */
diff --git a/tcg/ppc/tcg-target.c b/tcg/ppc/tcg-target.c
index 502df87..96cc461 100644
--- a/tcg/ppc/tcg-target.c
+++ b/tcg/ppc/tcg-target.c
@@ -24,10 +24,10 @@
 
 static uint8_t *tb_ret_addr;
 
-#ifdef __APPLE__
+#ifdef _CALL_DARWIN
 #define LINKAGE_AREA_SIZE 24
 #define LR_OFFSET 8
-#elif defined _AIX
+#elif defined _CALL_AIX
 #define LINKAGE_AREA_SIZE 52
 #define LR_OFFSET 8
 #else
@@ -104,7 +104,7 @@
     TCG_REG_R29,
     TCG_REG_R30,
     TCG_REG_R31,
-#ifdef __APPLE__
+#ifdef _CALL_DARWIN
     TCG_REG_R2,
 #endif
     TCG_REG_R3,
@@ -115,11 +115,11 @@
     TCG_REG_R8,
     TCG_REG_R9,
     TCG_REG_R10,
-#ifndef __APPLE__
+#ifndef _CALL_DARWIN
     TCG_REG_R11,
 #endif
     TCG_REG_R12,
-#ifndef __linux__
+#ifndef _CALL_SYSV
     TCG_REG_R13,
 #endif
     TCG_REG_R24,
@@ -145,11 +145,11 @@
 };
 
 static const int tcg_target_callee_save_regs[] = {
-#ifdef __APPLE__
+#ifdef _CALL_DARWIN
     TCG_REG_R11,
     TCG_REG_R13,
 #endif
-#ifdef _AIX
+#ifdef _CALL_AIX
     TCG_REG_R13,
 #endif
     TCG_REG_R14,
@@ -333,6 +333,7 @@
 #define STWU   OPCD(37)
 
 #define RLWINM OPCD(21)
+#define RLWNM  OPCD(23)
 
 #define BCLR   XO19( 16)
 #define BCCTR  XO19(528)
@@ -369,6 +370,9 @@
 #define NEG    XO31(104)
 #define MFCR   XO31( 19)
 #define CNTLZW XO31( 26)
+#define NOR    XO31(124)
+#define ANDC   XO31( 60)
+#define ORC    XO31(412)
 
 #define LBZX   XO31( 87)
 #define LHZX   XO31(279)
@@ -478,7 +482,7 @@
 
 static void tcg_out_call (TCGContext *s, tcg_target_long arg, int const_arg)
 {
-#ifdef _AIX
+#ifdef _CALL_AIX
     int reg;
 
     if (const_arg) {
@@ -908,7 +912,7 @@
         ;
     frame_size = (frame_size + 15) & ~15;
 
-#ifdef _AIX
+#ifdef _CALL_AIX
     {
         uint32_t addr;
 
@@ -1468,6 +1472,12 @@
         else
             tcg_out32 (s, XOR | SAB (args[1], args[0], args[2]));
         break;
+    case INDEX_op_andc_i32:
+        tcg_out32 (s, ANDC | SAB (args[1], args[0], args[2]));
+        break;
+    case INDEX_op_orc_i32:
+        tcg_out32 (s, ORC | SAB (args[1], args[0], args[2]));
+        break;
 
     case INDEX_op_mul_i32:
         if (const_args[2]) {
@@ -1549,6 +1559,45 @@
         else
             tcg_out32 (s, SRAW | SAB (args[1], args[0], args[2]));
         break;
+    case INDEX_op_rotl_i32:
+        {
+            int op = 0
+                | RA (args[0])
+                | RS (args[1])
+                | MB (0)
+                | ME (31)
+                | (const_args[2] ? RLWINM | SH (args[2])
+                                 : RLWNM | RB (args[2]))
+                ;
+            tcg_out32 (s, op);
+        }
+        break;
+    case INDEX_op_rotr_i32:
+        if (const_args[2]) {
+            if (!args[2]) {
+                tcg_out_mov (s, args[0], args[1]);
+            }
+            else {
+                tcg_out32 (s, RLWINM
+                           | RA (args[0])
+                           | RS (args[1])
+                           | SH (32 - args[2])
+                           | MB (0)
+                           | ME (31)
+                    );
+            }
+        }
+        else {
+            tcg_out32 (s, ADDI | RT (0) | RA (args[2]) | 0xffe0);
+            tcg_out32 (s, RLWNM
+                       | RA (args[0])
+                       | RS (args[1])
+                       | RB (0)
+                       | MB (0)
+                       | ME (31)
+                );
+        }
+        break;
 
     case INDEX_op_add2_i32:
         if (args[0] == args[3] || args[0] == args[5]) {
@@ -1591,6 +1640,10 @@
         tcg_out32 (s, NEG | RT (args[0]) | RA (args[1]));
         break;
 
+    case INDEX_op_not_i32:
+        tcg_out32 (s, NOR | SAB (args[1], args[0], args[0]));
+        break;
+
     case INDEX_op_qemu_ld8u:
         tcg_out_qemu_ld(s, args, 0);
         break;
@@ -1625,9 +1678,27 @@
     case INDEX_op_ext8s_i32:
         tcg_out32 (s, EXTSB | RS (args[1]) | RA (args[0]));
         break;
+    case INDEX_op_ext8u_i32:
+        tcg_out32 (s, RLWINM
+                   | RA (args[0])
+                   | RS (args[1])
+                   | SH (0)
+                   | MB (24)
+                   | ME (31)
+            );
+        break;
     case INDEX_op_ext16s_i32:
         tcg_out32 (s, EXTSH | RS (args[1]) | RA (args[0]));
         break;
+    case INDEX_op_ext16u_i32:
+        tcg_out32 (s, RLWINM
+                   | RA (args[0])
+                   | RS (args[1])
+                   | SH (0)
+                   | MB (16)
+                   | ME (31)
+            );
+        break;
 
     case INDEX_op_setcond_i32:
         tcg_out_setcond (s, args[3], args[0], args[1], args[2], const_args[2]);
@@ -1676,6 +1747,9 @@
     { INDEX_op_shr_i32, { "r", "r", "ri" } },
     { INDEX_op_sar_i32, { "r", "r", "ri" } },
 
+    { INDEX_op_rotl_i32, { "r", "r", "ri" } },
+    { INDEX_op_rotr_i32, { "r", "r", "ri" } },
+
     { INDEX_op_brcond_i32, { "r", "ri" } },
 
     { INDEX_op_add2_i32, { "r", "r", "r", "r", "r", "r" } },
@@ -1683,6 +1757,10 @@
     { INDEX_op_brcond2_i32, { "r", "r", "r", "r" } },
 
     { INDEX_op_neg_i32, { "r", "r" } },
+    { INDEX_op_not_i32, { "r", "r" } },
+
+    { INDEX_op_andc_i32, { "r", "r", "r" } },
+    { INDEX_op_orc_i32, { "r", "r", "r" } },
 
     { INDEX_op_setcond_i32, { "r", "r", "ri" } },
     { INDEX_op_setcond2_i32, { "r", "r", "r", "ri", "ri" } },
@@ -1693,7 +1771,6 @@
     { INDEX_op_qemu_ld16u, { "r", "L" } },
     { INDEX_op_qemu_ld16s, { "r", "L" } },
     { INDEX_op_qemu_ld32u, { "r", "L" } },
-    { INDEX_op_qemu_ld32s, { "r", "L" } },
     { INDEX_op_qemu_ld64, { "r", "r", "L" } },
 
     { INDEX_op_qemu_st8, { "K", "K" } },
@@ -1706,7 +1783,6 @@
     { INDEX_op_qemu_ld16u, { "r", "L", "L" } },
     { INDEX_op_qemu_ld16s, { "r", "L", "L" } },
     { INDEX_op_qemu_ld32u, { "r", "L", "L" } },
-    { INDEX_op_qemu_ld32s, { "r", "L", "L" } },
     { INDEX_op_qemu_ld64, { "r", "L", "L", "L" } },
 
     { INDEX_op_qemu_st8, { "K", "K", "K" } },
@@ -1716,7 +1792,9 @@
 #endif
 
     { INDEX_op_ext8s_i32, { "r", "r" } },
+    { INDEX_op_ext8u_i32, { "r", "r" } },
     { INDEX_op_ext16s_i32, { "r", "r" } },
+    { INDEX_op_ext16u_i32, { "r", "r" } },
 
     { -1 },
 };
@@ -1726,7 +1804,7 @@
     tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff);
     tcg_regset_set32(tcg_target_call_clobber_regs, 0,
                      (1 << TCG_REG_R0) |
-#ifdef __APPLE__
+#ifdef _CALL_DARWIN
                      (1 << TCG_REG_R2) |
 #endif
                      (1 << TCG_REG_R3) |
@@ -1744,10 +1822,10 @@
     tcg_regset_clear(s->reserved_regs);
     tcg_regset_set_reg(s->reserved_regs, TCG_REG_R0);
     tcg_regset_set_reg(s->reserved_regs, TCG_REG_R1);
-#ifndef __APPLE__
+#ifndef _CALL_DARWIN
     tcg_regset_set_reg(s->reserved_regs, TCG_REG_R2);
 #endif
-#ifdef __linux__
+#ifdef _CALL_SYSV
     tcg_regset_set_reg(s->reserved_regs, TCG_REG_R13);
 #endif
 #ifdef CONFIG_USE_GUEST_BASE
diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h
index 0197e79..0c71a11 100644
--- a/tcg/ppc/tcg-target.h
+++ b/tcg/ppc/tcg-target.h
@@ -65,11 +65,11 @@
 /* used for function call generation */
 #define TCG_REG_CALL_STACK TCG_REG_R1
 #define TCG_TARGET_STACK_ALIGN 16
-#if defined __APPLE__
+#if defined _CALL_DARWIN
 #define TCG_TARGET_CALL_STACK_OFFSET 24
-#elif defined _AIX
+#elif defined _CALL_AIX
 #define TCG_TARGET_CALL_STACK_OFFSET 52
-#elif defined __linux__
+#elif defined _CALL_SYSV
 #define TCG_TARGET_CALL_ALIGN_ARGS 1
 #define TCG_TARGET_CALL_STACK_OFFSET 8
 #else
@@ -77,10 +77,18 @@
 #endif
 
 /* optional instructions */
-#define TCG_TARGET_HAS_neg_i32
 #define TCG_TARGET_HAS_div_i32
+#define TCG_TARGET_HAS_rot_i32
 #define TCG_TARGET_HAS_ext8s_i32
 #define TCG_TARGET_HAS_ext16s_i32
+#define TCG_TARGET_HAS_ext8u_i32
+#define TCG_TARGET_HAS_ext16u_i32
+/* #define TCG_TARGET_HAS_bswap16_i32 */
+/* #define TCG_TARGET_HAS_bswap32_i32 */
+#define TCG_TARGET_HAS_not_i32
+#define TCG_TARGET_HAS_neg_i32
+#define TCG_TARGET_HAS_andc_i32
+#define TCG_TARGET_HAS_orc_i32
 
 #define TCG_AREG0 TCG_REG_R27
 #define TCG_AREG1 TCG_REG_R24
diff --git a/tcg/ppc64/tcg-target.h b/tcg/ppc64/tcg-target.h
index 94b800f..f5de642 100644
--- a/tcg/ppc64/tcg-target.h
+++ b/tcg/ppc64/tcg-target.h
@@ -68,15 +68,34 @@
 #define TCG_TARGET_CALL_STACK_OFFSET 48
 
 /* optional instructions */
-#define TCG_TARGET_HAS_neg_i32
 #define TCG_TARGET_HAS_div_i32
-#define TCG_TARGET_HAS_neg_i64
-#define TCG_TARGET_HAS_div_i64
+/* #define TCG_TARGET_HAS_rot_i32 */
 #define TCG_TARGET_HAS_ext8s_i32
 #define TCG_TARGET_HAS_ext16s_i32
+/* #define TCG_TARGET_HAS_ext8u_i32 */
+/* #define TCG_TARGET_HAS_ext16u_i32 */
+/* #define TCG_TARGET_HAS_bswap16_i32 */
+/* #define TCG_TARGET_HAS_bswap32_i32 */
+/* #define TCG_TARGET_HAS_not_i32 */
+#define TCG_TARGET_HAS_neg_i32
+/* #define TCG_TARGET_HAS_andc_i32 */
+/* #define TCG_TARGET_HAS_orc_i32 */
+
+#define TCG_TARGET_HAS_div_i64
+/* #define TCG_TARGET_HAS_rot_i64 */
 #define TCG_TARGET_HAS_ext8s_i64
 #define TCG_TARGET_HAS_ext16s_i64
 #define TCG_TARGET_HAS_ext32s_i64
+/* #define TCG_TARGET_HAS_ext8u_i64 */
+/* #define TCG_TARGET_HAS_ext16u_i64 */
+/* #define TCG_TARGET_HAS_ext32u_i64 */
+/* #define TCG_TARGET_HAS_bswap16_i64 */
+/* #define TCG_TARGET_HAS_bswap32_i64 */
+/* #define TCG_TARGET_HAS_bswap64_i64 */
+/* #define TCG_TARGET_HAS_not_i64 */
+#define TCG_TARGET_HAS_neg_i64
+/* #define TCG_TARGET_HAS_andc_i64 */
+/* #define TCG_TARGET_HAS_orc_i64 */
 
 #define TCG_AREG0 TCG_REG_R27
 #define TCG_AREG1 TCG_REG_R24
diff --git a/tcg/s390/tcg-target.h b/tcg/s390/tcg-target.h
index 91b931d..e803401 100644
--- a/tcg/s390/tcg-target.h
+++ b/tcg/s390/tcg-target.h
@@ -46,6 +46,36 @@
 };
 #define TCG_TARGET_NB_REGS 16
 
+/* optional instructions */
+// #define TCG_TARGET_HAS_div_i32
+// #define TCG_TARGET_HAS_rot_i32
+// #define TCG_TARGET_HAS_ext8s_i32
+// #define TCG_TARGET_HAS_ext16s_i32
+// #define TCG_TARGET_HAS_ext8u_i32
+// #define TCG_TARGET_HAS_ext16u_i32
+// #define TCG_TARGET_HAS_bswap16_i32
+// #define TCG_TARGET_HAS_bswap32_i32
+// #define TCG_TARGET_HAS_not_i32
+// #define TCG_TARGET_HAS_neg_i32
+// #define TCG_TARGET_HAS_andc_i32
+// #define TCG_TARGET_HAS_orc_i32
+
+// #define TCG_TARGET_HAS_div_i64
+// #define TCG_TARGET_HAS_rot_i64
+// #define TCG_TARGET_HAS_ext8s_i64
+// #define TCG_TARGET_HAS_ext16s_i64
+// #define TCG_TARGET_HAS_ext32s_i64
+// #define TCG_TARGET_HAS_ext8u_i64
+// #define TCG_TARGET_HAS_ext16u_i64
+// #define TCG_TARGET_HAS_ext32u_i64
+// #define TCG_TARGET_HAS_bswap16_i64
+// #define TCG_TARGET_HAS_bswap32_i64
+// #define TCG_TARGET_HAS_bswap64_i64
+// #define TCG_TARGET_HAS_not_i64
+// #define TCG_TARGET_HAS_neg_i64
+// #define TCG_TARGET_HAS_andc_i64
+// #define TCG_TARGET_HAS_orc_i64
+
 /* used for function call generation */
 #define TCG_REG_CALL_STACK		TCG_REG_R15
 #define TCG_TARGET_STACK_ALIGN		8
diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c
index dd7a598..d4ddaa7 100644
--- a/tcg/sparc/tcg-target.c
+++ b/tcg/sparc/tcg-target.c
@@ -194,6 +194,7 @@
 #define INSN_RS2(x) (x)
 #define INSN_ASI(x) ((x) << 5)
 
+#define INSN_IMM11(x) ((1 << 13) | ((x) & 0x7ff))
 #define INSN_IMM13(x) ((1 << 13) | ((x) & 0x1fff))
 #define INSN_OFF19(x) (((x) >> 2) & 0x07ffff)
 #define INSN_OFF22(x) (((x) >> 2) & 0x3fffff)
@@ -217,11 +218,16 @@
 #define COND_VC    0xf
 #define BA         (INSN_OP(0) | INSN_COND(COND_A, 0) | INSN_OP2(0x2))
 
+#define MOVCC_ICC  (1 << 18)
+#define MOVCC_XCC  (1 << 18 | 1 << 12)
+
 #define ARITH_ADD  (INSN_OP(2) | INSN_OP3(0x00))
 #define ARITH_ADDCC (INSN_OP(2) | INSN_OP3(0x10))
 #define ARITH_AND  (INSN_OP(2) | INSN_OP3(0x01))
+#define ARITH_ANDN (INSN_OP(2) | INSN_OP3(0x05))
 #define ARITH_OR   (INSN_OP(2) | INSN_OP3(0x02))
 #define ARITH_ORCC (INSN_OP(2) | INSN_OP3(0x12))
+#define ARITH_ORN  (INSN_OP(2) | INSN_OP3(0x06))
 #define ARITH_XOR  (INSN_OP(2) | INSN_OP3(0x03))
 #define ARITH_SUB  (INSN_OP(2) | INSN_OP3(0x04))
 #define ARITH_SUBCC (INSN_OP(2) | INSN_OP3(0x14))
@@ -233,6 +239,7 @@
 #define ARITH_MULX (INSN_OP(2) | INSN_OP3(0x09))
 #define ARITH_UDIVX (INSN_OP(2) | INSN_OP3(0x0d))
 #define ARITH_SDIVX (INSN_OP(2) | INSN_OP3(0x2d))
+#define ARITH_MOVCC (INSN_OP(2) | INSN_OP3(0x2c))
 
 #define SHIFT_SLL  (INSN_OP(2) | INSN_OP3(0x25))
 #define SHIFT_SRL  (INSN_OP(2) | INSN_OP3(0x26))
@@ -580,6 +587,109 @@
 }
 #endif
 
+static void tcg_out_setcond_i32(TCGContext *s, int cond, TCGArg ret,
+                                TCGArg c1, TCGArg c2, int c2const)
+{
+    TCGArg t;
+
+    /* For 32-bit comparisons, we can play games with ADDX/SUBX.  */
+    switch (cond) {
+    case TCG_COND_EQ:
+    case TCG_COND_NE:
+        if (c2 != 0) {
+            tcg_out_arithc(s, ret, c1, c2, c2const, ARITH_XOR);
+        }
+        c1 = TCG_REG_G0, c2 = ret, c2const = 0;
+        cond = (cond == TCG_COND_EQ ? TCG_COND_LEU : TCG_COND_LTU);
+	break;
+
+    case TCG_COND_GTU:
+    case TCG_COND_GEU:
+        if (c2const && c2 != 0) {
+            tcg_out_movi_imm13(s, TCG_REG_I5, c2);
+            c2 = TCG_REG_I5;
+        }
+        t = c1, c1 = c2, c2 = t, c2const = 0;
+        cond = tcg_swap_cond(cond);
+        break;
+
+    case TCG_COND_LTU:
+    case TCG_COND_LEU:
+        break;
+
+    default:
+        tcg_out_cmp(s, c1, c2, c2const);
+#if defined(__sparc_v9__) || defined(__sparc_v8plus__)
+        tcg_out_movi_imm13(s, ret, 0);
+        tcg_out32 (s, ARITH_MOVCC | INSN_RD(ret)
+                   | INSN_RS1(tcg_cond_to_bcond[cond])
+                   | MOVCC_ICC | INSN_IMM11(1));
+#else
+        t = gen_new_label();
+        tcg_out_branch_i32(s, INSN_COND(tcg_cond_to_bcond[cond], 1), t);
+        tcg_out_movi_imm13(s, ret, 1);
+        tcg_out_movi_imm13(s, ret, 0);
+        tcg_out_label(s, t, (tcg_target_long)s->code_ptr);
+#endif
+        return;
+    }
+
+    tcg_out_cmp(s, c1, c2, c2const);
+    if (cond == TCG_COND_LTU) {
+        tcg_out_arithi(s, ret, TCG_REG_G0, 0, ARITH_ADDX);
+    } else {
+        tcg_out_arithi(s, ret, TCG_REG_G0, -1, ARITH_SUBX);
+    }
+}
+
+#if TCG_TARGET_REG_BITS == 64
+static void tcg_out_setcond_i64(TCGContext *s, int cond, TCGArg ret,
+                                TCGArg c1, TCGArg c2, int c2const)
+{
+    tcg_out_cmp(s, c1, c2, c2const);
+    tcg_out_movi_imm13(s, ret, 0);
+    tcg_out32 (s, ARITH_MOVCC | INSN_RD(ret)
+               | INSN_RS1(tcg_cond_to_bcond[cond])
+               | MOVCC_XCC | INSN_IMM11(1));
+}
+#else
+static void tcg_out_setcond2_i32(TCGContext *s, int cond, TCGArg ret,
+                                 TCGArg al, TCGArg ah,
+                                 TCGArg bl, int blconst,
+                                 TCGArg bh, int bhconst)
+{
+    int lab;
+
+    switch (cond) {
+    case TCG_COND_EQ:
+        tcg_out_setcond_i32(s, TCG_COND_EQ, TCG_REG_I5, al, bl, blconst);
+        tcg_out_setcond_i32(s, TCG_COND_EQ, ret, ah, bh, bhconst);
+        tcg_out_arith(s, ret, ret, TCG_REG_I5, ARITH_AND);
+        break;
+
+    case TCG_COND_NE:
+        tcg_out_setcond_i32(s, TCG_COND_NE, TCG_REG_I5, al, al, blconst);
+        tcg_out_setcond_i32(s, TCG_COND_NE, ret, ah, bh, bhconst);
+        tcg_out_arith(s, ret, ret, TCG_REG_I5, ARITH_OR);
+        break;
+
+    default:
+        lab = gen_new_label();
+
+        tcg_out_cmp(s, ah, bh, bhconst);
+        tcg_out_branch_i32(s, INSN_COND(tcg_cond_to_bcond[cond], 1), lab);
+        tcg_out_movi_imm13(s, ret, 1);
+        tcg_out_branch_i32(s, INSN_COND(COND_NE, 1), lab);
+        tcg_out_movi_imm13(s, ret, 0);
+
+        tcg_out_setcond_i32(s, tcg_unsigned_cond(cond), ret, al, bl, blconst);
+
+        tcg_out_label(s, lab, (tcg_target_long)s->code_ptr);
+        break;
+    }
+}
+#endif
+
 /* Generate global QEMU prologue and epilogue code */
 void tcg_target_qemu_prologue(TCGContext *s)
 {
@@ -1107,9 +1217,15 @@
     OP_32_64(and):
         c = ARITH_AND;
         goto gen_arith;
+    OP_32_64(andc):
+        c = ARITH_ANDN;
+        goto gen_arith;
     OP_32_64(or):
         c = ARITH_OR;
         goto gen_arith;
+    OP_32_64(orc):
+        c = ARITH_ORN;
+        goto gen_arith;
     OP_32_64(xor):
         c = ARITH_XOR;
         goto gen_arith;
@@ -1126,6 +1242,13 @@
         c = ARITH_UMUL;
         goto gen_arith;
 
+    OP_32_64(neg):
+	c = ARITH_SUB;
+	goto gen_arith1;
+    OP_32_64(not):
+	c = ARITH_ORN;
+	goto gen_arith1;
+
     case INDEX_op_div_i32:
         tcg_out_div32(s, args[0], args[1], args[2], const_args[2], 0);
         break;
@@ -1146,12 +1269,22 @@
         tcg_out_brcond_i32(s, args[2], args[0], args[1], const_args[1],
                            args[3]);
         break;
+    case INDEX_op_setcond_i32:
+        tcg_out_setcond_i32(s, args[3], args[0], args[1],
+                            args[2], const_args[2]);
+        break;
+
 #if TCG_TARGET_REG_BITS == 32
     case INDEX_op_brcond2_i32:
         tcg_out_brcond2_i32(s, args[4], args[0], args[1],
                             args[2], const_args[2],
                             args[3], const_args[3], args[5]);
         break;
+    case INDEX_op_setcond2_i32:
+        tcg_out_setcond2_i32(s, args[5], args[0], args[1], args[2],
+                             args[3], const_args[3],
+                             args[4], const_args[4]);
+        break;
     case INDEX_op_add2_i32:
         tcg_out_arithc(s, args[0], args[2], args[4], const_args[4],
                        ARITH_ADDCC);
@@ -1186,9 +1319,11 @@
     case INDEX_op_qemu_ld32u:
         tcg_out_qemu_ld(s, args, 2);
         break;
+#if TCG_TARGET_REG_BITS == 64
     case INDEX_op_qemu_ld32s:
         tcg_out_qemu_ld(s, args, 2 | 4);
         break;
+#endif
     case INDEX_op_qemu_st8:
         tcg_out_qemu_st(s, args, 0);
         break;
@@ -1257,6 +1392,11 @@
         tcg_out_brcond_i64(s, args[2], args[0], args[1], const_args[1],
                            args[3]);
         break;
+    case INDEX_op_setcond_i64:
+        tcg_out_setcond_i64(s, args[3], args[0], args[1],
+                            args[2], const_args[2]);
+        break;
+
     case INDEX_op_qemu_ld64:
         tcg_out_qemu_ld(s, args, 3);
         break;
@@ -1269,6 +1409,10 @@
         tcg_out_arithc(s, args[0], args[1], args[2], const_args[2], c);
         break;
 
+    gen_arith1:
+	tcg_out_arithc(s, args[0], TCG_REG_G0, args[1], const_args[1], c);
+	break;
+
     default:
         fprintf(stderr, "unknown opcode 0x%x\n", opc);
         tcg_abort();
@@ -1301,16 +1445,24 @@
     { INDEX_op_remu_i32, { "r", "r", "rJ" } },
     { INDEX_op_sub_i32, { "r", "r", "rJ" } },
     { INDEX_op_and_i32, { "r", "r", "rJ" } },
+    { INDEX_op_andc_i32, { "r", "r", "rJ" } },
     { INDEX_op_or_i32, { "r", "r", "rJ" } },
+    { INDEX_op_orc_i32, { "r", "r", "rJ" } },
     { INDEX_op_xor_i32, { "r", "r", "rJ" } },
 
     { INDEX_op_shl_i32, { "r", "r", "rJ" } },
     { INDEX_op_shr_i32, { "r", "r", "rJ" } },
     { INDEX_op_sar_i32, { "r", "r", "rJ" } },
 
+    { INDEX_op_neg_i32, { "r", "rJ" } },
+    { INDEX_op_not_i32, { "r", "rJ" } },
+
     { INDEX_op_brcond_i32, { "r", "rJ" } },
+    { INDEX_op_setcond_i32, { "r", "r", "rJ" } },
+
 #if TCG_TARGET_REG_BITS == 32
     { INDEX_op_brcond2_i32, { "r", "r", "rJ", "rJ" } },
+    { INDEX_op_setcond2_i32, { "r", "r", "r", "rJ", "rJ" } },
     { INDEX_op_add2_i32, { "r", "r", "r", "r", "rJ", "rJ" } },
     { INDEX_op_sub2_i32, { "r", "r", "r", "r", "rJ", "rJ" } },
     { INDEX_op_mulu2_i32, { "r", "r", "r", "rJ" } },
@@ -1321,7 +1473,9 @@
     { INDEX_op_qemu_ld16u, { "r", "L" } },
     { INDEX_op_qemu_ld16s, { "r", "L" } },
     { INDEX_op_qemu_ld32u, { "r", "L" } },
+#if TCG_TARGET_REG_BITS == 64
     { INDEX_op_qemu_ld32s, { "r", "L" } },
+#endif
 
     { INDEX_op_qemu_st8, { "L", "L" } },
     { INDEX_op_qemu_st16, { "L", "L" } },
@@ -1352,16 +1506,23 @@
     { INDEX_op_remu_i64, { "r", "r", "rJ" } },
     { INDEX_op_sub_i64, { "r", "r", "rJ" } },
     { INDEX_op_and_i64, { "r", "r", "rJ" } },
+    { INDEX_op_andc_i64, { "r", "r", "rJ" } },
     { INDEX_op_or_i64, { "r", "r", "rJ" } },
+    { INDEX_op_orc_i64, { "r", "r", "rJ" } },
     { INDEX_op_xor_i64, { "r", "r", "rJ" } },
 
     { INDEX_op_shl_i64, { "r", "r", "rJ" } },
     { INDEX_op_shr_i64, { "r", "r", "rJ" } },
     { INDEX_op_sar_i64, { "r", "r", "rJ" } },
+
+    { INDEX_op_neg_i64, { "r", "rJ" } },
+    { INDEX_op_not_i64, { "r", "rJ" } },
+
     { INDEX_op_ext32s_i64, { "r", "ri" } },
     { INDEX_op_ext32u_i64, { "r", "ri" } },
 
     { INDEX_op_brcond_i64, { "r", "rJ" } },
+    { INDEX_op_setcond_i64, { "r", "r", "rJ" } },
 #endif
     { -1 },
 };
diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h
index d27ed5a..dbc574d 100644
--- a/tcg/sparc/tcg-target.h
+++ b/tcg/sparc/tcg-target.h
@@ -89,19 +89,36 @@
 
 /* optional instructions */
 #define TCG_TARGET_HAS_div_i32
-#define TCG_TARGET_HAS_div_i64
+// #define TCG_TARGET_HAS_rot_i32
+// #define TCG_TARGET_HAS_ext8s_i32
+// #define TCG_TARGET_HAS_ext16s_i32
+// #define TCG_TARGET_HAS_ext8u_i32
+// #define TCG_TARGET_HAS_ext16u_i32
+// #define TCG_TARGET_HAS_bswap16_i32
+// #define TCG_TARGET_HAS_bswap32_i32
+#define TCG_TARGET_HAS_neg_i32
+#define TCG_TARGET_HAS_not_i32
+#define TCG_TARGET_HAS_andc_i32
+#define TCG_TARGET_HAS_orc_i32
 
 #if TCG_TARGET_REG_BITS == 64
+#define TCG_TARGET_HAS_div_i64
+// #define TCG_TARGET_HAS_rot_i64
+// #define TCG_TARGET_HAS_ext8s_i64
+// #define TCG_TARGET_HAS_ext16s_i64
 #define TCG_TARGET_HAS_ext32s_i64
+// #define TCG_TARGET_HAS_ext8u_i64
+// #define TCG_TARGET_HAS_ext16u_i64
 #define TCG_TARGET_HAS_ext32u_i64
+// #define TCG_TARGET_HAS_bswap16_i64
+// #define TCG_TARGET_HAS_bswap32_i64
+// #define TCG_TARGET_HAS_bswap64_i64
+#define TCG_TARGET_HAS_neg_i64
+#define TCG_TARGET_HAS_not_i64
+#define TCG_TARGET_HAS_andc_i64
+#define TCG_TARGET_HAS_orc_i64
 #endif
 
-//#define TCG_TARGET_HAS_bswap32_i32
-//#define TCG_TARGET_HAS_bswap64_i64
-//#define TCG_TARGET_HAS_neg_i32
-//#define TCG_TARGET_HAS_neg_i64
-
-
 /* Note: must be synced with dyngen-exec.h and Makefile.target */
 #ifdef CONFIG_SOLARIS
 #define TCG_AREG0 TCG_REG_G2
diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h
index 13eaa5a..6ae1760 100644
--- a/tcg/tcg-op.h
+++ b/tcg/tcg-op.h
@@ -1650,20 +1650,31 @@
 
 static inline void tcg_gen_andc_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
 {
+#ifdef TCG_TARGET_HAS_andc_i32
+    tcg_gen_op3_i32(INDEX_op_andc_i32, ret, arg1, arg2);
+#else
     TCGv_i32 t0;
     t0 = tcg_temp_new_i32();
     tcg_gen_not_i32(t0, arg2);
     tcg_gen_and_i32(ret, arg1, t0);
     tcg_temp_free_i32(t0);
+#endif
 }
 
 static inline void tcg_gen_andc_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
+#ifdef TCG_TARGET_HAS_andc_i64
+    tcg_gen_op3_i64(INDEX_op_andc_i64, ret, arg1, arg2);
+#elif defined(TCG_TARGET_HAS_andc_i32) && TCG_TARGET_REG_BITS == 32
+    tcg_gen_andc_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
+    tcg_gen_andc_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
+#else
     TCGv_i64 t0;
     t0 = tcg_temp_new_i64();
     tcg_gen_not_i64(t0, arg2);
     tcg_gen_and_i64(ret, arg1, t0);
     tcg_temp_free_i64(t0);
+#endif
 }
 
 static inline void tcg_gen_eqv_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
@@ -1704,20 +1715,31 @@
 
 static inline void tcg_gen_orc_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
 {
+#ifdef TCG_TARGET_HAS_orc_i32
+    tcg_gen_op3_i32(INDEX_op_orc_i32, ret, arg1, arg2);
+#else
     TCGv_i32 t0;
     t0 = tcg_temp_new_i32();
     tcg_gen_not_i32(t0, arg2);
     tcg_gen_or_i32(ret, arg1, t0);
     tcg_temp_free_i32(t0);
+#endif
 }
 
 static inline void tcg_gen_orc_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
+#ifdef TCG_TARGET_HAS_orc_i64
+    tcg_gen_op3_i64(INDEX_op_orc_i64, ret, arg1, arg2);
+#elif defined(TCG_TARGET_HAS_orc_i32) && TCG_TARGET_REG_BITS == 32
+    tcg_gen_orc_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
+    tcg_gen_orc_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
+#else
     TCGv_i64 t0;
     t0 = tcg_temp_new_i64();
     tcg_gen_not_i64(t0, arg2);
     tcg_gen_or_i64(ret, arg1, t0);
     tcg_temp_free_i64(t0);
+#endif
 }
 
 static inline void tcg_gen_rotl_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
diff --git a/tcg/tcg-opc.h b/tcg/tcg-opc.h
index 89db3b4..01fea1e 100644
--- a/tcg/tcg-opc.h
+++ b/tcg/tcg-opc.h
@@ -109,6 +109,12 @@
 #ifdef TCG_TARGET_HAS_neg_i32
 DEF2(neg_i32, 1, 1, 0, 0)
 #endif
+#ifdef TCG_TARGET_HAS_andc_i32
+DEF2(andc_i32, 1, 2, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_orc_i32
+DEF2(orc_i32, 1, 2, 0, 0)
+#endif
 
 #if TCG_TARGET_REG_BITS == 64
 DEF2(mov_i64, 1, 1, 0, 0)
@@ -185,6 +191,12 @@
 #ifdef TCG_TARGET_HAS_neg_i64
 DEF2(neg_i64, 1, 1, 0, 0)
 #endif
+#ifdef TCG_TARGET_HAS_andc_i64
+DEF2(andc_i64, 1, 2, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_orc_i64
+DEF2(orc_i64, 1, 2, 0, 0)
+#endif
 #endif
 
 /* QEMU specific */
@@ -224,11 +236,6 @@
 DEF2(qemu_ld32u, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
 #endif
 #if TARGET_LONG_BITS == 32
-DEF2(qemu_ld32s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
-#else
-DEF2(qemu_ld32s, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
-#endif
-#if TARGET_LONG_BITS == 32
 DEF2(qemu_ld64, 2, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
 #else
 DEF2(qemu_ld64, 2, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
diff --git a/tcg/tcg.c b/tcg/tcg.c
index 9949814..e6a1caf 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -981,9 +981,16 @@
         op = tdefs->op;
         assert(op >= 0 && op < NB_OPS);
         def = &tcg_op_defs[op];
+#if defined(CONFIG_DEBUG_TCG)
+        /* Duplicate entry in op definitions? */
+        assert(!def->used);
+        def->used = 1;
+#endif
         nb_args = def->nb_iargs + def->nb_oargs;
         for(i = 0; i < nb_args; i++) {
             ct_str = tdefs->args_ct_str[i];
+            /* Incomplete TCGTargetOpDef entry? */
+            assert(ct_str != NULL);
             tcg_regset_clear(def->args_ct[i].u.regs);
             def->args_ct[i].ct = 0;
             if (ct_str[0] >= '0' && ct_str[0] <= '9') {
@@ -1018,6 +1025,9 @@
             }
         }
 
+        /* TCGTargetOpDef entry with too much information? */
+        assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
+
         /* sort the constraints (XXX: this is just an heuristic) */
         sort_constraints(def, 0, def->nb_oargs);
         sort_constraints(def, def->nb_oargs, def->nb_iargs);
@@ -1035,6 +1045,17 @@
         tdefs++;
     }
 
+#if defined(CONFIG_DEBUG_TCG)
+    for (op = 0; op < ARRAY_SIZE(tcg_op_defs); op++) {
+        if (op < INDEX_op_call || op == INDEX_op_debug_insn_start) {
+            /* Wrong entry in op definitions? */
+            assert(!tcg_op_defs[op].used);
+        } else {
+            /* Missing entry in op definitions? */
+            assert(tcg_op_defs[op].used);
+        }
+    }
+#endif
 }
 
 #ifdef USE_LIVENESS_ANALYSIS
diff --git a/tcg/tcg.h b/tcg/tcg.h
index b218abe..cf3a508 100644
--- a/tcg/tcg.h
+++ b/tcg/tcg.h
@@ -205,11 +205,19 @@
     TCG_COND_GTU,
 } TCGCond;
 
+/* Invert the sense of the comparison.  */
 static inline TCGCond tcg_invert_cond(TCGCond c)
 {
     return (TCGCond)(c ^ 1);
 }
 
+/* Swap the operands in a comparison.  */
+static inline TCGCond tcg_swap_cond(TCGCond c)
+{
+    int mask = (c < TCG_COND_LT ? 0 : c < TCG_COND_LTU ? 7 : 15);
+    return (TCGCond)(c ^ mask);
+}
+
 static inline TCGCond tcg_unsigned_cond(TCGCond c)
 {
     return (c >= TCG_COND_LT && c <= TCG_COND_GT ? c + 4 : c);
@@ -404,6 +412,9 @@
     uint16_t copy_size;
     TCGArgConstraint *args_ct;
     int *sorted_args;
+#if defined(CONFIG_DEBUG_TCG)
+    int used;
+#endif
 } TCGOpDef;
         
 typedef struct TCGTargetOpDef {
diff --git a/tcg/x86_64/tcg-target.h b/tcg/x86_64/tcg-target.h
index 3ca392f..765f0b4 100644
--- a/tcg/x86_64/tcg-target.h
+++ b/tcg/x86_64/tcg-target.h
@@ -75,10 +75,14 @@
 #define TCG_TARGET_HAS_ext8u_i64
 #define TCG_TARGET_HAS_ext16u_i64
 #define TCG_TARGET_HAS_ext32u_i64
-
 #define TCG_TARGET_HAS_rot_i32
 #define TCG_TARGET_HAS_rot_i64
 
+// #define TCG_TARGET_HAS_andc_i32
+// #define TCG_TARGET_HAS_andc_i64
+// #define TCG_TARGET_HAS_orc_i32
+// #define TCG_TARGET_HAS_orc_i64
+
 #define TCG_TARGET_HAS_GUEST_BASE
 
 /* Note: must be synced with dyngen-exec.h */
diff --git a/vl.c b/vl.c
index dc05da3..db7a178 100644
--- a/vl.c
+++ b/vl.c
@@ -182,7 +182,6 @@
 struct drivelist drives = QTAILQ_HEAD_INITIALIZER(drives);
 struct driveoptlist driveopts = QTAILQ_HEAD_INITIALIZER(driveopts);
 enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB;
-static DisplayState *display_state;
 DisplayType display_type = DT_DEFAULT;
 const char* keyboard_layout = NULL;
 ram_addr_t ram_size;
@@ -2583,46 +2582,6 @@
 }
 
 /***********************************************************/
-/* register display */
-
-struct DisplayAllocator default_allocator = {
-    defaultallocator_create_displaysurface,
-    defaultallocator_resize_displaysurface,
-    defaultallocator_free_displaysurface
-};
-
-void register_displaystate(DisplayState *ds)
-{
-    DisplayState **s;
-    s = &display_state;
-    while (*s != NULL)
-        s = &(*s)->next;
-    ds->next = NULL;
-    *s = ds;
-}
-
-DisplayState *get_displaystate(void)
-{
-    return display_state;
-}
-
-DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da)
-{
-    if(ds->allocator ==  &default_allocator) ds->allocator = da;
-    return ds->allocator;
-}
-
-/* dumb display */
-
-static void dumb_display_init(void)
-{
-    DisplayState *ds = qemu_mallocz(sizeof(DisplayState));
-    ds->allocator = &default_allocator;
-    ds->surface = qemu_create_displaysurface(ds, 640, 480);
-    register_displaystate(ds);
-}
-
-/***********************************************************/
 /* I/O handling */
 
 typedef struct IOHandlerRecord {
@@ -4958,6 +4917,9 @@
             fclose(fp);
         }
     }
+#if defined(cpudef_setup)
+    cpudef_setup(); /* parse cpu definitions in target config file */
+#endif
 
     /* second pass of option parsing */
     optind = 1;
@@ -4991,8 +4953,10 @@
                 /* hw initialization will check this */
                 if (*optarg == '?') {
 /* XXX: implement xxx_cpu_list for targets that still miss it */
-#if defined(cpu_list)
-                    cpu_list(stdout, &fprintf);
+#if defined(cpu_list_id)
+                    cpu_list_id(stdout, &fprintf, optarg);
+#elif defined(cpu_list)
+                    cpu_list(stdout, &fprintf);	        /* deprecated */
 #endif
                     exit(0);
                 } else {
@@ -5978,10 +5942,10 @@
     if (qemu_opts_foreach(&qemu_device_opts, device_init_func, NULL, 1) != 0)
         exit(1);
 
-    if (!display_state)
-        dumb_display_init();
+    net_check_clients();
+
     /* just use the first displaystate for the moment */
-    ds = display_state;
+    ds = get_displaystate();
 
     if (display_type == DT_DEFAULT) {
 #if defined(CONFIG_SDL) || defined(CONFIG_COCOA)
@@ -6039,7 +6003,7 @@
         qemu_mod_timer(nographic_timer, qemu_get_clock(rt_clock));
     }
 
-    text_consoles_set_display(display_state);
+    text_consoles_set_display(ds);
 
     if (qemu_opts_foreach(&qemu_mon_opts, mon_init_func, NULL, 1) != 0)
         exit(1);