Merge branch 'target-arm.for-upstream' of git://git.linaro.org/people/pmaydell/qemu-arm
diff --git a/Makefile.objs b/Makefile.objs
index 44d9bb9..01587c8 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -81,7 +81,7 @@
 common-obj-$(CONFIG_WIN32) += os-win32.o
 common-obj-$(CONFIG_POSIX) += os-posix.o
 
-common-obj-y += tcg-runtime.o host-utils.o
+common-obj-y += tcg-runtime.o host-utils.o main-loop.o
 common-obj-y += irq.o input.o
 common-obj-$(CONFIG_PTIMER) += ptimer.o
 common-obj-$(CONFIG_MAX7310) += max7310.o
@@ -305,7 +305,7 @@
 adlib.o fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0
 hw-obj-$(CONFIG_SOUND) += $(sound-obj-y)
 
-9pfs-nested-$(CONFIG_VIRTFS)  = virtio-9p.o virtio-9p-debug.o
+9pfs-nested-$(CONFIG_VIRTFS)  = virtio-9p.o
 9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-local.o virtio-9p-xattr.o
 9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-xattr-user.o virtio-9p-posix-acl.o
 9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-coth.o cofs.o codir.o cofile.o
diff --git a/Makefile.target b/Makefile.target
index 417f23e..fe5f6f7 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -74,8 +74,15 @@
 ifeq ($(TARGET_BASE_ARCH), i386)
 libobj-y += cpuid.o
 endif
+libobj-$(TARGET_SPARC64) += vis_helper.o
 libobj-$(CONFIG_NEED_MMU) += mmu.o
 libobj-$(TARGET_ARM) += neon_helper.o iwmmxt_helper.o
+ifeq ($(TARGET_BASE_ARCH), sparc)
+libobj-y += fop_helper.o cc_helper.o win_helper.o mmu_helper.o ldst_helper.o
+libobj-y += cpu_init.o
+endif
+libobj-$(TARGET_SPARC) += int32_helper.o
+libobj-$(TARGET_SPARC64) += int64_helper.o
 
 libobj-y += disas.o
 
@@ -91,7 +98,7 @@
 
 # HELPER_CFLAGS is used for all the code compiled with static register
 # variables
-op_helper.o user-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
+op_helper.o ldst_helper.o user-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
 
 # Note: this is a workaround. The real fix is to avoid compiling
 # cpu_signal_handler() in user-exec.c.
diff --git a/arch_init.c b/arch_init.c
index a6c69c7..a411fdf 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -256,6 +256,7 @@
     uint64_t bytes_transferred_last;
     double bwidth = 0;
     uint64_t expected_time = 0;
+    int ret;
 
     if (stage < 0) {
         cpu_physical_memory_set_dirty_tracking(0);
@@ -263,8 +264,8 @@
     }
 
     if (cpu_physical_sync_dirty_bitmap(0, TARGET_PHYS_ADDR_MAX) != 0) {
-        qemu_file_set_error(f);
-        return 0;
+        qemu_file_set_error(f, -EINVAL);
+        return -EINVAL;
     }
 
     if (stage == 1) {
@@ -300,7 +301,7 @@
     bytes_transferred_last = bytes_transferred;
     bwidth = qemu_get_clock_ns(rt_clock);
 
-    while (!qemu_file_rate_limit(f)) {
+    while ((ret = qemu_file_rate_limit(f)) == 0) {
         int bytes_sent;
 
         bytes_sent = ram_save_block(f);
@@ -310,6 +311,10 @@
         }
     }
 
+    if (ret < 0) {
+        return ret;
+    }
+
     bwidth = qemu_get_clock_ns(rt_clock) - bwidth;
     bwidth = (bytes_transferred - bytes_transferred_last) / bwidth;
 
@@ -371,6 +376,7 @@
 {
     ram_addr_t addr;
     int flags;
+    int error;
 
     if (version_id < 3 || version_id > 4) {
         return -EINVAL;
@@ -451,8 +457,9 @@
 
             qemu_get_buffer(f, host, TARGET_PAGE_SIZE);
         }
-        if (qemu_file_has_error(f)) {
-            return -EIO;
+        error = qemu_file_get_error(f);
+        if (error) {
+            return error;
         }
     } while (!(flags & RAM_SAVE_FLAG_EOS));
 
diff --git a/async.c b/async.c
index ca13962..332d511 100644
--- a/async.c
+++ b/async.c
@@ -24,6 +24,7 @@
 
 #include "qemu-common.h"
 #include "qemu-aio.h"
+#include "main-loop.h"
 
 /* Anchor of the list of Bottom Halves belonging to the context */
 static struct QEMUBH *first_bh;
diff --git a/block-migration.c b/block-migration.c
index e2775ee..0bff075 100644
--- a/block-migration.c
+++ b/block-migration.c
@@ -263,7 +263,7 @@
 
 error:
     monitor_printf(mon, "Error reading sector %" PRId64 "\n", cur_sector);
-    qemu_file_set_error(f);
+    qemu_file_set_error(f, -EIO);
     g_free(blk->buf);
     g_free(blk);
     return 0;
@@ -383,6 +383,7 @@
     int64_t total_sectors = bmds->total_sectors;
     int64_t sector;
     int nr_sectors;
+    int ret = -EIO;
 
     for (sector = bmds->cur_dirty; sector < bmds->total_sectors;) {
         if (bmds_aio_inflight(bmds, sector)) {
@@ -418,8 +419,8 @@
                 block_mig_state.submitted++;
                 bmds_set_aio_inflight(bmds, sector, nr_sectors, 1);
             } else {
-                if (bdrv_read(bmds->bs, sector, blk->buf,
-                              nr_sectors) < 0) {
+                ret = bdrv_read(bmds->bs, sector, blk->buf, nr_sectors);
+                if (ret < 0) {
                     goto error;
                 }
                 blk_send(f, blk);
@@ -439,7 +440,7 @@
 
 error:
     monitor_printf(mon, "Error reading sector %" PRId64 "\n", sector);
-    qemu_file_set_error(f);
+    qemu_file_set_error(f, ret);
     g_free(blk->buf);
     g_free(blk);
     return 0;
@@ -473,7 +474,7 @@
             break;
         }
         if (blk->ret < 0) {
-            qemu_file_set_error(f);
+            qemu_file_set_error(f, blk->ret);
             break;
         }
         blk_send(f, blk);
@@ -556,6 +557,8 @@
 
 static int block_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
 {
+    int ret;
+
     DPRINTF("Enter save live stage %d submitted %d transferred %d\n",
             stage, block_mig_state.submitted, block_mig_state.transferred);
 
@@ -579,9 +582,10 @@
 
     flush_blks(f);
 
-    if (qemu_file_has_error(f)) {
+    ret = qemu_file_get_error(f);
+    if (ret) {
         blk_mig_cleanup(mon);
-        return 0;
+        return ret;
     }
 
     blk_mig_reset_dirty_cursor();
@@ -607,9 +611,10 @@
 
         flush_blks(f);
 
-        if (qemu_file_has_error(f)) {
+        ret = qemu_file_get_error(f);
+        if (ret) {
             blk_mig_cleanup(mon);
-            return 0;
+            return ret;
         }
     }
 
@@ -624,8 +629,9 @@
         /* report completion */
         qemu_put_be64(f, (100 << BDRV_SECTOR_BITS) | BLK_MIG_FLAG_PROGRESS);
 
-        if (qemu_file_has_error(f)) {
-            return 0;
+        ret = qemu_file_get_error(f);
+        if (ret) {
+            return ret;
         }
 
         monitor_printf(mon, "Block migration completed\n");
@@ -646,6 +652,7 @@
     uint8_t *buf;
     int64_t total_sectors = 0;
     int nr_sectors;
+    int ret;
 
     do {
         addr = qemu_get_be64(f);
@@ -654,7 +661,6 @@
         addr >>= BDRV_SECTOR_BITS;
 
         if (flags & BLK_MIG_FLAG_DEVICE_BLOCK) {
-            int ret;
             /* get device name */
             len = qemu_get_byte(f);
             qemu_get_buffer(f, (uint8_t *)device_name, len);
@@ -704,8 +710,9 @@
             fprintf(stderr, "Unknown flags\n");
             return -EINVAL;
         }
-        if (qemu_file_has_error(f)) {
-            return -EIO;
+        ret = qemu_file_get_error(f);
+        if (ret != 0) {
+            return ret;
         }
     } while (!(flags & BLK_MIG_FLAG_EOS));
 
diff --git a/block.c b/block.c
index 9873b57..70aab63 100644
--- a/block.c
+++ b/block.c
@@ -53,17 +53,12 @@
 static BlockDriverAIOCB *bdrv_aio_writev_em(BlockDriverState *bs,
         int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
         BlockDriverCompletionFunc *cb, void *opaque);
-static BlockDriverAIOCB *bdrv_aio_flush_em(BlockDriverState *bs,
-        BlockDriverCompletionFunc *cb, void *opaque);
-static BlockDriverAIOCB *bdrv_aio_noop_em(BlockDriverState *bs,
-        BlockDriverCompletionFunc *cb, void *opaque);
 static int coroutine_fn bdrv_co_readv_em(BlockDriverState *bs,
                                          int64_t sector_num, int nb_sectors,
                                          QEMUIOVector *iov);
 static int coroutine_fn bdrv_co_writev_em(BlockDriverState *bs,
                                          int64_t sector_num, int nb_sectors,
                                          QEMUIOVector *iov);
-static int coroutine_fn bdrv_co_flush_em(BlockDriverState *bs);
 static int coroutine_fn bdrv_co_do_readv(BlockDriverState *bs,
     int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
 static int coroutine_fn bdrv_co_do_writev(BlockDriverState *bs,
@@ -203,9 +198,6 @@
         }
     }
 
-    if (!bdrv->bdrv_aio_flush)
-        bdrv->bdrv_aio_flush = bdrv_aio_flush_em;
-
     QLIST_INSERT_HEAD(&bdrv_drivers, bdrv, list);
 }
 
@@ -1027,11 +1019,6 @@
                                    nb_sectors * BDRV_SECTOR_SIZE);
 }
 
-static inline bool bdrv_has_async_flush(BlockDriver *drv)
-{
-    return drv->bdrv_aio_flush != bdrv_aio_flush_em;
-}
-
 typedef struct RwCo {
     BlockDriverState *bs;
     int64_t sector_num;
@@ -1759,33 +1746,6 @@
     return bs->device_name;
 }
 
-int bdrv_flush(BlockDriverState *bs)
-{
-    if (bs->open_flags & BDRV_O_NO_FLUSH) {
-        return 0;
-    }
-
-    if (bs->drv && bdrv_has_async_flush(bs->drv) && qemu_in_coroutine()) {
-        return bdrv_co_flush_em(bs);
-    }
-
-    if (bs->drv && bs->drv->bdrv_flush) {
-        return bs->drv->bdrv_flush(bs);
-    }
-
-    /*
-     * Some block drivers always operate in either writethrough or unsafe mode
-     * and don't support bdrv_flush therefore. Usually qemu doesn't know how
-     * the server works (because the behaviour is hardcoded or depends on
-     * server-side configuration), so we can't ensure that everything is safe
-     * on disk. Returning an error doesn't work because that would break guests
-     * even if the server operates in writethrough mode.
-     *
-     * Let's hope the user knows what he's doing.
-     */
-    return 0;
-}
-
 void bdrv_flush_all(void)
 {
     BlockDriverState *bs;
@@ -1808,17 +1768,6 @@
     return 1;
 }
 
-int bdrv_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors)
-{
-    if (!bs->drv) {
-        return -ENOMEDIUM;
-    }
-    if (!bs->drv->bdrv_discard) {
-        return 0;
-    }
-    return bs->drv->bdrv_discard(bs, sector_num, nb_sectors);
-}
-
 /*
  * Returns true iff the specified sector is present in the disk image. Drivers
  * not implementing the functionality are assumed to not support backing files,
@@ -2610,22 +2559,6 @@
     return -1;
 }
 
-BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs,
-        BlockDriverCompletionFunc *cb, void *opaque)
-{
-    BlockDriver *drv = bs->drv;
-
-    trace_bdrv_aio_flush(bs, opaque);
-
-    if (bs->open_flags & BDRV_O_NO_FLUSH) {
-        return bdrv_aio_noop_em(bs, cb, opaque);
-    }
-
-    if (!drv)
-        return NULL;
-    return drv->bdrv_aio_flush(bs, cb, opaque);
-}
-
 void bdrv_aio_cancel(BlockDriverAIOCB *acb)
 {
     acb->pool->cancel(acb);
@@ -2735,7 +2668,7 @@
     .cancel             = bdrv_aio_co_cancel_em,
 };
 
-static void bdrv_co_rw_bh(void *opaque)
+static void bdrv_co_em_bh(void *opaque)
 {
     BlockDriverAIOCBCoroutine *acb = opaque;
 
@@ -2758,7 +2691,7 @@
             acb->req.nb_sectors, acb->req.qiov);
     }
 
-    acb->bh = qemu_bh_new(bdrv_co_rw_bh, acb);
+    acb->bh = qemu_bh_new(bdrv_co_em_bh, acb);
     qemu_bh_schedule(acb->bh);
 }
 
@@ -2785,41 +2718,56 @@
     return &acb->common;
 }
 
-static BlockDriverAIOCB *bdrv_aio_flush_em(BlockDriverState *bs,
+static void coroutine_fn bdrv_aio_flush_co_entry(void *opaque)
+{
+    BlockDriverAIOCBCoroutine *acb = opaque;
+    BlockDriverState *bs = acb->common.bs;
+
+    acb->req.error = bdrv_co_flush(bs);
+    acb->bh = qemu_bh_new(bdrv_co_em_bh, acb);
+    qemu_bh_schedule(acb->bh);
+}
+
+BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs,
         BlockDriverCompletionFunc *cb, void *opaque)
 {
-    BlockDriverAIOCBSync *acb;
+    trace_bdrv_aio_flush(bs, opaque);
 
-    acb = qemu_aio_get(&bdrv_em_aio_pool, bs, cb, opaque);
-    acb->is_write = 1; /* don't bounce in the completion hadler */
-    acb->qiov = NULL;
-    acb->bounce = NULL;
-    acb->ret = 0;
+    Coroutine *co;
+    BlockDriverAIOCBCoroutine *acb;
 
-    if (!acb->bh)
-        acb->bh = qemu_bh_new(bdrv_aio_bh_cb, acb);
+    acb = qemu_aio_get(&bdrv_em_co_aio_pool, bs, cb, opaque);
+    co = qemu_coroutine_create(bdrv_aio_flush_co_entry);
+    qemu_coroutine_enter(co, acb);
 
-    bdrv_flush(bs);
-    qemu_bh_schedule(acb->bh);
     return &acb->common;
 }
 
-static BlockDriverAIOCB *bdrv_aio_noop_em(BlockDriverState *bs,
+static void coroutine_fn bdrv_aio_discard_co_entry(void *opaque)
+{
+    BlockDriverAIOCBCoroutine *acb = opaque;
+    BlockDriverState *bs = acb->common.bs;
+
+    acb->req.error = bdrv_co_discard(bs, acb->req.sector, acb->req.nb_sectors);
+    acb->bh = qemu_bh_new(bdrv_co_em_bh, acb);
+    qemu_bh_schedule(acb->bh);
+}
+
+BlockDriverAIOCB *bdrv_aio_discard(BlockDriverState *bs,
+        int64_t sector_num, int nb_sectors,
         BlockDriverCompletionFunc *cb, void *opaque)
 {
-    BlockDriverAIOCBSync *acb;
+    Coroutine *co;
+    BlockDriverAIOCBCoroutine *acb;
 
-    acb = qemu_aio_get(&bdrv_em_aio_pool, bs, cb, opaque);
-    acb->is_write = 1; /* don't bounce in the completion handler */
-    acb->qiov = NULL;
-    acb->bounce = NULL;
-    acb->ret = 0;
+    trace_bdrv_aio_discard(bs, sector_num, nb_sectors, opaque);
 
-    if (!acb->bh) {
-        acb->bh = qemu_bh_new(bdrv_aio_bh_cb, acb);
-    }
+    acb = qemu_aio_get(&bdrv_em_co_aio_pool, bs, cb, opaque);
+    acb->req.sector = sector_num;
+    acb->req.nb_sectors = nb_sectors;
+    co = qemu_coroutine_create(bdrv_aio_discard_co_entry);
+    qemu_coroutine_enter(co, acb);
 
-    qemu_bh_schedule(acb->bh);
     return &acb->common;
 }
 
@@ -2916,19 +2864,131 @@
     return bdrv_co_io_em(bs, sector_num, nb_sectors, iov, true);
 }
 
-static int coroutine_fn bdrv_co_flush_em(BlockDriverState *bs)
+static void coroutine_fn bdrv_flush_co_entry(void *opaque)
 {
-    CoroutineIOCompletion co = {
-        .coroutine = qemu_coroutine_self(),
-    };
-    BlockDriverAIOCB *acb;
+    RwCo *rwco = opaque;
 
-    acb = bdrv_aio_flush(bs, bdrv_co_io_em_complete, &co);
-    if (!acb) {
-        return -EIO;
+    rwco->ret = bdrv_co_flush(rwco->bs);
+}
+
+int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
+{
+    if (bs->open_flags & BDRV_O_NO_FLUSH) {
+        return 0;
+    } else if (!bs->drv) {
+        return 0;
+    } else if (bs->drv->bdrv_co_flush) {
+        return bs->drv->bdrv_co_flush(bs);
+    } else if (bs->drv->bdrv_aio_flush) {
+        BlockDriverAIOCB *acb;
+        CoroutineIOCompletion co = {
+            .coroutine = qemu_coroutine_self(),
+        };
+
+        acb = bs->drv->bdrv_aio_flush(bs, bdrv_co_io_em_complete, &co);
+        if (acb == NULL) {
+            return -EIO;
+        } else {
+            qemu_coroutine_yield();
+            return co.ret;
+        }
+    } else {
+        /*
+         * Some block drivers always operate in either writethrough or unsafe
+         * mode and don't support bdrv_flush therefore. Usually qemu doesn't
+         * know how the server works (because the behaviour is hardcoded or
+         * depends on server-side configuration), so we can't ensure that
+         * everything is safe on disk. Returning an error doesn't work because
+         * that would break guests even if the server operates in writethrough
+         * mode.
+         *
+         * Let's hope the user knows what he's doing.
+         */
+        return 0;
     }
-    qemu_coroutine_yield();
-    return co.ret;
+}
+
+int bdrv_flush(BlockDriverState *bs)
+{
+    Coroutine *co;
+    RwCo rwco = {
+        .bs = bs,
+        .ret = NOT_DONE,
+    };
+
+    if (qemu_in_coroutine()) {
+        /* Fast-path if already in coroutine context */
+        bdrv_flush_co_entry(&rwco);
+    } else {
+        co = qemu_coroutine_create(bdrv_flush_co_entry);
+        qemu_coroutine_enter(co, &rwco);
+        while (rwco.ret == NOT_DONE) {
+            qemu_aio_wait();
+        }
+    }
+
+    return rwco.ret;
+}
+
+static void coroutine_fn bdrv_discard_co_entry(void *opaque)
+{
+    RwCo *rwco = opaque;
+
+    rwco->ret = bdrv_co_discard(rwco->bs, rwco->sector_num, rwco->nb_sectors);
+}
+
+int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num,
+                                 int nb_sectors)
+{
+    if (!bs->drv) {
+        return -ENOMEDIUM;
+    } else if (bdrv_check_request(bs, sector_num, nb_sectors)) {
+        return -EIO;
+    } else if (bs->read_only) {
+        return -EROFS;
+    } else if (bs->drv->bdrv_co_discard) {
+        return bs->drv->bdrv_co_discard(bs, sector_num, nb_sectors);
+    } else if (bs->drv->bdrv_aio_discard) {
+        BlockDriverAIOCB *acb;
+        CoroutineIOCompletion co = {
+            .coroutine = qemu_coroutine_self(),
+        };
+
+        acb = bs->drv->bdrv_aio_discard(bs, sector_num, nb_sectors,
+                                        bdrv_co_io_em_complete, &co);
+        if (acb == NULL) {
+            return -EIO;
+        } else {
+            qemu_coroutine_yield();
+            return co.ret;
+        }
+    } else {
+        return 0;
+    }
+}
+
+int bdrv_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors)
+{
+    Coroutine *co;
+    RwCo rwco = {
+        .bs = bs,
+        .sector_num = sector_num,
+        .nb_sectors = nb_sectors,
+        .ret = NOT_DONE,
+    };
+
+    if (qemu_in_coroutine()) {
+        /* Fast-path if already in coroutine context */
+        bdrv_discard_co_entry(&rwco);
+    } else {
+        co = qemu_coroutine_create(bdrv_discard_co_entry);
+        qemu_coroutine_enter(co, &rwco);
+        while (rwco.ret == NOT_DONE) {
+            qemu_aio_wait();
+        }
+    }
+
+    return rwco.ret;
 }
 
 /**************************************************************/
diff --git a/block.h b/block.h
index e77988e..5a042c9 100644
--- a/block.h
+++ b/block.h
@@ -166,6 +166,9 @@
                                   BlockDriverCompletionFunc *cb, void *opaque);
 BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs,
                                  BlockDriverCompletionFunc *cb, void *opaque);
+BlockDriverAIOCB *bdrv_aio_discard(BlockDriverState *bs,
+                                   int64_t sector_num, int nb_sectors,
+                                   BlockDriverCompletionFunc *cb, void *opaque);
 void bdrv_aio_cancel(BlockDriverAIOCB *acb);
 
 typedef struct BlockRequest {
@@ -191,10 +194,12 @@
 
 /* Ensure contents are flushed to disk.  */
 int bdrv_flush(BlockDriverState *bs);
+int coroutine_fn bdrv_co_flush(BlockDriverState *bs);
 void bdrv_flush_all(void);
 void bdrv_close_all(void);
 
 int bdrv_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors);
+int bdrv_co_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors);
 int bdrv_has_zero_init(BlockDriverState *bs);
 int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
                       int *pnum);
diff --git a/block/blkdebug.c b/block/blkdebug.c
index b3c5d42..9b88535 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -397,11 +397,6 @@
     }
 }
 
-static int blkdebug_flush(BlockDriverState *bs)
-{
-    return bdrv_flush(bs->file);
-}
-
 static BlockDriverAIOCB *blkdebug_aio_flush(BlockDriverState *bs,
     BlockDriverCompletionFunc *cb, void *opaque)
 {
@@ -454,7 +449,6 @@
 
     .bdrv_file_open     = blkdebug_open,
     .bdrv_close         = blkdebug_close,
-    .bdrv_flush         = blkdebug_flush,
 
     .bdrv_aio_readv     = blkdebug_aio_readv,
     .bdrv_aio_writev    = blkdebug_aio_writev,
diff --git a/block/blkverify.c b/block/blkverify.c
index c7522b4..483f3b3 100644
--- a/block/blkverify.c
+++ b/block/blkverify.c
@@ -116,14 +116,6 @@
     s->test_file = NULL;
 }
 
-static int blkverify_flush(BlockDriverState *bs)
-{
-    BDRVBlkverifyState *s = bs->opaque;
-
-    /* Only flush test file, the raw file is not important */
-    return bdrv_flush(s->test_file);
-}
-
 static int64_t blkverify_getlength(BlockDriverState *bs)
 {
     BDRVBlkverifyState *s = bs->opaque;
@@ -368,7 +360,6 @@
 
     .bdrv_file_open     = blkverify_open,
     .bdrv_close         = blkverify_close,
-    .bdrv_flush         = blkverify_flush,
 
     .bdrv_aio_readv     = blkverify_aio_readv,
     .bdrv_aio_writev    = blkverify_aio_writev,
diff --git a/block/bochs.c b/block/bochs.c
index 3c2f8d1..ab7944d 100644
--- a/block/bochs.c
+++ b/block/bochs.c
@@ -80,6 +80,7 @@
 };
 
 typedef struct BDRVBochsState {
+    CoMutex lock;
     uint32_t *catalog_bitmap;
     int catalog_size;
 
@@ -150,6 +151,7 @@
 
     s->extent_size = le32_to_cpu(bochs.extra.redolog.extent);
 
+    qemu_co_mutex_init(&s->lock);
     return 0;
  fail:
     return -1;
@@ -207,6 +209,17 @@
     return 0;
 }
 
+static coroutine_fn int bochs_co_read(BlockDriverState *bs, int64_t sector_num,
+                                      uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVBochsState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = bochs_read(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
 static void bochs_close(BlockDriverState *bs)
 {
     BDRVBochsState *s = bs->opaque;
@@ -218,7 +231,7 @@
     .instance_size	= sizeof(BDRVBochsState),
     .bdrv_probe		= bochs_probe,
     .bdrv_open		= bochs_open,
-    .bdrv_read		= bochs_read,
+    .bdrv_read          = bochs_co_read,
     .bdrv_close		= bochs_close,
 };
 
diff --git a/block/cloop.c b/block/cloop.c
index 8cff9f2..775f8a9 100644
--- a/block/cloop.c
+++ b/block/cloop.c
@@ -27,6 +27,7 @@
 #include <zlib.h>
 
 typedef struct BDRVCloopState {
+    CoMutex lock;
     uint32_t block_size;
     uint32_t n_blocks;
     uint64_t* offsets;
@@ -93,6 +94,7 @@
 
     s->sectors_per_block = s->block_size/512;
     bs->total_sectors = s->n_blocks*s->sectors_per_block;
+    qemu_co_mutex_init(&s->lock);
     return 0;
 
 cloop_close:
@@ -144,6 +146,17 @@
     return 0;
 }
 
+static coroutine_fn int cloop_co_read(BlockDriverState *bs, int64_t sector_num,
+                                      uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVCloopState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = cloop_read(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
 static void cloop_close(BlockDriverState *bs)
 {
     BDRVCloopState *s = bs->opaque;
@@ -159,7 +172,7 @@
     .instance_size	= sizeof(BDRVCloopState),
     .bdrv_probe		= cloop_probe,
     .bdrv_open		= cloop_open,
-    .bdrv_read		= cloop_read,
+    .bdrv_read          = cloop_co_read,
     .bdrv_close		= cloop_close,
 };
 
diff --git a/block/cow.c b/block/cow.c
index 4cf543c..707c0aa 100644
--- a/block/cow.c
+++ b/block/cow.c
@@ -42,6 +42,7 @@
 };
 
 typedef struct BDRVCowState {
+    CoMutex lock;
     int64_t cow_sectors_offset;
 } BDRVCowState;
 
@@ -84,6 +85,7 @@
 
     bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
     s->cow_sectors_offset = (bitmap_size + 511) & ~511;
+    qemu_co_mutex_init(&s->lock);
     return 0;
  fail:
     return -1;
@@ -199,6 +201,17 @@
     return 0;
 }
 
+static coroutine_fn int cow_co_read(BlockDriverState *bs, int64_t sector_num,
+                                    uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVCowState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = cow_read(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
 static int cow_write(BlockDriverState *bs, int64_t sector_num,
                      const uint8_t *buf, int nb_sectors)
 {
@@ -213,6 +226,17 @@
     return cow_update_bitmap(bs, sector_num, nb_sectors);
 }
 
+static coroutine_fn int cow_co_write(BlockDriverState *bs, int64_t sector_num,
+                                     const uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVCowState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = cow_write(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
 static void cow_close(BlockDriverState *bs)
 {
 }
@@ -282,9 +306,9 @@
     return ret;
 }
 
-static int cow_flush(BlockDriverState *bs)
+static coroutine_fn int cow_co_flush(BlockDriverState *bs)
 {
-    return bdrv_flush(bs->file);
+    return bdrv_co_flush(bs->file);
 }
 
 static QEMUOptionParameter cow_create_options[] = {
@@ -306,11 +330,11 @@
     .instance_size	= sizeof(BDRVCowState),
     .bdrv_probe		= cow_probe,
     .bdrv_open		= cow_open,
-    .bdrv_read		= cow_read,
-    .bdrv_write		= cow_write,
+    .bdrv_read          = cow_co_read,
+    .bdrv_write         = cow_co_write,
     .bdrv_close		= cow_close,
     .bdrv_create	= cow_create,
-    .bdrv_flush		= cow_flush,
+    .bdrv_co_flush      = cow_co_flush,
     .bdrv_is_allocated	= cow_is_allocated,
 
     .create_options = cow_create_options,
diff --git a/block/dmg.c b/block/dmg.c
index 64c3cce..37902a4 100644
--- a/block/dmg.c
+++ b/block/dmg.c
@@ -28,6 +28,7 @@
 #include <zlib.h>
 
 typedef struct BDRVDMGState {
+    CoMutex lock;
     /* each chunk contains a certain number of sectors,
      * offsets[i] is the offset in the .dmg file,
      * lengths[i] is the length of the compressed chunk,
@@ -177,6 +178,7 @@
 
     s->current_chunk = s->n_chunks;
 
+    qemu_co_mutex_init(&s->lock);
     return 0;
 fail:
     return -1;
@@ -280,6 +282,17 @@
     return 0;
 }
 
+static coroutine_fn int dmg_co_read(BlockDriverState *bs, int64_t sector_num,
+                                    uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVDMGState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = dmg_read(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
 static void dmg_close(BlockDriverState *bs)
 {
     BDRVDMGState *s = bs->opaque;
@@ -300,7 +313,7 @@
     .instance_size	= sizeof(BDRVDMGState),
     .bdrv_probe		= dmg_probe,
     .bdrv_open		= dmg_open,
-    .bdrv_read		= dmg_read,
+    .bdrv_read          = dmg_co_read,
     .bdrv_close		= dmg_close,
 };
 
diff --git a/block/nbd.c b/block/nbd.c
index 76f04d8..882b2dc 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -47,6 +47,7 @@
 #endif
 
 typedef struct BDRVNBDState {
+    CoMutex lock;
     int sock;
     uint32_t nbdflags;
     off_t size;
@@ -175,6 +176,7 @@
      */
     result = nbd_establish_connection(bs);
 
+    qemu_co_mutex_init(&s->lock);
     return result;
 }
 
@@ -238,6 +240,28 @@
     return 0;
 }
 
+static coroutine_fn int nbd_co_read(BlockDriverState *bs, int64_t sector_num,
+                                    uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVNBDState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = nbd_read(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
+static coroutine_fn int nbd_co_write(BlockDriverState *bs, int64_t sector_num,
+                                     const uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVNBDState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = nbd_write(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
 static void nbd_close(BlockDriverState *bs)
 {
     BDRVNBDState *s = bs->opaque;
@@ -258,8 +282,8 @@
     .format_name	= "nbd",
     .instance_size	= sizeof(BDRVNBDState),
     .bdrv_file_open	= nbd_open,
-    .bdrv_read		= nbd_read,
-    .bdrv_write		= nbd_write,
+    .bdrv_read          = nbd_co_read,
+    .bdrv_write         = nbd_co_write,
     .bdrv_close		= nbd_close,
     .bdrv_getlength	= nbd_getlength,
     .protocol_name	= "nbd",
diff --git a/block/parallels.c b/block/parallels.c
index c64103d..d30f0ec 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -46,6 +46,7 @@
 } QEMU_PACKED;
 
 typedef struct BDRVParallelsState {
+    CoMutex lock;
 
     uint32_t *catalog_bitmap;
     int catalog_size;
@@ -95,6 +96,7 @@
     for (i = 0; i < s->catalog_size; i++)
 	le32_to_cpus(&s->catalog_bitmap[i]);
 
+    qemu_co_mutex_init(&s->lock);
     return 0;
 fail:
     if (s->catalog_bitmap)
@@ -134,6 +136,17 @@
     return 0;
 }
 
+static coroutine_fn int parallels_co_read(BlockDriverState *bs, int64_t sector_num,
+                                          uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVParallelsState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = parallels_read(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
 static void parallels_close(BlockDriverState *bs)
 {
     BDRVParallelsState *s = bs->opaque;
@@ -145,7 +158,7 @@
     .instance_size	= sizeof(BDRVParallelsState),
     .bdrv_probe		= parallels_probe,
     .bdrv_open		= parallels_open,
-    .bdrv_read		= parallels_read,
+    .bdrv_read          = parallels_co_read,
     .bdrv_close		= parallels_close,
 };
 
diff --git a/block/qcow.c b/block/qcow.c
index eba5a04..ab36b29 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -781,15 +781,9 @@
     return 0;
 }
 
-static int qcow_flush(BlockDriverState *bs)
+static coroutine_fn int qcow_co_flush(BlockDriverState *bs)
 {
-    return bdrv_flush(bs->file);
-}
-
-static BlockDriverAIOCB *qcow_aio_flush(BlockDriverState *bs,
-        BlockDriverCompletionFunc *cb, void *opaque)
-{
-    return bdrv_aio_flush(bs->file, cb, opaque);
+    return bdrv_co_flush(bs->file);
 }
 
 static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
@@ -826,13 +820,12 @@
     .bdrv_open		= qcow_open,
     .bdrv_close		= qcow_close,
     .bdrv_create	= qcow_create,
-    .bdrv_flush		= qcow_flush,
     .bdrv_is_allocated	= qcow_is_allocated,
     .bdrv_set_key	= qcow_set_key,
     .bdrv_make_empty	= qcow_make_empty,
-    .bdrv_co_readv  = qcow_co_readv,
-    .bdrv_co_writev = qcow_co_writev,
-    .bdrv_aio_flush	= qcow_aio_flush,
+    .bdrv_co_readv      = qcow_co_readv,
+    .bdrv_co_writev     = qcow_co_writev,
+    .bdrv_co_flush      = qcow_co_flush,
     .bdrv_write_compressed = qcow_write_compressed,
     .bdrv_get_info	= qcow_get_info,
 
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 2f76311..f4e049f 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -568,8 +568,10 @@
     }
 
     cluster_offset = be64_to_cpu(l2_table[l2_index]);
-    if (cluster_offset & QCOW_OFLAG_COPIED)
-        return cluster_offset & ~QCOW_OFLAG_COPIED;
+    if (cluster_offset & QCOW_OFLAG_COPIED) {
+        qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
+        return 0;
+    }
 
     if (cluster_offset)
         qcow2_free_any_clusters(bs, cluster_offset, 1);
diff --git a/block/qcow2.c b/block/qcow2.c
index 510ff68..a181932 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -978,11 +978,17 @@
     return 0;
 }
 
-static int qcow2_discard(BlockDriverState *bs, int64_t sector_num,
-    int nb_sectors)
+static coroutine_fn int qcow2_co_discard(BlockDriverState *bs,
+    int64_t sector_num, int nb_sectors)
 {
-    return qcow2_discard_clusters(bs, sector_num << BDRV_SECTOR_BITS,
+    int ret;
+    BDRVQcowState *s = bs->opaque;
+
+    qemu_co_mutex_lock(&s->lock);
+    ret = qcow2_discard_clusters(bs, sector_num << BDRV_SECTOR_BITS,
         nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
 }
 
 static int qcow2_truncate(BlockDriverState *bs, int64_t offset)
@@ -1053,8 +1059,8 @@
                        Z_DEFLATED, -12,
                        9, Z_DEFAULT_STRATEGY);
     if (ret != 0) {
-        g_free(out_buf);
-        return -1;
+        ret = -EINVAL;
+        goto fail;
     }
 
     strm.avail_in = s->cluster_size;
@@ -1064,9 +1070,9 @@
 
     ret = deflate(&strm, Z_FINISH);
     if (ret != Z_STREAM_END && ret != Z_OK) {
-        g_free(out_buf);
         deflateEnd(&strm);
-        return -1;
+        ret = -EINVAL;
+        goto fail;
     }
     out_len = strm.next_out - out_buf;
 
@@ -1074,29 +1080,37 @@
 
     if (ret != Z_STREAM_END || out_len >= s->cluster_size) {
         /* could not compress: write normal cluster */
-        bdrv_write(bs, sector_num, buf, s->cluster_sectors);
+        ret = bdrv_write(bs, sector_num, buf, s->cluster_sectors);
+        if (ret < 0) {
+            goto fail;
+        }
     } else {
         cluster_offset = qcow2_alloc_compressed_cluster_offset(bs,
             sector_num << 9, out_len);
-        if (!cluster_offset)
-            return -1;
+        if (!cluster_offset) {
+            ret = -EIO;
+            goto fail;
+        }
         cluster_offset &= s->cluster_offset_mask;
         BLKDBG_EVENT(bs->file, BLKDBG_WRITE_COMPRESSED);
-        if (bdrv_pwrite(bs->file, cluster_offset, out_buf, out_len) != out_len) {
-            g_free(out_buf);
-            return -1;
+        ret = bdrv_pwrite(bs->file, cluster_offset, out_buf, out_len);
+        if (ret < 0) {
+            goto fail;
         }
     }
 
+    ret = 0;
+fail:
     g_free(out_buf);
-    return 0;
+    return ret;
 }
 
-static int qcow2_flush(BlockDriverState *bs)
+static int qcow2_co_flush(BlockDriverState *bs)
 {
     BDRVQcowState *s = bs->opaque;
     int ret;
 
+    qemu_co_mutex_lock(&s->lock);
     ret = qcow2_cache_flush(bs, s->l2_table_cache);
     if (ret < 0) {
         return ret;
@@ -1106,28 +1120,9 @@
     if (ret < 0) {
         return ret;
     }
+    qemu_co_mutex_unlock(&s->lock);
 
-    return bdrv_flush(bs->file);
-}
-
-static BlockDriverAIOCB *qcow2_aio_flush(BlockDriverState *bs,
-                                         BlockDriverCompletionFunc *cb,
-                                         void *opaque)
-{
-    BDRVQcowState *s = bs->opaque;
-    int ret;
-
-    ret = qcow2_cache_flush(bs, s->l2_table_cache);
-    if (ret < 0) {
-        return NULL;
-    }
-
-    ret = qcow2_cache_flush(bs, s->refcount_block_cache);
-    if (ret < 0) {
-        return NULL;
-    }
-
-    return bdrv_aio_flush(bs->file, cb, opaque);
+    return bdrv_co_flush(bs->file);
 }
 
 static int64_t qcow2_vm_state_offset(BDRVQcowState *s)
@@ -1242,16 +1237,15 @@
     .bdrv_open          = qcow2_open,
     .bdrv_close         = qcow2_close,
     .bdrv_create        = qcow2_create,
-    .bdrv_flush         = qcow2_flush,
     .bdrv_is_allocated  = qcow2_is_allocated,
     .bdrv_set_key       = qcow2_set_key,
     .bdrv_make_empty    = qcow2_make_empty,
 
     .bdrv_co_readv      = qcow2_co_readv,
     .bdrv_co_writev     = qcow2_co_writev,
-    .bdrv_aio_flush     = qcow2_aio_flush,
+    .bdrv_co_flush      = qcow2_co_flush,
 
-    .bdrv_discard           = qcow2_discard,
+    .bdrv_co_discard        = qcow2_co_discard,
     .bdrv_truncate          = qcow2_truncate,
     .bdrv_write_compressed  = qcow2_write_compressed,
 
diff --git a/block/qed.c b/block/qed.c
index e87dc4d..2e06992 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -533,11 +533,6 @@
     qemu_vfree(s->l1_table);
 }
 
-static int bdrv_qed_flush(BlockDriverState *bs)
-{
-    return bdrv_flush(bs->file);
-}
-
 static int qed_create(const char *filename, uint32_t cluster_size,
                       uint64_t image_size, uint32_t table_size,
                       const char *backing_file, const char *backing_fmt)
@@ -1479,7 +1474,6 @@
     .bdrv_open                = bdrv_qed_open,
     .bdrv_close               = bdrv_qed_close,
     .bdrv_create              = bdrv_qed_create,
-    .bdrv_flush               = bdrv_qed_flush,
     .bdrv_is_allocated        = bdrv_qed_is_allocated,
     .bdrv_make_empty          = bdrv_qed_make_empty,
     .bdrv_aio_readv           = bdrv_qed_aio_readv,
diff --git a/block/raw-posix.c b/block/raw-posix.c
index c7f5544..a3de373 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -583,19 +583,6 @@
     return result;
 }
 
-static int raw_flush(BlockDriverState *bs)
-{
-    BDRVRawState *s = bs->opaque;
-    int ret;
-
-    ret = qemu_fdatasync(s->fd);
-    if (ret < 0) {
-        return -errno;
-    }
-
-    return 0;
-}
-
 #ifdef CONFIG_XFS
 static int xfs_discard(BDRVRawState *s, int64_t sector_num, int nb_sectors)
 {
@@ -615,7 +602,8 @@
 }
 #endif
 
-static int raw_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors)
+static coroutine_fn int raw_co_discard(BlockDriverState *bs,
+    int64_t sector_num, int nb_sectors)
 {
 #ifdef CONFIG_XFS
     BDRVRawState *s = bs->opaque;
@@ -645,8 +633,7 @@
     .bdrv_file_open = raw_open,
     .bdrv_close = raw_close,
     .bdrv_create = raw_create,
-    .bdrv_flush = raw_flush,
-    .bdrv_discard = raw_discard,
+    .bdrv_co_discard = raw_co_discard,
 
     .bdrv_aio_readv = raw_aio_readv,
     .bdrv_aio_writev = raw_aio_writev,
@@ -915,7 +902,6 @@
     .bdrv_create        = hdev_create,
     .create_options     = raw_create_options,
     .bdrv_has_zero_init = hdev_has_zero_init,
-    .bdrv_flush         = raw_flush,
 
     .bdrv_aio_readv	= raw_aio_readv,
     .bdrv_aio_writev	= raw_aio_writev,
@@ -1035,7 +1021,6 @@
     .bdrv_create        = hdev_create,
     .create_options     = raw_create_options,
     .bdrv_has_zero_init = hdev_has_zero_init,
-    .bdrv_flush         = raw_flush,
 
     .bdrv_aio_readv     = raw_aio_readv,
     .bdrv_aio_writev    = raw_aio_writev,
@@ -1135,7 +1120,6 @@
     .bdrv_create        = hdev_create,
     .create_options     = raw_create_options,
     .bdrv_has_zero_init = hdev_has_zero_init,
-    .bdrv_flush         = raw_flush,
 
     .bdrv_aio_readv     = raw_aio_readv,
     .bdrv_aio_writev    = raw_aio_writev,
@@ -1255,7 +1239,6 @@
     .bdrv_create        = hdev_create,
     .create_options     = raw_create_options,
     .bdrv_has_zero_init = hdev_has_zero_init,
-    .bdrv_flush         = raw_flush,
 
     .bdrv_aio_readv     = raw_aio_readv,
     .bdrv_aio_writev    = raw_aio_writev,
diff --git a/block/raw-win32.c b/block/raw-win32.c
index b7dd357..f5f73bc 100644
--- a/block/raw-win32.c
+++ b/block/raw-win32.c
@@ -281,7 +281,7 @@
     .bdrv_file_open	= raw_open,
     .bdrv_close		= raw_close,
     .bdrv_create	= raw_create,
-    .bdrv_flush		= raw_flush,
+    .bdrv_co_flush      = raw_flush,
     .bdrv_read		= raw_read,
     .bdrv_write		= raw_write,
     .bdrv_truncate	= raw_truncate,
@@ -409,7 +409,7 @@
     .bdrv_probe_device	= hdev_probe_device,
     .bdrv_file_open	= hdev_open,
     .bdrv_close		= raw_close,
-    .bdrv_flush		= raw_flush,
+    .bdrv_co_flush      = raw_flush,
     .bdrv_has_zero_init = hdev_has_zero_init,
 
     .bdrv_read		= raw_read,
diff --git a/block/raw.c b/block/raw.c
index 5ca606b..33cc471 100644
--- a/block/raw.c
+++ b/block/raw.c
@@ -25,15 +25,9 @@
 {
 }
 
-static int raw_flush(BlockDriverState *bs)
+static int coroutine_fn raw_co_flush(BlockDriverState *bs)
 {
-    return bdrv_flush(bs->file);
-}
-
-static BlockDriverAIOCB *raw_aio_flush(BlockDriverState *bs,
-    BlockDriverCompletionFunc *cb, void *opaque)
-{
-    return bdrv_aio_flush(bs->file, cb, opaque);
+    return bdrv_co_flush(bs->file);
 }
 
 static int64_t raw_getlength(BlockDriverState *bs)
@@ -51,9 +45,10 @@
    return 1; /* everything can be opened as raw image */
 }
 
-static int raw_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors)
+static int coroutine_fn raw_co_discard(BlockDriverState *bs,
+                                       int64_t sector_num, int nb_sectors)
 {
-    return bdrv_discard(bs->file, sector_num, nb_sectors);
+    return bdrv_co_discard(bs->file, sector_num, nb_sectors);
 }
 
 static int raw_is_inserted(BlockDriverState *bs)
@@ -115,16 +110,16 @@
 
     .bdrv_open          = raw_open,
     .bdrv_close         = raw_close,
+
     .bdrv_co_readv      = raw_co_readv,
     .bdrv_co_writev     = raw_co_writev,
-    .bdrv_flush         = raw_flush,
+    .bdrv_co_flush      = raw_co_flush,
+    .bdrv_co_discard    = raw_co_discard,
+
     .bdrv_probe         = raw_probe,
     .bdrv_getlength     = raw_getlength,
     .bdrv_truncate      = raw_truncate,
 
-    .bdrv_aio_flush     = raw_aio_flush,
-    .bdrv_discard       = raw_discard,
-
     .bdrv_is_inserted   = raw_is_inserted,
     .bdrv_media_changed = raw_media_changed,
     .bdrv_eject         = raw_eject,
diff --git a/block/rbd.c b/block/rbd.c
index 3068c82..c684e0c 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -705,7 +705,7 @@
     return rbd_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
 }
 
-static int qemu_rbd_flush(BlockDriverState *bs)
+static int qemu_rbd_co_flush(BlockDriverState *bs)
 {
 #if LIBRBD_VERSION_CODE >= LIBRBD_VERSION(0, 1, 1)
     /* rbd_flush added in 0.1.1 */
@@ -851,7 +851,7 @@
     .bdrv_file_open     = qemu_rbd_open,
     .bdrv_close         = qemu_rbd_close,
     .bdrv_create        = qemu_rbd_create,
-    .bdrv_flush         = qemu_rbd_flush,
+    .bdrv_co_flush      = qemu_rbd_co_flush,
     .bdrv_get_info      = qemu_rbd_getinfo,
     .create_options     = qemu_rbd_create_options,
     .bdrv_getlength     = qemu_rbd_getlength,
diff --git a/block/sheepdog.c b/block/sheepdog.c
index ae857e2..9f80609 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -396,7 +396,7 @@
     return !QLIST_EMPTY(&acb->aioreq_head);
 }
 
-static void sd_finish_aiocb(SheepdogAIOCB *acb)
+static void coroutine_fn sd_finish_aiocb(SheepdogAIOCB *acb)
 {
     if (!acb->canceled) {
         qemu_coroutine_enter(acb->coroutine, NULL);
@@ -735,7 +735,7 @@
     return ret;
 }
 
-static int add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
+static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
                            struct iovec *iov, int niov, int create,
                            enum AIOCBState aiocb_type);
 
@@ -743,7 +743,7 @@
  * This function searchs pending requests to the object `oid', and
  * sends them.
  */
-static void send_pending_req(BDRVSheepdogState *s, uint64_t oid, uint32_t id)
+static void coroutine_fn send_pending_req(BDRVSheepdogState *s, uint64_t oid, uint32_t id)
 {
     AIOReq *aio_req, *next;
     SheepdogAIOCB *acb;
@@ -777,7 +777,7 @@
  * This function is registered as a fd handler, and called from the
  * main loop when s->fd is ready for reading responses.
  */
-static void aio_read_response(void *opaque)
+static void coroutine_fn aio_read_response(void *opaque)
 {
     SheepdogObjRsp rsp;
     BDRVSheepdogState *s = opaque;
@@ -1064,7 +1064,7 @@
     return ret;
 }
 
-static int add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
+static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
                            struct iovec *iov, int niov, int create,
                            enum AIOCBState aiocb_type)
 {
@@ -1517,7 +1517,7 @@
  * update metadata, this sends a write request to the vdi object.
  * Otherwise, this switches back to sd_co_readv/writev.
  */
-static void sd_write_done(SheepdogAIOCB *acb)
+static void coroutine_fn sd_write_done(SheepdogAIOCB *acb)
 {
     int ret;
     BDRVSheepdogState *s = acb->common.bs->opaque;
@@ -1615,7 +1615,7 @@
  * Returns 1 when we need to wait a response, 0 when there is no sent
  * request and -errno in error cases.
  */
-static int sd_co_rw_vector(void *p)
+static int coroutine_fn sd_co_rw_vector(void *p)
 {
     SheepdogAIOCB *acb = p;
     int ret = 0;
diff --git a/block/vdi.c b/block/vdi.c
index 1d5ad2b..883046d 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -936,10 +936,10 @@
 {
 }
 
-static int vdi_flush(BlockDriverState *bs)
+static coroutine_fn int vdi_co_flush(BlockDriverState *bs)
 {
     logout("\n");
-    return bdrv_flush(bs->file);
+    return bdrv_co_flush(bs->file);
 }
 
 
@@ -975,7 +975,7 @@
     .bdrv_open = vdi_open,
     .bdrv_close = vdi_close,
     .bdrv_create = vdi_create,
-    .bdrv_flush = vdi_flush,
+    .bdrv_co_flush = vdi_co_flush,
     .bdrv_is_allocated = vdi_is_allocated,
     .bdrv_make_empty = vdi_make_empty,
 
diff --git a/block/vmdk.c b/block/vmdk.c
index 5d16ec4..6be592f 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -90,6 +90,7 @@
 } VmdkExtent;
 
 typedef struct BDRVVmdkState {
+    CoMutex lock;
     int desc_offset;
     bool cid_updated;
     uint32_t parent_cid;
@@ -283,10 +284,12 @@
     char *p_name;
     char desc[DESC_SIZE + 1];
     BDRVVmdkState *s = bs->opaque;
+    int ret;
 
     desc[DESC_SIZE] = '\0';
-    if (bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE) != DESC_SIZE) {
-        return -1;
+    ret = bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE);
+    if (ret < 0) {
+        return ret;
     }
 
     p_name = strstr(desc, "parentFileNameHint");
@@ -296,10 +299,10 @@
         p_name += sizeof("parentFileNameHint") + 1;
         end_name = strchr(p_name, '\"');
         if (end_name == NULL) {
-            return -1;
+            return -EINVAL;
         }
         if ((end_name - p_name) > sizeof(bs->backing_file) - 1) {
-            return -1;
+            return -EINVAL;
         }
 
         pstrcpy(bs->backing_file, end_name - p_name + 1, p_name);
@@ -622,19 +625,7 @@
         return -ENOTSUP;
     }
     s->desc_offset = 0;
-    ret = vmdk_parse_extents(buf, bs, bs->file->filename);
-    if (ret) {
-        vmdk_free_extents(bs);
-        return ret;
-    }
-
-    /* try to open parent images, if exist */
-    if (vmdk_parent_open(bs)) {
-        vmdk_free_extents(bs);
-        return -EINVAL;
-    }
-    s->parent_cid = vmdk_read_cid(bs, 1);
-    return 0;
+    return vmdk_parse_extents(buf, bs, bs->file->filename);
 }
 
 static int vmdk_open(BlockDriverState *bs, int flags)
@@ -644,17 +635,24 @@
 
     if (vmdk_open_sparse(bs, bs->file, flags) == 0) {
         s->desc_offset = 0x200;
-        /* try to open parent images, if exist */
-        ret = vmdk_parent_open(bs);
-        if (ret) {
-            vmdk_free_extents(bs);
-            return ret;
-        }
-        s->parent_cid = vmdk_read_cid(bs, 1);
-        return 0;
     } else {
-        return vmdk_open_desc_file(bs, flags, 0);
+        ret = vmdk_open_desc_file(bs, flags, 0);
+        if (ret) {
+            goto fail;
+        }
     }
+    /* try to open parent images, if exist */
+    ret = vmdk_parent_open(bs);
+    if (ret) {
+        goto fail;
+    }
+    s->parent_cid = vmdk_read_cid(bs, 1);
+    qemu_co_mutex_init(&s->lock);
+    return ret;
+
+fail:
+    vmdk_free_extents(bs);
+    return ret;
 }
 
 static int get_whole_cluster(BlockDriverState *bs,
@@ -1026,6 +1024,17 @@
     return 0;
 }
 
+static coroutine_fn int vmdk_co_read(BlockDriverState *bs, int64_t sector_num,
+                                     uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVVmdkState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = vmdk_read(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
 static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
                      const uint8_t *buf, int nb_sectors)
 {
@@ -1107,6 +1116,17 @@
     return 0;
 }
 
+static coroutine_fn int vmdk_co_write(BlockDriverState *bs, int64_t sector_num,
+                                      const uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVVmdkState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = vmdk_write(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
 
 static int vmdk_create_extent(const char *filename, int64_t filesize,
                               bool flat, bool compress)
@@ -1474,14 +1494,14 @@
     vmdk_free_extents(bs);
 }
 
-static int vmdk_flush(BlockDriverState *bs)
+static coroutine_fn int vmdk_co_flush(BlockDriverState *bs)
 {
     int i, ret, err;
     BDRVVmdkState *s = bs->opaque;
 
-    ret = bdrv_flush(bs->file);
+    ret = bdrv_co_flush(bs->file);
     for (i = 0; i < s->num_extents; i++) {
-        err = bdrv_flush(s->extents[i].file);
+        err = bdrv_co_flush(s->extents[i].file);
         if (err < 0) {
             ret = err;
         }
@@ -1544,11 +1564,11 @@
     .instance_size  = sizeof(BDRVVmdkState),
     .bdrv_probe     = vmdk_probe,
     .bdrv_open      = vmdk_open,
-    .bdrv_read      = vmdk_read,
-    .bdrv_write     = vmdk_write,
+    .bdrv_read      = vmdk_co_read,
+    .bdrv_write     = vmdk_co_write,
     .bdrv_close     = vmdk_close,
     .bdrv_create    = vmdk_create,
-    .bdrv_flush     = vmdk_flush,
+    .bdrv_co_flush  = vmdk_co_flush,
     .bdrv_is_allocated  = vmdk_is_allocated,
     .bdrv_get_allocated_file_size  = vmdk_get_allocated_file_size,
 
diff --git a/block/vpc.c b/block/vpc.c
index cb6c570..79be7d0 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -110,6 +110,7 @@
 };
 
 typedef struct BDRVVPCState {
+    CoMutex lock;
     uint8_t footer_buf[HEADER_SIZE];
     uint64_t free_data_block_offset;
     int max_table_entries;
@@ -226,6 +227,7 @@
     s->last_pagetable = -1;
 #endif
 
+    qemu_co_mutex_init(&s->lock);
     return 0;
  fail:
     return err;
@@ -407,6 +409,17 @@
     return 0;
 }
 
+static coroutine_fn int vpc_co_read(BlockDriverState *bs, int64_t sector_num,
+                                    uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVVPCState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = vpc_read(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
 static int vpc_write(BlockDriverState *bs, int64_t sector_num,
     const uint8_t *buf, int nb_sectors)
 {
@@ -443,9 +456,20 @@
     return 0;
 }
 
-static int vpc_flush(BlockDriverState *bs)
+static coroutine_fn int vpc_co_write(BlockDriverState *bs, int64_t sector_num,
+                                     const uint8_t *buf, int nb_sectors)
 {
-    return bdrv_flush(bs->file);
+    int ret;
+    BDRVVPCState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = vpc_write(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
+static coroutine_fn int vpc_co_flush(BlockDriverState *bs)
+{
+    return bdrv_co_flush(bs->file);
 }
 
 /*
@@ -639,9 +663,9 @@
     .instance_size  = sizeof(BDRVVPCState),
     .bdrv_probe     = vpc_probe,
     .bdrv_open      = vpc_open,
-    .bdrv_read      = vpc_read,
-    .bdrv_write     = vpc_write,
-    .bdrv_flush     = vpc_flush,
+    .bdrv_read      = vpc_co_read,
+    .bdrv_write     = vpc_co_write,
+    .bdrv_co_flush  = vpc_co_flush,
     .bdrv_close     = vpc_close,
     .bdrv_create    = vpc_create,
 
diff --git a/block/vvfat.c b/block/vvfat.c
index 7e9e35a..e1fcdbc 100644
--- a/block/vvfat.c
+++ b/block/vvfat.c
@@ -317,6 +317,7 @@
 /* here begins the real VVFAT driver */
 
 typedef struct BDRVVVFATState {
+    CoMutex lock;
     BlockDriverState* bs; /* pointer to parent */
     unsigned int first_sectors_number; /* 1 for a single partition, 0x40 for a disk with partition table */
     unsigned char first_sectors[0x40*0x200];
@@ -1065,6 +1066,7 @@
 	bs->heads = bs->cyls = bs->secs = 0;
 
     //    assert(is_consistent(s));
+    qemu_co_mutex_init(&s->lock);
     return 0;
 }
 
@@ -1279,6 +1281,17 @@
     return 0;
 }
 
+static coroutine_fn int vvfat_co_read(BlockDriverState *bs, int64_t sector_num,
+                                      uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVVVFATState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = vvfat_read(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
 /* LATER TODO: statify all functions */
 
 /*
@@ -2714,6 +2727,17 @@
     return 0;
 }
 
+static coroutine_fn int vvfat_co_write(BlockDriverState *bs, int64_t sector_num,
+                                       const uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVVVFATState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = vvfat_write(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
 static int vvfat_is_allocated(BlockDriverState *bs,
 	int64_t sector_num, int nb_sectors, int* n)
 {
@@ -2803,8 +2827,8 @@
     .format_name	= "vvfat",
     .instance_size	= sizeof(BDRVVVFATState),
     .bdrv_file_open	= vvfat_open,
-    .bdrv_read		= vvfat_read,
-    .bdrv_write		= vvfat_write,
+    .bdrv_read          = vvfat_co_read,
+    .bdrv_write         = vvfat_co_write,
     .bdrv_close		= vvfat_close,
     .bdrv_is_allocated	= vvfat_is_allocated,
     .protocol_name	= "fat",
diff --git a/block_int.h b/block_int.h
index f2f4f2d..dac00f5 100644
--- a/block_int.h
+++ b/block_int.h
@@ -62,7 +62,6 @@
                       const uint8_t *buf, int nb_sectors);
     void (*bdrv_close)(BlockDriverState *bs);
     int (*bdrv_create)(const char *filename, QEMUOptionParameter *options);
-    int (*bdrv_flush)(BlockDriverState *bs);
     int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num,
                              int nb_sectors, int *pnum);
     int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
@@ -76,13 +75,17 @@
         BlockDriverCompletionFunc *cb, void *opaque);
     BlockDriverAIOCB *(*bdrv_aio_flush)(BlockDriverState *bs,
         BlockDriverCompletionFunc *cb, void *opaque);
-    int (*bdrv_discard)(BlockDriverState *bs, int64_t sector_num,
-                        int nb_sectors);
+    BlockDriverAIOCB *(*bdrv_aio_discard)(BlockDriverState *bs,
+        int64_t sector_num, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque);
 
     int coroutine_fn (*bdrv_co_readv)(BlockDriverState *bs,
         int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
     int coroutine_fn (*bdrv_co_writev)(BlockDriverState *bs,
         int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
+    int coroutine_fn (*bdrv_co_flush)(BlockDriverState *bs);
+    int coroutine_fn (*bdrv_co_discard)(BlockDriverState *bs,
+        int64_t sector_num, int nb_sectors);
 
     int (*bdrv_aio_multiwrite)(BlockDriverState *bs, BlockRequest *reqs,
         int num_reqs);
diff --git a/buffered_file.c b/buffered_file.c
index 486af57..fed9a22 100644
--- a/buffered_file.c
+++ b/buffered_file.c
@@ -27,7 +27,6 @@
     BufferedCloseFunc *close;
     void *opaque;
     QEMUFile *file;
-    int has_error;
     int freeze_output;
     size_t bytes_xfer;
     size_t xfer_limit;
@@ -72,9 +71,11 @@
 static void buffered_flush(QEMUFileBuffered *s)
 {
     size_t offset = 0;
+    int error;
 
-    if (s->has_error) {
-        DPRINTF("flush when error, bailing\n");
+    error = qemu_file_get_error(s->file);
+    if (error != 0) {
+        DPRINTF("flush when error, bailing: %s\n", strerror(-error));
         return;
     }
 
@@ -93,7 +94,7 @@
 
         if (ret <= 0) {
             DPRINTF("error flushing data, %zd\n", ret);
-            s->has_error = 1;
+            qemu_file_set_error(s->file, ret);
             break;
         } else {
             DPRINTF("flushed %zd byte(s)\n", ret);
@@ -109,14 +110,15 @@
 static int buffered_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size)
 {
     QEMUFileBuffered *s = opaque;
-    int offset = 0;
+    int offset = 0, error;
     ssize_t ret;
 
     DPRINTF("putting %d bytes at %" PRId64 "\n", size, pos);
 
-    if (s->has_error) {
-        DPRINTF("flush when error, bailing\n");
-        return -EINVAL;
+    error = qemu_file_get_error(s->file);
+    if (error) {
+        DPRINTF("flush when error, bailing: %s\n", strerror(-error));
+        return error;
     }
 
     DPRINTF("unfreezing output\n");
@@ -139,7 +141,7 @@
 
         if (ret <= 0) {
             DPRINTF("error putting\n");
-            s->has_error = 1;
+            qemu_file_set_error(s->file, ret);
             offset = -EINVAL;
             break;
         }
@@ -173,10 +175,10 @@
 
     DPRINTF("closing\n");
 
-    while (!s->has_error && s->buffer_size) {
+    while (!qemu_file_get_error(s->file) && s->buffer_size) {
         buffered_flush(s);
         if (s->freeze_output)
-            s->wait_for_unfreeze(s);
+            s->wait_for_unfreeze(s->opaque);
     }
 
     ret = s->close(s->opaque);
@@ -189,13 +191,21 @@
     return ret;
 }
 
+/*
+ * The meaning of the return values is:
+ *   0: We can continue sending
+ *   1: Time to stop
+ *   negative: There has been an error
+ */
 static int buffered_rate_limit(void *opaque)
 {
     QEMUFileBuffered *s = opaque;
+    int ret;
 
-    if (s->has_error)
-        return 0;
-
+    ret = qemu_file_get_error(s->file);
+    if (ret) {
+        return ret;
+    }
     if (s->freeze_output)
         return 1;
 
@@ -208,9 +218,9 @@
 static int64_t buffered_set_rate_limit(void *opaque, int64_t new_rate)
 {
     QEMUFileBuffered *s = opaque;
-    if (s->has_error)
+    if (qemu_file_get_error(s->file)) {
         goto out;
-
+    }
     if (new_rate > SIZE_MAX) {
         new_rate = SIZE_MAX;
     }
@@ -232,7 +242,7 @@
 {
     QEMUFileBuffered *s = opaque;
 
-    if (s->has_error) {
+    if (qemu_file_get_error(s->file)) {
         buffered_close(s);
         return;
     }
diff --git a/compatfd.c b/compatfd.c
index 31654c6..02306a4 100644
--- a/compatfd.c
+++ b/compatfd.c
@@ -119,9 +119,17 @@
 bool qemu_signalfd_available(void)
 {
 #ifdef CONFIG_SIGNALFD
+    sigset_t mask;
+    int fd;
+    bool ok;
+    sigemptyset(&mask);
     errno = 0;
-    syscall(SYS_signalfd, -1, NULL, _NSIG / 8);
-    return errno != ENOSYS;
+    fd = syscall(SYS_signalfd, -1, &mask, _NSIG / 8);
+    ok = (errno != ENOSYS);
+    if (fd >= 0) {
+        close(fd);
+    }
+    return ok;
 #else
     return false;
 #endif
diff --git a/configure b/configure
index 9b4fe34..4f87e0a 100755
--- a/configure
+++ b/configure
@@ -2557,6 +2557,31 @@
 fi
 
 ##########################################
+# check if we have open_by_handle_at
+
+open_by_hande_at=no
+cat > $TMPC << EOF
+#include <fcntl.h>
+int main(void) { struct file_handle *fh; open_by_handle_at(0, fh, 0); }
+EOF
+if compile_prog "" "" ; then
+    open_by_handle_at=yes
+fi
+
+########################################
+# check if we have linux/magic.h
+
+linux_magic_h=no
+cat > $TMPC << EOF
+#include <linux/magic.h>
+int main(void) {
+}
+EOF
+if compile_prog "" "" ; then
+    linux_magic_h=yes
+fi
+
+##########################################
 # End of CC checks
 # After here, no more $cc or $ld runs
 
@@ -3035,6 +3060,14 @@
   echo "CONFIG_UCONTEXT_COROUTINE=y" >> $config_host_mak
 fi
 
+if test "$open_by_handle_at" = "yes" ; then
+  echo "CONFIG_OPEN_BY_HANDLE=y" >> $config_host_mak
+fi
+
+if test "$linux_magic_h" = "yes" ; then
+  echo "CONFIG_LINUX_MAGIC_H=y" >> $config_host_mak
+fi
+
 # USB host support
 case "$usb" in
 linux)
diff --git a/cpus.c b/cpus.c
index 8978779..79a7656 100644
--- a/cpus.c
+++ b/cpus.c
@@ -33,17 +33,12 @@
 
 #include "qemu-thread.h"
 #include "cpus.h"
+#include "main-loop.h"
 
 #ifndef _WIN32
 #include "compatfd.h"
 #endif
 
-#ifdef SIGRTMIN
-#define SIG_IPI (SIGRTMIN+4)
-#else
-#define SIG_IPI SIGUSR1
-#endif
-
 #ifdef CONFIG_LINUX
 
 #include <sys/prctl.h>
@@ -65,6 +60,281 @@
 static CPUState *next_cpu;
 
 /***********************************************************/
+/* guest cycle counter */
+
+/* Conversion factor from emulated instructions to virtual clock ticks.  */
+static int icount_time_shift;
+/* Arbitrarily pick 1MIPS as the minimum allowable speed.  */
+#define MAX_ICOUNT_SHIFT 10
+/* Compensate for varying guest execution speed.  */
+static int64_t qemu_icount_bias;
+static QEMUTimer *icount_rt_timer;
+static QEMUTimer *icount_vm_timer;
+static QEMUTimer *icount_warp_timer;
+static int64_t vm_clock_warp_start;
+static int64_t qemu_icount;
+
+typedef struct TimersState {
+    int64_t cpu_ticks_prev;
+    int64_t cpu_ticks_offset;
+    int64_t cpu_clock_offset;
+    int32_t cpu_ticks_enabled;
+    int64_t dummy;
+} TimersState;
+
+TimersState timers_state;
+
+/* Return the virtual CPU time, based on the instruction counter.  */
+int64_t cpu_get_icount(void)
+{
+    int64_t icount;
+    CPUState *env = cpu_single_env;;
+
+    icount = qemu_icount;
+    if (env) {
+        if (!can_do_io(env)) {
+            fprintf(stderr, "Bad clock read\n");
+        }
+        icount -= (env->icount_decr.u16.low + env->icount_extra);
+    }
+    return qemu_icount_bias + (icount << icount_time_shift);
+}
+
+/* return the host CPU cycle counter and handle stop/restart */
+int64_t cpu_get_ticks(void)
+{
+    if (use_icount) {
+        return cpu_get_icount();
+    }
+    if (!timers_state.cpu_ticks_enabled) {
+        return timers_state.cpu_ticks_offset;
+    } else {
+        int64_t ticks;
+        ticks = cpu_get_real_ticks();
+        if (timers_state.cpu_ticks_prev > ticks) {
+            /* Note: non increasing ticks may happen if the host uses
+               software suspend */
+            timers_state.cpu_ticks_offset += timers_state.cpu_ticks_prev - ticks;
+        }
+        timers_state.cpu_ticks_prev = ticks;
+        return ticks + timers_state.cpu_ticks_offset;
+    }
+}
+
+/* return the host CPU monotonic timer and handle stop/restart */
+int64_t cpu_get_clock(void)
+{
+    int64_t ti;
+    if (!timers_state.cpu_ticks_enabled) {
+        return timers_state.cpu_clock_offset;
+    } else {
+        ti = get_clock();
+        return ti + timers_state.cpu_clock_offset;
+    }
+}
+
+/* enable cpu_get_ticks() */
+void cpu_enable_ticks(void)
+{
+    if (!timers_state.cpu_ticks_enabled) {
+        timers_state.cpu_ticks_offset -= cpu_get_real_ticks();
+        timers_state.cpu_clock_offset -= get_clock();
+        timers_state.cpu_ticks_enabled = 1;
+    }
+}
+
+/* disable cpu_get_ticks() : the clock is stopped. You must not call
+   cpu_get_ticks() after that.  */
+void cpu_disable_ticks(void)
+{
+    if (timers_state.cpu_ticks_enabled) {
+        timers_state.cpu_ticks_offset = cpu_get_ticks();
+        timers_state.cpu_clock_offset = cpu_get_clock();
+        timers_state.cpu_ticks_enabled = 0;
+    }
+}
+
+/* Correlation between real and virtual time is always going to be
+   fairly approximate, so ignore small variation.
+   When the guest is idle real and virtual time will be aligned in
+   the IO wait loop.  */
+#define ICOUNT_WOBBLE (get_ticks_per_sec() / 10)
+
+static void icount_adjust(void)
+{
+    int64_t cur_time;
+    int64_t cur_icount;
+    int64_t delta;
+    static int64_t last_delta;
+    /* If the VM is not running, then do nothing.  */
+    if (!runstate_is_running()) {
+        return;
+    }
+    cur_time = cpu_get_clock();
+    cur_icount = qemu_get_clock_ns(vm_clock);
+    delta = cur_icount - cur_time;
+    /* FIXME: This is a very crude algorithm, somewhat prone to oscillation.  */
+    if (delta > 0
+        && last_delta + ICOUNT_WOBBLE < delta * 2
+        && icount_time_shift > 0) {
+        /* The guest is getting too far ahead.  Slow time down.  */
+        icount_time_shift--;
+    }
+    if (delta < 0
+        && last_delta - ICOUNT_WOBBLE > delta * 2
+        && icount_time_shift < MAX_ICOUNT_SHIFT) {
+        /* The guest is getting too far behind.  Speed time up.  */
+        icount_time_shift++;
+    }
+    last_delta = delta;
+    qemu_icount_bias = cur_icount - (qemu_icount << icount_time_shift);
+}
+
+static void icount_adjust_rt(void *opaque)
+{
+    qemu_mod_timer(icount_rt_timer,
+                   qemu_get_clock_ms(rt_clock) + 1000);
+    icount_adjust();
+}
+
+static void icount_adjust_vm(void *opaque)
+{
+    qemu_mod_timer(icount_vm_timer,
+                   qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 10);
+    icount_adjust();
+}
+
+static int64_t qemu_icount_round(int64_t count)
+{
+    return (count + (1 << icount_time_shift) - 1) >> icount_time_shift;
+}
+
+static void icount_warp_rt(void *opaque)
+{
+    if (vm_clock_warp_start == -1) {
+        return;
+    }
+
+    if (runstate_is_running()) {
+        int64_t clock = qemu_get_clock_ns(rt_clock);
+        int64_t warp_delta = clock - vm_clock_warp_start;
+        if (use_icount == 1) {
+            qemu_icount_bias += warp_delta;
+        } else {
+            /*
+             * In adaptive mode, do not let the vm_clock run too
+             * far ahead of real time.
+             */
+            int64_t cur_time = cpu_get_clock();
+            int64_t cur_icount = qemu_get_clock_ns(vm_clock);
+            int64_t delta = cur_time - cur_icount;
+            qemu_icount_bias += MIN(warp_delta, delta);
+        }
+        if (qemu_clock_expired(vm_clock)) {
+            qemu_notify_event();
+        }
+    }
+    vm_clock_warp_start = -1;
+}
+
+void qemu_clock_warp(QEMUClock *clock)
+{
+    int64_t deadline;
+
+    /*
+     * There are too many global variables to make the "warp" behavior
+     * applicable to other clocks.  But a clock argument removes the
+     * need for if statements all over the place.
+     */
+    if (clock != vm_clock || !use_icount) {
+        return;
+    }
+
+    /*
+     * If the CPUs have been sleeping, advance the vm_clock timer now.  This
+     * ensures that the deadline for the timer is computed correctly below.
+     * This also makes sure that the insn counter is synchronized before the
+     * CPU starts running, in case the CPU is woken by an event other than
+     * the earliest vm_clock timer.
+     */
+    icount_warp_rt(NULL);
+    if (!all_cpu_threads_idle() || !qemu_clock_has_timers(vm_clock)) {
+        qemu_del_timer(icount_warp_timer);
+        return;
+    }
+
+    vm_clock_warp_start = qemu_get_clock_ns(rt_clock);
+    deadline = qemu_clock_deadline(vm_clock);
+    if (deadline > 0) {
+        /*
+         * Ensure the vm_clock proceeds even when the virtual CPU goes to
+         * sleep.  Otherwise, the CPU might be waiting for a future timer
+         * interrupt to wake it up, but the interrupt never comes because
+         * the vCPU isn't running any insns and thus doesn't advance the
+         * vm_clock.
+         *
+         * An extreme solution for this problem would be to never let VCPUs
+         * sleep in icount mode if there is a pending vm_clock timer; rather
+         * time could just advance to the next vm_clock event.  Instead, we
+         * do stop VCPUs and only advance vm_clock after some "real" time,
+         * (related to the time left until the next event) has passed.  This
+         * rt_clock timer will do this.  This avoids that the warps are too
+         * visible externally---for example, you will not be sending network
+         * packets continously instead of every 100ms.
+         */
+        qemu_mod_timer(icount_warp_timer, vm_clock_warp_start + deadline);
+    } else {
+        qemu_notify_event();
+    }
+}
+
+static const VMStateDescription vmstate_timers = {
+    .name = "timer",
+    .version_id = 2,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_INT64(cpu_ticks_offset, TimersState),
+        VMSTATE_INT64(dummy, TimersState),
+        VMSTATE_INT64_V(cpu_clock_offset, TimersState, 2),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+void configure_icount(const char *option)
+{
+    vmstate_register(NULL, 0, &vmstate_timers, &timers_state);
+    if (!option) {
+        return;
+    }
+
+    icount_warp_timer = qemu_new_timer_ns(rt_clock, icount_warp_rt, NULL);
+    if (strcmp(option, "auto") != 0) {
+        icount_time_shift = strtol(option, NULL, 0);
+        use_icount = 1;
+        return;
+    }
+
+    use_icount = 2;
+
+    /* 125MIPS seems a reasonable initial guess at the guest speed.
+       It will be corrected fairly quickly anyway.  */
+    icount_time_shift = 3;
+
+    /* Have both realtime and virtual time triggers for speed adjustment.
+       The realtime trigger catches emulated time passing too slowly,
+       the virtual time trigger catches emulated time passing too fast.
+       Realtime triggers occur even when idle, so use them less frequently
+       than VM triggers.  */
+    icount_rt_timer = qemu_new_timer_ms(rt_clock, icount_adjust_rt, NULL);
+    qemu_mod_timer(icount_rt_timer,
+                   qemu_get_clock_ms(rt_clock) + 1000);
+    icount_vm_timer = qemu_new_timer_ns(vm_clock, icount_adjust_vm, NULL);
+    qemu_mod_timer(icount_vm_timer,
+                   qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 10);
+}
+
+/***********************************************************/
 void hw_error(const char *fmt, ...)
 {
     va_list ap;
@@ -272,143 +542,10 @@
 #endif /* !CONFIG_LINUX */
 
 #ifndef _WIN32
-static int io_thread_fd = -1;
-
-static void qemu_event_increment(void)
-{
-    /* Write 8 bytes to be compatible with eventfd.  */
-    static const uint64_t val = 1;
-    ssize_t ret;
-
-    if (io_thread_fd == -1) {
-        return;
-    }
-    do {
-        ret = write(io_thread_fd, &val, sizeof(val));
-    } while (ret < 0 && errno == EINTR);
-
-    /* EAGAIN is fine, a read must be pending.  */
-    if (ret < 0 && errno != EAGAIN) {
-        fprintf(stderr, "qemu_event_increment: write() failed: %s\n",
-                strerror(errno));
-        exit (1);
-    }
-}
-
-static void qemu_event_read(void *opaque)
-{
-    int fd = (intptr_t)opaque;
-    ssize_t len;
-    char buffer[512];
-
-    /* Drain the notify pipe.  For eventfd, only 8 bytes will be read.  */
-    do {
-        len = read(fd, buffer, sizeof(buffer));
-    } while ((len == -1 && errno == EINTR) || len == sizeof(buffer));
-}
-
-static int qemu_event_init(void)
-{
-    int err;
-    int fds[2];
-
-    err = qemu_eventfd(fds);
-    if (err == -1) {
-        return -errno;
-    }
-    err = fcntl_setfl(fds[0], O_NONBLOCK);
-    if (err < 0) {
-        goto fail;
-    }
-    err = fcntl_setfl(fds[1], O_NONBLOCK);
-    if (err < 0) {
-        goto fail;
-    }
-    qemu_set_fd_handler2(fds[0], NULL, qemu_event_read, NULL,
-                         (void *)(intptr_t)fds[0]);
-
-    io_thread_fd = fds[1];
-    return 0;
-
-fail:
-    close(fds[0]);
-    close(fds[1]);
-    return err;
-}
-
 static void dummy_signal(int sig)
 {
 }
 
-/* If we have signalfd, we mask out the signals we want to handle and then
- * use signalfd to listen for them.  We rely on whatever the current signal
- * handler is to dispatch the signals when we receive them.
- */
-static void sigfd_handler(void *opaque)
-{
-    int fd = (intptr_t)opaque;
-    struct qemu_signalfd_siginfo info;
-    struct sigaction action;
-    ssize_t len;
-
-    while (1) {
-        do {
-            len = read(fd, &info, sizeof(info));
-        } while (len == -1 && errno == EINTR);
-
-        if (len == -1 && errno == EAGAIN) {
-            break;
-        }
-
-        if (len != sizeof(info)) {
-            printf("read from sigfd returned %zd: %m\n", len);
-            return;
-        }
-
-        sigaction(info.ssi_signo, NULL, &action);
-        if ((action.sa_flags & SA_SIGINFO) && action.sa_sigaction) {
-            action.sa_sigaction(info.ssi_signo,
-                                (siginfo_t *)&info, NULL);
-        } else if (action.sa_handler) {
-            action.sa_handler(info.ssi_signo);
-        }
-    }
-}
-
-static int qemu_signal_init(void)
-{
-    int sigfd;
-    sigset_t set;
-
-    /*
-     * SIG_IPI must be blocked in the main thread and must not be caught
-     * by sigwait() in the signal thread. Otherwise, the cpu thread will
-     * not catch it reliably.
-     */
-    sigemptyset(&set);
-    sigaddset(&set, SIG_IPI);
-    pthread_sigmask(SIG_BLOCK, &set, NULL);
-
-    sigemptyset(&set);
-    sigaddset(&set, SIGIO);
-    sigaddset(&set, SIGALRM);
-    sigaddset(&set, SIGBUS);
-    pthread_sigmask(SIG_BLOCK, &set, NULL);
-
-    sigfd = qemu_signalfd(&set);
-    if (sigfd == -1) {
-        fprintf(stderr, "failed to create signalfd\n");
-        return -errno;
-    }
-
-    fcntl_setfl(sigfd, O_NONBLOCK);
-
-    qemu_set_fd_handler2(sigfd, NULL, sigfd_handler, NULL,
-                         (void *)(intptr_t)sigfd);
-
-    return 0;
-}
-
 static void qemu_kvm_init_cpu_signals(CPUState *env)
 {
     int r;
@@ -452,38 +589,6 @@
 }
 
 #else /* _WIN32 */
-
-HANDLE qemu_event_handle;
-
-static void dummy_event_handler(void *opaque)
-{
-}
-
-static int qemu_event_init(void)
-{
-    qemu_event_handle = CreateEvent(NULL, FALSE, FALSE, NULL);
-    if (!qemu_event_handle) {
-        fprintf(stderr, "Failed CreateEvent: %ld\n", GetLastError());
-        return -1;
-    }
-    qemu_add_wait_object(qemu_event_handle, dummy_event_handler, NULL);
-    return 0;
-}
-
-static void qemu_event_increment(void)
-{
-    if (!SetEvent(qemu_event_handle)) {
-        fprintf(stderr, "qemu_event_increment: SetEvent failed: %ld\n",
-                GetLastError());
-        exit (1);
-    }
-}
-
-static int qemu_signal_init(void)
-{
-    return 0;
-}
-
 static void qemu_kvm_init_cpu_signals(CPUState *env)
 {
     abort();
@@ -509,38 +614,16 @@
 static QemuCond qemu_pause_cond;
 static QemuCond qemu_work_cond;
 
-int qemu_init_main_loop(void)
+void qemu_init_cpu_loop(void)
 {
-    int ret;
-
     qemu_init_sigbus();
-
-    ret = qemu_signal_init();
-    if (ret) {
-        return ret;
-    }
-
-    /* Note eventfd must be drained before signalfd handlers run */
-    ret = qemu_event_init();
-    if (ret) {
-        return ret;
-    }
-
     qemu_cond_init(&qemu_cpu_cond);
     qemu_cond_init(&qemu_pause_cond);
     qemu_cond_init(&qemu_work_cond);
     qemu_cond_init(&qemu_io_proceeded_cond);
     qemu_mutex_init(&qemu_global_mutex);
-    qemu_mutex_lock(&qemu_global_mutex);
 
     qemu_thread_get_self(&io_thread);
-
-    return 0;
-}
-
-void qemu_main_loop_start(void)
-{
-    resume_all_vcpus();
 }
 
 void run_on_cpu(CPUState *env, void (*func)(void *data), void *data)
@@ -686,7 +769,7 @@
 
     while (1) {
         cpu_exec_all();
-        if (use_icount && qemu_next_icount_deadline() <= 0) {
+        if (use_icount && qemu_clock_deadline(vm_clock) <= 0) {
             qemu_notify_event();
         }
         qemu_tcg_wait_io_event();
@@ -784,6 +867,7 @@
 {
     CPUState *penv = first_cpu;
 
+    qemu_clock_enable(vm_clock, false);
     while (penv) {
         penv->stop = 1;
         qemu_cpu_kick(penv);
@@ -858,11 +942,6 @@
     }
 }
 
-void qemu_notify_event(void)
-{
-    qemu_event_increment();
-}
-
 void cpu_stop_current(void)
 {
     if (cpu_single_env) {
@@ -887,6 +966,17 @@
     do_vm_stop(state);
 }
 
+/* does a state transition even if the VM is already stopped,
+   current state is forgotten forever */
+void vm_stop_force_state(RunState state)
+{
+    if (runstate_is_running()) {
+        vm_stop(state);
+    } else {
+        runstate_set(state);
+    }
+}
+
 static int tcg_cpu_exec(CPUState *env)
 {
     int ret;
@@ -903,7 +993,7 @@
         qemu_icount -= (env->icount_decr.u16.low + env->icount_extra);
         env->icount_decr.u16.low = 0;
         env->icount_extra = 0;
-        count = qemu_icount_round(qemu_next_icount_deadline());
+        count = qemu_icount_round(qemu_clock_deadline(vm_clock));
         qemu_icount += count;
         decr = (count > 0xffff) ? 0xffff : count;
         count -= decr;
@@ -995,22 +1085,6 @@
     cpu_set_log_filename(optarg);
 }
 
-/* Return the virtual CPU time, based on the instruction counter.  */
-int64_t cpu_get_icount(void)
-{
-    int64_t icount;
-    CPUState *env = cpu_single_env;;
-
-    icount = qemu_icount;
-    if (env) {
-        if (!can_do_io(env)) {
-            fprintf(stderr, "Bad clock read\n");
-        }
-        icount -= (env->icount_decr.u16.low + env->icount_extra);
-    }
-    return qemu_icount_bias + (icount << icount_time_shift);
-}
-
 void list_cpus(FILE *f, fprintf_function cpu_fprintf, const char *optarg)
 {
     /* XXX: implement xxx_cpu_list for targets that still miss it */
diff --git a/cpus.h b/cpus.h
index 5885885..3525375 100644
--- a/cpus.h
+++ b/cpus.h
@@ -2,8 +2,7 @@
 #define QEMU_CPUS_H
 
 /* cpus.c */
-int qemu_init_main_loop(void);
-void qemu_main_loop_start(void);
+void qemu_init_cpu_loop(void);
 void resume_all_vcpus(void);
 void pause_all_vcpus(void);
 void cpu_stop_current(void);
diff --git a/exec-all.h b/exec-all.h
index 1120f84..72ef246 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -356,4 +356,18 @@
 /* cpu-exec.c */
 extern volatile sig_atomic_t exit_request;
 
+/* Deterministic execution requires that IO only be performed on the last
+   instruction of a TB so that interrupts take effect immediately.  */
+static inline int can_do_io(CPUState *env)
+{
+    if (!use_icount) {
+        return 1;
+    }
+    /* If not executing code then assume we are ok.  */
+    if (!env->current_tb) {
+        return 1;
+    }
+    return env->can_do_io != 0;
+}
+
 #endif
diff --git a/exec.c b/exec.c
index d0cbf15..9dc4edb 100644
--- a/exec.c
+++ b/exec.c
@@ -125,9 +125,6 @@
    1 = Precise instruction counting.
    2 = Adaptive rate instruction counting.  */
 int use_icount = 0;
-/* Current instruction counter.  While executing translated code this may
-   include some instructions that have not yet been executed.  */
-int64_t qemu_icount;
 
 typedef struct PageDesc {
     /* list of TBs intersecting this ram page */
diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h
index 8de8abf..908e2a5 100644
--- a/fsdev/file-op-9p.h
+++ b/fsdev/file-op-9p.h
@@ -23,23 +23,6 @@
 #define SM_LOCAL_MODE_BITS    0600
 #define SM_LOCAL_DIR_MODE_BITS    0700
 
-typedef enum
-{
-    /*
-     * Server will try to set uid/gid.
-     * On failure ignore the error.
-     */
-    SM_NONE = 0,
-    /*
-     * uid/gid set on fileserver files
-     */
-    SM_PASSTHROUGH = 1,
-    /*
-     * uid/gid part of xattr
-     */
-    SM_MAPPED,
-} SecModel;
-
 typedef struct FsCred
 {
     uid_t   fc_uid;
@@ -49,17 +32,41 @@
 } FsCred;
 
 struct xattr_operations;
+struct FsContext;
+struct V9fsPath;
 
-/* FsContext flag values */
-#define PATHNAME_FSCONTEXT 0x1
+typedef struct extended_ops {
+    int (*get_st_gen)(struct FsContext *, struct V9fsPath *,
+                      mode_t, uint64_t *);
+} extended_ops;
+
+/* export flags */
+#define V9FS_IMMEDIATE_WRITEOUT     0x00000001
+#define V9FS_PATHNAME_FSCONTEXT     0x00000002
+/*
+ * uid/gid set on fileserver files
+ */
+#define V9FS_SM_PASSTHROUGH         0x00000004
+/*
+ * uid/gid part of xattr
+ */
+#define V9FS_SM_MAPPED              0x00000008
+/*
+ * Server will try to set uid/gid.
+ * On failure ignore the error.
+ */
+#define V9FS_SM_NONE                0x00000010
+
+
+#define V9FS_SEC_MASK               0x0000001C
 
 typedef struct FsContext
 {
-    int flags;
-    char *fs_root;
-    SecModel fs_sm;
     uid_t uid;
+    char *fs_root;
+    int export_flags;
     struct xattr_operations **xops;
+    struct extended_ops exops;
     /* fs driver specific data */
     void *private;
 } FsContext;
diff --git a/fsdev/qemu-fsdev.c b/fsdev/qemu-fsdev.c
index 768819f..5977bcc 100644
--- a/fsdev/qemu-fsdev.c
+++ b/fsdev/qemu-fsdev.c
@@ -18,46 +18,55 @@
 #include "qemu-common.h"
 #include "qemu-config.h"
 
-static QTAILQ_HEAD(FsTypeEntry_head, FsTypeListEntry) fstype_entries =
-    QTAILQ_HEAD_INITIALIZER(fstype_entries);
+static QTAILQ_HEAD(FsDriverEntry_head, FsDriverListEntry) fsdriver_entries =
+    QTAILQ_HEAD_INITIALIZER(fsdriver_entries);
 
-static FsTypeTable FsTypes[] = {
+static FsDriverTable FsDrivers[] = {
     { .name = "local", .ops = &local_ops},
     { .name = "handle", .ops = &handle_ops},
 };
 
 int qemu_fsdev_add(QemuOpts *opts)
 {
-    struct FsTypeListEntry *fsle;
+    struct FsDriverListEntry *fsle;
     int i;
     const char *fsdev_id = qemu_opts_id(opts);
-    const char *fstype = qemu_opt_get(opts, "fstype");
+    const char *fsdriver = qemu_opt_get(opts, "fsdriver");
     const char *path = qemu_opt_get(opts, "path");
     const char *sec_model = qemu_opt_get(opts, "security_model");
+    const char *writeout = qemu_opt_get(opts, "writeout");
+
 
     if (!fsdev_id) {
         fprintf(stderr, "fsdev: No id specified\n");
         return -1;
     }
 
-    if (fstype) {
-        for (i = 0; i < ARRAY_SIZE(FsTypes); i++) {
-            if (strcmp(FsTypes[i].name, fstype) == 0) {
+    if (fsdriver) {
+        for (i = 0; i < ARRAY_SIZE(FsDrivers); i++) {
+            if (strcmp(FsDrivers[i].name, fsdriver) == 0) {
                 break;
             }
         }
 
-        if (i == ARRAY_SIZE(FsTypes)) {
-            fprintf(stderr, "fsdev: fstype %s not found\n", fstype);
+        if (i == ARRAY_SIZE(FsDrivers)) {
+            fprintf(stderr, "fsdev: fsdriver %s not found\n", fsdriver);
             return -1;
         }
     } else {
-        fprintf(stderr, "fsdev: No fstype specified\n");
+        fprintf(stderr, "fsdev: No fsdriver specified\n");
         return -1;
     }
 
-    if (!sec_model) {
-        fprintf(stderr, "fsdev: No security_model specified.\n");
+    if (!strcmp(fsdriver, "local") && !sec_model) {
+        fprintf(stderr, "security model not specified, "
+                "local fs needs security model\nvalid options are:"
+                "\tsecurity_model=[passthrough|mapped|none]\n");
+        return -1;
+    }
+
+    if (strcmp(fsdriver, "local") && sec_model) {
+        fprintf(stderr, "only local fs driver needs security model\n");
         return -1;
     }
 
@@ -70,20 +79,40 @@
 
     fsle->fse.fsdev_id = g_strdup(fsdev_id);
     fsle->fse.path = g_strdup(path);
-    fsle->fse.security_model = g_strdup(sec_model);
-    fsle->fse.ops = FsTypes[i].ops;
+    fsle->fse.ops = FsDrivers[i].ops;
+    fsle->fse.export_flags = 0;
+    if (writeout) {
+        if (!strcmp(writeout, "immediate")) {
+            fsle->fse.export_flags |= V9FS_IMMEDIATE_WRITEOUT;
+        }
+    }
 
-    QTAILQ_INSERT_TAIL(&fstype_entries, fsle, next);
+    if (strcmp(fsdriver, "local")) {
+        goto done;
+    }
+
+    if (!strcmp(sec_model, "passthrough")) {
+        fsle->fse.export_flags |= V9FS_SM_PASSTHROUGH;
+    } else if (!strcmp(sec_model, "mapped")) {
+        fsle->fse.export_flags |= V9FS_SM_MAPPED;
+    } else if (!strcmp(sec_model, "none")) {
+        fsle->fse.export_flags |= V9FS_SM_NONE;
+    } else {
+        fprintf(stderr, "Invalid security model %s specified, valid options are"
+                "\n\t [passthrough|mapped|none]\n", sec_model);
+        return -1;
+    }
+done:
+    QTAILQ_INSERT_TAIL(&fsdriver_entries, fsle, next);
     return 0;
-
 }
 
-FsTypeEntry *get_fsdev_fsentry(char *id)
+FsDriverEntry *get_fsdev_fsentry(char *id)
 {
     if (id) {
-        struct FsTypeListEntry *fsle;
+        struct FsDriverListEntry *fsle;
 
-        QTAILQ_FOREACH(fsle, &fstype_entries, next) {
+        QTAILQ_FOREACH(fsle, &fsdriver_entries, next) {
             if (strcmp(fsle->fse.fsdev_id, id) == 0) {
                 return &fsle->fse;
             }
diff --git a/fsdev/qemu-fsdev.h b/fsdev/qemu-fsdev.h
index e04931a..5099085 100644
--- a/fsdev/qemu-fsdev.h
+++ b/fsdev/qemu-fsdev.h
@@ -29,28 +29,28 @@
  * -----------------
  *  etc
  */
-typedef struct FsTypeTable {
+typedef struct FsDriverTable {
     const char *name;
     FileOperations *ops;
-} FsTypeTable;
+} FsDriverTable;
 
 /*
  * Structure to store the various fsdev's passed through command line.
  */
-typedef struct FsTypeEntry {
+typedef struct FsDriverEntry {
     char *fsdev_id;
     char *path;
-    char *security_model;
+    int export_flags;
     FileOperations *ops;
-} FsTypeEntry;
+} FsDriverEntry;
 
-typedef struct FsTypeListEntry {
-    FsTypeEntry fse;
-    QTAILQ_ENTRY(FsTypeListEntry) next;
-} FsTypeListEntry;
+typedef struct FsDriverListEntry {
+    FsDriverEntry fse;
+    QTAILQ_ENTRY(FsDriverListEntry) next;
+} FsDriverListEntry;
 
 int qemu_fsdev_add(QemuOpts *opts);
-FsTypeEntry *get_fsdev_fsentry(char *id);
+FsDriverEntry *get_fsdev_fsentry(char *id);
 extern FileOperations local_ops;
 extern FileOperations handle_ops;
 #endif
diff --git a/hw/9pfs/cofile.c b/hw/9pfs/cofile.c
index 7ad4bec..692811e 100644
--- a/hw/9pfs/cofile.c
+++ b/hw/9pfs/cofile.c
@@ -17,6 +17,30 @@
 #include "qemu-coroutine.h"
 #include "virtio-9p-coth.h"
 
+int v9fs_co_st_gen(V9fsPDU *pdu, V9fsPath *path, mode_t st_mode,
+                   V9fsStatDotl *v9stat)
+{
+    int err = 0;
+    V9fsState *s = pdu->s;
+
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
+    if (s->ctx.exops.get_st_gen) {
+        v9fs_path_read_lock(s);
+        v9fs_co_run_in_worker(
+            {
+                err = s->ctx.exops.get_st_gen(&s->ctx, path, st_mode,
+                                              &v9stat->st_gen);
+                if (err < 0) {
+                    err = -errno;
+                }
+            });
+        v9fs_path_unlock(s);
+    }
+    return err;
+}
+
 int v9fs_co_lstat(V9fsPDU *pdu, V9fsPath *path, struct stat *stbuf)
 {
     int err;
diff --git a/hw/9pfs/cofs.c b/hw/9pfs/cofs.c
index 68745ad..83f125b 100644
--- a/hw/9pfs/cofs.c
+++ b/hw/9pfs/cofs.c
@@ -323,7 +323,7 @@
     int err;
     V9fsState *s = pdu->s;
 
-    if (s->ctx.flags & PATHNAME_FSCONTEXT) {
+    if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) {
         err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
         if (err < 0) {
             err = -errno;
diff --git a/hw/9pfs/virtio-9p-coth.h b/hw/9pfs/virtio-9p-coth.h
index 4630080..ca96b9c 100644
--- a/hw/9pfs/virtio-9p-coth.h
+++ b/hw/9pfs/virtio-9p-coth.h
@@ -101,4 +101,7 @@
                           struct iovec *, int, int64_t);
 extern int v9fs_co_name_to_path(V9fsPDU *, V9fsPath *,
                                 const char *, V9fsPath *);
+extern int v9fs_co_st_gen(V9fsPDU *pdu, V9fsPath *path, mode_t,
+                          V9fsStatDotl *v9stat);
+
 #endif
diff --git a/hw/9pfs/virtio-9p-debug.c b/hw/9pfs/virtio-9p-debug.c
deleted file mode 100644
index 96925f0..0000000
--- a/hw/9pfs/virtio-9p-debug.c
+++ /dev/null
@@ -1,646 +0,0 @@
-/*
- * Virtio 9p PDU debug
- *
- * Copyright IBM, Corp. 2010
- *
- * Authors:
- *  Anthony Liguori   <aliguori@us.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
- *
- */
-
-#include "hw/virtio.h"
-#include "hw/pc.h"
-#include "virtio-9p.h"
-#include "virtio-9p-debug.h"
-
-#define BUG_ON(cond) assert(!(cond))
-
-static FILE *llogfile;
-
-static struct iovec *get_sg(V9fsPDU *pdu, int rx)
-{
-    if (rx) {
-        return pdu->elem.in_sg;
-    }
-    return pdu->elem.out_sg;
-}
-
-static int get_sg_count(V9fsPDU *pdu, int rx)
-{
-    if (rx) {
-        return pdu->elem.in_num;
-    }
-    return pdu->elem.out_num;
-
-}
-
-static void pprint_int8(V9fsPDU *pdu, int rx, size_t *offsetp,
-                        const char *name)
-{
-    size_t copied;
-    int count = get_sg_count(pdu, rx);
-    size_t offset = *offsetp;
-    struct iovec *sg = get_sg(pdu, rx);
-    int8_t value;
-
-    copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value));
-
-    BUG_ON(copied != sizeof(value));
-    offset += sizeof(value);
-    fprintf(llogfile, "%s=0x%x", name, value);
-    *offsetp = offset;
-}
-
-static void pprint_int16(V9fsPDU *pdu, int rx, size_t *offsetp,
-                        const char *name)
-{
-    size_t copied;
-    int count = get_sg_count(pdu, rx);
-    struct iovec *sg = get_sg(pdu, rx);
-    size_t offset = *offsetp;
-    int16_t value;
-
-
-    copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value));
-
-    BUG_ON(copied != sizeof(value));
-    offset += sizeof(value);
-    fprintf(llogfile, "%s=0x%x", name, value);
-    *offsetp = offset;
-}
-
-static void pprint_int32(V9fsPDU *pdu, int rx, size_t *offsetp,
-                        const char *name)
-{
-    size_t copied;
-    int count = get_sg_count(pdu, rx);
-    struct iovec *sg = get_sg(pdu, rx);
-    size_t offset = *offsetp;
-    int32_t value;
-
-
-    copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value));
-
-    BUG_ON(copied != sizeof(value));
-    offset += sizeof(value);
-    fprintf(llogfile, "%s=0x%x", name, value);
-    *offsetp = offset;
-}
-
-static void pprint_int64(V9fsPDU *pdu, int rx, size_t *offsetp,
-                        const char *name)
-{
-    size_t copied;
-    int count = get_sg_count(pdu, rx);
-    struct iovec *sg = get_sg(pdu, rx);
-    size_t offset = *offsetp;
-    int64_t value;
-
-
-    copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value));
-
-    BUG_ON(copied != sizeof(value));
-    offset += sizeof(value);
-    fprintf(llogfile, "%s=0x%" PRIx64, name, value);
-    *offsetp = offset;
-}
-
-static void pprint_str(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
-{
-    int sg_count = get_sg_count(pdu, rx);
-    struct iovec *sg = get_sg(pdu, rx);
-    size_t offset = *offsetp;
-    uint16_t tmp_size, size;
-    size_t result;
-    size_t copied = 0;
-    int i = 0;
-
-    /* get the size */
-    copied = do_pdu_unpack(&tmp_size, sg, sg_count, offset, sizeof(tmp_size));
-    BUG_ON(copied != sizeof(tmp_size));
-    size = le16_to_cpupu(&tmp_size);
-    offset += copied;
-
-    fprintf(llogfile, "%s=", name);
-    for (i = 0; size && i < sg_count; i++) {
-        size_t len;
-        if (offset >= sg[i].iov_len) {
-            /* skip this sg */
-            offset -= sg[i].iov_len;
-            continue;
-        } else {
-            len = MIN(sg[i].iov_len - offset, size);
-            result = fwrite(sg[i].iov_base + offset, 1, len, llogfile);
-            BUG_ON(result != len);
-            size -= len;
-            copied += len;
-            if (size) {
-                offset = 0;
-                continue;
-            }
-        }
-    }
-    *offsetp += copied;
-}
-
-static void pprint_qid(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
-{
-    fprintf(llogfile, "%s={", name);
-    pprint_int8(pdu, rx, offsetp, "type");
-    pprint_int32(pdu, rx, offsetp, ", version");
-    pprint_int64(pdu, rx, offsetp, ", path");
-    fprintf(llogfile, "}");
-}
-
-static void pprint_stat(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
-{
-    fprintf(llogfile, "%s={", name);
-    pprint_int16(pdu, rx, offsetp, "size");
-    pprint_int16(pdu, rx, offsetp, ", type");
-    pprint_int32(pdu, rx, offsetp, ", dev");
-    pprint_qid(pdu, rx, offsetp, ", qid");
-    pprint_int32(pdu, rx, offsetp, ", mode");
-    pprint_int32(pdu, rx, offsetp, ", atime");
-    pprint_int32(pdu, rx, offsetp, ", mtime");
-    pprint_int64(pdu, rx, offsetp, ", length");
-    pprint_str(pdu, rx, offsetp, ", name");
-    pprint_str(pdu, rx, offsetp, ", uid");
-    pprint_str(pdu, rx, offsetp, ", gid");
-    pprint_str(pdu, rx, offsetp, ", muid");
-    pprint_str(pdu, rx, offsetp, ", extension");
-    pprint_int32(pdu, rx, offsetp, ", uid");
-    pprint_int32(pdu, rx, offsetp, ", gid");
-    pprint_int32(pdu, rx, offsetp, ", muid");
-    fprintf(llogfile, "}");
-}
-
-static void pprint_stat_dotl(V9fsPDU *pdu, int rx, size_t *offsetp,
-                                                  const char *name)
-{
-    fprintf(llogfile, "%s={", name);
-    pprint_qid(pdu, rx, offsetp, "qid");
-    pprint_int32(pdu, rx, offsetp, ", st_mode");
-    pprint_int64(pdu, rx, offsetp, ", st_nlink");
-    pprint_int32(pdu, rx, offsetp, ", st_uid");
-    pprint_int32(pdu, rx, offsetp, ", st_gid");
-    pprint_int64(pdu, rx, offsetp, ", st_rdev");
-    pprint_int64(pdu, rx, offsetp, ", st_size");
-    pprint_int64(pdu, rx, offsetp, ", st_blksize");
-    pprint_int64(pdu, rx, offsetp, ", st_blocks");
-    pprint_int64(pdu, rx, offsetp, ", atime");
-    pprint_int64(pdu, rx, offsetp, ", atime_nsec");
-    pprint_int64(pdu, rx, offsetp, ", mtime");
-    pprint_int64(pdu, rx, offsetp, ", mtime_nsec");
-    pprint_int64(pdu, rx, offsetp, ", ctime");
-    pprint_int64(pdu, rx, offsetp, ", ctime_nsec");
-    fprintf(llogfile, "}");
-}
-
-
-
-static void pprint_strs(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
-{
-    int sg_count = get_sg_count(pdu, rx);
-    struct iovec *sg = get_sg(pdu, rx);
-    size_t offset = *offsetp;
-    uint16_t tmp_count, count, i;
-    size_t copied = 0;
-
-    fprintf(llogfile, "%s={", name);
-
-    /* Get the count */
-    copied = do_pdu_unpack(&tmp_count, sg, sg_count, offset, sizeof(tmp_count));
-    BUG_ON(copied != sizeof(tmp_count));
-    count = le16_to_cpupu(&tmp_count);
-    offset += copied;
-
-    for (i = 0; i < count; i++) {
-        char str[512];
-        if (i) {
-            fprintf(llogfile, ", ");
-        }
-        snprintf(str, sizeof(str), "[%d]", i);
-        pprint_str(pdu, rx, &offset, str);
-    }
-
-    fprintf(llogfile, "}");
-
-    *offsetp = offset;
-}
-
-static void pprint_qids(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
-{
-    int sg_count = get_sg_count(pdu, rx);
-    struct iovec *sg = get_sg(pdu, rx);
-    size_t offset = *offsetp;
-    uint16_t tmp_count, count, i;
-    size_t copied = 0;
-
-    fprintf(llogfile, "%s={", name);
-
-    copied = do_pdu_unpack(&tmp_count, sg, sg_count, offset, sizeof(tmp_count));
-    BUG_ON(copied != sizeof(tmp_count));
-    count = le16_to_cpupu(&tmp_count);
-    offset += copied;
-
-    for (i = 0; i < count; i++) {
-        char str[512];
-        if (i) {
-            fprintf(llogfile, ", ");
-        }
-        snprintf(str, sizeof(str), "[%d]", i);
-        pprint_qid(pdu, rx, &offset, str);
-    }
-
-    fprintf(llogfile, "}");
-
-    *offsetp = offset;
-}
-
-static void pprint_sg(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
-{
-    struct iovec *sg = get_sg(pdu, rx);
-    unsigned int count;
-    int i;
-
-    if (rx) {
-        count = pdu->elem.in_num;
-    } else {
-        count = pdu->elem.out_num;
-    }
-
-    fprintf(llogfile, "%s={", name);
-    for (i = 0; i < count; i++) {
-        if (i) {
-            fprintf(llogfile, ", ");
-        }
-        fprintf(llogfile, "(%p, 0x%zx)", sg[i].iov_base, sg[i].iov_len);
-    }
-    fprintf(llogfile, "}");
-}
-
-/* FIXME: read from a directory fid returns serialized stat_t's */
-#ifdef DEBUG_DATA
-static void pprint_data(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
-{
-    struct iovec *sg = get_sg(pdu, rx);
-    size_t offset = *offsetp;
-    unsigned int count;
-    int32_t size;
-    int total, i, j;
-    ssize_t len;
-
-    if (rx) {
-        count = pdu->elem.in_num;
-    } else {
-        count = pdu->elem.out_num;
-    }
-
-    BUG_ON((offset + sizeof(size)) > sg[0].iov_len);
-
-    memcpy(&size, sg[0].iov_base + offset, sizeof(size));
-    offset += sizeof(size);
-
-    fprintf(llogfile, "size: %x\n", size);
-
-    sg[0].iov_base += 11; /* skip header */
-    sg[0].iov_len -= 11;
-
-    total = 0;
-    for (i = 0; i < count; i++) {
-        total += sg[i].iov_len;
-        if (total >= size) {
-            /* trim sg list so writev does the right thing */
-            sg[i].iov_len -= (total - size);
-            i++;
-            break;
-        }
-    }
-
-    fprintf(llogfile, "%s={\"", name);
-    fflush(llogfile);
-    for (j = 0; j < i; j++) {
-        if (j) {
-            fprintf(llogfile, "\", \"");
-            fflush(llogfile);
-        }
-
-        do {
-            len = writev(fileno(llogfile), &sg[j], 1);
-        } while (len == -1 && errno == EINTR);
-        fprintf(llogfile, "len == %ld: %m\n", len);
-        BUG_ON(len != sg[j].iov_len);
-    }
-    fprintf(llogfile, "\"}");
-
-    sg[0].iov_base -= 11;
-    sg[0].iov_len += 11;
-
-}
-#endif
-
-void pprint_pdu(V9fsPDU *pdu)
-{
-    size_t offset = 7;
-
-    if (llogfile == NULL) {
-        llogfile = fopen("/tmp/pdu.log", "w");
-    }
-
-    BUG_ON(!llogfile);
-
-    switch (pdu->id) {
-    case P9_TREADDIR:
-        fprintf(llogfile, "TREADDIR: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        pprint_int64(pdu, 0, &offset, ", initial offset");
-        pprint_int32(pdu, 0, &offset, ", max count");
-        break;
-    case P9_RREADDIR:
-        fprintf(llogfile, "RREADDIR: (");
-        pprint_int32(pdu, 1, &offset, "count");
-#ifdef DEBUG_DATA
-        pprint_data(pdu, 1, &offset, ", data");
-#endif
-        break;
-    case P9_TMKDIR:
-        fprintf(llogfile, "TMKDIR: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        pprint_str(pdu, 0, &offset, "name");
-        pprint_int32(pdu, 0, &offset, "mode");
-        pprint_int32(pdu, 0, &offset, "gid");
-        break;
-    case P9_RMKDIR:
-        fprintf(llogfile, "RMKDIR: (");
-        pprint_qid(pdu, 0, &offset, "qid");
-        break;
-    case P9_TVERSION:
-        fprintf(llogfile, "TVERSION: (");
-        pprint_int32(pdu, 0, &offset, "msize");
-        pprint_str(pdu, 0, &offset, ", version");
-        break;
-    case P9_RVERSION:
-        fprintf(llogfile, "RVERSION: (");
-        pprint_int32(pdu, 1, &offset, "msize");
-        pprint_str(pdu, 1, &offset, ", version");
-        break;
-    case P9_TGETATTR:
-        fprintf(llogfile, "TGETATTR: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        break;
-    case P9_RGETATTR:
-        fprintf(llogfile, "RGETATTR: (");
-        pprint_stat_dotl(pdu, 1, &offset, "getattr");
-        break;
-    case P9_TAUTH:
-        fprintf(llogfile, "TAUTH: (");
-        pprint_int32(pdu, 0, &offset, "afid");
-        pprint_str(pdu, 0, &offset, ", uname");
-        pprint_str(pdu, 0, &offset, ", aname");
-        pprint_int32(pdu, 0, &offset, ", n_uname");
-        break;
-    case P9_RAUTH:
-        fprintf(llogfile, "RAUTH: (");
-        pprint_qid(pdu, 1, &offset, "qid");
-        break;
-    case P9_TATTACH:
-        fprintf(llogfile, "TATTACH: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        pprint_int32(pdu, 0, &offset, ", afid");
-        pprint_str(pdu, 0, &offset, ", uname");
-        pprint_str(pdu, 0, &offset, ", aname");
-        pprint_int32(pdu, 0, &offset, ", n_uname");
-        break;
-    case P9_RATTACH:
-        fprintf(llogfile, "RATTACH: (");
-        pprint_qid(pdu, 1, &offset, "qid");
-        break;
-    case P9_TERROR:
-        fprintf(llogfile, "TERROR: (");
-        break;
-    case P9_RERROR:
-        fprintf(llogfile, "RERROR: (");
-        pprint_str(pdu, 1, &offset, "ename");
-        pprint_int32(pdu, 1, &offset, ", ecode");
-        break;
-    case P9_TFLUSH:
-        fprintf(llogfile, "TFLUSH: (");
-        pprint_int16(pdu, 0, &offset, "oldtag");
-        break;
-    case P9_RFLUSH:
-        fprintf(llogfile, "RFLUSH: (");
-        break;
-    case P9_TWALK:
-        fprintf(llogfile, "TWALK: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        pprint_int32(pdu, 0, &offset, ", newfid");
-        pprint_strs(pdu, 0, &offset, ", wnames");
-        break;
-    case P9_RWALK:
-        fprintf(llogfile, "RWALK: (");
-        pprint_qids(pdu, 1, &offset, "wqids");
-        break;
-    case P9_TOPEN:
-        fprintf(llogfile, "TOPEN: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        pprint_int8(pdu, 0, &offset, ", mode");
-        break;
-    case P9_ROPEN:
-        fprintf(llogfile, "ROPEN: (");
-        pprint_qid(pdu, 1, &offset, "qid");
-        pprint_int32(pdu, 1, &offset, ", iounit");
-        break;
-    case P9_TCREATE:
-        fprintf(llogfile, "TCREATE: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        pprint_str(pdu, 0, &offset, ", name");
-        pprint_int32(pdu, 0, &offset, ", perm");
-        pprint_int8(pdu, 0, &offset, ", mode");
-        pprint_str(pdu, 0, &offset, ", extension");
-        break;
-    case P9_RCREATE:
-        fprintf(llogfile, "RCREATE: (");
-        pprint_qid(pdu, 1, &offset, "qid");
-        pprint_int32(pdu, 1, &offset, ", iounit");
-        break;
-    case P9_TSYMLINK:
-        fprintf(llogfile, "TSYMLINK: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        pprint_str(pdu, 0, &offset, ", name");
-        pprint_str(pdu, 0, &offset, ", symname");
-        pprint_int32(pdu, 0, &offset, ", gid");
-        break;
-    case P9_RSYMLINK:
-        fprintf(llogfile, "RSYMLINK: (");
-        pprint_qid(pdu, 1, &offset, "qid");
-        break;
-    case P9_TLCREATE:
-        fprintf(llogfile, "TLCREATE: (");
-        pprint_int32(pdu, 0, &offset, "dfid");
-        pprint_str(pdu, 0, &offset, ", name");
-        pprint_int32(pdu, 0, &offset, ", flags");
-        pprint_int32(pdu, 0, &offset, ", mode");
-        pprint_int32(pdu, 0, &offset, ", gid");
-        break;
-    case P9_RLCREATE:
-        fprintf(llogfile, "RLCREATE: (");
-        pprint_qid(pdu, 1, &offset, "qid");
-        pprint_int32(pdu, 1, &offset, ", iounit");
-        break;
-    case P9_TMKNOD:
-	fprintf(llogfile, "TMKNOD: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        pprint_str(pdu, 0, &offset, "name");
-        pprint_int32(pdu, 0, &offset, "mode");
-        pprint_int32(pdu, 0, &offset, "major");
-        pprint_int32(pdu, 0, &offset, "minor");
-        pprint_int32(pdu, 0, &offset, "gid");
-        break;
-    case P9_RMKNOD:
-        fprintf(llogfile, "RMKNOD: )");
-        pprint_qid(pdu, 0, &offset, "qid");
-        break;
-    case P9_TREADLINK:
-	fprintf(llogfile, "TREADLINK: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        break;
-    case P9_RREADLINK:
-	fprintf(llogfile, "RREADLINK: (");
-        pprint_str(pdu, 0, &offset, "target");
-        break;
-    case P9_TREAD:
-        fprintf(llogfile, "TREAD: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        pprint_int64(pdu, 0, &offset, ", offset");
-        pprint_int32(pdu, 0, &offset, ", count");
-        pprint_sg(pdu, 0, &offset, ", sg");
-        break;
-    case P9_RREAD:
-        fprintf(llogfile, "RREAD: (");
-        pprint_int32(pdu, 1, &offset, "count");
-        pprint_sg(pdu, 1, &offset, ", sg");
-        offset = 7;
-#ifdef DEBUG_DATA
-        pprint_data(pdu, 1, &offset, ", data");
-#endif
-        break;
-    case P9_TWRITE:
-        fprintf(llogfile, "TWRITE: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        pprint_int64(pdu, 0, &offset, ", offset");
-        pprint_int32(pdu, 0, &offset, ", count");
-        break;
-    case P9_RWRITE:
-        fprintf(llogfile, "RWRITE: (");
-        pprint_int32(pdu, 1, &offset, "count");
-        break;
-    case P9_TCLUNK:
-        fprintf(llogfile, "TCLUNK: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        break;
-    case P9_RCLUNK:
-        fprintf(llogfile, "RCLUNK: (");
-        break;
-    case P9_TFSYNC:
-        fprintf(llogfile, "TFSYNC: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        break;
-    case P9_RFSYNC:
-        fprintf(llogfile, "RFSYNC: (");
-        break;
-    case P9_TLINK:
-        fprintf(llogfile, "TLINK: (");
-        pprint_int32(pdu, 0, &offset, "dfid");
-        pprint_int32(pdu, 0, &offset, ", fid");
-        pprint_str(pdu, 0, &offset, ", newpath");
-        break;
-    case P9_RLINK:
-        fprintf(llogfile, "RLINK: (");
-        break;
-    case P9_TREMOVE:
-        fprintf(llogfile, "TREMOVE: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        break;
-    case P9_RREMOVE:
-        fprintf(llogfile, "RREMOVE: (");
-        break;
-    case P9_TSTAT:
-        fprintf(llogfile, "TSTAT: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        break;
-    case P9_RSTAT:
-        fprintf(llogfile, "RSTAT: (");
-        offset += 2; /* ignored */
-        pprint_stat(pdu, 1, &offset, "stat");
-        break;
-    case P9_TWSTAT:
-        fprintf(llogfile, "TWSTAT: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        offset += 2; /* ignored */
-        pprint_stat(pdu, 0, &offset, ", stat");
-        break;
-    case P9_RWSTAT:
-        fprintf(llogfile, "RWSTAT: (");
-        break;
-    case P9_TXATTRWALK:
-        fprintf(llogfile, "TXATTRWALK: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        pprint_int32(pdu, 0, &offset, ", newfid");
-        pprint_str(pdu, 0, &offset, ", xattr name");
-        break;
-    case P9_RXATTRWALK:
-        fprintf(llogfile, "RXATTRWALK: (");
-        pprint_int64(pdu, 1, &offset, "xattrsize");
-    case P9_TXATTRCREATE:
-        fprintf(llogfile, "TXATTRCREATE: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        pprint_str(pdu, 0, &offset, ", name");
-        pprint_int64(pdu, 0, &offset, ", xattrsize");
-        pprint_int32(pdu, 0, &offset, ", flags");
-        break;
-    case P9_RXATTRCREATE:
-        fprintf(llogfile, "RXATTRCREATE: (");
-        break;
-    case P9_TLOCK:
-        fprintf(llogfile, "TLOCK: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        pprint_int8(pdu, 0, &offset, ", type");
-        pprint_int32(pdu, 0, &offset, ", flags");
-        pprint_int64(pdu, 0, &offset, ", start");
-        pprint_int64(pdu, 0, &offset, ", length");
-        pprint_int32(pdu, 0, &offset, ", proc_id");
-        pprint_str(pdu, 0, &offset, ", client_id");
-        break;
-    case P9_RLOCK:
-        fprintf(llogfile, "RLOCK: (");
-        pprint_int8(pdu, 0, &offset, "status");
-        break;
-    case P9_TGETLOCK:
-        fprintf(llogfile, "TGETLOCK: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        pprint_int8(pdu, 0, &offset, ", type");
-        pprint_int64(pdu, 0, &offset, ", start");
-        pprint_int64(pdu, 0, &offset, ", length");
-        pprint_int32(pdu, 0, &offset, ", proc_id");
-        pprint_str(pdu, 0, &offset, ", client_id");
-        break;
-    case P9_RGETLOCK:
-        fprintf(llogfile, "RGETLOCK: (");
-        pprint_int8(pdu, 0, &offset, "type");
-        pprint_int64(pdu, 0, &offset, ", start");
-        pprint_int64(pdu, 0, &offset, ", length");
-        pprint_int32(pdu, 0, &offset, ", proc_id");
-        pprint_str(pdu, 0, &offset, ", client_id");
-        break;
-    default:
-        fprintf(llogfile, "unknown(%d): (", pdu->id);
-        break;
-    }
-
-    fprintf(llogfile, ")\n");
-    /* Flush the log message out */
-    fflush(llogfile);
-}
diff --git a/hw/9pfs/virtio-9p-debug.h b/hw/9pfs/virtio-9p-debug.h
deleted file mode 100644
index d9a2491..0000000
--- a/hw/9pfs/virtio-9p-debug.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _QEMU_VIRTIO_9P_DEBUG_H
-#define _QEMU_VIRTIO_9P_DEBUG_H
-
-void pprint_pdu(V9fsPDU *pdu);
-
-#endif
diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
index 513e181..bba4c54 100644
--- a/hw/9pfs/virtio-9p-device.c
+++ b/hw/9pfs/virtio-9p-device.c
@@ -49,7 +49,8 @@
     V9fsState *s;
     int i, len;
     struct stat stat;
-    FsTypeEntry *fse;
+    FsDriverEntry *fse;
+    V9fsPath path;
 
     s = (V9fsState *)virtio_common_init("virtio-9p",
                                     VIRTIO_ID_9P,
@@ -82,55 +83,33 @@
         exit(1);
     }
 
-    if (!strcmp(fse->security_model, "passthrough")) {
-        /* Files on the Fileserver set to client user credentials */
-        s->ctx.fs_sm = SM_PASSTHROUGH;
-        s->ctx.xops = passthrough_xattr_ops;
-    } else if (!strcmp(fse->security_model, "mapped")) {
-        /* Files on the fileserver are set to QEMU credentials.
-         * Client user credentials are saved in extended attributes.
-         */
-        s->ctx.fs_sm = SM_MAPPED;
-        s->ctx.xops = mapped_xattr_ops;
-    } else if (!strcmp(fse->security_model, "none")) {
-        /*
-         * Files on the fileserver are set to QEMU credentials.
-         */
-        s->ctx.fs_sm = SM_NONE;
-        s->ctx.xops = none_xattr_ops;
-    } else {
-        fprintf(stderr, "Default to security_model=none. You may want"
-                " enable advanced security model using "
-                "security option:\n\t security_model=passthrough\n\t "
-                "security_model=mapped\n");
-        s->ctx.fs_sm = SM_NONE;
-        s->ctx.xops = none_xattr_ops;
-    }
-
-    if (lstat(fse->path, &stat)) {
-        fprintf(stderr, "share path %s does not exist\n", fse->path);
-        exit(1);
-    } else if (!S_ISDIR(stat.st_mode)) {
-        fprintf(stderr, "share path %s is not a directory\n", fse->path);
-        exit(1);
-    }
-
+    s->ctx.export_flags = fse->export_flags;
     s->ctx.fs_root = g_strdup(fse->path);
+    s->ctx.exops.get_st_gen = NULL;
+
+    if (fse->export_flags & V9FS_SM_PASSTHROUGH) {
+        s->ctx.xops = passthrough_xattr_ops;
+    } else if (fse->export_flags & V9FS_SM_MAPPED) {
+        s->ctx.xops = mapped_xattr_ops;
+    } else if (fse->export_flags & V9FS_SM_NONE) {
+        s->ctx.xops = none_xattr_ops;
+    }
+
     len = strlen(conf->tag);
     if (len > MAX_TAG_LEN) {
-        len = MAX_TAG_LEN;
+        fprintf(stderr, "mount tag '%s' (%d bytes) is longer than "
+                "maximum (%d bytes)", conf->tag, len, MAX_TAG_LEN);
+        exit(1);
     }
     /* s->tag is non-NULL terminated string */
     s->tag = g_malloc(len);
     memcpy(s->tag, conf->tag, len);
     s->tag_len = len;
     s->ctx.uid = -1;
-    s->ctx.flags = 0;
 
     s->ops = fse->ops;
     s->vdev.get_features = virtio_9p_get_features;
-    s->config_size = sizeof(struct virtio_9p_config) +
-                        s->tag_len;
+    s->config_size = sizeof(struct virtio_9p_config) + s->tag_len;
     s->vdev.get_config = virtio_9p_get_config;
     s->fid_list = NULL;
     qemu_co_rwlock_init(&s->rename_lock);
@@ -144,6 +123,27 @@
         fprintf(stderr, "worker thread initialization failed\n");
         exit(1);
     }
+
+    /*
+     * Check details of export path, We need to use fs driver
+     * call back to do that. Since we are in the init path, we don't
+     * use co-routines here.
+     */
+    v9fs_path_init(&path);
+    if (s->ops->name_to_path(&s->ctx, NULL, "/", &path) < 0) {
+        fprintf(stderr,
+                "error in converting name to path %s", strerror(errno));
+        exit(1);
+    }
+    if (s->ops->lstat(&s->ctx, &path, &stat)) {
+        fprintf(stderr, "share path %s does not exist\n", fse->path);
+        exit(1);
+    } else if (!S_ISDIR(stat.st_mode)) {
+        fprintf(stderr, "share path %s is not a directory\n", fse->path);
+        exit(1);
+    }
+    v9fs_path_free(&path);
+
     return &s->vdev;
 }
 
@@ -169,6 +169,8 @@
     .revision  = VIRTIO_PCI_ABI_VERSION,
     .class_id  = 0x2,
     .qdev.props = (Property[]) {
+        DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
+                        VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
         DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
         DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
         DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag),
diff --git a/hw/9pfs/virtio-9p-handle.c b/hw/9pfs/virtio-9p-handle.c
index 5c8b5ed..98809f1 100644
--- a/hw/9pfs/virtio-9p-handle.c
+++ b/hw/9pfs/virtio-9p-handle.c
@@ -21,19 +21,48 @@
 #include <sys/un.h>
 #include <attr/xattr.h>
 #include <unistd.h>
+#include <linux/fs.h>
+#ifdef CONFIG_LINUX_MAGIC_H
+#include <linux/magic.h>
+#endif
+#include <sys/ioctl.h>
+
+#ifndef XFS_SUPER_MAGIC
+#define XFS_SUPER_MAGIC  0x58465342
+#endif
+#ifndef EXT2_SUPER_MAGIC
+#define EXT2_SUPER_MAGIC 0xEF53
+#endif
+#ifndef REISERFS_SUPER_MAGIC
+#define REISERFS_SUPER_MAGIC 0x52654973
+#endif
+#ifndef BTRFS_SUPER_MAGIC
+#define BTRFS_SUPER_MAGIC 0x9123683E
+#endif
 
 struct handle_data {
     int mountfd;
     int handle_bytes;
 };
 
-#if __GLIBC__ <= 2 && __GLIBC_MINOR__ < 14
+#ifdef CONFIG_OPEN_BY_HANDLE
+static inline int name_to_handle(int dirfd, const char *name,
+                                 struct file_handle *fh, int *mnt_id, int flags)
+{
+    return name_to_handle_at(dirfd, name, fh, mnt_id, flags);
+}
+
+static inline int open_by_handle(int mountfd, const char *fh, int flags)
+{
+    return open_by_handle_at(mountfd, (struct file_handle *)fh, flags);
+}
+#else
+
 struct file_handle {
-        unsigned int handle_bytes;
-        int handle_type;
-        unsigned char handle[0];
+    unsigned int handle_bytes;
+    int handle_type;
+    unsigned char handle[0];
 };
-#endif
 
 #ifndef AT_EMPTY_PATH
 #define AT_EMPTY_PATH   0x1000  /* Allow empty relative pathname */
@@ -42,28 +71,6 @@
 #define O_PATH    010000000
 #endif
 
-#ifndef __NR_name_to_handle_at
-#if defined(__i386__)
-#define __NR_name_to_handle_at  341
-#define __NR_open_by_handle_at  342
-#elif defined(__x86_64__)
-#define __NR_name_to_handle_at  303
-#define __NR_open_by_handle_at  304
-#endif
-#endif
-
-#ifdef __NR_name_to_handle_at
-static inline int name_to_handle(int dirfd, const char *name,
-                                 struct file_handle *fh, int *mnt_id, int flags)
-{
-    return syscall(__NR_name_to_handle_at, dirfd, name, fh, mnt_id, flags);
-}
-
-static inline int open_by_handle(int mountfd, const char *fh, int flags)
-{
-    return syscall(__NR_open_by_handle_at, mountfd, fh, flags);
-}
-#else
 static inline int name_to_handle(int dirfd, const char *name,
                                  struct file_handle *fh, int *mnt_id, int flags)
 {
@@ -192,16 +199,29 @@
 static ssize_t handle_pwritev(FsContext *ctx, int fd, const struct iovec *iov,
                               int iovcnt, off_t offset)
 {
+    ssize_t ret;
 #ifdef CONFIG_PREADV
-    return pwritev(fd, iov, iovcnt, offset);
+    ret = pwritev(fd, iov, iovcnt, offset);
 #else
     int err = lseek(fd, offset, SEEK_SET);
     if (err == -1) {
         return err;
     } else {
-        return writev(fd, iov, iovcnt);
+        ret = writev(fd, iov, iovcnt);
     }
 #endif
+#ifdef CONFIG_SYNC_FILE_RANGE
+    if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) {
+        /*
+         * Initiate a writeback. This is not a data integrity sync.
+         * We want to ensure that we don't leave dirty pages in the cache
+         * after write when writeout=immediate is sepcified.
+         */
+        sync_file_range(fd, offset, ret,
+                        SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE);
+    }
+#endif
+    return ret;
 }
 
 static int handle_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
@@ -367,7 +387,9 @@
 static int handle_utimensat(FsContext *ctx, V9fsPath *fs_path,
                             const struct timespec *buf)
 {
-    int fd, ret;
+    int ret;
+#ifdef CONFIG_UTIMENSAT
+    int fd;
     struct handle_data *data = (struct handle_data *)ctx->private;
 
     fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
@@ -376,6 +398,10 @@
     }
     ret = futimens(fd, buf);
     close(fd);
+#else
+    ret = -1;
+    errno = ENOSYS;
+#endif
     return ret;
 }
 
@@ -546,16 +572,50 @@
     return ret;
 }
 
+static int handle_ioc_getversion(FsContext *ctx, V9fsPath *path,
+                                 mode_t st_mode, uint64_t *st_gen)
+{
+    int err, fd;
+
+    /*
+     * Do not try to open special files like device nodes, fifos etc
+     * We can get fd for regular files and directories only
+     */
+    if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
+            return 0;
+    }
+    fd = handle_open(ctx, path, O_RDONLY);
+    if (fd < 0) {
+        return fd;
+    }
+    err = ioctl(fd, FS_IOC_GETVERSION, st_gen);
+    handle_close(ctx, fd);
+    return err;
+}
+
 static int handle_init(FsContext *ctx)
 {
     int ret, mnt_id;
+    struct statfs stbuf;
     struct file_handle fh;
     struct handle_data *data = g_malloc(sizeof(struct handle_data));
+
     data->mountfd = open(ctx->fs_root, O_DIRECTORY);
     if (data->mountfd < 0) {
         ret = data->mountfd;
         goto err_out;
     }
+    ret = statfs(ctx->fs_root, &stbuf);
+    if (!ret) {
+        switch (stbuf.f_type) {
+        case EXT2_SUPER_MAGIC:
+        case BTRFS_SUPER_MAGIC:
+        case REISERFS_SUPER_MAGIC:
+        case XFS_SUPER_MAGIC:
+            ctx->exops.get_st_gen = handle_ioc_getversion;
+            break;
+        }
+    }
     memset(&fh, 0, sizeof(struct file_handle));
     ret = name_to_handle(data->mountfd, ".", &fh, &mnt_id, 0);
     if (ret && errno == EOVERFLOW) {
diff --git a/hw/9pfs/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c
index 9559ff6..d561de8 100644
--- a/hw/9pfs/virtio-9p-local.c
+++ b/hw/9pfs/virtio-9p-local.c
@@ -20,6 +20,24 @@
 #include <sys/socket.h>
 #include <sys/un.h>
 #include <attr/xattr.h>
+#include <linux/fs.h>
+#ifdef CONFIG_LINUX_MAGIC_H
+#include <linux/magic.h>
+#endif
+#include <sys/ioctl.h>
+
+#ifndef XFS_SUPER_MAGIC
+#define XFS_SUPER_MAGIC  0x58465342
+#endif
+#ifndef EXT2_SUPER_MAGIC
+#define EXT2_SUPER_MAGIC 0xEF53
+#endif
+#ifndef REISERFS_SUPER_MAGIC
+#define REISERFS_SUPER_MAGIC 0x52654973
+#endif
+#ifndef BTRFS_SUPER_MAGIC
+#define BTRFS_SUPER_MAGIC 0x9123683E
+#endif
 
 static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
 {
@@ -31,7 +49,7 @@
     if (err) {
         return err;
     }
-    if (fs_ctx->fs_sm == SM_MAPPED) {
+    if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
         /* Actual credentials are part of extended attrs */
         uid_t tmp_uid;
         gid_t tmp_gid;
@@ -106,7 +124,7 @@
          * If we fail to change ownership and if we are
          * using security model none. Ignore the error
          */
-        if (fs_ctx->fs_sm != SM_NONE) {
+        if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) {
             return -1;
         }
     }
@@ -120,7 +138,7 @@
     char buffer[PATH_MAX];
     char *path = fs_path->data;
 
-    if (fs_ctx->fs_sm == SM_MAPPED) {
+    if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
         int fd;
         fd = open(rpath(fs_ctx, path, buffer), O_RDONLY);
         if (fd == -1) {
@@ -131,8 +149,8 @@
         } while (tsize == -1 && errno == EINTR);
         close(fd);
         return tsize;
-    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
-               (fs_ctx->fs_sm == SM_NONE)) {
+    } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
+               (fs_ctx->export_flags & V9FS_SM_NONE)) {
         tsize = readlink(rpath(fs_ctx, path, buffer), buf, bufsz);
     }
     return tsize;
@@ -203,16 +221,30 @@
 static ssize_t local_pwritev(FsContext *ctx, int fd, const struct iovec *iov,
                              int iovcnt, off_t offset)
 {
+    ssize_t ret
+;
 #ifdef CONFIG_PREADV
-    return pwritev(fd, iov, iovcnt, offset);
+    ret = pwritev(fd, iov, iovcnt, offset);
 #else
     int err = lseek(fd, offset, SEEK_SET);
     if (err == -1) {
         return err;
     } else {
-        return writev(fd, iov, iovcnt);
+        ret = writev(fd, iov, iovcnt);
     }
 #endif
+#ifdef CONFIG_SYNC_FILE_RANGE
+    if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) {
+        /*
+         * Initiate a writeback. This is not a data integrity sync.
+         * We want to ensure that we don't leave dirty pages in the cache
+         * after write when writeout=immediate is sepcified.
+         */
+        sync_file_range(fd, offset, ret,
+                        SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE);
+    }
+#endif
+    return ret;
 }
 
 static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
@@ -220,10 +252,10 @@
     char buffer[PATH_MAX];
     char *path = fs_path->data;
 
-    if (fs_ctx->fs_sm == SM_MAPPED) {
+    if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
         return local_set_xattr(rpath(fs_ctx, path, buffer), credp);
-    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
-               (fs_ctx->fs_sm == SM_NONE)) {
+    } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
+               (fs_ctx->export_flags & V9FS_SM_NONE)) {
         return chmod(rpath(fs_ctx, path, buffer), credp->fc_mode);
     }
     return -1;
@@ -243,7 +275,7 @@
     path = fullname.data;
 
     /* Determine the security model */
-    if (fs_ctx->fs_sm == SM_MAPPED) {
+    if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
         err = mknod(rpath(fs_ctx, path, buffer),
                 SM_LOCAL_MODE_BITS|S_IFREG, 0);
         if (err == -1) {
@@ -254,8 +286,8 @@
             serrno = errno;
             goto err_end;
         }
-    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
-               (fs_ctx->fs_sm == SM_NONE)) {
+    } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
+               (fs_ctx->export_flags & V9FS_SM_NONE)) {
         err = mknod(rpath(fs_ctx, path, buffer), credp->fc_mode,
                 credp->fc_rdev);
         if (err == -1) {
@@ -291,7 +323,7 @@
     path = fullname.data;
 
     /* Determine the security model */
-    if (fs_ctx->fs_sm == SM_MAPPED) {
+    if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
         err = mkdir(rpath(fs_ctx, path, buffer), SM_LOCAL_DIR_MODE_BITS);
         if (err == -1) {
             goto out;
@@ -302,8 +334,8 @@
             serrno = errno;
             goto err_end;
         }
-    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
-               (fs_ctx->fs_sm == SM_NONE)) {
+    } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
+               (fs_ctx->export_flags & V9FS_SM_NONE)) {
         err = mkdir(rpath(fs_ctx, path, buffer), credp->fc_mode);
         if (err == -1) {
             goto out;
@@ -331,7 +363,7 @@
     if (err) {
         return err;
     }
-    if (fs_ctx->fs_sm == SM_MAPPED) {
+    if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
         /* Actual credentials are part of extended attrs */
         uid_t tmp_uid;
         gid_t tmp_gid;
@@ -369,7 +401,7 @@
     path = fullname.data;
 
     /* Determine the security model */
-    if (fs_ctx->fs_sm == SM_MAPPED) {
+    if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
         fd = open(rpath(fs_ctx, path, buffer), flags, SM_LOCAL_MODE_BITS);
         if (fd == -1) {
             err = fd;
@@ -382,8 +414,8 @@
             serrno = errno;
             goto err_end;
         }
-    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
-               (fs_ctx->fs_sm == SM_NONE)) {
+    } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
+               (fs_ctx->export_flags & V9FS_SM_NONE)) {
         fd = open(rpath(fs_ctx, path, buffer), flags, credp->fc_mode);
         if (fd == -1) {
             err = fd;
@@ -422,7 +454,7 @@
     newpath = fullname.data;
 
     /* Determine the security model */
-    if (fs_ctx->fs_sm == SM_MAPPED) {
+    if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
         int fd;
         ssize_t oldpath_size, write_size;
         fd = open(rpath(fs_ctx, newpath, buffer), O_CREAT|O_EXCL|O_RDWR,
@@ -451,8 +483,8 @@
             serrno = errno;
             goto err_end;
         }
-    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
-               (fs_ctx->fs_sm == SM_NONE)) {
+    } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
+               (fs_ctx->export_flags & V9FS_SM_NONE)) {
         err = symlink(oldpath, rpath(fs_ctx, newpath, buffer));
         if (err) {
             goto out;
@@ -464,7 +496,7 @@
              * If we fail to change ownership and if we are
              * using security model none. Ignore the error
              */
-            if (fs_ctx->fs_sm != SM_NONE) {
+            if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) {
                 serrno = errno;
                 goto err_end;
             } else
@@ -519,13 +551,13 @@
     char *path = fs_path->data;
 
     if ((credp->fc_uid == -1 && credp->fc_gid == -1) ||
-            (fs_ctx->fs_sm == SM_PASSTHROUGH)) {
+            (fs_ctx->export_flags & V9FS_SM_PASSTHROUGH)) {
         return lchown(rpath(fs_ctx, path, buffer), credp->fc_uid,
                 credp->fc_gid);
-    } else if (fs_ctx->fs_sm == SM_MAPPED) {
+    } else if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
         return local_set_xattr(rpath(fs_ctx, path, buffer), credp);
-    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
-               (fs_ctx->fs_sm == SM_NONE)) {
+    } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
+               (fs_ctx->export_flags & V9FS_SM_NONE)) {
         return lchown(rpath(fs_ctx, path, buffer), credp->fc_uid,
                 credp->fc_gid);
     }
@@ -645,10 +677,44 @@
     return ret;
 }
 
+static int local_ioc_getversion(FsContext *ctx, V9fsPath *path,
+                                mode_t st_mode, uint64_t *st_gen)
+{
+    int err, fd;
+    /*
+     * Do not try to open special files like device nodes, fifos etc
+     * We can get fd for regular files and directories only
+     */
+    if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
+            return 0;
+    }
+    fd = local_open(ctx, path, O_RDONLY);
+    if (fd < 0) {
+        return fd;
+    }
+    err = ioctl(fd, FS_IOC_GETVERSION, st_gen);
+    local_close(ctx, fd);
+    return err;
+}
+
 static int local_init(FsContext *ctx)
 {
-    ctx->flags |= PATHNAME_FSCONTEXT;
-    return 0;
+    int err;
+    struct statfs stbuf;
+
+    ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT;
+    err = statfs(ctx->fs_root, &stbuf);
+    if (!err) {
+        switch (stbuf.f_type) {
+        case EXT2_SUPER_MAGIC:
+        case BTRFS_SUPER_MAGIC:
+        case REISERFS_SUPER_MAGIC:
+        case XFS_SUPER_MAGIC:
+            ctx->exops.get_st_gen = local_ioc_getversion;
+            break;
+        }
+    }
+    return err;
 }
 
 FileOperations local_ops = {
diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index c01c31a..aab3beb 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -17,11 +17,10 @@
 #include "hw/virtio-pci.h"
 #include "virtio-9p.h"
 #include "fsdev/qemu-fsdev.h"
-#include "virtio-9p-debug.h"
 #include "virtio-9p-xattr.h"
 #include "virtio-9p-coth.h"
+#include "trace.h"
 
-int debug_9p_pdu;
 int open_fd_hw;
 int total_open_fd;
 static int open_fd_rc;
@@ -72,6 +71,55 @@
     return ret;
 }
 
+static int dotl_to_at_flags(int flags)
+{
+    int rflags = 0;
+    if (flags & P9_DOTL_AT_REMOVEDIR) {
+        rflags |= AT_REMOVEDIR;
+    }
+    return rflags;
+}
+
+struct dotl_openflag_map {
+    int dotl_flag;
+    int open_flag;
+};
+
+static int dotl_to_open_flags(int flags)
+{
+    int i;
+    /*
+     * We have same bits for P9_DOTL_READONLY, P9_DOTL_WRONLY
+     * and P9_DOTL_NOACCESS
+     */
+    int oflags = flags & O_ACCMODE;
+
+    struct dotl_openflag_map dotl_oflag_map[] = {
+        { P9_DOTL_CREATE, O_CREAT },
+        { P9_DOTL_EXCL, O_EXCL },
+        { P9_DOTL_NOCTTY , O_NOCTTY },
+        { P9_DOTL_TRUNC, O_TRUNC },
+        { P9_DOTL_APPEND, O_APPEND },
+        { P9_DOTL_NONBLOCK, O_NONBLOCK } ,
+        { P9_DOTL_DSYNC, O_DSYNC },
+        { P9_DOTL_FASYNC, FASYNC },
+        { P9_DOTL_DIRECT, O_DIRECT },
+        { P9_DOTL_LARGEFILE, O_LARGEFILE },
+        { P9_DOTL_DIRECTORY, O_DIRECTORY },
+        { P9_DOTL_NOFOLLOW, O_NOFOLLOW },
+        { P9_DOTL_NOATIME, O_NOATIME },
+        { P9_DOTL_SYNC, O_SYNC },
+    };
+
+    for (i = 0; i < ARRAY_SIZE(dotl_oflag_map); i++) {
+        if (flags & dotl_oflag_map[i].dotl_flag) {
+            oflags |= dotl_oflag_map[i].open_flag;
+        }
+    }
+
+    return oflags;
+}
+
 void cred_init(FsCred *credp)
 {
     credp->fc_uid = -1;
@@ -80,6 +128,21 @@
     credp->fc_rdev = -1;
 }
 
+static int get_dotl_openflags(V9fsState *s, int oflags)
+{
+    int flags;
+    /*
+     * Filter the client open flags
+     */
+    flags = dotl_to_open_flags(oflags);
+    flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT);
+    /*
+     * Ignore direct disk access hint until the server supports it.
+     */
+    flags &= ~O_DIRECT;
+    return flags;
+}
+
 void v9fs_string_init(V9fsString *str)
 {
     str->data = NULL;
@@ -621,9 +684,6 @@
 static void free_pdu(V9fsState *s, V9fsPDU *pdu)
 {
     if (pdu) {
-        if (debug_9p_pdu) {
-            pprint_pdu(pdu);
-        }
         /*
          * Cancelled pdu are added back to the freelist
          * by flush request .
@@ -909,6 +969,7 @@
         if (s->proto_version == V9FS_PROTO_2000L) {
             id = P9_RLERROR;
         }
+        trace_complete_pdu(pdu->tag, pdu->id, err); /* Trace ERROR */
     }
 
     /* fill out the header */
@@ -1218,6 +1279,7 @@
     size_t offset = 7;
 
     pdu_unmarshal(pdu, offset, "ds", &s->msize, &version);
+    trace_v9fs_version(pdu->tag, pdu->id, s->msize, version.data);
 
     if (!strcmp(version.data, "9P2000.u")) {
         s->proto_version = V9FS_PROTO_2000U;
@@ -1228,6 +1290,8 @@
     }
 
     offset += pdu_marshal(pdu, offset, "ds", s->msize, &version);
+    trace_v9fs_version_return(pdu->tag, pdu->id, s->msize, version.data);
+
     complete_pdu(s, pdu, offset);
 
     v9fs_string_free(&version);
@@ -1246,6 +1310,7 @@
     ssize_t err;
 
     pdu_unmarshal(pdu, offset, "ddssd", &fid, &afid, &uname, &aname, &n_uname);
+    trace_v9fs_attach(pdu->tag, pdu->id, fid, afid, uname.data, aname.data);
 
     fidp = alloc_fid(s, fid);
     if (fidp == NULL) {
@@ -1270,6 +1335,8 @@
 out:
     put_fid(pdu, fidp);
 out_nofid:
+    trace_v9fs_attach_return(pdu->tag, pdu->id,
+                             qid.type, qid.version, qid.path);
     complete_pdu(s, pdu, err);
     v9fs_string_free(&uname);
     v9fs_string_free(&aname);
@@ -1287,6 +1354,7 @@
     V9fsState *s = pdu->s;
 
     pdu_unmarshal(pdu, offset, "d", &fid);
+    trace_v9fs_stat(pdu->tag, pdu->id, fid);
 
     fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
@@ -1307,6 +1375,9 @@
 out:
     put_fid(pdu, fidp);
 out_nofid:
+    trace_v9fs_stat_return(pdu->tag, pdu->id, v9stat.mode,
+                           v9stat.atime, v9stat.mtime, v9stat.length);
+
     complete_pdu(s, pdu, err);
 }
 
@@ -1323,6 +1394,7 @@
     V9fsState *s = pdu->s;
 
     pdu_unmarshal(pdu, offset, "dq", &fid, &request_mask);
+    trace_v9fs_getattr(pdu->tag, pdu->id, fid, request_mask);
 
     fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
@@ -1338,11 +1410,24 @@
         goto out;
     }
     stat_to_v9stat_dotl(s, &stbuf, &v9stat_dotl);
+
+    /*  fill st_gen if requested and supported by underlying fs */
+    if (request_mask & P9_STATS_GEN) {
+        retval = v9fs_co_st_gen(pdu, &fidp->path, stbuf.st_mode, &v9stat_dotl);
+        if (retval < 0) {
+            goto out;
+        }
+        v9stat_dotl.st_result_mask |= P9_STATS_GEN;
+    }
     retval = offset;
     retval += pdu_marshal(pdu, offset, "A", &v9stat_dotl);
 out:
     put_fid(pdu, fidp);
 out_nofid:
+    trace_v9fs_getattr_return(pdu->tag, pdu->id, v9stat_dotl.st_result_mask,
+                              v9stat_dotl.st_mode, v9stat_dotl.st_uid,
+                              v9stat_dotl.st_gid);
+
     complete_pdu(s, pdu, retval);
 }
 
@@ -1470,6 +1555,8 @@
     offset += pdu_unmarshal(pdu, offset, "ddw", &fid,
                             &newfid, &nwnames);
 
+    trace_v9fs_walk(pdu->tag, pdu->id, fid, newfid, nwnames);
+
     if (nwnames && nwnames <= P9_MAXWELEM) {
         wnames = g_malloc0(sizeof(wnames[0]) * nwnames);
         qids   = g_malloc0(sizeof(qids[0]) * nwnames);
@@ -1526,6 +1613,7 @@
     v9fs_path_free(&dpath);
     v9fs_path_free(&path);
 out_nofid:
+    trace_v9fs_walk_return(pdu->tag, pdu->id, nwnames, qids);
     complete_pdu(s, pdu, err);
     if (nwnames && nwnames <= P9_MAXWELEM) {
         for (name_idx = 0; name_idx < nwnames; name_idx++) {
@@ -1576,6 +1664,8 @@
     } else {
         pdu_unmarshal(pdu, offset, "db", &fid, &mode);
     }
+    trace_v9fs_open(pdu->tag, pdu->id, fid, mode);
+
     fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         err = -ENOENT;
@@ -1598,10 +1688,7 @@
         err = offset;
     } else {
         if (s->proto_version == V9FS_PROTO_2000L) {
-            flags = mode;
-            flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT);
-            /* Ignore direct disk access hint until the server supports it. */
-            flags &= ~O_DIRECT;
+            flags = get_dotl_openflags(s, mode);
         } else {
             flags = omode_to_uflags(mode);
         }
@@ -1625,6 +1712,8 @@
 out:
     put_fid(pdu, fidp);
 out_nofid:
+    trace_v9fs_open_return(pdu->tag, pdu->id,
+                           qid.type, qid.version, qid.path, iounit);
     complete_pdu(s, pdu, err);
 }
 
@@ -1643,6 +1732,7 @@
 
     pdu_unmarshal(pdu, offset, "dsddd", &dfid, &name, &flags,
                   &mode, &gid);
+    trace_v9fs_lcreate(pdu->tag, pdu->id, dfid, flags, mode, gid);
 
     fidp = get_fid(pdu, dfid);
     if (fidp == NULL) {
@@ -1650,8 +1740,7 @@
         goto out_nofid;
     }
 
-    /* Ignore direct disk access hint until the server supports it. */
-    flags &= ~O_DIRECT;
+    flags = get_dotl_openflags(pdu->s, flags);
     err = v9fs_co_open2(pdu, fidp, &name, gid,
                         flags | O_CREAT, mode, &stbuf);
     if (err < 0) {
@@ -1673,6 +1762,8 @@
 out:
     put_fid(pdu, fidp);
 out_nofid:
+    trace_v9fs_lcreate_return(pdu->tag, pdu->id,
+                              qid.type, qid.version, qid.path, iounit);
     complete_pdu(pdu->s, pdu, err);
     v9fs_string_free(&name);
 }
@@ -1688,6 +1779,8 @@
     V9fsState *s = pdu->s;
 
     pdu_unmarshal(pdu, offset, "dd", &fid, &datasync);
+    trace_v9fs_fsync(pdu->tag, pdu->id, fid, datasync);
+
     fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         err = -ENOENT;
@@ -1712,6 +1805,7 @@
     V9fsState *s = pdu->s;
 
     pdu_unmarshal(pdu, offset, "d", &fid);
+    trace_v9fs_clunk(pdu->tag, pdu->id, fid);
 
     fidp = clunk_fid(s, fid);
     if (fidp == NULL) {
@@ -1828,6 +1922,7 @@
     V9fsState *s = pdu->s;
 
     pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &max_count);
+    trace_v9fs_read(pdu->tag, pdu->id, fid, off, max_count);
 
     fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
@@ -1886,6 +1981,7 @@
 out:
     put_fid(pdu, fidp);
 out_nofid:
+    trace_v9fs_read_return(pdu->tag, pdu->id, count, err);
     complete_pdu(s, pdu, err);
 }
 
@@ -1970,6 +2066,8 @@
 
     pdu_unmarshal(pdu, offset, "dqd", &fid, &initial_offset, &max_count);
 
+    trace_v9fs_readdir(pdu->tag, pdu->id, fid, initial_offset, max_count);
+
     fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         retval = -EINVAL;
@@ -1995,6 +2093,7 @@
 out:
     put_fid(pdu, fidp);
 out_nofid:
+    trace_v9fs_readdir_return(pdu->tag, pdu->id, count, retval);
     complete_pdu(s, pdu, retval);
 }
 
@@ -2059,6 +2158,7 @@
     V9fsState *s = pdu->s;
 
     pdu_unmarshal(pdu, offset, "dqdv", &fid, &off, &count, sg, &cnt);
+    trace_v9fs_write(pdu->tag, pdu->id, fid, off, count, cnt);
 
     fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
@@ -2105,6 +2205,7 @@
 out:
     put_fid(pdu, fidp);
 out_nofid:
+    trace_v9fs_write_return(pdu->tag, pdu->id, total, err);
     complete_pdu(s, pdu, err);
 }
 
@@ -2129,6 +2230,8 @@
     pdu_unmarshal(pdu, offset, "dsdbs", &fid, &name,
                   &perm, &mode, &extension);
 
+    trace_v9fs_create(pdu->tag, pdu->id, fid, name.data, perm, mode);
+
     fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         err = -EINVAL;
@@ -2262,6 +2365,8 @@
 out:
     put_fid(pdu, fidp);
 out_nofid:
+   trace_v9fs_create_return(pdu->tag, pdu->id,
+                            qid.type, qid.version, qid.path, iounit);
    complete_pdu(pdu->s, pdu, err);
    v9fs_string_free(&name);
    v9fs_string_free(&extension);
@@ -2282,6 +2387,7 @@
     size_t offset = 7;
 
     pdu_unmarshal(pdu, offset, "dssd", &dfid, &name, &symname, &gid);
+    trace_v9fs_symlink(pdu->tag, pdu->id, dfid, name.data, symname.data, gid);
 
     dfidp = get_fid(pdu, dfid);
     if (dfidp == NULL) {
@@ -2298,6 +2404,8 @@
 out:
     put_fid(pdu, dfidp);
 out_nofid:
+    trace_v9fs_symlink_return(pdu->tag, pdu->id,
+                              qid.type, qid.version, qid.path);
     complete_pdu(pdu->s, pdu, err);
     v9fs_string_free(&name);
     v9fs_string_free(&symname);
@@ -2312,6 +2420,7 @@
     V9fsState *s = pdu->s;
 
     pdu_unmarshal(pdu, offset, "w", &tag);
+    trace_v9fs_flush(pdu->tag, pdu->id, tag);
 
     QLIST_FOREACH(cancel_pdu, &s->active_list, next) {
         if (cancel_pdu->tag == tag) {
@@ -2342,6 +2451,7 @@
     int err = 0;
 
     pdu_unmarshal(pdu, offset, "dds", &dfid, &oldfid, &name);
+    trace_v9fs_link(pdu->tag, pdu->id, dfid, oldfid, name.data);
 
     dfidp = get_fid(pdu, dfid);
     if (dfidp == NULL) {
@@ -2375,6 +2485,7 @@
     V9fsPDU *pdu = opaque;
 
     pdu_unmarshal(pdu, offset, "d", &fid);
+    trace_v9fs_remove(pdu->tag, pdu->id, fid);
 
     fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
@@ -2382,7 +2493,7 @@
         goto out_nofid;
     }
     /* if fs driver is not path based, return EOPNOTSUPP */
-    if (!pdu->s->ctx.flags & PATHNAME_FSCONTEXT) {
+    if (!(pdu->s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT)) {
         err = -EOPNOTSUPP;
         goto out_err;
     }
@@ -2417,6 +2528,7 @@
     V9fsPDU *pdu = opaque;
 
     pdu_unmarshal(pdu, offset, "dsd", &dfid, &name, &flags);
+    flags = dotl_to_at_flags(flags);
 
     dfidp = get_fid(pdu, dfid);
     if (dfidp == NULL) {
@@ -2528,7 +2640,7 @@
     }
     BUG_ON(fidp->fid_type != P9_FID_NONE);
     /* if fs driver is not path based, return EOPNOTSUPP */
-    if (!pdu->s->ctx.flags & PATHNAME_FSCONTEXT) {
+    if (!(pdu->s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT)) {
         err = -EOPNOTSUPP;
         goto out;
     }
@@ -2601,7 +2713,7 @@
     if (err < 0) {
         goto out;
     }
-    if (s->ctx.flags & PATHNAME_FSCONTEXT) {
+    if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) {
         /* Only for path based fid  we need to do the below fixup */
         v9fs_fix_fid_paths(pdu, &olddirfidp->path, old_name,
                            &newdirfidp->path, new_name);
@@ -2653,6 +2765,8 @@
     V9fsState *s = pdu->s;
 
     pdu_unmarshal(pdu, offset, "dwS", &fid, &unused, &v9stat);
+    trace_v9fs_wstat(pdu->tag, pdu->id, fid,
+                     v9stat.mode, v9stat.atime, v9stat.mtime);
 
     fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
@@ -2821,6 +2935,7 @@
 
     pdu_unmarshal(pdu, offset, "dsdddd", &fid, &name, &mode,
                   &major, &minor, &gid);
+    trace_v9fs_mknod(pdu->tag, pdu->id, fid, mode, major, minor);
 
     fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
@@ -2838,6 +2953,7 @@
 out:
     put_fid(pdu, fidp);
 out_nofid:
+    trace_v9fs_mknod_return(pdu->tag, pdu->id, qid.type, qid.version, qid.path);
     complete_pdu(s, pdu, err);
     v9fs_string_free(&name);
 }
@@ -2865,6 +2981,10 @@
     pdu_unmarshal(pdu, offset, "dbdqqds", &fid, &flock->type,
                   &flock->flags, &flock->start, &flock->length,
                   &flock->proc_id, &flock->client_id);
+
+    trace_v9fs_lock(pdu->tag, pdu->id, fid,
+                    flock->type, flock->start, flock->length);
+
     status = P9_LOCK_ERROR;
 
     /* We support only block flag now (that too ignored currently) */
@@ -2887,6 +3007,7 @@
 out_nofid:
     err = offset;
     err += pdu_marshal(pdu, offset, "b", status);
+    trace_v9fs_lock_return(pdu->tag, pdu->id, status);
     complete_pdu(s, pdu, err);
     v9fs_string_free(&flock->client_id);
     g_free(flock);
@@ -2911,6 +3032,9 @@
                   &glock->start, &glock->length, &glock->proc_id,
                   &glock->client_id);
 
+    trace_v9fs_getlock(pdu->tag, pdu->id, fid,
+                       glock->type, glock->start, glock->length);
+
     fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         err = -ENOENT;
@@ -2920,7 +3044,7 @@
     if (err < 0) {
         goto out;
     }
-    glock->type = F_UNLCK;
+    glock->type = P9_LOCK_TYPE_UNLCK;
     offset += pdu_marshal(pdu, offset, "bqqds", glock->type,
                           glock->start, glock->length, glock->proc_id,
                           &glock->client_id);
@@ -2928,6 +3052,9 @@
 out:
     put_fid(pdu, fidp);
 out_nofid:
+    trace_v9fs_getlock_return(pdu->tag, pdu->id, glock->type, glock->start,
+                              glock->length, glock->proc_id);
+
     complete_pdu(s, pdu, err);
     v9fs_string_free(&glock->client_id);
     g_free(glock);
@@ -2948,6 +3075,8 @@
 
     pdu_unmarshal(pdu, offset, "dsdd", &fid, &name, &mode, &gid);
 
+    trace_v9fs_mkdir(pdu->tag, pdu->id, fid, name.data, mode, gid);
+
     fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         err = -ENOENT;
@@ -2963,6 +3092,8 @@
 out:
     put_fid(pdu, fidp);
 out_nofid:
+    trace_v9fs_mkdir_return(pdu->tag, pdu->id,
+                            qid.type, qid.version, qid.path, err);
     complete_pdu(pdu->s, pdu, err);
     v9fs_string_free(&name);
 }
@@ -2980,6 +3111,8 @@
     V9fsState *s = pdu->s;
 
     pdu_unmarshal(pdu, offset, "dds", &fid, &newfid, &name);
+    trace_v9fs_xattrwalk(pdu->tag, pdu->id, fid, newfid, name.data);
+
     file_fidp = get_fid(pdu, fid);
     if (file_fidp == NULL) {
         err = -ENOENT;
@@ -3056,6 +3189,7 @@
         put_fid(pdu, xattr_fidp);
     }
 out_nofid:
+    trace_v9fs_xattrwalk_return(pdu->tag, pdu->id, size);
     complete_pdu(s, pdu, err);
     v9fs_string_free(&name);
 }
@@ -3075,6 +3209,7 @@
 
     pdu_unmarshal(pdu, offset, "dsqd",
                   &fid, &name, &size, &flags);
+    trace_v9fs_xattrcreate(pdu->tag, pdu->id, fid, name.data, size, flags);
 
     file_fidp = get_fid(pdu, fid);
     if (file_fidp == NULL) {
@@ -3111,6 +3246,7 @@
     V9fsFidState *fidp;
 
     pdu_unmarshal(pdu, offset, "d", &fid);
+    trace_v9fs_readlink(pdu->tag, pdu->id, fid);
     fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         err = -ENOENT;
@@ -3128,6 +3264,7 @@
 out:
     put_fid(pdu, fidp);
 out_nofid:
+    trace_v9fs_readlink_return(pdu->tag, pdu->id, target.data);
     complete_pdu(pdu->s, pdu, err);
 }
 
@@ -3179,9 +3316,6 @@
     Coroutine *co;
     CoroutineEntry *handler;
 
-    if (debug_9p_pdu) {
-        pprint_pdu(pdu);
-    }
     if (pdu->id >= ARRAY_SIZE(pdu_co_handlers) ||
         (pdu_co_handlers[pdu->id] == NULL)) {
         handler = v9fs_op_not_supp;
diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h
index 60b8a56..802f580 100644
--- a/hw/9pfs/virtio-9p.h
+++ b/hw/9pfs/virtio-9p.h
@@ -352,6 +352,35 @@
     V9fsString fullname;
 } V9fsMkState;
 
+/* 9p2000.L open flags */
+#define P9_DOTL_RDONLY        00000000
+#define P9_DOTL_WRONLY        00000001
+#define P9_DOTL_RDWR          00000002
+#define P9_DOTL_NOACCESS      00000003
+#define P9_DOTL_CREATE        00000100
+#define P9_DOTL_EXCL          00000200
+#define P9_DOTL_NOCTTY        00000400
+#define P9_DOTL_TRUNC         00001000
+#define P9_DOTL_APPEND        00002000
+#define P9_DOTL_NONBLOCK      00004000
+#define P9_DOTL_DSYNC         00010000
+#define P9_DOTL_FASYNC        00020000
+#define P9_DOTL_DIRECT        00040000
+#define P9_DOTL_LARGEFILE     00100000
+#define P9_DOTL_DIRECTORY     00200000
+#define P9_DOTL_NOFOLLOW      00400000
+#define P9_DOTL_NOATIME       01000000
+#define P9_DOTL_CLOEXEC       02000000
+#define P9_DOTL_SYNC          04000000
+
+/* 9p2000.L at flags */
+#define P9_DOTL_AT_REMOVEDIR         0x200
+
+/* 9P2000.L lock type */
+#define P9_LOCK_TYPE_RDLCK 0
+#define P9_LOCK_TYPE_WRLCK 1
+#define P9_LOCK_TYPE_UNLCK 2
+
 #define P9_LOCK_SUCCESS 0
 #define P9_LOCK_BLOCKED 1
 #define P9_LOCK_ERROR 2
@@ -393,21 +422,21 @@
 
 static inline void v9fs_path_write_lock(V9fsState *s)
 {
-    if (s->ctx.flags & PATHNAME_FSCONTEXT) {
+    if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) {
         qemu_co_rwlock_wrlock(&s->rename_lock);
     }
 }
 
 static inline void v9fs_path_read_lock(V9fsState *s)
 {
-    if (s->ctx.flags & PATHNAME_FSCONTEXT) {
+    if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) {
         qemu_co_rwlock_rdlock(&s->rename_lock);
     }
 }
 
 static inline void v9fs_path_unlock(V9fsState *s)
 {
-    if (s->ctx.flags & PATHNAME_FSCONTEXT) {
+    if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) {
         qemu_co_rwlock_unlock(&s->rename_lock);
     }
 }
diff --git a/hw/arm_gic.c b/hw/arm_gic.c
index 83213dd..8dd8742 100644
--- a/hw/arm_gic.c
+++ b/hw/arm_gic.c
@@ -658,9 +658,6 @@
     qemu_put_be32(f, s->enabled);
     for (i = 0; i < NUM_CPU(s); i++) {
         qemu_put_be32(f, s->cpu_enabled[i]);
-#ifndef NVIC
-        qemu_put_be32(f, s->irq_target[i]);
-#endif
         for (j = 0; j < 32; j++)
             qemu_put_be32(f, s->priority1[j][i]);
         for (j = 0; j < GIC_NIRQ; j++)
@@ -674,6 +671,9 @@
         qemu_put_be32(f, s->priority2[i]);
     }
     for (i = 0; i < GIC_NIRQ; i++) {
+#ifndef NVIC
+        qemu_put_be32(f, s->irq_target[i]);
+#endif
         qemu_put_byte(f, s->irq_state[i].enabled);
         qemu_put_byte(f, s->irq_state[i].pending);
         qemu_put_byte(f, s->irq_state[i].active);
@@ -689,15 +689,12 @@
     int i;
     int j;
 
-    if (version_id != 1)
+    if (version_id != 2)
         return -EINVAL;
 
     s->enabled = qemu_get_be32(f);
     for (i = 0; i < NUM_CPU(s); i++) {
         s->cpu_enabled[i] = qemu_get_be32(f);
-#ifndef NVIC
-        s->irq_target[i] = qemu_get_be32(f);
-#endif
         for (j = 0; j < 32; j++)
             s->priority1[j][i] = qemu_get_be32(f);
         for (j = 0; j < GIC_NIRQ; j++)
@@ -711,6 +708,9 @@
         s->priority2[i] = qemu_get_be32(f);
     }
     for (i = 0; i < GIC_NIRQ; i++) {
+#ifndef NVIC
+        s->irq_target[i] = qemu_get_be32(f);
+#endif
         s->irq_state[i].enabled = qemu_get_byte(f);
         s->irq_state[i].pending = qemu_get_byte(f);
         s->irq_state[i].active = qemu_get_byte(f);
@@ -739,5 +739,5 @@
     }
     memory_region_init_io(&s->iomem, &gic_dist_ops, s, "gic_dist", 0x1000);
     gic_reset(s);
-    register_savevm(NULL, "arm_gic", -1, 1, gic_save, gic_load, s);
+    register_savevm(NULL, "arm_gic", -1, 2, gic_save, gic_load, s);
 }
diff --git a/hw/collie.c b/hw/collie.c
index a10cc1b..8dd6e4e 100644
--- a/hw/collie.c
+++ b/hw/collie.c
@@ -13,6 +13,7 @@
 #include "arm-misc.h"
 #include "flash.h"
 #include "blockdev.h"
+#include "exec-memory.h"
 
 static struct arm_boot_info collie_binfo = {
     .loader_start = SA_SDCS0,
@@ -26,12 +27,13 @@
 {
     StrongARMState *s;
     DriveInfo *dinfo;
+    MemoryRegion *sysmem = get_system_memory();
 
     if (!cpu_model) {
         cpu_model = "sa1110";
     }
 
-    s = sa1110_init(collie_binfo.ram_size, cpu_model);
+    s = sa1110_init(sysmem, collie_binfo.ram_size, cpu_model);
 
     dinfo = drive_get(IF_PFLASH, 0, 0);
     pflash_cfi01_register(SA_CS0, NULL, "collie.fl1", 0x02000000,
diff --git a/hw/devices.h b/hw/devices.h
index 8ac384f..1a55c1e 100644
--- a/hw/devices.h
+++ b/hw/devices.h
@@ -53,7 +53,8 @@
 /* tc6393xb.c */
 typedef struct TC6393xbState TC6393xbState;
 #define TC6393XB_RAM	0x110000 /* amount of ram for Video and USB */
-TC6393xbState *tc6393xb_init(uint32_t base, qemu_irq irq);
+TC6393xbState *tc6393xb_init(struct MemoryRegion *sysmem,
+                             uint32_t base, qemu_irq irq);
 void tc6393xb_gpio_out_set(TC6393xbState *s, int line,
                     qemu_irq handler);
 qemu_irq *tc6393xb_gpio_in_get(TC6393xbState *s);
diff --git a/hw/ds1225y.c b/hw/ds1225y.c
index 9875c44..6852a61 100644
--- a/hw/ds1225y.c
+++ b/hw/ds1225y.c
@@ -29,7 +29,7 @@
     DeviceState qdev;
     uint32_t chip_size;
     char *filename;
-    QEMUFile *file;
+    FILE *file;
     uint8_t *contents;
 } NvRamState;
 
@@ -70,9 +70,9 @@
 
     s->contents[addr] = val;
     if (s->file) {
-        qemu_fseek(s->file, addr, SEEK_SET);
-        qemu_put_byte(s->file, (int)val);
-        qemu_fflush(s->file);
+        fseek(s->file, addr, SEEK_SET);
+        fputc(val, s->file);
+        fflush(s->file);
     }
 }
 
@@ -108,15 +108,17 @@
 
     /* Close file, as filename may has changed in load/store process */
     if (s->file) {
-        qemu_fclose(s->file);
+        fclose(s->file);
     }
 
     /* Write back nvram contents */
-    s->file = qemu_fopen(s->filename, "wb");
+    s->file = fopen(s->filename, "wb");
     if (s->file) {
         /* Write back contents, as 'wb' mode cleaned the file */
-        qemu_put_buffer(s->file, s->contents, s->chip_size);
-        qemu_fflush(s->file);
+        if (fwrite(s->contents, s->chip_size, 1, s->file) != 1) {
+            printf("nvram_post_load: short write\n");
+        }
+        fflush(s->file);
     }
 
     return 0;
@@ -143,7 +145,7 @@
 static int nvram_sysbus_initfn(SysBusDevice *dev)
 {
     NvRamState *s = &FROM_SYSBUS(SysBusNvRamState, dev)->nvram;
-    QEMUFile *file;
+    FILE *file;
     int s_io;
 
     s->contents = g_malloc0(s->chip_size);
@@ -153,11 +155,13 @@
     sysbus_init_mmio(dev, s->chip_size, s_io);
 
     /* Read current file */
-    file = qemu_fopen(s->filename, "rb");
+    file = fopen(s->filename, "rb");
     if (file) {
         /* Read nvram contents */
-        qemu_get_buffer(file, s->contents, s->chip_size);
-        qemu_fclose(file);
+        if (fread(s->contents, s->chip_size, 1, file) != 1) {
+            printf("nvram_sysbus_initfn: short read\n");
+        }
+        fclose(file);
     }
     nvram_post_load(s, 0);
 
diff --git a/hw/fdc.c b/hw/fdc.c
index 4b06e04..ecaad09 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -434,6 +434,7 @@
     FDCtrl *fdctrl = opaque;
     uint32_t retval;
 
+    reg &= 7;
     switch (reg) {
     case FD_REG_SRA:
         retval = fdctrl_read_statusA(fdctrl);
@@ -471,6 +472,7 @@
 
     FLOPPY_DPRINTF("write reg%d: 0x%02x\n", reg & 7, value);
 
+    reg &= 7;
     switch (reg) {
     case FD_REG_DOR:
         fdctrl_write_dor(fdctrl, value);
@@ -1945,6 +1947,18 @@
     return fdctrl_init_common(fdctrl);
 }
 
+void fdc_get_bs(BlockDriverState *bs[], ISADevice *dev)
+{
+    FDCtrlISABus *isa = DO_UPCAST(FDCtrlISABus, busdev, dev);
+    FDCtrl *fdctrl = &isa->state;
+    int i;
+
+    for (i = 0; i < MAX_FD; i++) {
+        bs[i] = fdctrl->drives[i].bs;
+    }
+}
+
+
 static const VMStateDescription vmstate_isa_fdc ={
     .name = "fdc",
     .version_id = 2,
diff --git a/hw/fdc.h b/hw/fdc.h
index 09f73c6..506feb6 100644
--- a/hw/fdc.h
+++ b/hw/fdc.h
@@ -7,14 +7,15 @@
 /* fdc.c */
 #define MAX_FD 2
 
-static inline void fdctrl_init_isa(DriveInfo **fds)
+static inline ISADevice *fdctrl_init_isa(DriveInfo **fds)
 {
     ISADevice *dev;
 
     dev = isa_try_create("isa-fdc");
     if (!dev) {
-        return;
+        return NULL;
     }
+
     if (fds[0]) {
         qdev_prop_set_drive_nofail(&dev->qdev, "driveA", fds[0]->bdrv);
     }
@@ -22,10 +23,14 @@
         qdev_prop_set_drive_nofail(&dev->qdev, "driveB", fds[1]->bdrv);
     }
     qdev_init_nofail(&dev->qdev);
+
+    return dev;
 }
 
 void fdctrl_init_sysbus(qemu_irq irq, int dma_chann,
                         target_phys_addr_t mmio_base, DriveInfo **fds);
 void sun4m_fdctrl_init(qemu_irq irq, target_phys_addr_t io_base,
                        DriveInfo **fds, qemu_irq *fdc_tc);
+void fdc_get_bs(BlockDriverState *bs[], ISADevice *dev);
+
 #endif
diff --git a/hw/hda-audio.c b/hw/hda-audio.c
index c699d6f..9b089e6 100644
--- a/hw/hda-audio.c
+++ b/hw/hda-audio.c
@@ -466,7 +466,8 @@
     QEMUSoundCard card;
     const desc_codec *desc;
     HDAAudioStream st[4];
-    bool running[16];
+    bool running_compat[16];
+    bool running_real[2 * 16];
 
     /* properties */
     uint32_t debug;
@@ -663,7 +664,7 @@
         st->channel = payload & 0x0f;
         dprint(a, 2, "%s: stream %d, channel %d\n",
                st->node->name, st->stream, st->channel);
-        hda_audio_set_running(st, a->running[st->stream]);
+        hda_audio_set_running(st, a->running_real[st->output * 16 + st->stream]);
         hda_codec_response(hda, true, 0);
         break;
     case AC_VERB_GET_CONV:
@@ -746,16 +747,20 @@
     hda_codec_response(hda, true, 0);
 }
 
-static void hda_audio_stream(HDACodecDevice *hda, uint32_t stnr, bool running)
+static void hda_audio_stream(HDACodecDevice *hda, uint32_t stnr, bool running, bool output)
 {
     HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda);
     int s;
 
-    a->running[stnr] = running;
+    a->running_compat[stnr] = running;
+    a->running_real[output * 16 + stnr] = running;
     for (s = 0; s < ARRAY_SIZE(a->st); s++) {
         if (a->st[s].node == NULL) {
             continue;
         }
+        if (a->st[s].output != output) {
+            continue;
+        }
         if (a->st[s].stream != stnr) {
             continue;
         }
@@ -837,6 +842,12 @@
     int i;
 
     dprint(a, 1, "%s\n", __FUNCTION__);
+    if (version == 1) {
+        /* assume running_compat[] is for output streams */
+        for (i = 0; i < ARRAY_SIZE(a->running_compat); i++)
+            a->running_real[16 + i] = a->running_compat[i];
+    }
+
     for (i = 0; i < ARRAY_SIZE(a->st); i++) {
         st = a->st + i;
         if (st->node == NULL)
@@ -844,7 +855,7 @@
         hda_codec_parse_fmt(st->format, &st->as);
         hda_audio_setup(st);
         hda_audio_set_amp(st);
-        hda_audio_set_running(st, a->running[st->stream]);
+        hda_audio_set_running(st, a->running_real[st->output * 16 + st->stream]);
     }
     return 0;
 }
@@ -868,13 +879,14 @@
 
 static const VMStateDescription vmstate_hda_audio = {
     .name = "hda-audio",
-    .version_id = 1,
+    .version_id = 2,
     .post_load = hda_audio_post_load,
     .fields = (VMStateField []) {
         VMSTATE_STRUCT_ARRAY(st, HDAAudioState, 4, 0,
                              vmstate_hda_audio_stream,
                              HDAAudioStream),
-        VMSTATE_BOOL_ARRAY(running, HDAAudioState, 16),
+        VMSTATE_BOOL_ARRAY(running_compat, HDAAudioState, 16),
+        VMSTATE_BOOL_ARRAY_V(running_real, HDAAudioState, 2 * 16, 2),
         VMSTATE_END_OF_LIST()
     }
 };
diff --git a/hw/hw.h b/hw/hw.h
index a124da9..ed20f5a 100644
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -85,8 +85,8 @@
 int qemu_file_rate_limit(QEMUFile *f);
 int64_t qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate);
 int64_t qemu_file_get_rate_limit(QEMUFile *f);
-int qemu_file_has_error(QEMUFile *f);
-void qemu_file_set_error(QEMUFile *f);
+int qemu_file_get_error(QEMUFile *f);
+void qemu_file_set_error(QEMUFile *f, int error);
 
 /* Try to send any outstanding data.  This function is useful when output is
  * halted due to rate limiting or EAGAIN errors occur as it can be used to
diff --git a/hw/intel-hda.c b/hw/intel-hda.c
index 4272204..f97775c 100644
--- a/hw/intel-hda.c
+++ b/hw/intel-hda.c
@@ -389,14 +389,15 @@
 {
     HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus);
     IntelHDAState *d = container_of(bus, IntelHDAState, codecs);
-    IntelHDAStream *st = NULL;
     target_phys_addr_t addr;
     uint32_t s, copy, left;
+    IntelHDAStream *st;
     bool irq = false;
 
-    for (s = 0; s < ARRAY_SIZE(d->st); s++) {
-        if (stnr == ((d->st[s].ctl >> 20) & 0x0f)) {
-            st = d->st + s;
+    st = output ? d->st + 4 : d->st;
+    for (s = 0; s < 4; s++) {
+        if (stnr == ((st[s].ctl >> 20) & 0x0f)) {
+            st = st + s;
             break;
         }
     }
@@ -484,7 +485,7 @@
     st->bp    = 0;
 }
 
-static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool running)
+static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool running, bool output)
 {
     DeviceState *qdev;
     HDACodecDevice *cdev;
@@ -492,7 +493,7 @@
     QLIST_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
         cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
         if (cdev->info->stream) {
-            cdev->info->stream(cdev, stream, running);
+            cdev->info->stream(cdev, stream, running, output);
         }
     }
 }
@@ -566,6 +567,7 @@
 
 static void intel_hda_set_st_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
 {
+    bool output = reg->stream >= 4;
     IntelHDAStream *st = d->st + reg->stream;
 
     if (st->ctl & 0x01) {
@@ -581,11 +583,11 @@
             dprint(d, 1, "st #%d: start %d (ring buf %d bytes)\n",
                    reg->stream, stnr, st->cbl);
             intel_hda_parse_bdl(d, st);
-            intel_hda_notify_codecs(d, stnr, true);
+            intel_hda_notify_codecs(d, stnr, true, output);
         } else {
             /* stop */
             dprint(d, 1, "st #%d: stop %d\n", reg->stream, stnr);
-            intel_hda_notify_codecs(d, stnr, false);
+            intel_hda_notify_codecs(d, stnr, false, output);
         }
     }
     intel_hda_update_irq(d);
diff --git a/hw/intel-hda.h b/hw/intel-hda.h
index 4e44e38..65fd2a8 100644
--- a/hw/intel-hda.h
+++ b/hw/intel-hda.h
@@ -34,7 +34,7 @@
     int (*init)(HDACodecDevice *dev);
     int (*exit)(HDACodecDevice *dev);
     void (*command)(HDACodecDevice *dev, uint32_t nid, uint32_t data);
-    void (*stream)(HDACodecDevice *dev, uint32_t stnr, bool running);
+    void (*stream)(HDACodecDevice *dev, uint32_t stnr, bool running, bool output);
 };
 
 void hda_codec_bus_init(DeviceState *dev, HDACodecBus *bus,
diff --git a/hw/m48t59.c b/hw/m48t59.c
index f318e67..a77937e 100644
--- a/hw/m48t59.c
+++ b/hw/m48t59.c
@@ -480,7 +480,6 @@
 {
     M48t59State *NVRAM = opaque;
 
-    addr -= NVRAM->io_base;
     NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, addr, val);
     switch (addr) {
     case 0:
@@ -492,7 +491,7 @@
         NVRAM->addr |= val << 8;
         break;
     case 3:
-        m48t59_write(NVRAM, val, NVRAM->addr);
+        m48t59_write(NVRAM, NVRAM->addr, val);
         NVRAM->addr = 0x0000;
         break;
     default:
@@ -505,7 +504,6 @@
     M48t59State *NVRAM = opaque;
     uint32_t retval;
 
-    addr -= NVRAM->io_base;
     switch (addr) {
     case 3:
         retval = m48t59_read(NVRAM, NVRAM->addr);
diff --git a/hw/mac_dbdma.c b/hw/mac_dbdma.c
index 5affdd1..1791ec1 100644
--- a/hw/mac_dbdma.c
+++ b/hw/mac_dbdma.c
@@ -661,11 +661,6 @@
     ch->io.channel = ch;
 }
 
-void DBDMA_schedule(void)
-{
-    qemu_notify_event();
-}
-
 static void
 dbdma_control_write(DBDMA_channel *ch)
 {
diff --git a/hw/mac_dbdma.h b/hw/mac_dbdma.h
index 933e17c..6d1abe6 100644
--- a/hw/mac_dbdma.h
+++ b/hw/mac_dbdma.h
@@ -41,5 +41,4 @@
 void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq,
                             DBDMA_rw rw, DBDMA_flush flush,
                             void *opaque);
-void DBDMA_schedule(void);
 void* DBDMA_init (MemoryRegion **dbdma_mem);
diff --git a/hw/omap2.c b/hw/omap2.c
index 838c32f..5197fef 100644
--- a/hw/omap2.c
+++ b/hw/omap2.c
@@ -2409,6 +2409,11 @@
                        qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK3));
     sysbus_connect_irq(busdev, 9,
                        qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK4));
+    if (s->mpu_model == omap2430) {
+        sysbus_connect_irq(busdev, 12,
+                           qdev_get_gpio_in(s->ih[0],
+                                            OMAP_INT_243X_GPIO_BANK5));
+    }
     ta = omap_l4ta(s->l4, 3);
     sysbus_mmio_map(busdev, 0, omap_l4_region_base(ta, 1));
     sysbus_mmio_map(busdev, 1, omap_l4_region_base(ta, 0));
diff --git a/hw/pc.c b/hw/pc.c
index f0802b7..eb4c2d8 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -331,12 +331,12 @@
 
 void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
                   const char *boot_device,
-                  BusState *idebus0, BusState *idebus1,
+                  ISADevice *floppy, BusState *idebus0, BusState *idebus1,
                   ISADevice *s)
 {
     int val, nb, nb_heads, max_track, last_sect, i;
     FDriveType fd_type[2];
-    DriveInfo *fd[2];
+    BlockDriverState *fd[MAX_FD];
     static pc_cmos_init_late_arg arg;
 
     /* various important CMOS locations needed by PC/Bochs bios */
@@ -378,14 +378,16 @@
     }
 
     /* floppy type */
-    for (i = 0; i < 2; i++) {
-        fd[i] = drive_get(IF_FLOPPY, 0, i);
-        if (fd[i] && bdrv_is_inserted(fd[i]->bdrv)) {
-            bdrv_get_floppy_geometry_hint(fd[i]->bdrv, &nb_heads, &max_track,
-                                          &last_sect, FDRIVE_DRV_NONE,
-                                          &fd_type[i]);
-        } else {
-            fd_type[i] = FDRIVE_DRV_NONE;
+    if (floppy) {
+        fdc_get_bs(fd, floppy);
+        for (i = 0; i < 2; i++) {
+            if (fd[i] && bdrv_is_inserted(fd[i])) {
+                bdrv_get_floppy_geometry_hint(fd[i], &nb_heads, &max_track,
+                                              &last_sect, FDRIVE_DRV_NONE,
+                                              &fd_type[i]);
+            } else {
+                fd_type[i] = FDRIVE_DRV_NONE;
+            }
         }
     }
     val = (cmos_get_fd_drive_type(fd_type[0]) << 4) |
@@ -1124,6 +1126,7 @@
 
 void pc_basic_device_init(qemu_irq *gsi,
                           ISADevice **rtc_state,
+                          ISADevice **floppy,
                           bool no_vmport)
 {
     int i;
@@ -1188,7 +1191,7 @@
     for(i = 0; i < MAX_FD; i++) {
         fd[i] = drive_get(IF_FLOPPY, 0, i);
     }
-    fdctrl_init_isa(fd);
+    *floppy = fdctrl_init_isa(fd);
 }
 
 void pc_pci_device_init(PCIBus *pci_bus)
diff --git a/hw/pc.h b/hw/pc.h
index b8ad9a3..4515006 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -142,11 +142,12 @@
 void pc_vga_init(PCIBus *pci_bus);
 void pc_basic_device_init(qemu_irq *gsi,
                           ISADevice **rtc_state,
+                          ISADevice **floppy,
                           bool no_vmport);
 void pc_init_ne2k_isa(NICInfo *nd);
 void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
                   const char *boot_device,
-                  BusState *ide0, BusState *ide1,
+                  ISADevice *floppy, BusState *ide0, BusState *ide1,
                   ISADevice *s);
 void pc_pci_device_init(PCIBus *pci_bus);
 
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index c89042f..8c7f2b7 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -95,6 +95,7 @@
     DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
     BusState *idebus[MAX_IDE_BUS];
     ISADevice *rtc_state;
+    ISADevice *floppy;
     MemoryRegion *ram_memory;
     MemoryRegion *pci_memory;
     MemoryRegion *rom_memory;
@@ -174,7 +175,7 @@
     }
 
     /* init basic PC hardware */
-    pc_basic_device_init(gsi, &rtc_state, xen_enabled());
+    pc_basic_device_init(gsi, &rtc_state, &floppy, xen_enabled());
 
     for(i = 0; i < nb_nics; i++) {
         NICInfo *nd = &nd_table[i];
@@ -207,7 +208,7 @@
     audio_init(gsi, pci_enabled ? pci_bus : NULL);
 
     pc_cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device,
-                 idebus[0], idebus[1], rtc_state);
+                 floppy, idebus[0], idebus[1], rtc_state);
 
     if (pci_enabled && usb_enabled) {
         usb_uhci_piix3_init(pci_bus, piix3_devfn + 2);
diff --git a/hw/pci.c b/hw/pci.c
index 749e8d8..e8cc1b0 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -998,17 +998,8 @@
         }
         r->addr = new_addr;
         if (r->addr != PCI_BAR_UNMAPPED) {
-            if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
-                memory_region_add_subregion_overlap(r->address_space,
-                                                    r->addr,
-                                                    r->memory,
-                                                    1);
-            } else {
-                memory_region_add_subregion_overlap(r->address_space,
-                                                    r->addr,
-                                                    r->memory,
-                                                    1);
-            }
+            memory_region_add_subregion_overlap(r->address_space,
+                                                r->addr, r->memory, 1);
         }
     }
 }
diff --git a/hw/pci_bridge.c b/hw/pci_bridge.c
index b6287cd..650d165 100644
--- a/hw/pci_bridge.c
+++ b/hw/pci_bridge.c
@@ -319,7 +319,7 @@
     sec_bus->parent_dev = dev;
     sec_bus->map_irq = br->map_irq;
     sec_bus->address_space_mem = &br->address_space_mem;
-    memory_region_init(&br->address_space_mem, "pci_pridge_pci", INT64_MAX);
+    memory_region_init(&br->address_space_mem, "pci_bridge_pci", INT64_MAX);
     sec_bus->address_space_io = &br->address_space_io;
     memory_region_init(&br->address_space_io, "pci_bridge_io", 65536);
     pci_bridge_region_init(br);
diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c
index ebcaafa..aac3526 100644
--- a/hw/ppc_oldworld.c
+++ b/hw/ppc_oldworld.c
@@ -73,11 +73,13 @@
                                const char *initrd_filename,
                                const char *cpu_model)
 {
+    MemoryRegion *sysmem = get_system_memory();
     CPUState *env = NULL;
     char *filename;
     qemu_irq *pic, **heathrow_irqs;
     int linux_boot, i;
-    ram_addr_t ram_offset, bios_offset;
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    MemoryRegion *bios = g_new(MemoryRegion, 1);
     uint32_t kernel_base, initrd_base, cmdline_base = 0;
     int32_t kernel_size, initrd_size;
     PCIBus *pci_bus;
@@ -114,15 +116,16 @@
         exit(1);
     }
 
-    ram_offset = qemu_ram_alloc(NULL, "ppc_heathrow.ram", ram_size);
-    cpu_register_physical_memory(0, ram_size, ram_offset);
+    memory_region_init_ram(ram, NULL, "ppc_heathrow.ram", ram_size);
+    memory_region_add_subregion(sysmem, 0, ram);
 
     /* allocate and load BIOS */
-    bios_offset = qemu_ram_alloc(NULL, "ppc_heathrow.bios", BIOS_SIZE);
+    memory_region_init_ram(bios, NULL, "ppc_heathrow.bios", BIOS_SIZE);
     if (bios_name == NULL)
         bios_name = PROM_FILENAME;
     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
-    cpu_register_physical_memory(PROM_ADDR, BIOS_SIZE, bios_offset | IO_MEM_ROM);
+    memory_region_set_readonly(bios, true);
+    memory_region_add_subregion(sysmem, PROM_ADDR, bios);
 
     /* Load OpenBIOS (ELF) */
     if (filename) {
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index 6427baa..f22d5b9 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -116,16 +116,17 @@
 
 /* PCI intack register */
 /* Read-only register (?) */
-static void _PPC_intack_write (void *opaque,
-                               target_phys_addr_t addr, uint32_t value)
+static void PPC_intack_write (void *opaque, target_phys_addr_t addr,
+                              uint64_t value, unsigned size)
 {
 #if 0
-    printf("%s: 0x" TARGET_FMT_plx " => 0x%08" PRIx32 "\n", __func__, addr,
+    printf("%s: 0x" TARGET_FMT_plx " => 0x%08" PRIx64 "\n", __func__, addr,
            value);
 #endif
 }
 
-static inline uint32_t _PPC_intack_read(target_phys_addr_t addr)
+static uint64_t PPC_intack_read(void *opaque, target_phys_addr_t addr,
+                                unsigned size)
 {
     uint32_t retval = 0;
 
@@ -139,31 +140,10 @@
     return retval;
 }
 
-static uint32_t PPC_intack_readb (void *opaque, target_phys_addr_t addr)
-{
-    return _PPC_intack_read(addr);
-}
-
-static uint32_t PPC_intack_readw (void *opaque, target_phys_addr_t addr)
-{
-    return _PPC_intack_read(addr);
-}
-
-static uint32_t PPC_intack_readl (void *opaque, target_phys_addr_t addr)
-{
-    return _PPC_intack_read(addr);
-}
-
-static CPUWriteMemoryFunc * const PPC_intack_write[] = {
-    &_PPC_intack_write,
-    &_PPC_intack_write,
-    &_PPC_intack_write,
-};
-
-static CPUReadMemoryFunc * const PPC_intack_read[] = {
-    &PPC_intack_readb,
-    &PPC_intack_readw,
-    &PPC_intack_readl,
+static const MemoryRegionOps PPC_intack_ops = {
+    .read = PPC_intack_read,
+    .write = PPC_intack_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
 /* PowerPC control and status registers */
@@ -244,17 +224,14 @@
     return retval;
 }
 
-static CPUWriteMemoryFunc * const PPC_XCSR_write[] = {
-    &PPC_XCSR_writeb,
-    &PPC_XCSR_writew,
-    &PPC_XCSR_writel,
+static const MemoryRegionOps PPC_XCSR_ops = {
+    .old_mmio = {
+        .read = { PPC_XCSR_readb, PPC_XCSR_readw, PPC_XCSR_readl, },
+        .write = { PPC_XCSR_writeb, PPC_XCSR_writew, PPC_XCSR_writel, },
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
-static CPUReadMemoryFunc * const PPC_XCSR_read[] = {
-    &PPC_XCSR_readb,
-    &PPC_XCSR_readw,
-    &PPC_XCSR_readl,
-};
 #endif
 
 /* Fake super-io ports for PREP platform (Intel 82378ZB) */
@@ -503,16 +480,12 @@
     return ret;
 }
 
-static CPUWriteMemoryFunc * const PPC_prep_io_write[] = {
-    &PPC_prep_io_writeb,
-    &PPC_prep_io_writew,
-    &PPC_prep_io_writel,
-};
-
-static CPUReadMemoryFunc * const PPC_prep_io_read[] = {
-    &PPC_prep_io_readb,
-    &PPC_prep_io_readw,
-    &PPC_prep_io_readl,
+static const MemoryRegionOps PPC_prep_io_ops = {
+    .old_mmio = {
+        .read = { PPC_prep_io_readb, PPC_prep_io_readw, PPC_prep_io_readl },
+        .write = { PPC_prep_io_writeb, PPC_prep_io_writew, PPC_prep_io_writel },
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
 #define NVRAM_SIZE        0x2000
@@ -534,13 +507,19 @@
                            const char *initrd_filename,
                            const char *cpu_model)
 {
+    MemoryRegion *sysmem = get_system_memory();
     CPUState *env = NULL;
     char *filename;
     nvram_t nvram;
     M48t59State *m48t59;
-    int PPC_io_memory;
+    MemoryRegion *PPC_io_memory = g_new(MemoryRegion, 1);
+    MemoryRegion *intack = g_new(MemoryRegion, 1);
+#if 0
+    MemoryRegion *xcsr = g_new(MemoryRegion, 1);
+#endif
     int linux_boot, i, nb_nics1, bios_size;
-    ram_addr_t ram_offset, bios_offset;
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    MemoryRegion *bios = g_new(MemoryRegion, 1);
     uint32_t kernel_base, initrd_base;
     long kernel_size, initrd_size;
     PCIBus *pci_bus;
@@ -574,11 +553,11 @@
     }
 
     /* allocate RAM */
-    ram_offset = qemu_ram_alloc(NULL, "ppc_prep.ram", ram_size);
-    cpu_register_physical_memory(0, ram_size, ram_offset);
+    memory_region_init_ram(ram, NULL, "ppc_prep.ram", ram_size);
+    memory_region_add_subregion(sysmem, 0, ram);
 
     /* allocate and load BIOS */
-    bios_offset = qemu_ram_alloc(NULL, "ppc_prep.bios", BIOS_SIZE);
+    memory_region_init_ram(bios, NULL, "ppc_prep.bios", BIOS_SIZE);
     if (bios_name == NULL)
         bios_name = BIOS_FILENAME;
     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
@@ -591,8 +570,8 @@
         target_phys_addr_t bios_addr;
         bios_size = (bios_size + 0xfff) & ~0xfff;
         bios_addr = (uint32_t)(-bios_size);
-        cpu_register_physical_memory(bios_addr, bios_size,
-                                     bios_offset | IO_MEM_ROM);
+        memory_region_set_readonly(bios, true);
+        memory_region_add_subregion(sysmem, bios_addr, bios);
         bios_size = load_image_targphys(filename, bios_addr, bios_size);
     }
     if (bios_size < 0 || bios_size > BIOS_SIZE) {
@@ -655,10 +634,9 @@
     isa_bus_irqs(i8259);
     //    pci_bus = i440fx_init();
     /* Register 8 MB of ISA IO space (needed for non-contiguous map) */
-    PPC_io_memory = cpu_register_io_memory(PPC_prep_io_read,
-                                           PPC_prep_io_write, sysctrl,
-                                           DEVICE_LITTLE_ENDIAN);
-    cpu_register_physical_memory(0x80000000, 0x00800000, PPC_io_memory);
+    memory_region_init_io(PPC_io_memory, &PPC_prep_io_ops, sysctrl,
+                          "ppc-io", 0x00800000);
+    memory_region_add_subregion(sysmem, 0x80000000, PPC_io_memory);
 
     /* init basic PC hardware */
     pci_vga_init(pci_bus);
@@ -713,15 +691,12 @@
     register_ioport_read(0x0800, 0x52, 1, &PREP_io_800_readb, sysctrl);
     register_ioport_write(0x0800, 0x52, 1, &PREP_io_800_writeb, sysctrl);
     /* PCI intack location */
-    PPC_io_memory = cpu_register_io_memory(PPC_intack_read,
-                                           PPC_intack_write, NULL,
-                                           DEVICE_LITTLE_ENDIAN);
-    cpu_register_physical_memory(0xBFFFFFF0, 0x4, PPC_io_memory);
+    memory_region_init_io(intack, &PPC_intack_ops, NULL, "ppc-intack", 4);
+    memory_region_add_subregion(sysmem, 0xBFFFFFF0, intack);
     /* PowerPC control and status register group */
 #if 0
-    PPC_io_memory = cpu_register_io_memory(PPC_XCSR_read, PPC_XCSR_write,
-                                           NULL, DEVICE_LITTLE_ENDIAN);
-    cpu_register_physical_memory(0xFEFF0000, 0x1000, PPC_io_memory);
+    memory_region_init_io(xcsr, &PPC_XCSR_ops, NULL, "ppc-xcsr", 0x1000);
+    memory_region_add_subregion(sysmem, 0xFEFF0000, xcsr);
 #endif
 
     if (usb_enabled) {
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index 5bf8eab..51b6abd 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -229,6 +229,7 @@
                          const char *cpu_model)
 {
     MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
     PCIBus *pci_bus;
     CPUState *env = NULL;
     uint64_t elf_entry;
@@ -291,8 +292,8 @@
     ram_size &= ~(RAM_SIZES_ALIGN - 1);
 
     /* Register Memory */
-    cpu_register_physical_memory(0, ram_size, qemu_ram_alloc(NULL,
-                                 "mpc8544ds.ram", ram_size));
+    memory_region_init_ram(ram, NULL, "mpc8544ds.ram", ram_size);
+    memory_region_add_subregion(address_space_mem, 0, ram);
 
     /* MPIC */
     mpic = mpic_init(address_space_mem, MPC8544_MPIC_REGS_BASE,
diff --git a/hw/pxa.h b/hw/pxa.h
index 1204165..7e98384 100644
--- a/hw/pxa.h
+++ b/hw/pxa.h
@@ -122,6 +122,11 @@
     CPUState *env;
     DeviceState *pic;
     qemu_irq reset;
+    MemoryRegion sdram;
+    MemoryRegion internal;
+    MemoryRegion cm_iomem;
+    MemoryRegion mm_iomem;
+    MemoryRegion pm_iomem;
     DeviceState *dma;
     DeviceState *gpio;
     PXA2xxLCDState *lcd;
@@ -151,6 +156,7 @@
 } PXA2xxState;
 
 struct PXA2xxI2SState {
+    MemoryRegion iomem;
     qemu_irq irq;
     qemu_irq rx_dma;
     qemu_irq tx_dma;
diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c
index 70d7c8a06..bfc28a9 100644
--- a/hw/pxa2xx.c
+++ b/hw/pxa2xx.c
@@ -88,7 +88,8 @@
 #define PCMD0	0x80	/* Power Manager I2C Command register File 0 */
 #define PCMD31	0xfc	/* Power Manager I2C Command register File 31 */
 
-static uint32_t pxa2xx_pm_read(void *opaque, target_phys_addr_t addr)
+static uint64_t pxa2xx_pm_read(void *opaque, target_phys_addr_t addr,
+                               unsigned size)
 {
     PXA2xxState *s = (PXA2xxState *) opaque;
 
@@ -107,7 +108,7 @@
 }
 
 static void pxa2xx_pm_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                            uint64_t value, unsigned size)
 {
     PXA2xxState *s = (PXA2xxState *) opaque;
 
@@ -134,16 +135,10 @@
     }
 }
 
-static CPUReadMemoryFunc * const pxa2xx_pm_readfn[] = {
-    pxa2xx_pm_read,
-    pxa2xx_pm_read,
-    pxa2xx_pm_read,
-};
-
-static CPUWriteMemoryFunc * const pxa2xx_pm_writefn[] = {
-    pxa2xx_pm_write,
-    pxa2xx_pm_write,
-    pxa2xx_pm_write,
+static const MemoryRegionOps pxa2xx_pm_ops = {
+    .read = pxa2xx_pm_read,
+    .write = pxa2xx_pm_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static const VMStateDescription vmstate_pxa2xx_pm = {
@@ -162,7 +157,8 @@
 #define OSCC	0x08	/* Oscillator Configuration register */
 #define CCSR	0x0c	/* Core Clock Status register */
 
-static uint32_t pxa2xx_cm_read(void *opaque, target_phys_addr_t addr)
+static uint64_t pxa2xx_cm_read(void *opaque, target_phys_addr_t addr,
+                               unsigned size)
 {
     PXA2xxState *s = (PXA2xxState *) opaque;
 
@@ -183,7 +179,7 @@
 }
 
 static void pxa2xx_cm_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                            uint64_t value, unsigned size)
 {
     PXA2xxState *s = (PXA2xxState *) opaque;
 
@@ -206,16 +202,10 @@
     }
 }
 
-static CPUReadMemoryFunc * const pxa2xx_cm_readfn[] = {
-    pxa2xx_cm_read,
-    pxa2xx_cm_read,
-    pxa2xx_cm_read,
-};
-
-static CPUWriteMemoryFunc * const pxa2xx_cm_writefn[] = {
-    pxa2xx_cm_write,
-    pxa2xx_cm_write,
-    pxa2xx_cm_write,
+static const MemoryRegionOps pxa2xx_cm_ops = {
+    .read = pxa2xx_cm_read,
+    .write = pxa2xx_cm_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static const VMStateDescription vmstate_pxa2xx_cm = {
@@ -461,7 +451,8 @@
 #define BSCNTR3		0x60	/* Memory Buffer Strength Control register 3 */
 #define SA1110		0x64	/* SA-1110 Memory Compatibility register */
 
-static uint32_t pxa2xx_mm_read(void *opaque, target_phys_addr_t addr)
+static uint64_t pxa2xx_mm_read(void *opaque, target_phys_addr_t addr,
+                               unsigned size)
 {
     PXA2xxState *s = (PXA2xxState *) opaque;
 
@@ -478,7 +469,7 @@
 }
 
 static void pxa2xx_mm_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                            uint64_t value, unsigned size)
 {
     PXA2xxState *s = (PXA2xxState *) opaque;
 
@@ -495,16 +486,10 @@
     }
 }
 
-static CPUReadMemoryFunc * const pxa2xx_mm_readfn[] = {
-    pxa2xx_mm_read,
-    pxa2xx_mm_read,
-    pxa2xx_mm_read,
-};
-
-static CPUWriteMemoryFunc * const pxa2xx_mm_writefn[] = {
-    pxa2xx_mm_write,
-    pxa2xx_mm_write,
-    pxa2xx_mm_write,
+static const MemoryRegionOps pxa2xx_mm_ops = {
+    .read = pxa2xx_mm_read,
+    .write = pxa2xx_mm_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static const VMStateDescription vmstate_pxa2xx_mm = {
@@ -521,6 +506,7 @@
 /* Synchronous Serial Ports */
 typedef struct {
     SysBusDevice busdev;
+    MemoryRegion iomem;
     qemu_irq irq;
     int enable;
     SSIBus *bus;
@@ -627,7 +613,8 @@
     pxa2xx_ssp_int_update(s);
 }
 
-static uint32_t pxa2xx_ssp_read(void *opaque, target_phys_addr_t addr)
+static uint64_t pxa2xx_ssp_read(void *opaque, target_phys_addr_t addr,
+                                unsigned size)
 {
     PXA2xxSSPState *s = (PXA2xxSSPState *) opaque;
     uint32_t retval;
@@ -673,9 +660,10 @@
 }
 
 static void pxa2xx_ssp_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                             uint64_t value64, unsigned size)
 {
     PXA2xxSSPState *s = (PXA2xxSSPState *) opaque;
+    uint32_t value = value64;
 
     switch (addr) {
     case SSCR0:
@@ -762,16 +750,10 @@
     }
 }
 
-static CPUReadMemoryFunc * const pxa2xx_ssp_readfn[] = {
-    pxa2xx_ssp_read,
-    pxa2xx_ssp_read,
-    pxa2xx_ssp_read,
-};
-
-static CPUWriteMemoryFunc * const pxa2xx_ssp_writefn[] = {
-    pxa2xx_ssp_write,
-    pxa2xx_ssp_write,
-    pxa2xx_ssp_write,
+static const MemoryRegionOps pxa2xx_ssp_ops = {
+    .read = pxa2xx_ssp_read,
+    .write = pxa2xx_ssp_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void pxa2xx_ssp_save(QEMUFile *f, void *opaque)
@@ -823,15 +805,12 @@
 
 static int pxa2xx_ssp_init(SysBusDevice *dev)
 {
-    int iomemtype;
     PXA2xxSSPState *s = FROM_SYSBUS(PXA2xxSSPState, dev);
 
     sysbus_init_irq(dev, &s->irq);
 
-    iomemtype = cpu_register_io_memory(pxa2xx_ssp_readfn,
-                                       pxa2xx_ssp_writefn, s,
-                                       DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, 0x1000, iomemtype);
+    memory_region_init_io(&s->iomem, &pxa2xx_ssp_ops, s, "pxa2xx-ssp", 0x1000);
+    sysbus_init_mmio_region(dev, &s->iomem);
     register_savevm(&dev->qdev, "pxa2xx_ssp", -1, 0,
                     pxa2xx_ssp_save, pxa2xx_ssp_load, s);
 
@@ -858,6 +837,7 @@
 
 typedef struct {
     SysBusDevice busdev;
+    MemoryRegion iomem;
     uint32_t rttr;
     uint32_t rtsr;
     uint32_t rtar;
@@ -1009,7 +989,8 @@
     pxa2xx_rtc_int_update(s);
 }
 
-static uint32_t pxa2xx_rtc_read(void *opaque, target_phys_addr_t addr)
+static uint64_t pxa2xx_rtc_read(void *opaque, target_phys_addr_t addr,
+                                unsigned size)
 {
     PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
 
@@ -1055,9 +1036,10 @@
 }
 
 static void pxa2xx_rtc_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                             uint64_t value64, unsigned size)
 {
     PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
+    uint32_t value = value64;
 
     switch (addr) {
     case RTTR:
@@ -1157,16 +1139,10 @@
     }
 }
 
-static CPUReadMemoryFunc * const pxa2xx_rtc_readfn[] = {
-    pxa2xx_rtc_read,
-    pxa2xx_rtc_read,
-    pxa2xx_rtc_read,
-};
-
-static CPUWriteMemoryFunc * const pxa2xx_rtc_writefn[] = {
-    pxa2xx_rtc_write,
-    pxa2xx_rtc_write,
-    pxa2xx_rtc_write,
+static const MemoryRegionOps pxa2xx_rtc_ops = {
+    .read = pxa2xx_rtc_read,
+    .write = pxa2xx_rtc_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static int pxa2xx_rtc_init(SysBusDevice *dev)
@@ -1174,7 +1150,6 @@
     PXA2xxRTCState *s = FROM_SYSBUS(PXA2xxRTCState, dev);
     struct tm tm;
     int wom;
-    int iomemtype;
 
     s->rttr = 0x7fff;
     s->rtsr = 0;
@@ -1201,9 +1176,8 @@
 
     sysbus_init_irq(dev, &s->rtc_irq);
 
-    iomemtype = cpu_register_io_memory(pxa2xx_rtc_readfn,
-                    pxa2xx_rtc_writefn, s, DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, 0x10000, iomemtype);
+    memory_region_init_io(&s->iomem, &pxa2xx_rtc_ops, s, "pxa2xx-rtc", 0x10000);
+    sysbus_init_mmio_region(dev, &s->iomem);
 
     return 0;
 }
@@ -1272,6 +1246,7 @@
 
 struct PXA2xxI2CState {
     SysBusDevice busdev;
+    MemoryRegion iomem;
     PXA2xxI2CSlaveState *slave;
     i2c_bus *bus;
     qemu_irq irq;
@@ -1356,7 +1331,8 @@
     return 1;
 }
 
-static uint32_t pxa2xx_i2c_read(void *opaque, target_phys_addr_t addr)
+static uint64_t pxa2xx_i2c_read(void *opaque, target_phys_addr_t addr,
+                                unsigned size)
 {
     PXA2xxI2CState *s = (PXA2xxI2CState *) opaque;
 
@@ -1384,9 +1360,10 @@
 }
 
 static void pxa2xx_i2c_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                             uint64_t value64, unsigned size)
 {
     PXA2xxI2CState *s = (PXA2xxI2CState *) opaque;
+    uint32_t value = value64;
     int ack;
 
     addr -= s->offset;
@@ -1453,16 +1430,10 @@
     }
 }
 
-static CPUReadMemoryFunc * const pxa2xx_i2c_readfn[] = {
-    pxa2xx_i2c_read,
-    pxa2xx_i2c_read,
-    pxa2xx_i2c_read,
-};
-
-static CPUWriteMemoryFunc * const pxa2xx_i2c_writefn[] = {
-    pxa2xx_i2c_write,
-    pxa2xx_i2c_write,
-    pxa2xx_i2c_write,
+static const MemoryRegionOps pxa2xx_i2c_ops = {
+    .read = pxa2xx_i2c_read,
+    .write = pxa2xx_i2c_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static const VMStateDescription vmstate_pxa2xx_i2c_slave = {
@@ -1536,13 +1507,12 @@
 static int pxa2xx_i2c_initfn(SysBusDevice *dev)
 {
     PXA2xxI2CState *s = FROM_SYSBUS(PXA2xxI2CState, dev);
-    int iomemtype;
 
     s->bus = i2c_init_bus(&dev->qdev, "i2c");
 
-    iomemtype = cpu_register_io_memory(pxa2xx_i2c_readfn,
-                    pxa2xx_i2c_writefn, s, DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, s->region_size, iomemtype);
+    memory_region_init_io(&s->iomem, &pxa2xx_i2c_ops, s,
+                          "pxa2xx-i2x", s->region_size);
+    sysbus_init_mmio_region(dev, &s->iomem);
     sysbus_init_irq(dev, &s->irq);
 
     return 0;
@@ -1621,7 +1591,8 @@
 #define SADIV	0x60	/* Serial Audio Clock Divider register */
 #define SADR	0x80	/* Serial Audio Data register */
 
-static uint32_t pxa2xx_i2s_read(void *opaque, target_phys_addr_t addr)
+static uint64_t pxa2xx_i2s_read(void *opaque, target_phys_addr_t addr,
+                                unsigned size)
 {
     PXA2xxI2SState *s = (PXA2xxI2SState *) opaque;
 
@@ -1653,7 +1624,7 @@
 }
 
 static void pxa2xx_i2s_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                             uint64_t value, unsigned size)
 {
     PXA2xxI2SState *s = (PXA2xxI2SState *) opaque;
     uint32_t *sample;
@@ -1707,16 +1678,10 @@
     }
 }
 
-static CPUReadMemoryFunc * const pxa2xx_i2s_readfn[] = {
-    pxa2xx_i2s_read,
-    pxa2xx_i2s_read,
-    pxa2xx_i2s_read,
-};
-
-static CPUWriteMemoryFunc * const pxa2xx_i2s_writefn[] = {
-    pxa2xx_i2s_write,
-    pxa2xx_i2s_write,
-    pxa2xx_i2s_write,
+static const MemoryRegionOps pxa2xx_i2s_ops = {
+    .read = pxa2xx_i2s_read,
+    .write = pxa2xx_i2s_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static const VMStateDescription vmstate_pxa2xx_i2s = {
@@ -1759,10 +1724,10 @@
     pxa2xx_i2s_update(s);
 }
 
-static PXA2xxI2SState *pxa2xx_i2s_init(target_phys_addr_t base,
+static PXA2xxI2SState *pxa2xx_i2s_init(MemoryRegion *sysmem,
+                target_phys_addr_t base,
                 qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma)
 {
-    int iomemtype;
     PXA2xxI2SState *s = (PXA2xxI2SState *)
             g_malloc0(sizeof(PXA2xxI2SState));
 
@@ -1773,9 +1738,9 @@
 
     pxa2xx_i2s_reset(s);
 
-    iomemtype = cpu_register_io_memory(pxa2xx_i2s_readfn,
-                    pxa2xx_i2s_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x100000, iomemtype);
+    memory_region_init_io(&s->iomem, &pxa2xx_i2s_ops, s,
+                          "pxa2xx-i2s", 0x100000);
+    memory_region_add_subregion(sysmem, base, &s->iomem);
 
     vmstate_register(NULL, base, &vmstate_pxa2xx_i2s, s);
 
@@ -1784,6 +1749,7 @@
 
 /* PXA Fast Infra-red Communications Port */
 struct PXA2xxFIrState {
+    MemoryRegion iomem;
     qemu_irq irq;
     qemu_irq rx_dma;
     qemu_irq tx_dma;
@@ -1854,7 +1820,8 @@
 #define ICSR1	0x18	/* FICP Status register 1 */
 #define ICFOR	0x1c	/* FICP FIFO Occupancy Status register */
 
-static uint32_t pxa2xx_fir_read(void *opaque, target_phys_addr_t addr)
+static uint64_t pxa2xx_fir_read(void *opaque, target_phys_addr_t addr,
+                                unsigned size)
 {
     PXA2xxFIrState *s = (PXA2xxFIrState *) opaque;
     uint8_t ret;
@@ -1892,9 +1859,10 @@
 }
 
 static void pxa2xx_fir_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                             uint64_t value64, unsigned size)
 {
     PXA2xxFIrState *s = (PXA2xxFIrState *) opaque;
+    uint32_t value = value64;
     uint8_t ch;
 
     switch (addr) {
@@ -1936,16 +1904,10 @@
     }
 }
 
-static CPUReadMemoryFunc * const pxa2xx_fir_readfn[] = {
-    pxa2xx_fir_read,
-    pxa2xx_fir_read,
-    pxa2xx_fir_read,
-};
-
-static CPUWriteMemoryFunc * const pxa2xx_fir_writefn[] = {
-    pxa2xx_fir_write,
-    pxa2xx_fir_write,
-    pxa2xx_fir_write,
+static const MemoryRegionOps pxa2xx_fir_ops = {
+    .read = pxa2xx_fir_read,
+    .write = pxa2xx_fir_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static int pxa2xx_fir_is_empty(void *opaque)
@@ -2019,11 +1981,11 @@
     return 0;
 }
 
-static PXA2xxFIrState *pxa2xx_fir_init(target_phys_addr_t base,
+static PXA2xxFIrState *pxa2xx_fir_init(MemoryRegion *sysmem,
+                target_phys_addr_t base,
                 qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma,
                 CharDriverState *chr)
 {
-    int iomemtype;
     PXA2xxFIrState *s = (PXA2xxFIrState *)
             g_malloc0(sizeof(PXA2xxFIrState));
 
@@ -2034,9 +1996,8 @@
 
     pxa2xx_fir_reset(s);
 
-    iomemtype = cpu_register_io_memory(pxa2xx_fir_readfn,
-                    pxa2xx_fir_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x1000, iomemtype);
+    memory_region_init_io(&s->iomem, &pxa2xx_fir_ops, s, "pxa2xx-fir", 0x1000);
+    memory_region_add_subregion(sysmem, base, &s->iomem);
 
     if (chr)
         qemu_chr_add_handlers(chr, pxa2xx_fir_is_empty,
@@ -2063,7 +2024,7 @@
                          unsigned int sdram_size, const char *revision)
 {
     PXA2xxState *s;
-    int iomemtype, i;
+    int i;
     DriveInfo *dinfo;
     s = (PXA2xxState *) g_malloc0(sizeof(PXA2xxState));
 
@@ -2082,12 +2043,11 @@
     s->reset = qemu_allocate_irqs(pxa2xx_reset, s, 1)[0];
 
     /* SDRAM & Internal Memory Storage */
-    cpu_register_physical_memory(PXA2XX_SDRAM_BASE,
-                    sdram_size, qemu_ram_alloc(NULL, "pxa270.sdram",
-                                               sdram_size) | IO_MEM_RAM);
-    cpu_register_physical_memory(PXA2XX_INTERNAL_BASE,
-                    0x40000, qemu_ram_alloc(NULL, "pxa270.internal",
-                                            0x40000) | IO_MEM_RAM);
+    memory_region_init_ram(&s->sdram, NULL, "pxa270.sdram", sdram_size);
+    memory_region_add_subregion(address_space, PXA2XX_SDRAM_BASE, &s->sdram);
+    memory_region_init_ram(&s->internal, NULL, "pxa270.internal", 0x40000);
+    memory_region_add_subregion(address_space, PXA2XX_INTERNAL_BASE,
+                                &s->internal);
 
     s->pic = pxa2xx_pic_init(0x40d00000, s->env);
 
@@ -2125,7 +2085,7 @@
         }
     }
     if (serial_hds[i])
-        s->fir = pxa2xx_fir_init(0x40800000,
+        s->fir = pxa2xx_fir_init(address_space, 0x40800000,
                         qdev_get_gpio_in(s->pic, PXA2XX_PIC_ICP),
                         qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_ICP),
                         qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_ICP),
@@ -2137,9 +2097,8 @@
     s->cm_base = 0x41300000;
     s->cm_regs[CCCR >> 2] = 0x02000210;	/* 416.0 MHz */
     s->clkcfg = 0x00000009;		/* Turbo mode active */
-    iomemtype = cpu_register_io_memory(pxa2xx_cm_readfn,
-                    pxa2xx_cm_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(s->cm_base, 0x1000, iomemtype);
+    memory_region_init_io(&s->cm_iomem, &pxa2xx_cm_ops, s, "pxa2xx-cm", 0x1000);
+    memory_region_add_subregion(address_space, s->cm_base, &s->cm_iomem);
     vmstate_register(NULL, 0, &vmstate_pxa2xx_cm, s);
 
     cpu_arm_set_cp_io(s->env, 14, pxa2xx_cp14_read, pxa2xx_cp14_write, s);
@@ -2148,15 +2107,13 @@
     s->mm_regs[MDMRS >> 2] = 0x00020002;
     s->mm_regs[MDREFR >> 2] = 0x03ca4000;
     s->mm_regs[MECR >> 2] = 0x00000001;	/* Two PC Card sockets */
-    iomemtype = cpu_register_io_memory(pxa2xx_mm_readfn,
-                    pxa2xx_mm_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(s->mm_base, 0x1000, iomemtype);
+    memory_region_init_io(&s->mm_iomem, &pxa2xx_mm_ops, s, "pxa2xx-mm", 0x1000);
+    memory_region_add_subregion(address_space, s->mm_base, &s->mm_iomem);
     vmstate_register(NULL, 0, &vmstate_pxa2xx_mm, s);
 
     s->pm_base = 0x40f00000;
-    iomemtype = cpu_register_io_memory(pxa2xx_pm_readfn,
-                    pxa2xx_pm_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(s->pm_base, 0x100, iomemtype);
+    memory_region_init_io(&s->pm_iomem, &pxa2xx_pm_ops, s, "pxa2xx-pm", 0x100);
+    memory_region_add_subregion(address_space, s->pm_base, &s->pm_iomem);
     vmstate_register(NULL, 0, &vmstate_pxa2xx_pm, s);
 
     for (i = 0; pxa27x_ssp[i].io_base; i ++);
@@ -2184,7 +2141,7 @@
     s->i2c[1] = pxa2xx_i2c_init(0x40f00100,
                     qdev_get_gpio_in(s->pic, PXA2XX_PIC_PWRI2C), 0xff);
 
-    s->i2s = pxa2xx_i2s_init(0x40400000,
+    s->i2s = pxa2xx_i2s_init(address_space, 0x40400000,
                     qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2S),
                     qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_I2S),
                     qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_I2S));
@@ -2202,7 +2159,7 @@
 PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size)
 {
     PXA2xxState *s;
-    int iomemtype, i;
+    int i;
     DriveInfo *dinfo;
 
     s = (PXA2xxState *) g_malloc0(sizeof(PXA2xxState));
@@ -2215,12 +2172,12 @@
     s->reset = qemu_allocate_irqs(pxa2xx_reset, s, 1)[0];
 
     /* SDRAM & Internal Memory Storage */
-    cpu_register_physical_memory(PXA2XX_SDRAM_BASE, sdram_size,
-                    qemu_ram_alloc(NULL, "pxa255.sdram",
-                                   sdram_size) | IO_MEM_RAM);
-    cpu_register_physical_memory(PXA2XX_INTERNAL_BASE, PXA2XX_INTERNAL_SIZE,
-                    qemu_ram_alloc(NULL, "pxa255.internal",
-                                   PXA2XX_INTERNAL_SIZE) | IO_MEM_RAM);
+    memory_region_init_ram(&s->sdram, NULL, "pxa255.sdram", sdram_size);
+    memory_region_add_subregion(address_space, PXA2XX_SDRAM_BASE, &s->sdram);
+    memory_region_init_ram(&s->internal, NULL, "pxa255.internal",
+                           PXA2XX_INTERNAL_SIZE);
+    memory_region_add_subregion(address_space, PXA2XX_INTERNAL_BASE,
+                                &s->internal);
 
     s->pic = pxa2xx_pic_init(0x40d00000, s->env);
 
@@ -2257,7 +2214,7 @@
         }
     }
     if (serial_hds[i])
-        s->fir = pxa2xx_fir_init(0x40800000,
+        s->fir = pxa2xx_fir_init(address_space, 0x40800000,
                         qdev_get_gpio_in(s->pic, PXA2XX_PIC_ICP),
                         qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_ICP),
                         qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_ICP),
@@ -2269,9 +2226,8 @@
     s->cm_base = 0x41300000;
     s->cm_regs[CCCR >> 2] = 0x02000210;	/* 416.0 MHz */
     s->clkcfg = 0x00000009;		/* Turbo mode active */
-    iomemtype = cpu_register_io_memory(pxa2xx_cm_readfn,
-                    pxa2xx_cm_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(s->cm_base, 0x1000, iomemtype);
+    memory_region_init_io(&s->cm_iomem, &pxa2xx_cm_ops, s, "pxa2xx-cm", 0x1000);
+    memory_region_add_subregion(address_space, s->cm_base, &s->cm_iomem);
     vmstate_register(NULL, 0, &vmstate_pxa2xx_cm, s);
 
     cpu_arm_set_cp_io(s->env, 14, pxa2xx_cp14_read, pxa2xx_cp14_write, s);
@@ -2280,15 +2236,13 @@
     s->mm_regs[MDMRS >> 2] = 0x00020002;
     s->mm_regs[MDREFR >> 2] = 0x03ca4000;
     s->mm_regs[MECR >> 2] = 0x00000001;	/* Two PC Card sockets */
-    iomemtype = cpu_register_io_memory(pxa2xx_mm_readfn,
-                    pxa2xx_mm_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(s->mm_base, 0x1000, iomemtype);
+    memory_region_init_io(&s->mm_iomem, &pxa2xx_mm_ops, s, "pxa2xx-mm", 0x1000);
+    memory_region_add_subregion(address_space, s->mm_base, &s->mm_iomem);
     vmstate_register(NULL, 0, &vmstate_pxa2xx_mm, s);
 
     s->pm_base = 0x40f00000;
-    iomemtype = cpu_register_io_memory(pxa2xx_pm_readfn,
-                    pxa2xx_pm_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(s->pm_base, 0x100, iomemtype);
+    memory_region_init_io(&s->pm_iomem, &pxa2xx_pm_ops, s, "pxa2xx-pm", 0x100);
+    memory_region_add_subregion(address_space, s->pm_base, &s->pm_iomem);
     vmstate_register(NULL, 0, &vmstate_pxa2xx_pm, s);
 
     for (i = 0; pxa255_ssp[i].io_base; i ++);
@@ -2316,7 +2270,7 @@
     s->i2c[1] = pxa2xx_i2c_init(0x40f00100,
                     qdev_get_gpio_in(s->pic, PXA2XX_PIC_PWRI2C), 0xff);
 
-    s->i2s = pxa2xx_i2s_init(0x40400000,
+    s->i2s = pxa2xx_i2s_init(address_space, 0x40400000,
                     qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2S),
                     qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_I2S),
                     qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_I2S));
diff --git a/hw/r2d.c b/hw/r2d.c
index 82377a0..b65fd42 100644
--- a/hw/r2d.c
+++ b/hw/r2d.c
@@ -82,6 +82,7 @@
 
 /* output pin */
     qemu_irq irl;
+    MemoryRegion iomem;
 } r2d_fpga_t;
 
 enum r2d_fpga_irq {
@@ -168,31 +169,25 @@
     }
 }
 
-static CPUReadMemoryFunc * const r2d_fpga_readfn[] = {
-    r2d_fpga_read,
-    r2d_fpga_read,
-    NULL,
+static const MemoryRegionOps r2d_fpga_ops = {
+    .old_mmio = {
+        .read = { r2d_fpga_read, r2d_fpga_read, NULL, },
+        .write = { r2d_fpga_write, r2d_fpga_write, NULL, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static CPUWriteMemoryFunc * const r2d_fpga_writefn[] = {
-    r2d_fpga_write,
-    r2d_fpga_write,
-    NULL,
-};
-
-static qemu_irq *r2d_fpga_init(target_phys_addr_t base, qemu_irq irl)
+static qemu_irq *r2d_fpga_init(MemoryRegion *sysmem,
+                               target_phys_addr_t base, qemu_irq irl)
 {
-    int iomemtype;
     r2d_fpga_t *s;
 
     s = g_malloc0(sizeof(r2d_fpga_t));
 
     s->irl = irl;
 
-    iomemtype = cpu_register_io_memory(r2d_fpga_readfn,
-				       r2d_fpga_writefn, s,
-                                       DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x40, iomemtype);
+    memory_region_init_io(&s->iomem, &r2d_fpga_ops, s, "r2d-fpga", 0x40);
+    memory_region_add_subregion(sysmem, base, &s->iomem);
     return qemu_allocate_irqs(r2d_fpga_irq_set, s, NR_IRQS);
 }
 
@@ -232,7 +227,7 @@
     CPUState *env;
     ResetData *reset_info;
     struct SH7750State *s;
-    ram_addr_t sdram_addr;
+    MemoryRegion *sdram = g_new(MemoryRegion, 1);
     qemu_irq *irq;
     DriveInfo *dinfo;
     int i;
@@ -252,11 +247,11 @@
     qemu_register_reset(main_cpu_reset, reset_info);
 
     /* Allocate memory space */
-    sdram_addr = qemu_ram_alloc(NULL, "r2d.sdram", SDRAM_SIZE);
-    cpu_register_physical_memory(SDRAM_BASE, SDRAM_SIZE, sdram_addr);
+    memory_region_init_ram(sdram, NULL, "r2d.sdram", SDRAM_SIZE);
+    memory_region_add_subregion(address_space_mem, SDRAM_BASE, sdram);
     /* Register peripherals */
     s = sh7750_init(env);
-    irq = r2d_fpga_init(0x04000000, sh7750_irl(s));
+    irq = r2d_fpga_init(address_space_mem, 0x04000000, sh7750_irl(s));
     sysbus_create_varargs("sh_pci", 0x1e200000, irq[PCI_INTA], irq[PCI_INTB],
                           irq[PCI_INTC], irq[PCI_INTD], NULL);
 
diff --git a/hw/realview.c b/hw/realview.c
index 11ffb8a..14281b0 100644
--- a/hw/realview.c
+++ b/hw/realview.c
@@ -18,17 +18,20 @@
 #include "boards.h"
 #include "bitbang_i2c.h"
 #include "blockdev.h"
+#include "exec-memory.h"
 
 #define SMP_BOOT_ADDR 0xe0000000
 
 typedef struct {
     SysBusDevice busdev;
+    MemoryRegion iomem;
     bitbang_i2c_interface *bitbang;
     int out;
     int in;
 } RealViewI2CState;
 
-static uint32_t realview_i2c_read(void *opaque, target_phys_addr_t offset)
+static uint64_t realview_i2c_read(void *opaque, target_phys_addr_t offset,
+                                  unsigned size)
 {
     RealViewI2CState *s = (RealViewI2CState *)opaque;
 
@@ -41,7 +44,7 @@
 }
 
 static void realview_i2c_write(void *opaque, target_phys_addr_t offset,
-                               uint32_t value)
+                               uint64_t value, unsigned size)
 {
     RealViewI2CState *s = (RealViewI2CState *)opaque;
 
@@ -59,30 +62,22 @@
     s->in = bitbang_i2c_set(s->bitbang, BITBANG_I2C_SDA, (s->out & 2) != 0);
 }
 
-static CPUReadMemoryFunc * const realview_i2c_readfn[] = {
-   realview_i2c_read,
-   realview_i2c_read,
-   realview_i2c_read
-};
-
-static CPUWriteMemoryFunc * const realview_i2c_writefn[] = {
-   realview_i2c_write,
-   realview_i2c_write,
-   realview_i2c_write
+static const MemoryRegionOps realview_i2c_ops = {
+    .read = realview_i2c_read,
+    .write = realview_i2c_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static int realview_i2c_init(SysBusDevice *dev)
 {
     RealViewI2CState *s = FROM_SYSBUS(RealViewI2CState, dev);
     i2c_bus *bus;
-    int iomemtype;
 
     bus = i2c_init_bus(&dev->qdev, "i2c");
     s->bitbang = bitbang_i2c_init(bus);
-    iomemtype = cpu_register_io_memory(realview_i2c_readfn,
-                                       realview_i2c_writefn, s,
-                                       DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, 0x1000, iomemtype);
+    memory_region_init_io(&s->iomem, &realview_i2c_ops, s,
+                          "realview-i2c", 0x1000);
+    sysbus_init_mmio_region(dev, &s->iomem);
     return 0;
 }
 
@@ -125,7 +120,11 @@
                      enum realview_board_type board_type)
 {
     CPUState *env = NULL;
-    ram_addr_t ram_offset;
+    MemoryRegion *sysmem = get_system_memory();
+    MemoryRegion *ram_lo = g_new(MemoryRegion, 1);
+    MemoryRegion *ram_hi = g_new(MemoryRegion, 1);
+    MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
+    MemoryRegion *ram_hack = g_new(MemoryRegion, 1);
     DeviceState *dev, *sysctl, *gpio2;
     SysBusDevice *busdev;
     qemu_irq *irqp;
@@ -184,21 +183,21 @@
         /* Core tile RAM.  */
         low_ram_size = ram_size - 0x20000000;
         ram_size = 0x20000000;
-        ram_offset = qemu_ram_alloc(NULL, "realview.lowmem", low_ram_size);
-        cpu_register_physical_memory(0x20000000, low_ram_size,
-                                     ram_offset | IO_MEM_RAM);
+        memory_region_init_ram(ram_lo, NULL, "realview.lowmem", low_ram_size);
+        memory_region_add_subregion(sysmem, 0x20000000, ram_lo);
     }
 
-    ram_offset = qemu_ram_alloc(NULL, "realview.highmem", ram_size);
+    memory_region_init_ram(ram_hi, NULL, "realview.highmem", ram_size);
     low_ram_size = ram_size;
     if (low_ram_size > 0x10000000)
       low_ram_size = 0x10000000;
     /* SDRAM at address zero.  */
-    cpu_register_physical_memory(0, low_ram_size, ram_offset | IO_MEM_RAM);
+    memory_region_init_alias(ram_alias, "realview.alias",
+                             ram_hi, 0, low_ram_size);
+    memory_region_add_subregion(sysmem, 0, ram_alias);
     if (is_pb) {
         /* And again at a high address.  */
-        cpu_register_physical_memory(0x70000000, ram_size,
-                                     ram_offset | IO_MEM_RAM);
+        memory_region_add_subregion(sysmem, 0x70000000, ram_hi);
     } else {
         ram_size = low_ram_size;
     }
@@ -372,9 +371,8 @@
        startup code.  I guess this works on real hardware because the
        BootROM happens to be in ROM/flash or in memory that isn't clobbered
        until after Linux boots the secondary CPUs.  */
-    ram_offset = qemu_ram_alloc(NULL, "realview.hack", 0x1000);
-    cpu_register_physical_memory(SMP_BOOT_ADDR, 0x1000,
-                                 ram_offset | IO_MEM_RAM);
+    memory_region_init_ram(ram_hack, NULL, "realview.hack", 0x1000);
+    memory_region_add_subregion(sysmem, SMP_BOOT_ADDR, ram_hack);
 
     realview_binfo.ram_size = ram_size;
     realview_binfo.kernel_filename = kernel_filename;
diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c
index 778cffe..60c66e9 100644
--- a/hw/s390-virtio.c
+++ b/hw/s390-virtio.c
@@ -29,6 +29,7 @@
 #include "hw/virtio.h"
 #include "hw/sysbus.h"
 #include "kvm.h"
+#include "exec-memory.h"
 
 #include "hw/s390-virtio-bus.h"
 
@@ -128,7 +129,8 @@
                       const char *cpu_model)
 {
     CPUState *env = NULL;
-    ram_addr_t ram_addr;
+    MemoryRegion *sysmem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
     ram_addr_t kernel_size = 0;
     ram_addr_t initrd_offset;
     ram_addr_t initrd_size = 0;
@@ -150,8 +152,8 @@
     s390_bus = s390_virtio_bus_init(&my_ram_size);
 
     /* allocate RAM */
-    ram_addr = qemu_ram_alloc(NULL, "s390.ram", my_ram_size);
-    cpu_register_physical_memory(0, my_ram_size, ram_addr);
+    memory_region_init_ram(ram, NULL, "s390.ram", my_ram_size);
+    memory_region_add_subregion(sysmem, 0, ram);
 
     /* allocate storage keys */
     storage_keys = g_malloc0(my_ram_size / TARGET_PAGE_SIZE);
diff --git a/hw/sm501.c b/hw/sm501.c
index a7ed6fa..297bc9c 100644
--- a/hw/sm501.c
+++ b/hw/sm501.c
@@ -459,7 +459,7 @@
     target_phys_addr_t base;
     uint32_t local_mem_size_index;
     uint8_t * local_mem;
-    ram_addr_t local_mem_offset;
+    MemoryRegion local_mem_region;
     uint32_t last_width;
     uint32_t last_height;
 
@@ -726,7 +726,8 @@
     }
 }
 
-static uint32_t sm501_system_config_read(void *opaque, target_phys_addr_t addr)
+static uint64_t sm501_system_config_read(void *opaque, target_phys_addr_t addr,
+                                         unsigned size)
 {
     SM501State * s = (SM501State *)opaque;
     uint32_t ret = 0;
@@ -778,12 +779,12 @@
     return ret;
 }
 
-static void sm501_system_config_write(void *opaque,
-				      target_phys_addr_t addr, uint32_t value)
+static void sm501_system_config_write(void *opaque, target_phys_addr_t addr,
+                                      uint64_t value, unsigned size)
 {
     SM501State * s = (SM501State *)opaque;
     SM501_DPRINTF("sm501 system config regs : write addr=%x, val=%x\n",
-		  addr, value);
+		  (uint32_t)addr, (uint32_t)value);
 
     switch(addr) {
     case SM501_SYSTEM_CONTROL:
@@ -821,21 +822,19 @@
 
     default:
 	printf("sm501 system config : not implemented register write."
-	       " addr=%x, val=%x\n", (int)addr, value);
+	       " addr=%x, val=%x\n", (int)addr, (uint32_t)value);
         abort();
     }
 }
 
-static CPUReadMemoryFunc * const sm501_system_config_readfn[] = {
-    NULL,
-    NULL,
-    &sm501_system_config_read,
-};
-
-static CPUWriteMemoryFunc * const sm501_system_config_writefn[] = {
-    NULL,
-    NULL,
-    &sm501_system_config_write,
+static const MemoryRegionOps sm501_system_config_ops = {
+    .read = sm501_system_config_read,
+    .write = sm501_system_config_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static uint32_t sm501_palette_read(void *opaque, target_phys_addr_t addr)
@@ -864,7 +863,8 @@
     *(uint32_t*)&s->dc_palette[addr] = value;
 }
 
-static uint32_t sm501_disp_ctrl_read(void *opaque, target_phys_addr_t addr)
+static uint64_t sm501_disp_ctrl_read(void *opaque, target_phys_addr_t addr,
+                                     unsigned size)
 {
     SM501State * s = (SM501State *)opaque;
     uint32_t ret = 0;
@@ -958,13 +958,12 @@
     return ret;
 }
 
-static void sm501_disp_ctrl_write(void *opaque,
-					   target_phys_addr_t addr,
-					   uint32_t value)
+static void sm501_disp_ctrl_write(void *opaque, target_phys_addr_t addr,
+                                  uint64_t value, unsigned size)
 {
     SM501State * s = (SM501State *)opaque;
     SM501_DPRINTF("sm501 disp ctrl regs : write addr=%x, val=%x\n",
-		  addr, value);
+		  (unsigned)addr, (unsigned)value);
 
     switch(addr) {
     case SM501_DC_PANEL_CONTROL:
@@ -1059,24 +1058,23 @@
 
     default:
 	printf("sm501 disp ctrl : not implemented register write."
-	       " addr=%x, val=%x\n", (int)addr, value);
+	       " addr=%x, val=%x\n", (int)addr, (unsigned)value);
         abort();
     }
 }
 
-static CPUReadMemoryFunc * const sm501_disp_ctrl_readfn[] = {
-    NULL,
-    NULL,
-    &sm501_disp_ctrl_read,
+static const MemoryRegionOps sm501_disp_ctrl_ops = {
+    .read = sm501_disp_ctrl_read,
+    .write = sm501_disp_ctrl_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static CPUWriteMemoryFunc * const sm501_disp_ctrl_writefn[] = {
-    NULL,
-    NULL,
-    &sm501_disp_ctrl_write,
-};
-
-static uint32_t sm501_2d_engine_read(void *opaque, target_phys_addr_t addr)
+static uint64_t sm501_2d_engine_read(void *opaque, target_phys_addr_t addr,
+                                     unsigned size)
 {
     SM501State * s = (SM501State *)opaque;
     uint32_t ret = 0;
@@ -1095,12 +1093,12 @@
     return ret;
 }
 
-static void sm501_2d_engine_write(void *opaque,
-                                  target_phys_addr_t addr, uint32_t value)
+static void sm501_2d_engine_write(void *opaque, target_phys_addr_t addr,
+                                  uint64_t value, unsigned size)
 {
     SM501State * s = (SM501State *)opaque;
     SM501_DPRINTF("sm501 2d engine regs : write addr=%x, val=%x\n",
-                  addr, value);
+                  (unsigned)addr, (unsigned)value);
 
     switch(addr) {
     case SM501_2D_SOURCE:
@@ -1148,21 +1146,19 @@
         break;
     default:
         printf("sm501 2d engine : not implemented register write."
-               " addr=%x, val=%x\n", (int)addr, value);
+               " addr=%x, val=%x\n", (int)addr, (unsigned)value);
         abort();
     }
 }
 
-static CPUReadMemoryFunc * const sm501_2d_engine_readfn[] = {
-    NULL,
-    NULL,
-    &sm501_2d_engine_read,
-};
-
-static CPUWriteMemoryFunc * const sm501_2d_engine_writefn[] = {
-    NULL,
-    NULL,
-    &sm501_2d_engine_write,
+static const MemoryRegionOps sm501_2d_engine_ops = {
+    .read = sm501_2d_engine_read,
+    .write = sm501_2d_engine_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 /* draw line functions for all console modes */
@@ -1276,7 +1272,7 @@
     int y_start = -1;
     ram_addr_t page_min = ~0l;
     ram_addr_t page_max = 0l;
-    ram_addr_t offset = s->local_mem_offset;
+    ram_addr_t offset = 0;
 
     /* choose draw_line function */
     switch (s->dc_crt_control & 3) {
@@ -1333,7 +1329,8 @@
 
 	/* check dirty flags for each line */
 	for (page = page0; page <= page1; page += TARGET_PAGE_SIZE)
-	    if (cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG))
+            if (memory_region_get_dirty(&s->local_mem_region, page,
+                                        DIRTY_MEMORY_VGA))
 		update = 1;
 
 	/* draw line and change status */
@@ -1372,8 +1369,9 @@
 
     /* clear dirty flags */
     if (page_min != ~0l) {
-	cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
-					VGA_DIRTY_FLAG);
+	memory_region_reset_dirty(&s->local_mem_region,
+                                  page_min, page_max + TARGET_PAGE_SIZE,
+                                  DIRTY_MEMORY_VGA);
     }
 }
 
@@ -1390,9 +1388,9 @@
 {
     SM501State * s;
     DeviceState *dev;
-    int sm501_system_config_index;
-    int sm501_disp_ctrl_index;
-    int sm501_2d_engine_index;
+    MemoryRegion *sm501_system_config = g_new(MemoryRegion, 1);
+    MemoryRegion *sm501_disp_ctrl = g_new(MemoryRegion, 1);
+    MemoryRegion *sm501_2d_engine = g_new(MemoryRegion, 1);
 
     /* allocate management data region */
     s = (SM501State *)g_malloc0(sizeof(SM501State));
@@ -1407,27 +1405,26 @@
     s->dc_crt_control = 0x00010000;
 
     /* allocate local memory */
-    s->local_mem_offset = qemu_ram_alloc(NULL, "sm501.local", local_mem_bytes);
-    s->local_mem = qemu_get_ram_ptr(s->local_mem_offset);
-    cpu_register_physical_memory(base, local_mem_bytes, s->local_mem_offset);
+    memory_region_init_ram(&s->local_mem_region, NULL, "sm501.local",
+                           local_mem_bytes);
+    s->local_mem = memory_region_get_ram_ptr(&s->local_mem_region);
+    memory_region_add_subregion(address_space_mem, base, &s->local_mem_region);
 
     /* map mmio */
-    sm501_system_config_index
-	= cpu_register_io_memory(sm501_system_config_readfn,
-				 sm501_system_config_writefn, s,
-                                 DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base + MMIO_BASE_OFFSET,
-				 0x6c, sm501_system_config_index);
-    sm501_disp_ctrl_index = cpu_register_io_memory(sm501_disp_ctrl_readfn,
-						   sm501_disp_ctrl_writefn, s,
-                                                   DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base + MMIO_BASE_OFFSET + SM501_DC,
-                                 0x1000, sm501_disp_ctrl_index);
-    sm501_2d_engine_index = cpu_register_io_memory(sm501_2d_engine_readfn,
-                                                   sm501_2d_engine_writefn, s,
-                                                   DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base + MMIO_BASE_OFFSET + SM501_2D_ENGINE,
-                                 0x54, sm501_2d_engine_index);
+    memory_region_init_io(sm501_system_config, &sm501_system_config_ops, s,
+                          "sm501-system-config", 0x6c);
+    memory_region_add_subregion(address_space_mem, base + MMIO_BASE_OFFSET,
+                                sm501_system_config);
+    memory_region_init_io(sm501_disp_ctrl, &sm501_disp_ctrl_ops, s,
+                          "sm501-disp-ctrl", 0x1000);
+    memory_region_add_subregion(address_space_mem,
+                                base + MMIO_BASE_OFFSET + SM501_DC,
+                                sm501_disp_ctrl);
+    memory_region_init_io(sm501_2d_engine, &sm501_2d_engine_ops, s,
+                          "sm501-2d-engine", 0x54);
+    memory_region_add_subregion(address_space_mem,
+                                base + MMIO_BASE_OFFSET + SM501_2D_ENGINE,
+                                sm501_2d_engine);
 
     /* bridge to usb host emulation module */
     dev = qdev_create(NULL, "sysbus-ohci");
diff --git a/hw/spapr.c b/hw/spapr.c
index b118975..63e5d33 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -41,6 +41,8 @@
 #include "kvm.h"
 #include "kvm_ppc.h"
 
+#include "exec-memory.h"
+
 #include <libfdt.h>
 
 #define KERNEL_LOAD_ADDR        0x00000000
@@ -324,7 +326,8 @@
 {
     CPUState *env;
     int i;
-    ram_addr_t ram_offset;
+    MemoryRegion *sysmem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
     uint32_t initrd_base;
     long kernel_size, initrd_size, fw_size;
     long pteg_shift = 17;
@@ -361,8 +364,8 @@
 
     /* allocate RAM */
     spapr->ram_limit = ram_size;
-    ram_offset = qemu_ram_alloc(NULL, "ppc_spapr.ram", spapr->ram_limit);
-    cpu_register_physical_memory(0, ram_size, ram_offset);
+    memory_region_init_ram(ram, NULL, "ppc_spapr.ram", spapr->ram_limit);
+    memory_region_add_subregion(sysmem, 0, ram);
 
     /* allocate hash page table.  For now we always make this 16mb,
      * later we should probably make it scale to the size of guest
diff --git a/hw/spitz.c b/hw/spitz.c
index 6f8a94c..23f9d41 100644
--- a/hw/spitz.c
+++ b/hw/spitz.c
@@ -49,6 +49,7 @@
 
 typedef struct {
     SysBusDevice busdev;
+    MemoryRegion iomem;
     DeviceState *nand;
     uint8_t ctl;
     uint8_t manf_id;
@@ -56,7 +57,7 @@
     ECCState ecc;
 } SLNANDState;
 
-static uint32_t sl_readb(void *opaque, target_phys_addr_t addr)
+static uint64_t sl_read(void *opaque, target_phys_addr_t addr, unsigned size)
 {
     SLNANDState *s = (SLNANDState *) opaque;
     int ryby;
@@ -86,6 +87,10 @@
             return s->ctl;
 
     case FLASH_FLASHIO:
+        if (size == 4) {
+            return ecc_digest(&s->ecc, nand_getio(s->nand)) |
+                (ecc_digest(&s->ecc, nand_getio(s->nand)) << 16);
+        }
         return ecc_digest(&s->ecc, nand_getio(s->nand));
 
     default:
@@ -94,19 +99,8 @@
     return 0;
 }
 
-static uint32_t sl_readl(void *opaque, target_phys_addr_t addr)
-{
-    SLNANDState *s = (SLNANDState *) opaque;
-
-    if (addr == FLASH_FLASHIO)
-        return ecc_digest(&s->ecc, nand_getio(s->nand)) |
-                (ecc_digest(&s->ecc, nand_getio(s->nand)) << 16);
-
-    return sl_readb(opaque, addr);
-}
-
-static void sl_writeb(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+static void sl_write(void *opaque, target_phys_addr_t addr,
+                     uint64_t value, unsigned size)
 {
     SLNANDState *s = (SLNANDState *) opaque;
 
@@ -140,15 +134,10 @@
     FLASH_1024M,
 };
 
-static CPUReadMemoryFunc * const sl_readfn[] = {
-    sl_readb,
-    sl_readb,
-    sl_readl,
-};
-static CPUWriteMemoryFunc * const sl_writefn[] = {
-    sl_writeb,
-    sl_writeb,
-    sl_writeb,
+static const MemoryRegionOps sl_ops = {
+    .read = sl_read,
+    .write = sl_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void sl_flash_register(PXA2xxState *cpu, int size)
@@ -168,7 +157,6 @@
 }
 
 static int sl_nand_init(SysBusDevice *dev) {
-    int iomemtype;
     SLNANDState *s;
     DriveInfo *nand;
 
@@ -178,10 +166,8 @@
     nand = drive_get(IF_MTD, 0, 0);
     s->nand = nand_init(nand ? nand->bdrv : NULL, s->manf_id, s->chip_id);
 
-    iomemtype = cpu_register_io_memory(sl_readfn,
-                    sl_writefn, s, DEVICE_NATIVE_ENDIAN);
-
-    sysbus_init_mmio(dev, 0x40, iomemtype);
+    memory_region_init_io(&s->iomem, &sl_ops, s, "sl", 0x40);
+    sysbus_init_mmio_region(dev, &s->iomem);
 
     return 0;
 }
@@ -898,6 +884,7 @@
     PXA2xxState *cpu;
     DeviceState *scp0, *scp1 = NULL;
     MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *rom = g_new(MemoryRegion, 1);
 
     if (!cpu_model)
         cpu_model = (model == terrier) ? "pxa270-c5" : "pxa270-c0";
@@ -907,8 +894,9 @@
 
     sl_flash_register(cpu, (model == spitz) ? FLASH_128M : FLASH_1024M);
 
-    cpu_register_physical_memory(0, SPITZ_ROM,
-                    qemu_ram_alloc(NULL, "spitz.rom", SPITZ_ROM) | IO_MEM_ROM);
+    memory_region_init_ram(rom, NULL, "spitz.rom", SPITZ_ROM);
+    memory_region_set_readonly(rom, true);
+    memory_region_add_subregion(address_space_mem, 0, rom);
 
     /* Setup peripherals */
     spitz_keyboard_register(cpu);
diff --git a/hw/strongarm.c b/hw/strongarm.c
index 6097ea2..a3d9080 100644
--- a/hw/strongarm.c
+++ b/hw/strongarm.c
@@ -68,6 +68,7 @@
 /* Interrupt Controller */
 typedef struct {
     SysBusDevice busdev;
+    MemoryRegion iomem;
     qemu_irq    irq;
     qemu_irq    fiq;
 
@@ -109,7 +110,8 @@
     strongarm_pic_update(s);
 }
 
-static uint32_t strongarm_pic_mem_read(void *opaque, target_phys_addr_t offset)
+static uint64_t strongarm_pic_mem_read(void *opaque, target_phys_addr_t offset,
+                                       unsigned size)
 {
     StrongARMPICState *s = opaque;
 
@@ -134,7 +136,7 @@
 }
 
 static void strongarm_pic_mem_write(void *opaque, target_phys_addr_t offset,
-                uint32_t value)
+                                    uint64_t value, unsigned size)
 {
     StrongARMPICState *s = opaque;
 
@@ -156,27 +158,19 @@
     strongarm_pic_update(s);
 }
 
-static CPUReadMemoryFunc * const strongarm_pic_readfn[] = {
-    strongarm_pic_mem_read,
-    strongarm_pic_mem_read,
-    strongarm_pic_mem_read,
-};
-
-static CPUWriteMemoryFunc * const strongarm_pic_writefn[] = {
-    strongarm_pic_mem_write,
-    strongarm_pic_mem_write,
-    strongarm_pic_mem_write,
+static const MemoryRegionOps strongarm_pic_ops = {
+    .read = strongarm_pic_mem_read,
+    .write = strongarm_pic_mem_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static int strongarm_pic_initfn(SysBusDevice *dev)
 {
     StrongARMPICState *s = FROM_SYSBUS(StrongARMPICState, dev);
-    int iomemtype;
 
     qdev_init_gpio_in(&dev->qdev, strongarm_pic_set_irq, SA_PIC_SRCS);
-    iomemtype = cpu_register_io_memory(strongarm_pic_readfn,
-                    strongarm_pic_writefn, s, DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, 0x1000, iomemtype);
+    memory_region_init_io(&s->iomem, &strongarm_pic_ops, s, "pic", 0x1000);
+    sysbus_init_mmio_region(dev, &s->iomem);
     sysbus_init_irq(dev, &s->irq);
     sysbus_init_irq(dev, &s->fiq);
 
@@ -229,6 +223,7 @@
 
 typedef struct {
     SysBusDevice busdev;
+    MemoryRegion iomem;
     uint32_t rttr;
     uint32_t rtsr;
     uint32_t rtar;
@@ -287,7 +282,8 @@
     strongarm_rtc_int_update(s);
 }
 
-static uint32_t strongarm_rtc_read(void *opaque, target_phys_addr_t addr)
+static uint64_t strongarm_rtc_read(void *opaque, target_phys_addr_t addr,
+                                   unsigned size)
 {
     StrongARMRTCState *s = opaque;
 
@@ -309,7 +305,7 @@
 }
 
 static void strongarm_rtc_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                                uint64_t value, unsigned size)
 {
     StrongARMRTCState *s = opaque;
     uint32_t old_rtsr;
@@ -349,23 +345,16 @@
     }
 }
 
-static CPUReadMemoryFunc * const strongarm_rtc_readfn[] = {
-    strongarm_rtc_read,
-    strongarm_rtc_read,
-    strongarm_rtc_read,
-};
-
-static CPUWriteMemoryFunc * const strongarm_rtc_writefn[] = {
-    strongarm_rtc_write,
-    strongarm_rtc_write,
-    strongarm_rtc_write,
+static const MemoryRegionOps strongarm_rtc_ops = {
+    .read = strongarm_rtc_read,
+    .write = strongarm_rtc_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static int strongarm_rtc_init(SysBusDevice *dev)
 {
     StrongARMRTCState *s = FROM_SYSBUS(StrongARMRTCState, dev);
     struct tm tm;
-    int iomemtype;
 
     s->rttr = 0x0;
     s->rtsr = 0;
@@ -381,9 +370,8 @@
     sysbus_init_irq(dev, &s->rtc_irq);
     sysbus_init_irq(dev, &s->rtc_hz_irq);
 
-    iomemtype = cpu_register_io_memory(strongarm_rtc_readfn,
-                    strongarm_rtc_writefn, s, DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, 0x10000, iomemtype);
+    memory_region_init_io(&s->iomem, &strongarm_rtc_ops, s, "rtc", 0x10000);
+    sysbus_init_mmio_region(dev, &s->iomem);
 
     return 0;
 }
@@ -443,6 +431,7 @@
 typedef struct StrongARMGPIOInfo StrongARMGPIOInfo;
 struct StrongARMGPIOInfo {
     SysBusDevice busdev;
+    MemoryRegion iomem;
     qemu_irq handler[28];
     qemu_irq irqs[11];
     qemu_irq irqX;
@@ -507,7 +496,8 @@
     s->prev_level = level;
 }
 
-static uint32_t strongarm_gpio_read(void *opaque, target_phys_addr_t offset)
+static uint64_t strongarm_gpio_read(void *opaque, target_phys_addr_t offset,
+                                    unsigned size)
 {
     StrongARMGPIOInfo *s = opaque;
 
@@ -548,8 +538,8 @@
     return 0;
 }
 
-static void strongarm_gpio_write(void *opaque,
-                target_phys_addr_t offset, uint32_t value)
+static void strongarm_gpio_write(void *opaque, target_phys_addr_t offset,
+                                 uint64_t value, unsigned size)
 {
     StrongARMGPIOInfo *s = opaque;
 
@@ -592,16 +582,10 @@
     }
 }
 
-static CPUReadMemoryFunc * const strongarm_gpio_readfn[] = {
-    strongarm_gpio_read,
-    strongarm_gpio_read,
-    strongarm_gpio_read
-};
-
-static CPUWriteMemoryFunc * const strongarm_gpio_writefn[] = {
-    strongarm_gpio_write,
-    strongarm_gpio_write,
-    strongarm_gpio_write
+static const MemoryRegionOps strongarm_gpio_ops = {
+    .read = strongarm_gpio_read,
+    .write = strongarm_gpio_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static DeviceState *strongarm_gpio_init(target_phys_addr_t base,
@@ -623,7 +607,6 @@
 
 static int strongarm_gpio_initfn(SysBusDevice *dev)
 {
-    int iomemtype;
     StrongARMGPIOInfo *s;
     int i;
 
@@ -632,10 +615,9 @@
     qdev_init_gpio_in(&dev->qdev, strongarm_gpio_set, 28);
     qdev_init_gpio_out(&dev->qdev, s->handler, 28);
 
-    iomemtype = cpu_register_io_memory(strongarm_gpio_readfn,
-                    strongarm_gpio_writefn, s, DEVICE_NATIVE_ENDIAN);
+    memory_region_init_io(&s->iomem, &strongarm_gpio_ops, s, "gpio", 0x1000);
 
-    sysbus_init_mmio(dev, 0x1000, iomemtype);
+    sysbus_init_mmio_region(dev, &s->iomem);
     for (i = 0; i < 11; i++) {
         sysbus_init_irq(dev, &s->irqs[i]);
     }
@@ -678,6 +660,7 @@
 typedef struct StrongARMPPCInfo StrongARMPPCInfo;
 struct StrongARMPPCInfo {
     SysBusDevice busdev;
+    MemoryRegion iomem;
     qemu_irq handler[28];
 
     uint32_t ilevel;
@@ -716,7 +699,8 @@
     s->prev_level = level;
 }
 
-static uint32_t strongarm_ppc_read(void *opaque, target_phys_addr_t offset)
+static uint64_t strongarm_ppc_read(void *opaque, target_phys_addr_t offset,
+                                   unsigned size)
 {
     StrongARMPPCInfo *s = opaque;
 
@@ -745,8 +729,8 @@
     return 0;
 }
 
-static void strongarm_ppc_write(void *opaque,
-                target_phys_addr_t offset, uint32_t value)
+static void strongarm_ppc_write(void *opaque, target_phys_addr_t offset,
+                                uint64_t value, unsigned size)
 {
     StrongARMPPCInfo *s = opaque;
 
@@ -778,21 +762,14 @@
     }
 }
 
-static CPUReadMemoryFunc * const strongarm_ppc_readfn[] = {
-    strongarm_ppc_read,
-    strongarm_ppc_read,
-    strongarm_ppc_read
-};
-
-static CPUWriteMemoryFunc * const strongarm_ppc_writefn[] = {
-    strongarm_ppc_write,
-    strongarm_ppc_write,
-    strongarm_ppc_write
+static const MemoryRegionOps strongarm_ppc_ops = {
+    .read = strongarm_ppc_read,
+    .write = strongarm_ppc_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static int strongarm_ppc_init(SysBusDevice *dev)
 {
-    int iomemtype;
     StrongARMPPCInfo *s;
 
     s = FROM_SYSBUS(StrongARMPPCInfo, dev);
@@ -800,10 +777,9 @@
     qdev_init_gpio_in(&dev->qdev, strongarm_ppc_set, 22);
     qdev_init_gpio_out(&dev->qdev, s->handler, 22);
 
-    iomemtype = cpu_register_io_memory(strongarm_ppc_readfn,
-                    strongarm_ppc_writefn, s, DEVICE_NATIVE_ENDIAN);
+    memory_region_init_io(&s->iomem, &strongarm_ppc_ops, s, "ppc", 0x1000);
 
-    sysbus_init_mmio(dev, 0x1000, iomemtype);
+    sysbus_init_mmio_region(dev, &s->iomem);
 
     return 0;
 }
@@ -871,6 +847,7 @@
 
 typedef struct {
     SysBusDevice busdev;
+    MemoryRegion iomem;
     CharDriverState *chr;
     qemu_irq irq;
 
@@ -1079,7 +1056,8 @@
     strongarm_uart_update_int_status(s);
 }
 
-static uint32_t strongarm_uart_read(void *opaque, target_phys_addr_t addr)
+static uint64_t strongarm_uart_read(void *opaque, target_phys_addr_t addr,
+                                    unsigned size)
 {
     StrongARMUARTState *s = opaque;
     uint16_t ret;
@@ -1121,7 +1099,7 @@
 }
 
 static void strongarm_uart_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                                 uint64_t value, unsigned size)
 {
     StrongARMUARTState *s = opaque;
 
@@ -1176,26 +1154,18 @@
     }
 }
 
-static CPUReadMemoryFunc * const strongarm_uart_readfn[] = {
-    strongarm_uart_read,
-    strongarm_uart_read,
-    strongarm_uart_read,
-};
-
-static CPUWriteMemoryFunc * const strongarm_uart_writefn[] = {
-    strongarm_uart_write,
-    strongarm_uart_write,
-    strongarm_uart_write,
+static const MemoryRegionOps strongarm_uart_ops = {
+    .read = strongarm_uart_read,
+    .write = strongarm_uart_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static int strongarm_uart_init(SysBusDevice *dev)
 {
     StrongARMUARTState *s = FROM_SYSBUS(StrongARMUARTState, dev);
-    int iomemtype;
 
-    iomemtype = cpu_register_io_memory(strongarm_uart_readfn,
-                    strongarm_uart_writefn, s, DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, 0x10000, iomemtype);
+    memory_region_init_io(&s->iomem, &strongarm_uart_ops, s, "uart", 0x10000);
+    sysbus_init_mmio_region(dev, &s->iomem);
     sysbus_init_irq(dev, &s->irq);
 
     s->rx_timeout_timer = qemu_new_timer_ns(vm_clock, strongarm_uart_rx_to, s);
@@ -1288,6 +1258,7 @@
 /* Synchronous Serial Ports */
 typedef struct {
     SysBusDevice busdev;
+    MemoryRegion iomem;
     qemu_irq irq;
     SSIBus *bus;
 
@@ -1355,7 +1326,8 @@
     strongarm_ssp_int_update(s);
 }
 
-static uint32_t strongarm_ssp_read(void *opaque, target_phys_addr_t addr)
+static uint64_t strongarm_ssp_read(void *opaque, target_phys_addr_t addr,
+                                   unsigned size)
 {
     StrongARMSSPState *s = opaque;
     uint32_t retval;
@@ -1388,7 +1360,7 @@
 }
 
 static void strongarm_ssp_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                                uint64_t value, unsigned size)
 {
     StrongARMSSPState *s = opaque;
 
@@ -1397,7 +1369,7 @@
         s->sscr[0] = value & 0xffbf;
         if ((s->sscr[0] & SSCR0_SSE) && SSCR0_DSS(value) < 4) {
             printf("%s: Wrong data size: %i bits\n", __func__,
-                            SSCR0_DSS(value));
+                   (int)SSCR0_DSS(value));
         }
         if (!(value & SSCR0_SSE)) {
             s->sssr = 0;
@@ -1452,16 +1424,10 @@
     }
 }
 
-static CPUReadMemoryFunc * const strongarm_ssp_readfn[] = {
-    strongarm_ssp_read,
-    strongarm_ssp_read,
-    strongarm_ssp_read,
-};
-
-static CPUWriteMemoryFunc * const strongarm_ssp_writefn[] = {
-    strongarm_ssp_write,
-    strongarm_ssp_write,
-    strongarm_ssp_write,
+static const MemoryRegionOps strongarm_ssp_ops = {
+    .read = strongarm_ssp_read,
+    .write = strongarm_ssp_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static int strongarm_ssp_post_load(void *opaque, int version_id)
@@ -1475,15 +1441,12 @@
 
 static int strongarm_ssp_init(SysBusDevice *dev)
 {
-    int iomemtype;
     StrongARMSSPState *s = FROM_SYSBUS(StrongARMSSPState, dev);
 
     sysbus_init_irq(dev, &s->irq);
 
-    iomemtype = cpu_register_io_memory(strongarm_ssp_readfn,
-                                       strongarm_ssp_writefn, s,
-                                       DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, 0x1000, iomemtype);
+    memory_region_init_io(&s->iomem, &strongarm_ssp_ops, s, "ssp", 0x1000);
+    sysbus_init_mmio_region(dev, &s->iomem);
 
     s->bus = ssi_create_bus(&dev->qdev, "ssi");
     return 0;
@@ -1523,7 +1486,8 @@
 };
 
 /* Main CPU functions */
-StrongARMState *sa1110_init(unsigned int sdram_size, const char *rev)
+StrongARMState *sa1110_init(MemoryRegion *sysmem,
+                            unsigned int sdram_size, const char *rev)
 {
     StrongARMState *s;
     qemu_irq *pic;
@@ -1547,9 +1511,8 @@
         exit(1);
     }
 
-    cpu_register_physical_memory(SA_SDCS0,
-                    sdram_size, qemu_ram_alloc(NULL, "strongarm.sdram",
-                                                sdram_size) | IO_MEM_RAM);
+    memory_region_init_ram(&s->sdram, NULL, "strongarm.sdram", sdram_size);
+    memory_region_add_subregion(sysmem, SA_SDCS0, &s->sdram);
 
     pic = arm_pic_init_cpu(s->env);
     s->pic = sysbus_create_varargs("strongarm_pic", 0x90050000,
diff --git a/hw/strongarm.h b/hw/strongarm.h
index a81b110..684f61b 100644
--- a/hw/strongarm.h
+++ b/hw/strongarm.h
@@ -1,6 +1,8 @@
 #ifndef _STRONGARM_H
 #define _STRONGARM_H
 
+#include "memory.h"
+
 #define SA_CS0          0x00000000
 #define SA_CS1          0x08000000
 #define SA_CS2          0x10000000
@@ -52,6 +54,7 @@
 
 typedef struct {
     CPUState *env;
+    MemoryRegion sdram;
     DeviceState *pic;
     DeviceState *gpio;
     DeviceState *ppc;
@@ -59,6 +62,7 @@
     SSIBus *ssp_bus;
 } StrongARMState;
 
-StrongARMState *sa1110_init(unsigned int sdram_size, const char *rev);
+StrongARMState *sa1110_init(MemoryRegion *sysmem,
+                            unsigned int sdram_size, const char *rev);
 
 #endif
diff --git a/hw/sun4m.c b/hw/sun4m.c
index 71bf648..314edc4 100644
--- a/hw/sun4m.c
+++ b/hw/sun4m.c
@@ -593,19 +593,25 @@
     cpu_physical_memory_write_rom(addr, idreg_data, sizeof(idreg_data));
 }
 
+typedef struct IDRegState {
+    SysBusDevice busdev;
+    MemoryRegion mem;
+} IDRegState;
+
 static int idreg_init1(SysBusDevice *dev)
 {
-    ram_addr_t idreg_offset;
+    IDRegState *s = FROM_SYSBUS(IDRegState, dev);
 
-    idreg_offset = qemu_ram_alloc(NULL, "sun4m.idreg", sizeof(idreg_data));
-    sysbus_init_mmio(dev, sizeof(idreg_data), idreg_offset | IO_MEM_ROM);
+    memory_region_init_ram(&s->mem, NULL, "sun4m.idreg", sizeof(idreg_data));
+    memory_region_set_readonly(&s->mem, true);
+    sysbus_init_mmio_region(dev, &s->mem);
     return 0;
 }
 
 static SysBusDeviceInfo idreg_info = {
     .init = idreg_init1,
     .qdev.name  = "macio_idreg",
-    .qdev.size  = sizeof(SysBusDevice),
+    .qdev.size  = sizeof(IDRegState),
 };
 
 static void idreg_register_devices(void)
@@ -615,6 +621,11 @@
 
 device_init(idreg_register_devices);
 
+typedef struct AFXState {
+    SysBusDevice busdev;
+    MemoryRegion mem;
+} AFXState;
+
 /* SS-5 TCX AFX register */
 static void afx_init(target_phys_addr_t addr)
 {
@@ -630,17 +641,17 @@
 
 static int afx_init1(SysBusDevice *dev)
 {
-    ram_addr_t afx_offset;
+    AFXState *s = FROM_SYSBUS(AFXState, dev);
 
-    afx_offset = qemu_ram_alloc(NULL, "sun4m.afx", 4);
-    sysbus_init_mmio(dev, 4, afx_offset | IO_MEM_RAM);
+    memory_region_init_ram(&s->mem, NULL, "sun4m.afx", 4);
+    sysbus_init_mmio_region(dev, &s->mem);
     return 0;
 }
 
 static SysBusDeviceInfo afx_info = {
     .init = afx_init1,
     .qdev.name  = "tcx_afx",
-    .qdev.size  = sizeof(SysBusDevice),
+    .qdev.size  = sizeof(AFXState),
 };
 
 static void afx_register_devices(void)
@@ -650,6 +661,11 @@
 
 device_init(afx_register_devices);
 
+typedef struct PROMState {
+    SysBusDevice busdev;
+    MemoryRegion prom;
+} PROMState;
+
 /* Boot PROM (OpenBIOS) */
 static uint64_t translate_prom_address(void *opaque, uint64_t addr)
 {
@@ -693,17 +709,18 @@
 
 static int prom_init1(SysBusDevice *dev)
 {
-    ram_addr_t prom_offset;
+    PROMState *s = FROM_SYSBUS(PROMState, dev);
 
-    prom_offset = qemu_ram_alloc(NULL, "sun4m.prom", PROM_SIZE_MAX);
-    sysbus_init_mmio(dev, PROM_SIZE_MAX, prom_offset | IO_MEM_ROM);
+    memory_region_init_ram(&s->prom, NULL, "sun4m.prom", PROM_SIZE_MAX);
+    memory_region_set_readonly(&s->prom, true);
+    sysbus_init_mmio_region(dev, &s->prom);
     return 0;
 }
 
 static SysBusDeviceInfo prom_info = {
     .init = prom_init1,
     .qdev.name  = "openprom",
-    .qdev.size  = sizeof(SysBusDevice),
+    .qdev.size  = sizeof(PROMState),
     .qdev.props = (Property[]) {
         {/* end of property list */}
     }
@@ -719,19 +736,17 @@
 typedef struct RamDevice
 {
     SysBusDevice busdev;
+    MemoryRegion ram;
     uint64_t size;
 } RamDevice;
 
 /* System RAM */
 static int ram_init1(SysBusDevice *dev)
 {
-    ram_addr_t RAM_size, ram_offset;
     RamDevice *d = FROM_SYSBUS(RamDevice, dev);
 
-    RAM_size = d->size;
-
-    ram_offset = qemu_ram_alloc(NULL, "sun4m.ram", RAM_size);
-    sysbus_init_mmio(dev, RAM_size, ram_offset);
+    memory_region_init_ram(&d->ram, NULL, "sun4m.ram", d->size);
+    sysbus_init_mmio_region(dev, &d->ram);
     return 0;
 }
 
diff --git a/hw/sun4u.c b/hw/sun4u.c
index 96fc3d0..eaaefe3 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -574,6 +574,11 @@
 
 device_init(pci_ebus_register);
 
+typedef struct PROMState {
+    SysBusDevice busdev;
+    MemoryRegion prom;
+} PROMState;
+
 static uint64_t translate_prom_address(void *opaque, uint64_t addr)
 {
     target_phys_addr_t *base_addr = (target_phys_addr_t *)opaque;
@@ -617,17 +622,18 @@
 
 static int prom_init1(SysBusDevice *dev)
 {
-    ram_addr_t prom_offset;
+    PROMState *s = FROM_SYSBUS(PROMState, dev);
 
-    prom_offset = qemu_ram_alloc(NULL, "sun4u.prom", PROM_SIZE_MAX);
-    sysbus_init_mmio(dev, PROM_SIZE_MAX, prom_offset | IO_MEM_ROM);
+    memory_region_init_ram(&s->prom, NULL, "sun4u.prom", PROM_SIZE_MAX);
+    memory_region_set_readonly(&s->prom, true);
+    sysbus_init_mmio_region(dev, &s->prom);
     return 0;
 }
 
 static SysBusDeviceInfo prom_info = {
     .init = prom_init1,
     .qdev.name  = "openprom",
-    .qdev.size  = sizeof(SysBusDevice),
+    .qdev.size  = sizeof(PROMState),
     .qdev.props = (Property[]) {
         {/* end of property list */}
     }
@@ -644,19 +650,17 @@
 typedef struct RamDevice
 {
     SysBusDevice busdev;
+    MemoryRegion ram;
     uint64_t size;
 } RamDevice;
 
 /* System RAM */
 static int ram_init1(SysBusDevice *dev)
 {
-    ram_addr_t RAM_size, ram_offset;
     RamDevice *d = FROM_SYSBUS(RamDevice, dev);
 
-    RAM_size = d->size;
-
-    ram_offset = qemu_ram_alloc(NULL, "sun4u.ram", RAM_size);
-    sysbus_init_mmio(dev, RAM_size, ram_offset);
+    memory_region_init_ram(&d->ram, NULL, "sun4u.ram", d->size);
+    sysbus_init_mmio_region(dev, &d->ram);
     return 0;
 }
 
diff --git a/hw/syborg.c b/hw/syborg.c
index bc200e4..248de54 100644
--- a/hw/syborg.c
+++ b/hw/syborg.c
@@ -26,6 +26,7 @@
 #include "boards.h"
 #include "arm-misc.h"
 #include "net.h"
+#include "exec-memory.h"
 
 static struct arm_boot_info syborg_binfo;
 
@@ -35,9 +36,10 @@
                         const char *initrd_filename, const char *cpu_model)
 {
     CPUState *env;
+    MemoryRegion *sysmem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
     qemu_irq *cpu_pic;
     qemu_irq pic[64];
-    ram_addr_t ram_addr;
     DeviceState *dev;
     int i;
 
@@ -50,8 +52,8 @@
     }
 
     /* RAM at address zero. */
-    ram_addr = qemu_ram_alloc(NULL, "syborg.ram", ram_size);
-    cpu_register_physical_memory(0, ram_size, ram_addr | IO_MEM_RAM);
+    memory_region_init_ram(ram, NULL, "syborg.ram", ram_size);
+    memory_region_add_subregion(sysmem, 0, ram);
 
     cpu_pic = arm_pic_init_cpu(env);
     dev = sysbus_create_simple("syborg,interrupt", 0xC0000000,
diff --git a/hw/tc6393xb.c b/hw/tc6393xb.c
index c28005a..c144dcf 100644
--- a/hw/tc6393xb.c
+++ b/hw/tc6393xb.c
@@ -79,6 +79,7 @@
 #define NAND_MODE_ECC_RST   0x60
 
 struct TC6393xbState {
+    MemoryRegion iomem;
     qemu_irq irq;
     qemu_irq *sub_irqs;
     struct {
@@ -122,7 +123,7 @@
     ECCState ecc;
 
     DisplayState *ds;
-    ram_addr_t vram_addr;
+    MemoryRegion vram;
     uint16_t *vram_ptr;
     uint32_t scr_width, scr_height; /* in pixels */
     qemu_irq l3v;
@@ -495,7 +496,9 @@
 }
 
 
-static uint32_t tc6393xb_readb(void *opaque, target_phys_addr_t addr) {
+static uint64_t tc6393xb_readb(void *opaque, target_phys_addr_t addr,
+                               unsigned size)
+{
     TC6393xbState *s = opaque;
 
     switch (addr >> 8) {
@@ -516,7 +519,8 @@
     return 0;
 }
 
-static void tc6393xb_writeb(void *opaque, target_phys_addr_t addr, uint32_t value) {
+static void tc6393xb_writeb(void *opaque, target_phys_addr_t addr,
+                            uint64_t value, unsigned size) {
     TC6393xbState *s = opaque;
 
     switch (addr >> 8) {
@@ -532,51 +536,21 @@
         tc6393xb_nand_writeb(s, addr & 0xff, value);
     else
         fprintf(stderr, "tc6393xb: unhandled write at %08x: %02x\n",
-					(uint32_t) addr, value & 0xff);
+                (uint32_t) addr, (int)value & 0xff);
 }
 
-static uint32_t tc6393xb_readw(void *opaque, target_phys_addr_t addr)
+TC6393xbState *tc6393xb_init(MemoryRegion *sysmem, uint32_t base, qemu_irq irq)
 {
-    return (tc6393xb_readb(opaque, addr) & 0xff) |
-        (tc6393xb_readb(opaque, addr + 1) << 8);
-}
-
-static uint32_t tc6393xb_readl(void *opaque, target_phys_addr_t addr)
-{
-    return (tc6393xb_readb(opaque, addr) & 0xff) |
-        ((tc6393xb_readb(opaque, addr + 1) & 0xff) << 8) |
-        ((tc6393xb_readb(opaque, addr + 2) & 0xff) << 16) |
-        ((tc6393xb_readb(opaque, addr + 3) & 0xff) << 24);
-}
-
-static void tc6393xb_writew(void *opaque, target_phys_addr_t addr, uint32_t value)
-{
-    tc6393xb_writeb(opaque, addr, value);
-    tc6393xb_writeb(opaque, addr + 1, value >> 8);
-}
-
-static void tc6393xb_writel(void *opaque, target_phys_addr_t addr, uint32_t value)
-{
-    tc6393xb_writeb(opaque, addr, value);
-    tc6393xb_writeb(opaque, addr + 1, value >> 8);
-    tc6393xb_writeb(opaque, addr + 2, value >> 16);
-    tc6393xb_writeb(opaque, addr + 3, value >> 24);
-}
-
-TC6393xbState *tc6393xb_init(uint32_t base, qemu_irq irq)
-{
-    int iomemtype;
     TC6393xbState *s;
     DriveInfo *nand;
-    CPUReadMemoryFunc * const tc6393xb_readfn[] = {
-        tc6393xb_readb,
-        tc6393xb_readw,
-        tc6393xb_readl,
-    };
-    CPUWriteMemoryFunc * const tc6393xb_writefn[] = {
-        tc6393xb_writeb,
-        tc6393xb_writew,
-        tc6393xb_writel,
+    static const MemoryRegionOps tc6393xb_ops = {
+        .read = tc6393xb_readb,
+        .write = tc6393xb_writeb,
+        .endianness = DEVICE_NATIVE_ENDIAN,
+        .impl = {
+            .min_access_size = 1,
+            .max_access_size = 1,
+        },
     };
 
     s = (TC6393xbState *) g_malloc0(sizeof(TC6393xbState));
@@ -591,13 +565,12 @@
     nand = drive_get(IF_MTD, 0, 0);
     s->flash = nand_init(nand ? nand->bdrv : NULL, NAND_MFR_TOSHIBA, 0x76);
 
-    iomemtype = cpu_register_io_memory(tc6393xb_readfn,
-                    tc6393xb_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x10000, iomemtype);
+    memory_region_init_io(&s->iomem, &tc6393xb_ops, s, "tc6393xb", 0x10000);
+    memory_region_add_subregion(sysmem, base, &s->iomem);
 
-    s->vram_addr = qemu_ram_alloc(NULL, "tc6393xb.vram", 0x100000);
-    s->vram_ptr = qemu_get_ram_ptr(s->vram_addr);
-    cpu_register_physical_memory(base + 0x100000, 0x100000, s->vram_addr);
+    memory_region_init_ram(&s->vram, NULL, "tc6393xb.vram", 0x100000);
+    s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
+    memory_region_add_subregion(sysmem, base + 0x100000, &s->vram);
     s->scr_width = 480;
     s->scr_height = 640;
     s->ds = graphic_console_init(tc6393xb_update_display,
diff --git a/hw/tcx.c b/hw/tcx.c
index 309600d..cd24100 100644
--- a/hw/tcx.c
+++ b/hw/tcx.c
@@ -40,7 +40,15 @@
     DisplayState *ds;
     uint8_t *vram;
     uint32_t *vram24, *cplane;
-    ram_addr_t vram_offset, vram24_offset, cplane_offset;
+    MemoryRegion vram_mem;
+    MemoryRegion vram_8bit;
+    MemoryRegion vram_24bit;
+    MemoryRegion vram_cplane;
+    MemoryRegion dac;
+    MemoryRegion tec;
+    MemoryRegion thc24;
+    MemoryRegion thc8;
+    ram_addr_t vram24_offset, cplane_offset;
     uint32_t vram_size;
     uint32_t palette[256];
     uint8_t r[256], g[256], b[256];
@@ -56,7 +64,7 @@
     unsigned int i;
 
     for (i = 0; i < MAXX * MAXY; i += TARGET_PAGE_SIZE) {
-        cpu_physical_memory_set_dirty(s->vram_offset + i);
+        memory_region_set_dirty(&s->vram_mem, i);
     }
 }
 
@@ -65,8 +73,8 @@
     unsigned int i;
 
     for (i = 0; i < MAXX * MAXY * 4; i += TARGET_PAGE_SIZE) {
-        cpu_physical_memory_set_dirty(s->vram24_offset + i);
-        cpu_physical_memory_set_dirty(s->cplane_offset + i);
+        memory_region_set_dirty(&s->vram_mem, s->vram24_offset + i);
+        memory_region_set_dirty(&s->vram_mem, s->cplane_offset + i);
     }
 }
 
@@ -174,16 +182,18 @@
     }
 }
 
-static inline int check_dirty(ram_addr_t page, ram_addr_t page24,
+static inline int check_dirty(TCXState *s, ram_addr_t page, ram_addr_t page24,
                               ram_addr_t cpage)
 {
     int ret;
     unsigned int off;
 
-    ret = cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG);
+    ret = memory_region_get_dirty(&s->vram_mem, page, DIRTY_MEMORY_VGA);
     for (off = 0; off < TARGET_PAGE_SIZE * 4; off += TARGET_PAGE_SIZE) {
-        ret |= cpu_physical_memory_get_dirty(page24 + off, VGA_DIRTY_FLAG);
-        ret |= cpu_physical_memory_get_dirty(cpage + off, VGA_DIRTY_FLAG);
+        ret |= memory_region_get_dirty(&s->vram_mem, page24 + off,
+                                       DIRTY_MEMORY_VGA);
+        ret |= memory_region_get_dirty(&s->vram_mem, cpage + off,
+                                       DIRTY_MEMORY_VGA);
     }
     return ret;
 }
@@ -192,16 +202,17 @@
                                ram_addr_t page_max, ram_addr_t page24,
                               ram_addr_t cpage)
 {
-    cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
-                                    VGA_DIRTY_FLAG);
-    page_min -= ts->vram_offset;
-    page_max -= ts->vram_offset;
-    cpu_physical_memory_reset_dirty(page24 + page_min * 4,
-                                    page24 + page_max * 4 + TARGET_PAGE_SIZE,
-                                    VGA_DIRTY_FLAG);
-    cpu_physical_memory_reset_dirty(cpage + page_min * 4,
-                                    cpage + page_max * 4 + TARGET_PAGE_SIZE,
-                                    VGA_DIRTY_FLAG);
+    memory_region_reset_dirty(&ts->vram_mem,
+                              page_min, page_max + TARGET_PAGE_SIZE,
+                              DIRTY_MEMORY_VGA);
+    memory_region_reset_dirty(&ts->vram_mem,
+                              page24 + page_min * 4,
+                              page24 + page_max * 4 + TARGET_PAGE_SIZE,
+                              DIRTY_MEMORY_VGA);
+    memory_region_reset_dirty(&ts->vram_mem,
+                              cpage + page_min * 4,
+                              cpage + page_max * 4 + TARGET_PAGE_SIZE,
+                              DIRTY_MEMORY_VGA);
 }
 
 /* Fixed line length 1024 allows us to do nice tricks not possible on
@@ -216,7 +227,7 @@
 
     if (ds_get_bits_per_pixel(ts->ds) == 0)
         return;
-    page = ts->vram_offset;
+    page = 0;
     y_start = -1;
     page_min = -1;
     page_max = 0;
@@ -242,7 +253,7 @@
     }
 
     for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) {
-        if (cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG)) {
+        if (memory_region_get_dirty(&ts->vram_mem, page, DIRTY_MEMORY_VGA)) {
             if (y_start < 0)
                 y_start = y;
             if (page < page_min)
@@ -279,8 +290,9 @@
     }
     /* reset modified pages */
     if (page_max >= page_min) {
-        cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
-                                        VGA_DIRTY_FLAG);
+        memory_region_reset_dirty(&ts->vram_mem,
+                                  page_min, page_max + TARGET_PAGE_SIZE,
+                                  DIRTY_MEMORY_VGA);
     }
 }
 
@@ -294,7 +306,7 @@
 
     if (ds_get_bits_per_pixel(ts->ds) != 32)
             return;
-    page = ts->vram_offset;
+    page = 0;
     page24 = ts->vram24_offset;
     cpage = ts->cplane_offset;
     y_start = -1;
@@ -309,7 +321,7 @@
 
     for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE,
             page24 += TARGET_PAGE_SIZE, cpage += TARGET_PAGE_SIZE) {
-        if (check_dirty(page, page24, cpage)) {
+        if (check_dirty(ts, page, page24, cpage)) {
             if (y_start < 0)
                 y_start = y;
             if (page < page_min)
@@ -421,18 +433,20 @@
     s->r[255] = s->g[255] = s->b[255] = 255;
     update_palette_entries(s, 0, 256);
     memset(s->vram, 0, MAXX*MAXY);
-    cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset +
-                                    MAXX * MAXY * (1 + 4 + 4), VGA_DIRTY_FLAG);
+    memory_region_reset_dirty(&s->vram_mem, 0, MAXX * MAXY * (1 + 4 + 4),
+                              DIRTY_MEMORY_VGA);
     s->dac_index = 0;
     s->dac_state = 0;
 }
 
-static uint32_t tcx_dac_readl(void *opaque, target_phys_addr_t addr)
+static uint64_t tcx_dac_readl(void *opaque, target_phys_addr_t addr,
+                              unsigned size)
 {
     return 0;
 }
 
-static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint64_t val,
+                           unsigned size)
 {
     TCXState *s = opaque;
 
@@ -468,77 +482,77 @@
     return;
 }
 
-static CPUReadMemoryFunc * const tcx_dac_read[3] = {
-    NULL,
-    NULL,
-    tcx_dac_readl,
+static const MemoryRegionOps tcx_dac_ops = {
+    .read = tcx_dac_readl,
+    .write = tcx_dac_writel,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
 };
 
-static CPUWriteMemoryFunc * const tcx_dac_write[3] = {
-    NULL,
-    NULL,
-    tcx_dac_writel,
-};
-
-static uint32_t tcx_dummy_readl(void *opaque, target_phys_addr_t addr)
+static uint64_t dummy_readl(void *opaque, target_phys_addr_t addr,
+                            unsigned size)
 {
     return 0;
 }
 
-static void tcx_dummy_writel(void *opaque, target_phys_addr_t addr,
-                             uint32_t val)
+static void dummy_writel(void *opaque, target_phys_addr_t addr,
+                         uint64_t val, unsigned size)
 {
 }
 
-static CPUReadMemoryFunc * const tcx_dummy_read[3] = {
-    NULL,
-    NULL,
-    tcx_dummy_readl,
-};
-
-static CPUWriteMemoryFunc * const tcx_dummy_write[3] = {
-    NULL,
-    NULL,
-    tcx_dummy_writel,
+static const MemoryRegionOps dummy_ops = {
+    .read = dummy_readl,
+    .write = dummy_writel,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
 };
 
 static int tcx_init1(SysBusDevice *dev)
 {
     TCXState *s = FROM_SYSBUS(TCXState, dev);
-    int io_memory, dummy_memory;
-    ram_addr_t vram_offset;
+    ram_addr_t vram_offset = 0;
     int size;
     uint8_t *vram_base;
 
-    vram_offset = qemu_ram_alloc(NULL, "tcx.vram", s->vram_size * (1 + 4 + 4));
-    vram_base = qemu_get_ram_ptr(vram_offset);
-    s->vram_offset = vram_offset;
+    memory_region_init_ram(&s->vram_mem, NULL, "tcx.vram",
+                           s->vram_size * (1 + 4 + 4));
+    vram_base = memory_region_get_ram_ptr(&s->vram_mem);
 
     /* 8-bit plane */
     s->vram = vram_base;
     size = s->vram_size;
-    sysbus_init_mmio(dev, size, s->vram_offset);
+    memory_region_init_alias(&s->vram_8bit, "tcx.vram.8bit",
+                             &s->vram_mem, vram_offset, size);
+    sysbus_init_mmio_region(dev, &s->vram_8bit);
     vram_offset += size;
     vram_base += size;
 
     /* DAC */
-    io_memory = cpu_register_io_memory(tcx_dac_read, tcx_dac_write, s,
-                                       DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, TCX_DAC_NREGS, io_memory);
+    memory_region_init_io(&s->dac, &tcx_dac_ops, s, "tcx.dac", TCX_DAC_NREGS);
+    sysbus_init_mmio_region(dev, &s->dac);
 
     /* TEC (dummy) */
-    dummy_memory = cpu_register_io_memory(tcx_dummy_read, tcx_dummy_write,
-                                          s, DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, TCX_TEC_NREGS, dummy_memory);
+    memory_region_init_io(&s->tec, &dummy_ops, s, "tcx.tec", TCX_TEC_NREGS);
+    sysbus_init_mmio_region(dev, &s->tec);
     /* THC: NetBSD writes here even with 8-bit display: dummy */
-    sysbus_init_mmio(dev, TCX_THC_NREGS_24, dummy_memory);
+    memory_region_init_io(&s->thc24, &dummy_ops, s, "tcx.thc24",
+                          TCX_THC_NREGS_24);
+    sysbus_init_mmio_region(dev, &s->thc24);
 
     if (s->depth == 24) {
         /* 24-bit plane */
         size = s->vram_size * 4;
         s->vram24 = (uint32_t *)vram_base;
         s->vram24_offset = vram_offset;
-        sysbus_init_mmio(dev, size, vram_offset);
+        memory_region_init_alias(&s->vram_24bit, "tcx.vram.24bit",
+                                 &s->vram_mem, vram_offset, size);
+        sysbus_init_mmio_region(dev, &s->vram_24bit);
         vram_offset += size;
         vram_base += size;
 
@@ -546,14 +560,18 @@
         size = s->vram_size * 4;
         s->cplane = (uint32_t *)vram_base;
         s->cplane_offset = vram_offset;
-        sysbus_init_mmio(dev, size, vram_offset);
+        memory_region_init_alias(&s->vram_cplane, "tcx.vram.cplane",
+                                 &s->vram_mem, vram_offset, size);
+        sysbus_init_mmio_region(dev, &s->vram_cplane);
 
         s->ds = graphic_console_init(tcx24_update_display,
                                      tcx24_invalidate_display,
                                      tcx24_screen_dump, NULL, s);
     } else {
         /* THC 8 bit (dummy) */
-        sysbus_init_mmio(dev, TCX_THC_NREGS_8, dummy_memory);
+        memory_region_init_io(&s->thc8, &dummy_ops, s, "tcx.thc8",
+                              TCX_THC_NREGS_8);
+        sysbus_init_mmio_region(dev, &s->thc8);
 
         s->ds = graphic_console_init(tcx_update_display,
                                      tcx_invalidate_display,
diff --git a/hw/tosa.c b/hw/tosa.c
index 92702d1..b992b99 100644
--- a/hw/tosa.c
+++ b/hw/tosa.c
@@ -220,7 +220,7 @@
     cpu_register_physical_memory(0, TOSA_ROM,
                     qemu_ram_alloc(NULL, "tosa.rom", TOSA_ROM) | IO_MEM_ROM);
 
-    tmio = tc6393xb_init(0x10000000,
+    tmio = tc6393xb_init(address_space_mem, 0x10000000,
             qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_TC6393XB_INT));
 
     scp0 = sysbus_create_simple("scoop", 0x08800000, NULL);
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index df27c19..ca5923c 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -83,11 +83,6 @@
 /* Flags track per-device state like workarounds for quirks in older guests. */
 #define VIRTIO_PCI_FLAG_BUS_MASTER_BUG  (1 << 0)
 
-/* Performance improves when virtqueue kick processing is decoupled from the
- * vcpu thread using ioeventfd for some devices. */
-#define VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT 1
-#define VIRTIO_PCI_FLAG_USE_IOEVENTFD   (1 << VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT)
-
 /* QEMU doesn't strictly need write barriers since everything runs in
  * lock-step.  We'll leave the calls to wmb() in though to make it obvious for
  * KVM or if kqemu gets SMP support.
diff --git a/hw/virtio-pci.h b/hw/virtio-pci.h
index 14c10f7..f8404de 100644
--- a/hw/virtio-pci.h
+++ b/hw/virtio-pci.h
@@ -18,6 +18,11 @@
 #include "virtio-net.h"
 #include "virtio-serial.h"
 
+/* Performance improves when virtqueue kick processing is decoupled from the
+ * vcpu thread using ioeventfd for some devices. */
+#define VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT 1
+#define VIRTIO_PCI_FLAG_USE_IOEVENTFD   (1 << VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT)
+
 typedef struct {
     PCIDevice pci_dev;
     VirtIODevice *vdev;
diff --git a/hw/xen_disk.c b/hw/xen_disk.c
index 8a9fac4..286bbac 100644
--- a/hw/xen_disk.c
+++ b/hw/xen_disk.c
@@ -620,7 +620,7 @@
 static int blk_init(struct XenDevice *xendev)
 {
     struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
-    int index, qflags, have_barriers, info = 0;
+    int index, qflags, info = 0;
 
     /* read xenstore entries */
     if (blkdev->params == NULL) {
@@ -706,7 +706,6 @@
                       blkdev->bs->drv ? blkdev->bs->drv->format_name : "-");
         blkdev->file_size = 0;
     }
-    have_barriers = blkdev->bs->drv && blkdev->bs->drv->bdrv_flush ? 1 : 0;
 
     xen_be_printf(xendev, 1, "type \"%s\", fileproto \"%s\", filename \"%s\","
                   " size %" PRId64 " (%" PRId64 " MB)\n",
@@ -714,7 +713,7 @@
                   blkdev->file_size, blkdev->file_size >> 20);
 
     /* fill info */
-    xenstore_write_be_int(&blkdev->xendev, "feature-barrier", have_barriers);
+    xenstore_write_be_int(&blkdev->xendev, "feature-barrier", 1);
     xenstore_write_be_int(&blkdev->xendev, "info",            info);
     xenstore_write_be_int(&blkdev->xendev, "sector-size",     blkdev->file_blk);
     xenstore_write_be_int(&blkdev->xendev, "sectors",
diff --git a/iohandler.c b/iohandler.c
index 4cc1c5a..5640d49 100644
--- a/iohandler.c
+++ b/iohandler.c
@@ -26,6 +26,7 @@
 #include "qemu-common.h"
 #include "qemu-char.h"
 #include "qemu-queue.h"
+#include "main-loop.h"
 
 #ifndef _WIN32
 #include <sys/wait.h>
@@ -80,64 +81,12 @@
     return 0;
 }
 
-typedef struct IOTrampoline
-{
-    GIOChannel *chan;
-    IOHandler *fd_read;
-    IOHandler *fd_write;
-    void *opaque;
-    guint tag;
-} IOTrampoline;
-
-static gboolean fd_trampoline(GIOChannel *chan, GIOCondition cond, gpointer opaque)
-{
-    IOTrampoline *tramp = opaque;
-
-    if ((cond & G_IO_IN) && tramp->fd_read) {
-        tramp->fd_read(tramp->opaque);
-    }
-
-    if ((cond & G_IO_OUT) && tramp->fd_write) {
-        tramp->fd_write(tramp->opaque);
-    }
-
-    return TRUE;
-}
-
 int qemu_set_fd_handler(int fd,
                         IOHandler *fd_read,
                         IOHandler *fd_write,
                         void *opaque)
 {
-    static IOTrampoline fd_trampolines[FD_SETSIZE];
-    IOTrampoline *tramp = &fd_trampolines[fd];
-
-    if (tramp->tag != 0) {
-        g_io_channel_unref(tramp->chan);
-        g_source_remove(tramp->tag);
-        tramp->tag = 0;
-    }
-
-    if (fd_read || fd_write || opaque) {
-        GIOCondition cond = 0;
-
-        tramp->fd_read = fd_read;
-        tramp->fd_write = fd_write;
-        tramp->opaque = opaque;
-
-        if (fd_read) {
-            cond |= G_IO_IN | G_IO_ERR;
-        }
-
-        if (fd_write) {
-            cond |= G_IO_OUT | G_IO_ERR;
-        }
-
-        tramp->chan = g_io_channel_unix_new(fd);
-        tramp->tag = g_io_add_watch(tramp->chan, cond, fd_trampoline, tramp);
-    }
-
-    return 0;
+    return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque);
 }
 
 void qemu_iohandler_fill(int *pnfds, fd_set *readfds, fd_set *writefds, fd_set *xfds)
diff --git a/linux-user/main.c b/linux-user/main.c
index 186358b..e7dad54 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -3084,6 +3084,7 @@
 {
     printf("qemu-" TARGET_ARCH " version " QEMU_VERSION QEMU_PKGVERSION
            ", Copyright (c) 2003-2008 Fabrice Bellard\n");
+    exit(0);
 }
 
 struct qemu_argument {
@@ -3129,7 +3130,7 @@
     {"strace",     "QEMU_STRACE",      false, handle_arg_strace,
      "",           "log system calls"},
     {"version",    "QEMU_VERSION",     false, handle_arg_version,
-     "",           "log system calls"},
+     "",           "display version information and exit"},
     {NULL, NULL, false, NULL, NULL, NULL}
 };
 
@@ -3231,16 +3232,15 @@
 
         for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
             if (!strcmp(r, arginfo->argv)) {
-                if (optind >= argc) {
-                    usage();
-                }
-
-                arginfo->handle_opt(argv[optind]);
-
                 if (arginfo->has_arg) {
+                    if (optind >= argc) {
+                        usage();
+                    }
+                    arginfo->handle_opt(argv[optind]);
                     optind++;
+                } else {
+                    arginfo->handle_opt(NULL);
                 }
-
                 break;
             }
         }
@@ -3276,9 +3276,6 @@
     int i;
     int ret;
 
-    if (argc <= 1)
-        usage();
-
     qemu_cache_utils_init(envp);
 
     if ((envlist = envlist_create()) == NULL) {
diff --git a/main-loop.c b/main-loop.c
new file mode 100644
index 0000000..60e9748
--- /dev/null
+++ b/main-loop.c
@@ -0,0 +1,475 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 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.
+ */
+
+#include "qemu-common.h"
+#include "qemu-timer.h"
+#include "slirp/slirp.h"
+#include "main-loop.h"
+
+#ifndef _WIN32
+
+#include "compatfd.h"
+
+static int io_thread_fd = -1;
+
+void qemu_notify_event(void)
+{
+    /* Write 8 bytes to be compatible with eventfd.  */
+    static const uint64_t val = 1;
+    ssize_t ret;
+
+    if (io_thread_fd == -1) {
+        return;
+    }
+    do {
+        ret = write(io_thread_fd, &val, sizeof(val));
+    } while (ret < 0 && errno == EINTR);
+
+    /* EAGAIN is fine, a read must be pending.  */
+    if (ret < 0 && errno != EAGAIN) {
+        fprintf(stderr, "qemu_notify_event: write() failed: %s\n",
+                strerror(errno));
+        exit(1);
+    }
+}
+
+static void qemu_event_read(void *opaque)
+{
+    int fd = (intptr_t)opaque;
+    ssize_t len;
+    char buffer[512];
+
+    /* Drain the notify pipe.  For eventfd, only 8 bytes will be read.  */
+    do {
+        len = read(fd, buffer, sizeof(buffer));
+    } while ((len == -1 && errno == EINTR) || len == sizeof(buffer));
+}
+
+static int qemu_event_init(void)
+{
+    int err;
+    int fds[2];
+
+    err = qemu_eventfd(fds);
+    if (err == -1) {
+        return -errno;
+    }
+    err = fcntl_setfl(fds[0], O_NONBLOCK);
+    if (err < 0) {
+        goto fail;
+    }
+    err = fcntl_setfl(fds[1], O_NONBLOCK);
+    if (err < 0) {
+        goto fail;
+    }
+    qemu_set_fd_handler2(fds[0], NULL, qemu_event_read, NULL,
+                         (void *)(intptr_t)fds[0]);
+
+    io_thread_fd = fds[1];
+    return 0;
+
+fail:
+    close(fds[0]);
+    close(fds[1]);
+    return err;
+}
+
+/* If we have signalfd, we mask out the signals we want to handle and then
+ * use signalfd to listen for them.  We rely on whatever the current signal
+ * handler is to dispatch the signals when we receive them.
+ */
+static void sigfd_handler(void *opaque)
+{
+    int fd = (intptr_t)opaque;
+    struct qemu_signalfd_siginfo info;
+    struct sigaction action;
+    ssize_t len;
+
+    while (1) {
+        do {
+            len = read(fd, &info, sizeof(info));
+        } while (len == -1 && errno == EINTR);
+
+        if (len == -1 && errno == EAGAIN) {
+            break;
+        }
+
+        if (len != sizeof(info)) {
+            printf("read from sigfd returned %zd: %m\n", len);
+            return;
+        }
+
+        sigaction(info.ssi_signo, NULL, &action);
+        if ((action.sa_flags & SA_SIGINFO) && action.sa_sigaction) {
+            action.sa_sigaction(info.ssi_signo,
+                                (siginfo_t *)&info, NULL);
+        } else if (action.sa_handler) {
+            action.sa_handler(info.ssi_signo);
+        }
+    }
+}
+
+static int qemu_signal_init(void)
+{
+    int sigfd;
+    sigset_t set;
+
+    /*
+     * SIG_IPI must be blocked in the main thread and must not be caught
+     * by sigwait() in the signal thread. Otherwise, the cpu thread will
+     * not catch it reliably.
+     */
+    sigemptyset(&set);
+    sigaddset(&set, SIG_IPI);
+    pthread_sigmask(SIG_BLOCK, &set, NULL);
+
+    sigemptyset(&set);
+    sigaddset(&set, SIGIO);
+    sigaddset(&set, SIGALRM);
+    sigaddset(&set, SIGBUS);
+    pthread_sigmask(SIG_BLOCK, &set, NULL);
+
+    sigfd = qemu_signalfd(&set);
+    if (sigfd == -1) {
+        fprintf(stderr, "failed to create signalfd\n");
+        return -errno;
+    }
+
+    fcntl_setfl(sigfd, O_NONBLOCK);
+
+    qemu_set_fd_handler2(sigfd, NULL, sigfd_handler, NULL,
+                         (void *)(intptr_t)sigfd);
+
+    return 0;
+}
+
+#else /* _WIN32 */
+
+HANDLE qemu_event_handle;
+
+static void dummy_event_handler(void *opaque)
+{
+}
+
+static int qemu_event_init(void)
+{
+    qemu_event_handle = CreateEvent(NULL, FALSE, FALSE, NULL);
+    if (!qemu_event_handle) {
+        fprintf(stderr, "Failed CreateEvent: %ld\n", GetLastError());
+        return -1;
+    }
+    qemu_add_wait_object(qemu_event_handle, dummy_event_handler, NULL);
+    return 0;
+}
+
+void qemu_notify_event(void)
+{
+    if (!SetEvent(qemu_event_handle)) {
+        fprintf(stderr, "qemu_notify_event: SetEvent failed: %ld\n",
+                GetLastError());
+        exit(1);
+    }
+}
+
+static int qemu_signal_init(void)
+{
+    return 0;
+}
+#endif
+
+int qemu_init_main_loop(void)
+{
+    int ret;
+
+    qemu_mutex_lock_iothread();
+    ret = qemu_signal_init();
+    if (ret) {
+        return ret;
+    }
+
+    /* Note eventfd must be drained before signalfd handlers run */
+    ret = qemu_event_init();
+    if (ret) {
+        return ret;
+    }
+
+    return 0;
+}
+
+
+static GPollFD poll_fds[1024 * 2]; /* this is probably overkill */
+static int n_poll_fds;
+static int max_priority;
+
+static void glib_select_fill(int *max_fd, fd_set *rfds, fd_set *wfds,
+                             fd_set *xfds, struct timeval *tv)
+{
+    GMainContext *context = g_main_context_default();
+    int i;
+    int timeout = 0, cur_timeout;
+
+    g_main_context_prepare(context, &max_priority);
+
+    n_poll_fds = g_main_context_query(context, max_priority, &timeout,
+                                      poll_fds, ARRAY_SIZE(poll_fds));
+    g_assert(n_poll_fds <= ARRAY_SIZE(poll_fds));
+
+    for (i = 0; i < n_poll_fds; i++) {
+        GPollFD *p = &poll_fds[i];
+
+        if ((p->events & G_IO_IN)) {
+            FD_SET(p->fd, rfds);
+            *max_fd = MAX(*max_fd, p->fd);
+        }
+        if ((p->events & G_IO_OUT)) {
+            FD_SET(p->fd, wfds);
+            *max_fd = MAX(*max_fd, p->fd);
+        }
+        if ((p->events & G_IO_ERR)) {
+            FD_SET(p->fd, xfds);
+            *max_fd = MAX(*max_fd, p->fd);
+        }
+    }
+
+    cur_timeout = (tv->tv_sec * 1000) + ((tv->tv_usec + 500) / 1000);
+    if (timeout >= 0 && timeout < cur_timeout) {
+        tv->tv_sec = timeout / 1000;
+        tv->tv_usec = (timeout % 1000) * 1000;
+    }
+}
+
+static void glib_select_poll(fd_set *rfds, fd_set *wfds, fd_set *xfds,
+                             bool err)
+{
+    GMainContext *context = g_main_context_default();
+
+    if (!err) {
+        int i;
+
+        for (i = 0; i < n_poll_fds; i++) {
+            GPollFD *p = &poll_fds[i];
+
+            if ((p->events & G_IO_IN) && FD_ISSET(p->fd, rfds)) {
+                p->revents |= G_IO_IN;
+            }
+            if ((p->events & G_IO_OUT) && FD_ISSET(p->fd, wfds)) {
+                p->revents |= G_IO_OUT;
+            }
+            if ((p->events & G_IO_ERR) && FD_ISSET(p->fd, xfds)) {
+                p->revents |= G_IO_ERR;
+            }
+        }
+    }
+
+    if (g_main_context_check(context, max_priority, poll_fds, n_poll_fds)) {
+        g_main_context_dispatch(context);
+    }
+}
+
+#ifdef _WIN32
+/***********************************************************/
+/* Polling handling */
+
+typedef struct PollingEntry {
+    PollingFunc *func;
+    void *opaque;
+    struct PollingEntry *next;
+} PollingEntry;
+
+static PollingEntry *first_polling_entry;
+
+int qemu_add_polling_cb(PollingFunc *func, void *opaque)
+{
+    PollingEntry **ppe, *pe;
+    pe = g_malloc0(sizeof(PollingEntry));
+    pe->func = func;
+    pe->opaque = opaque;
+    for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next);
+    *ppe = pe;
+    return 0;
+}
+
+void qemu_del_polling_cb(PollingFunc *func, void *opaque)
+{
+    PollingEntry **ppe, *pe;
+    for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next) {
+        pe = *ppe;
+        if (pe->func == func && pe->opaque == opaque) {
+            *ppe = pe->next;
+            g_free(pe);
+            break;
+        }
+    }
+}
+
+/***********************************************************/
+/* Wait objects support */
+typedef struct WaitObjects {
+    int num;
+    HANDLE events[MAXIMUM_WAIT_OBJECTS + 1];
+    WaitObjectFunc *func[MAXIMUM_WAIT_OBJECTS + 1];
+    void *opaque[MAXIMUM_WAIT_OBJECTS + 1];
+} WaitObjects;
+
+static WaitObjects wait_objects = {0};
+
+int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
+{
+    WaitObjects *w = &wait_objects;
+    if (w->num >= MAXIMUM_WAIT_OBJECTS) {
+        return -1;
+    }
+    w->events[w->num] = handle;
+    w->func[w->num] = func;
+    w->opaque[w->num] = opaque;
+    w->num++;
+    return 0;
+}
+
+void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
+{
+    int i, found;
+    WaitObjects *w = &wait_objects;
+
+    found = 0;
+    for (i = 0; i < w->num; i++) {
+        if (w->events[i] == handle) {
+            found = 1;
+        }
+        if (found) {
+            w->events[i] = w->events[i + 1];
+            w->func[i] = w->func[i + 1];
+            w->opaque[i] = w->opaque[i + 1];
+        }
+    }
+    if (found) {
+        w->num--;
+    }
+}
+
+static void os_host_main_loop_wait(int *timeout)
+{
+    int ret, ret2, i;
+    PollingEntry *pe;
+
+    /* XXX: need to suppress polling by better using win32 events */
+    ret = 0;
+    for (pe = first_polling_entry; pe != NULL; pe = pe->next) {
+        ret |= pe->func(pe->opaque);
+    }
+    if (ret == 0) {
+        int err;
+        WaitObjects *w = &wait_objects;
+
+        qemu_mutex_unlock_iothread();
+        ret = WaitForMultipleObjects(w->num, w->events, FALSE, *timeout);
+        qemu_mutex_lock_iothread();
+        if (WAIT_OBJECT_0 + 0 <= ret && ret <= WAIT_OBJECT_0 + w->num - 1) {
+            if (w->func[ret - WAIT_OBJECT_0]) {
+                w->func[ret - WAIT_OBJECT_0](w->opaque[ret - WAIT_OBJECT_0]);
+            }
+
+            /* Check for additional signaled events */
+            for (i = (ret - WAIT_OBJECT_0 + 1); i < w->num; i++) {
+                /* Check if event is signaled */
+                ret2 = WaitForSingleObject(w->events[i], 0);
+                if (ret2 == WAIT_OBJECT_0) {
+                    if (w->func[i]) {
+                        w->func[i](w->opaque[i]);
+                    }
+                } else if (ret2 != WAIT_TIMEOUT) {
+                    err = GetLastError();
+                    fprintf(stderr, "WaitForSingleObject error %d %d\n", i, err);
+                }
+            }
+        } else if (ret != WAIT_TIMEOUT) {
+            err = GetLastError();
+            fprintf(stderr, "WaitForMultipleObjects error %d %d\n", ret, err);
+        }
+    }
+
+    *timeout = 0;
+}
+#else
+static inline void os_host_main_loop_wait(int *timeout)
+{
+}
+#endif
+
+int main_loop_wait(int nonblocking)
+{
+    fd_set rfds, wfds, xfds;
+    int ret, nfds;
+    struct timeval tv;
+    int timeout;
+
+    if (nonblocking) {
+        timeout = 0;
+    } else {
+        timeout = qemu_calculate_timeout();
+        qemu_bh_update_timeout(&timeout);
+    }
+
+    os_host_main_loop_wait(&timeout);
+
+    tv.tv_sec = timeout / 1000;
+    tv.tv_usec = (timeout % 1000) * 1000;
+
+    /* poll any events */
+    /* XXX: separate device handlers from system ones */
+    nfds = -1;
+    FD_ZERO(&rfds);
+    FD_ZERO(&wfds);
+    FD_ZERO(&xfds);
+
+#ifdef CONFIG_SLIRP
+    slirp_select_fill(&nfds, &rfds, &wfds, &xfds);
+#endif
+    qemu_iohandler_fill(&nfds, &rfds, &wfds, &xfds);
+    glib_select_fill(&nfds, &rfds, &wfds, &xfds, &tv);
+
+    if (timeout > 0) {
+        qemu_mutex_unlock_iothread();
+    }
+
+    ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv);
+
+    if (timeout > 0) {
+        qemu_mutex_lock_iothread();
+    }
+
+    glib_select_poll(&rfds, &wfds, &xfds, (ret < 0));
+    qemu_iohandler_poll(&rfds, &wfds, &xfds, ret);
+#ifdef CONFIG_SLIRP
+    slirp_select_poll(&rfds, &wfds, &xfds, (ret < 0));
+#endif
+
+    qemu_run_all_timers();
+
+    /* Check bottom-halves last in case any of the earlier events triggered
+       them.  */
+    qemu_bh_poll();
+
+    return ret;
+}
diff --git a/main-loop.h b/main-loop.h
new file mode 100644
index 0000000..8a716b1
--- /dev/null
+++ b/main-loop.h
@@ -0,0 +1,351 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 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.
+ */
+
+#ifndef QEMU_MAIN_LOOP_H
+#define QEMU_MAIN_LOOP_H 1
+
+#ifdef SIGRTMIN
+#define SIG_IPI (SIGRTMIN+4)
+#else
+#define SIG_IPI SIGUSR1
+#endif
+
+/**
+ * qemu_init_main_loop: Set up the process so that it can run the main loop.
+ *
+ * This includes setting up signal handlers.  It should be called before
+ * any other threads are created.  In addition, threads other than the
+ * main one should block signals that are trapped by the main loop.
+ * For simplicity, you can consider these signals to be safe: SIGUSR1,
+ * SIGUSR2, thread signals (SIGFPE, SIGILL, SIGSEGV, SIGBUS) and real-time
+ * signals if available.  Remember that Windows in practice does not have
+ * signals, though.
+ */
+int qemu_init_main_loop(void);
+
+/**
+ * main_loop_wait: Run one iteration of the main loop.
+ *
+ * If @nonblocking is true, poll for events, otherwise suspend until
+ * one actually occurs.  The main loop usually consists of a loop that
+ * repeatedly calls main_loop_wait(false).
+ *
+ * Main loop services include file descriptor callbacks, bottom halves
+ * and timers (defined in qemu-timer.h).  Bottom halves are similar to timers
+ * that execute immediately, but have a lower overhead and scheduling them
+ * is wait-free, thread-safe and signal-safe.
+ *
+ * It is sometimes useful to put a whole program in a coroutine.  In this
+ * case, the coroutine actually should be started from within the main loop,
+ * so that the main loop can run whenever the coroutine yields.  To do this,
+ * you can use a bottom half to enter the coroutine as soon as the main loop
+ * starts:
+ *
+ *     void enter_co_bh(void *opaque) {
+ *         QEMUCoroutine *co = opaque;
+ *         qemu_coroutine_enter(co, NULL);
+ *     }
+ *
+ *     ...
+ *     QEMUCoroutine *co = qemu_coroutine_create(coroutine_entry);
+ *     QEMUBH *start_bh = qemu_bh_new(enter_co_bh, co);
+ *     qemu_bh_schedule(start_bh);
+ *     while (...) {
+ *         main_loop_wait(false);
+ *     }
+ *
+ * (In the future we may provide a wrapper for this).
+ *
+ * @nonblocking: Whether the caller should block until an event occurs.
+ */
+int main_loop_wait(int nonblocking);
+
+/**
+ * qemu_notify_event: Force processing of pending events.
+ *
+ * Similar to signaling a condition variable, qemu_notify_event forces
+ * main_loop_wait to look at pending events and exit.  The caller of
+ * main_loop_wait will usually call it again very soon, so qemu_notify_event
+ * also has the side effect of recalculating the sets of file descriptors
+ * that the main loop waits for.
+ *
+ * Calling qemu_notify_event is rarely necessary, because main loop
+ * services (bottom halves and timers) call it themselves.  One notable
+ * exception occurs when using qemu_set_fd_handler2 (see below).
+ */
+void qemu_notify_event(void);
+
+#ifdef _WIN32
+/* return TRUE if no sleep should be done afterwards */
+typedef int PollingFunc(void *opaque);
+
+/**
+ * qemu_add_polling_cb: Register a Windows-specific polling callback
+ *
+ * Currently, under Windows some events are polled rather than waited for.
+ * Polling callbacks do not ensure that @func is called timely, because
+ * the main loop might wait for an arbitrarily long time.  If possible,
+ * you should instead create a separate thread that does a blocking poll
+ * and set a Win32 event object.  The event can then be passed to
+ * qemu_add_wait_object.
+ *
+ * Polling callbacks really have nothing Windows specific in them, but
+ * as they are a hack and are currenly not necessary under POSIX systems,
+ * they are only available when QEMU is running under Windows.
+ *
+ * @func: The function that does the polling, and returns 1 to force
+ * immediate completion of main_loop_wait.
+ * @opaque: A pointer-size value that is passed to @func.
+ */
+int qemu_add_polling_cb(PollingFunc *func, void *opaque);
+
+/**
+ * qemu_del_polling_cb: Unregister a Windows-specific polling callback
+ *
+ * This function removes a callback that was registered with
+ * qemu_add_polling_cb.
+ *
+ * @func: The function that was passed to qemu_add_polling_cb.
+ * @opaque: A pointer-size value that was passed to qemu_add_polling_cb.
+ */
+void qemu_del_polling_cb(PollingFunc *func, void *opaque);
+
+/* Wait objects handling */
+typedef void WaitObjectFunc(void *opaque);
+
+/**
+ * qemu_add_wait_object: Register a callback for a Windows handle
+ *
+ * Under Windows, the iohandler mechanism can only be used with sockets.
+ * QEMU must use the WaitForMultipleObjects API to wait on other handles.
+ * This function registers a #HANDLE with QEMU, so that it will be included
+ * in the main loop's calls to WaitForMultipleObjects.  When the handle
+ * is in a signaled state, QEMU will call @func.
+ *
+ * @handle: The Windows handle to be observed.
+ * @func: A function to be called when @handle is in a signaled state.
+ * @opaque: A pointer-size value that is passed to @func.
+ */
+int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque);
+
+/**
+ * qemu_del_wait_object: Unregister a callback for a Windows handle
+ *
+ * This function removes a callback that was registered with
+ * qemu_add_wait_object.
+ *
+ * @func: The function that was passed to qemu_add_wait_object.
+ * @opaque: A pointer-size value that was passed to qemu_add_wait_object.
+ */
+void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque);
+#endif
+
+/* async I/O support */
+
+typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size);
+typedef int IOCanReadHandler(void *opaque);
+typedef void IOHandler(void *opaque);
+
+/**
+ * qemu_set_fd_handler2: Register a file descriptor with the main loop
+ *
+ * This function tells the main loop to wake up whenever one of the
+ * following conditions is true:
+ *
+ * 1) if @fd_write is not %NULL, when the file descriptor is writable;
+ *
+ * 2) if @fd_read is not %NULL, when the file descriptor is readable.
+ *
+ * @fd_read_poll can be used to disable the @fd_read callback temporarily.
+ * This is useful to avoid calling qemu_set_fd_handler2 every time the
+ * client becomes interested in reading (or dually, stops being interested).
+ * A typical example is when @fd is a listening socket and you want to bound
+ * the number of active clients.  Remember to call qemu_notify_event whenever
+ * the condition may change from %false to %true.
+ *
+ * The callbacks that are set up by qemu_set_fd_handler2 are level-triggered.
+ * If @fd_read does not read from @fd, or @fd_write does not write to @fd
+ * until its buffers are full, they will be called again on the next
+ * iteration.
+ *
+ * @fd: The file descriptor to be observed.  Under Windows it must be
+ * a #SOCKET.
+ *
+ * @fd_read_poll: A function that returns 1 if the @fd_read callback
+ * should be fired.  If the function returns 0, the main loop will not
+ * end its iteration even if @fd becomes readable.
+ *
+ * @fd_read: A level-triggered callback that is fired if @fd is readable
+ * at the beginning of a main loop iteration, or if it becomes readable
+ * during one.
+ *
+ * @fd_write: A level-triggered callback that is fired when @fd is writable
+ * at the beginning of a main loop iteration, or if it becomes writable
+ * during one.
+ *
+ * @opaque: A pointer-sized value that is passed to @fd_read_poll,
+ * @fd_read and @fd_write.
+ */
+int qemu_set_fd_handler2(int fd,
+                         IOCanReadHandler *fd_read_poll,
+                         IOHandler *fd_read,
+                         IOHandler *fd_write,
+                         void *opaque);
+
+/**
+ * qemu_set_fd_handler: Register a file descriptor with the main loop
+ *
+ * This function tells the main loop to wake up whenever one of the
+ * following conditions is true:
+ *
+ * 1) if @fd_write is not %NULL, when the file descriptor is writable;
+ *
+ * 2) if @fd_read is not %NULL, when the file descriptor is readable.
+ *
+ * The callbacks that are set up by qemu_set_fd_handler are level-triggered.
+ * If @fd_read does not read from @fd, or @fd_write does not write to @fd
+ * until its buffers are full, they will be called again on the next
+ * iteration.
+ *
+ * @fd: The file descriptor to be observed.  Under Windows it must be
+ * a #SOCKET.
+ *
+ * @fd_read: A level-triggered callback that is fired if @fd is readable
+ * at the beginning of a main loop iteration, or if it becomes readable
+ * during one.
+ *
+ * @fd_write: A level-triggered callback that is fired when @fd is writable
+ * at the beginning of a main loop iteration, or if it becomes writable
+ * during one.
+ *
+ * @opaque: A pointer-sized value that is passed to @fd_read and @fd_write.
+ */
+int qemu_set_fd_handler(int fd,
+                        IOHandler *fd_read,
+                        IOHandler *fd_write,
+                        void *opaque);
+
+typedef struct QEMUBH QEMUBH;
+typedef void QEMUBHFunc(void *opaque);
+
+/**
+ * qemu_bh_new: Allocate a new bottom half structure.
+ *
+ * Bottom halves are lightweight callbacks whose invocation is guaranteed
+ * to be wait-free, thread-safe and signal-safe.  The #QEMUBH structure
+ * is opaque and must be allocated prior to its use.
+ */
+QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque);
+
+/**
+ * qemu_bh_schedule: Schedule a bottom half.
+ *
+ * Scheduling a bottom half interrupts the main loop and causes the
+ * execution of the callback that was passed to qemu_bh_new.
+ *
+ * Bottom halves that are scheduled from a bottom half handler are instantly
+ * invoked.  This can create an infinite loop if a bottom half handler
+ * schedules itself.
+ *
+ * @bh: The bottom half to be scheduled.
+ */
+void qemu_bh_schedule(QEMUBH *bh);
+
+/**
+ * qemu_bh_cancel: Cancel execution of a bottom half.
+ *
+ * Canceling execution of a bottom half undoes the effect of calls to
+ * qemu_bh_schedule without freeing its resources yet.  While cancellation
+ * itself is also wait-free and thread-safe, it can of course race with the
+ * loop that executes bottom halves unless you are holding the iothread
+ * mutex.  This makes it mostly useless if you are not holding the mutex.
+ *
+ * @bh: The bottom half to be canceled.
+ */
+void qemu_bh_cancel(QEMUBH *bh);
+
+/**
+ *qemu_bh_delete: Cancel execution of a bottom half and free its resources.
+ *
+ * Deleting a bottom half frees the memory that was allocated for it by
+ * qemu_bh_new.  It also implies canceling the bottom half if it was
+ * scheduled.
+ *
+ * @bh: The bottom half to be deleted.
+ */
+void qemu_bh_delete(QEMUBH *bh);
+
+#ifdef CONFIG_POSIX
+/**
+ * qemu_add_child_watch: Register a child process for reaping.
+ *
+ * Under POSIX systems, a parent process must read the exit status of
+ * its child processes using waitpid, or the operating system will not
+ * free some of the resources attached to that process.
+ *
+ * This function directs the QEMU main loop to observe a child process
+ * and call waitpid as soon as it exits; the watch is then removed
+ * automatically.  It is useful whenever QEMU forks a child process
+ * but will find out about its termination by other means such as a
+ * "broken pipe".
+ *
+ * @pid: The pid that QEMU should observe.
+ */
+int qemu_add_child_watch(pid_t pid);
+#endif
+
+/**
+ * qemu_mutex_lock_iothread: Lock the main loop mutex.
+ *
+ * This function locks the main loop mutex.  The mutex is taken by
+ * qemu_init_main_loop and always taken except while waiting on
+ * external events (such as with select).  The mutex should be taken
+ * by threads other than the main loop thread when calling
+ * qemu_bh_new(), qemu_set_fd_handler() and basically all other
+ * functions documented in this file.
+ */
+void qemu_mutex_lock_iothread(void);
+
+/**
+ * qemu_mutex_unlock_iothread: Unlock the main loop mutex.
+ *
+ * This function unlocks the main loop mutex.  The mutex is taken by
+ * qemu_init_main_loop and always taken except while waiting on
+ * external events (such as with select).  The mutex should be unlocked
+ * as soon as possible by threads other than the main loop thread,
+ * because it prevents the main loop from processing callbacks,
+ * including timers and bottom halves.
+ */
+void qemu_mutex_unlock_iothread(void);
+
+/* internal interfaces */
+
+void qemu_iohandler_fill(int *pnfds, fd_set *readfds, fd_set *writefds, fd_set *xfds);
+void qemu_iohandler_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds, int rc);
+
+void qemu_bh_schedule_idle(QEMUBH *bh);
+int qemu_bh_poll(void);
+void qemu_bh_update_timeout(int *timeout);
+
+#endif
diff --git a/migration-exec.c b/migration-exec.c
index 2cfb6f2..b7b1055 100644
--- a/migration-exec.c
+++ b/migration-exec.c
@@ -32,17 +32,17 @@
     do { } while (0)
 #endif
 
-static int file_errno(FdMigrationState *s)
+static int file_errno(MigrationState *s)
 {
     return errno;
 }
 
-static int file_write(FdMigrationState *s, const void * buf, size_t size)
+static int file_write(MigrationState *s, const void * buf, size_t size)
 {
     return write(s->fd, buf, size);
 }
 
-static int exec_close(FdMigrationState *s)
+static int exec_close(MigrationState *s)
 {
     int ret = 0;
     DPRINTF("exec_close\n");
@@ -61,22 +61,14 @@
     return ret;
 }
 
-MigrationState *exec_start_outgoing_migration(Monitor *mon,
-                                              const char *command,
-					      int64_t bandwidth_limit,
-					      int detach,
-					      int blk,
-					      int inc)
+int exec_start_outgoing_migration(MigrationState *s, const char *command)
 {
-    FdMigrationState *s;
     FILE *f;
 
-    s = g_malloc0(sizeof(*s));
-
     f = popen(command, "w");
     if (f == NULL) {
         DPRINTF("Unable to popen exec target\n");
-        goto err_after_alloc;
+        goto err_after_popen;
     }
 
     s->fd = fileno(f);
@@ -92,29 +84,14 @@
     s->close = exec_close;
     s->get_error = file_errno;
     s->write = file_write;
-    s->mig_state.cancel = migrate_fd_cancel;
-    s->mig_state.get_status = migrate_fd_get_status;
-    s->mig_state.release = migrate_fd_release;
-
-    s->mig_state.blk = blk;
-    s->mig_state.shared = inc;
-
-    s->state = MIG_STATE_ACTIVE;
-    s->mon = NULL;
-    s->bandwidth_limit = bandwidth_limit;
-
-    if (!detach) {
-        migrate_fd_monitor_suspend(s, mon);
-    }
 
     migrate_fd_connect(s);
-    return &s->mig_state;
+    return 0;
 
 err_after_open:
     pclose(f);
-err_after_alloc:
-    g_free(s);
-    return NULL;
+err_after_popen:
+    return -1;
 }
 
 static void exec_accept_incoming_migration(void *opaque)
diff --git a/migration-fd.c b/migration-fd.c
index aee690a..d0aec89 100644
--- a/migration-fd.c
+++ b/migration-fd.c
@@ -30,17 +30,17 @@
     do { } while (0)
 #endif
 
-static int fd_errno(FdMigrationState *s)
+static int fd_errno(MigrationState *s)
 {
     return errno;
 }
 
-static int fd_write(FdMigrationState *s, const void * buf, size_t size)
+static int fd_write(MigrationState *s, const void * buf, size_t size)
 {
     return write(s->fd, buf, size);
 }
 
-static int fd_close(FdMigrationState *s)
+static int fd_close(MigrationState *s)
 {
     DPRINTF("fd_close\n");
     if (s->fd != -1) {
@@ -50,21 +50,12 @@
     return 0;
 }
 
-MigrationState *fd_start_outgoing_migration(Monitor *mon,
-					    const char *fdname,
-					    int64_t bandwidth_limit,
-					    int detach,
-					    int blk,
-					    int inc)
+int fd_start_outgoing_migration(MigrationState *s, const char *fdname)
 {
-    FdMigrationState *s;
-
-    s = g_malloc0(sizeof(*s));
-
-    s->fd = monitor_get_fd(mon, fdname);
+    s->fd = monitor_get_fd(s->mon, fdname);
     if (s->fd == -1) {
         DPRINTF("fd_migration: invalid file descriptor identifier\n");
-        goto err_after_alloc;
+        goto err_after_get_fd;
     }
 
     if (fcntl(s->fd, F_SETFL, O_NONBLOCK) == -1) {
@@ -75,29 +66,14 @@
     s->get_error = fd_errno;
     s->write = fd_write;
     s->close = fd_close;
-    s->mig_state.cancel = migrate_fd_cancel;
-    s->mig_state.get_status = migrate_fd_get_status;
-    s->mig_state.release = migrate_fd_release;
-
-    s->mig_state.blk = blk;
-    s->mig_state.shared = inc;
-
-    s->state = MIG_STATE_ACTIVE;
-    s->mon = NULL;
-    s->bandwidth_limit = bandwidth_limit;
-
-    if (!detach) {
-        migrate_fd_monitor_suspend(s, mon);
-    }
 
     migrate_fd_connect(s);
-    return &s->mig_state;
+    return 0;
 
 err_after_open:
     close(s->fd);
-err_after_alloc:
-    g_free(s);
-    return NULL;
+err_after_get_fd:
+    return -1;
 }
 
 static void fd_accept_incoming_migration(void *opaque)
diff --git a/migration-tcp.c b/migration-tcp.c
index c431e03..5aa742c 100644
--- a/migration-tcp.c
+++ b/migration-tcp.c
@@ -28,17 +28,17 @@
     do { } while (0)
 #endif
 
-static int socket_errno(FdMigrationState *s)
+static int socket_errno(MigrationState *s)
 {
     return socket_error();
 }
 
-static int socket_write(FdMigrationState *s, const void * buf, size_t size)
+static int socket_write(MigrationState *s, const void * buf, size_t size)
 {
     return send(s->fd, buf, size, 0);
 }
 
-static int tcp_close(FdMigrationState *s)
+static int tcp_close(MigrationState *s)
 {
     DPRINTF("tcp_close\n");
     if (s->fd != -1) {
@@ -48,17 +48,16 @@
     return 0;
 }
 
-
 static void tcp_wait_for_connect(void *opaque)
 {
-    FdMigrationState *s = opaque;
+    MigrationState *s = opaque;
     int val, ret;
     socklen_t valsize = sizeof(val);
 
     DPRINTF("connect completed\n");
     do {
         ret = getsockopt(s->fd, SOL_SOCKET, SO_ERROR, (void *) &val, &valsize);
-    } while (ret == -1 && (s->get_error(s)) == EINTR);
+    } while (ret == -1 && (socket_error()) == EINTR);
 
     if (ret < 0) {
         migrate_fd_error(s);
@@ -75,63 +74,46 @@
     }
 }
 
-MigrationState *tcp_start_outgoing_migration(Monitor *mon,
-                                             const char *host_port,
-                                             int64_t bandwidth_limit,
-                                             int detach,
-					     int blk,
-					     int inc)
+int tcp_start_outgoing_migration(MigrationState *s, const char *host_port)
 {
     struct sockaddr_in addr;
-    FdMigrationState *s;
     int ret;
 
-    if (parse_host_port(&addr, host_port) < 0)
-        return NULL;
-
-    s = g_malloc0(sizeof(*s));
+    ret = parse_host_port(&addr, host_port);
+    if (ret < 0) {
+        return ret;
+    }
 
     s->get_error = socket_errno;
     s->write = socket_write;
     s->close = tcp_close;
-    s->mig_state.cancel = migrate_fd_cancel;
-    s->mig_state.get_status = migrate_fd_get_status;
-    s->mig_state.release = migrate_fd_release;
 
-    s->mig_state.blk = blk;
-    s->mig_state.shared = inc;
-
-    s->state = MIG_STATE_ACTIVE;
-    s->mon = NULL;
-    s->bandwidth_limit = bandwidth_limit;
     s->fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
     if (s->fd == -1) {
-        g_free(s);
-        return NULL;
+        DPRINTF("Unable to open socket");
+        return -socket_error();
     }
 
     socket_set_nonblock(s->fd);
 
-    if (!detach) {
-        migrate_fd_monitor_suspend(s, mon);
-    }
-
     do {
         ret = connect(s->fd, (struct sockaddr *)&addr, sizeof(addr));
-        if (ret == -1)
-            ret = -(s->get_error(s));
-
-        if (ret == -EINPROGRESS || ret == -EWOULDBLOCK)
+        if (ret == -1) {
+            ret = -socket_error();
+        }
+        if (ret == -EINPROGRESS || ret == -EWOULDBLOCK) {
             qemu_set_fd_handler2(s->fd, NULL, NULL, tcp_wait_for_connect, s);
+            return 0;
+        }
     } while (ret == -EINTR);
 
-    if (ret < 0 && ret != -EINPROGRESS && ret != -EWOULDBLOCK) {
+    if (ret < 0) {
         DPRINTF("connect failed\n");
         migrate_fd_error(s);
-    } else if (ret >= 0)
-        migrate_fd_connect(s);
-
-    return &s->mig_state;
+        return ret;
+    }
+    migrate_fd_connect(s);
+    return 0;
 }
 
 static void tcp_accept_incoming_migration(void *opaque)
@@ -174,23 +156,27 @@
     int val;
     int s;
 
+    DPRINTF("Attempting to start an incoming migration\n");
+
     if (parse_host_port(&addr, host_port) < 0) {
         fprintf(stderr, "invalid host/port combination: %s\n", host_port);
         return -EINVAL;
     }
 
     s = qemu_socket(PF_INET, SOCK_STREAM, 0);
-    if (s == -1)
+    if (s == -1) {
         return -socket_error();
+    }
 
     val = 1;
     setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
 
-    if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1)
+    if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
         goto err;
-
-    if (listen(s, 1) == -1)
+    }
+    if (listen(s, 1) == -1) {
         goto err;
+    }
 
     qemu_set_fd_handler2(s, NULL, tcp_accept_incoming_migration, NULL,
                          (void *)(intptr_t)s);
diff --git a/migration-unix.c b/migration-unix.c
index 6dc985d..8596353 100644
--- a/migration-unix.c
+++ b/migration-unix.c
@@ -28,17 +28,17 @@
     do { } while (0)
 #endif
 
-static int unix_errno(FdMigrationState *s)
+static int unix_errno(MigrationState *s)
 {
     return errno;
 }
 
-static int unix_write(FdMigrationState *s, const void * buf, size_t size)
+static int unix_write(MigrationState *s, const void * buf, size_t size)
 {
     return write(s->fd, buf, size);
 }
 
-static int unix_close(FdMigrationState *s)
+static int unix_close(MigrationState *s)
 {
     DPRINTF("unix_close\n");
     if (s->fd != -1) {
@@ -50,14 +50,14 @@
 
 static void unix_wait_for_connect(void *opaque)
 {
-    FdMigrationState *s = opaque;
+    MigrationState *s = opaque;
     int val, ret;
     socklen_t valsize = sizeof(val);
 
     DPRINTF("connect completed\n");
     do {
         ret = getsockopt(s->fd, SOL_SOCKET, SO_ERROR, (void *) &val, &valsize);
-    } while (ret == -1 && (s->get_error(s)) == EINTR);
+    } while (ret == -1 && errno == EINTR);
 
     if (ret < 0) {
         migrate_fd_error(s);
@@ -74,72 +74,43 @@
     }
 }
 
-MigrationState *unix_start_outgoing_migration(Monitor *mon,
-                                              const char *path,
-					      int64_t bandwidth_limit,
-					      int detach,
-					      int blk,
-					      int inc)
+int unix_start_outgoing_migration(MigrationState *s, const char *path)
 {
-    FdMigrationState *s;
     struct sockaddr_un addr;
     int ret;
 
     addr.sun_family = AF_UNIX;
     snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", path);
-
-    s = g_malloc0(sizeof(*s));
-
     s->get_error = unix_errno;
     s->write = unix_write;
     s->close = unix_close;
-    s->mig_state.cancel = migrate_fd_cancel;
-    s->mig_state.get_status = migrate_fd_get_status;
-    s->mig_state.release = migrate_fd_release;
 
-    s->mig_state.blk = blk;
-    s->mig_state.shared = inc;
-
-    s->state = MIG_STATE_ACTIVE;
-    s->mon = NULL;
-    s->bandwidth_limit = bandwidth_limit;
     s->fd = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
-    if (s->fd < 0) {
+    if (s->fd == -1) {
         DPRINTF("Unable to open socket");
-        goto err_after_alloc;
+        return -errno;
     }
 
     socket_set_nonblock(s->fd);
 
     do {
         ret = connect(s->fd, (struct sockaddr *)&addr, sizeof(addr));
-        if (ret == -1)
-	    ret = -(s->get_error(s));
-
-        if (ret == -EINPROGRESS || ret == -EWOULDBLOCK)
+        if (ret == -1) {
+            ret = -errno;
+        }
+        if (ret == -EINPROGRESS || ret == -EWOULDBLOCK) {
 	    qemu_set_fd_handler2(s->fd, NULL, NULL, unix_wait_for_connect, s);
+            return 0;
+        }
     } while (ret == -EINTR);
 
-    if (ret < 0 && ret != -EINPROGRESS && ret != -EWOULDBLOCK) {
+    if (ret < 0) {
         DPRINTF("connect failed\n");
-        goto err_after_open;
+        migrate_fd_error(s);
+        return ret;
     }
-
-    if (!detach) {
-        migrate_fd_monitor_suspend(s, mon);
-    }
-
-    if (ret >= 0)
-        migrate_fd_connect(s);
-
-    return &s->mig_state;
-
-err_after_open:
-    close(s->fd);
-
-err_after_alloc:
-    g_free(s);
-    return NULL;
+    migrate_fd_connect(s);
+    return 0;
 }
 
 static void unix_accept_incoming_migration(void *opaque)
@@ -152,13 +123,13 @@
 
     do {
         c = qemu_accept(s, (struct sockaddr *)&addr, &addrlen);
-    } while (c == -1 && socket_error() == EINTR);
+    } while (c == -1 && errno == EINTR);
 
     DPRINTF("accepted migration\n");
 
     if (c == -1) {
         fprintf(stderr, "could not accept migration connection\n");
-        return;
+        goto out2;
     }
 
     f = qemu_fopen_socket(c);
@@ -170,45 +141,49 @@
     process_incoming_migration(f);
     qemu_fclose(f);
 out:
+    close(c);
+out2:
     qemu_set_fd_handler2(s, NULL, NULL, NULL, NULL);
     close(s);
-    close(c);
 }
 
 int unix_start_incoming_migration(const char *path)
 {
-    struct sockaddr_un un;
-    int sock;
+    struct sockaddr_un addr;
+    int s;
+    int ret;
 
     DPRINTF("Attempting to start an incoming migration\n");
 
-    sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
-    if (sock < 0) {
+    s = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
+    if (s == -1) {
         fprintf(stderr, "Could not open unix socket: %s\n", strerror(errno));
-        return -EINVAL;
+        return -errno;
     }
 
-    memset(&un, 0, sizeof(un));
-    un.sun_family = AF_UNIX;
-    snprintf(un.sun_path, sizeof(un.sun_path), "%s", path);
+    memset(&addr, 0, sizeof(addr));
+    addr.sun_family = AF_UNIX;
+    snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", path);
 
-    unlink(un.sun_path);
-    if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) {
-        fprintf(stderr, "bind(unix:%s): %s\n", un.sun_path, strerror(errno));
+    unlink(addr.sun_path);
+    if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+        ret = -errno;
+        fprintf(stderr, "bind(unix:%s): %s\n", addr.sun_path, strerror(errno));
         goto err;
     }
-    if (listen(sock, 1) < 0) {
-        fprintf(stderr, "listen(unix:%s): %s\n", un.sun_path, strerror(errno));
+    if (listen(s, 1) == -1) {
+        fprintf(stderr, "listen(unix:%s): %s\n", addr.sun_path,
+                strerror(errno));
+        ret = -errno;
         goto err;
     }
 
-    qemu_set_fd_handler2(sock, NULL, unix_accept_incoming_migration, NULL,
-			 (void *)(intptr_t)sock);
+    qemu_set_fd_handler2(s, NULL, unix_accept_incoming_migration, NULL,
+                         (void *)(intptr_t)s);
 
     return 0;
 
 err:
-    close(sock);
-
-    return -EINVAL;
+    close(s);
+    return ret;
 }
diff --git a/migration.c b/migration.c
index 77a51ad..bdca72e 100644
--- a/migration.c
+++ b/migration.c
@@ -31,14 +31,33 @@
     do { } while (0)
 #endif
 
-/* Migration speed throttling */
-static int64_t max_throttle = (32 << 20);
+enum {
+    MIG_STATE_ERROR,
+    MIG_STATE_SETUP,
+    MIG_STATE_CANCELLED,
+    MIG_STATE_ACTIVE,
+    MIG_STATE_COMPLETED,
+};
 
-static MigrationState *current_migration;
+#define MAX_THROTTLE  (32 << 20)      /* Migration speed throttling */
 
 static NotifierList migration_state_notifiers =
     NOTIFIER_LIST_INITIALIZER(migration_state_notifiers);
 
+/* When we add fault tolerance, we could have several
+   migrations at once.  For now we don't need to add
+   dynamic creation of migration */
+
+static MigrationState *migrate_get_current(void)
+{
+    static MigrationState current_migration = {
+        .state = MIG_STATE_SETUP,
+        .bandwidth_limit = MAX_THROTTLE,
+    };
+
+    return &current_migration;
+}
+
 int qemu_start_incoming_migration(const char *uri)
 {
     const char *p;
@@ -77,87 +96,6 @@
     }
 }
 
-int do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data)
-{
-    MigrationState *s = NULL;
-    const char *p;
-    int detach = qdict_get_try_bool(qdict, "detach", 0);
-    int blk = qdict_get_try_bool(qdict, "blk", 0);
-    int inc = qdict_get_try_bool(qdict, "inc", 0);
-    const char *uri = qdict_get_str(qdict, "uri");
-
-    if (current_migration &&
-        current_migration->get_status(current_migration) == MIG_STATE_ACTIVE) {
-        monitor_printf(mon, "migration already in progress\n");
-        return -1;
-    }
-
-    if (qemu_savevm_state_blocked(mon)) {
-        return -1;
-    }
-
-    if (strstart(uri, "tcp:", &p)) {
-        s = tcp_start_outgoing_migration(mon, p, max_throttle, detach,
-                                         blk, inc);
-#if !defined(WIN32)
-    } else if (strstart(uri, "exec:", &p)) {
-        s = exec_start_outgoing_migration(mon, p, max_throttle, detach,
-                                          blk, inc);
-    } else if (strstart(uri, "unix:", &p)) {
-        s = unix_start_outgoing_migration(mon, p, max_throttle, detach,
-                                          blk, inc);
-    } else if (strstart(uri, "fd:", &p)) {
-        s = fd_start_outgoing_migration(mon, p, max_throttle, detach, 
-                                        blk, inc);
-#endif
-    } else {
-        monitor_printf(mon, "unknown migration protocol: %s\n", uri);
-        return -1;
-    }
-
-    if (s == NULL) {
-        monitor_printf(mon, "migration failed\n");
-        return -1;
-    }
-
-    if (current_migration) {
-        current_migration->release(current_migration);
-    }
-
-    current_migration = s;
-    notifier_list_notify(&migration_state_notifiers, NULL);
-    return 0;
-}
-
-int do_migrate_cancel(Monitor *mon, const QDict *qdict, QObject **ret_data)
-{
-    MigrationState *s = current_migration;
-
-    if (s)
-        s->cancel(s);
-
-    return 0;
-}
-
-int do_migrate_set_speed(Monitor *mon, const QDict *qdict, QObject **ret_data)
-{
-    int64_t d;
-    FdMigrationState *s;
-
-    d = qdict_get_int(qdict, "value");
-    if (d < 0) {
-        d = 0;
-    }
-    max_throttle = d;
-
-    s = migrate_to_fms(current_migration);
-    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.
  * the choice of nanoseconds is because it is the maximum resolution that
  * get_clock() can achieve. It is an internal measure. All user-visible
@@ -169,18 +107,6 @@
     return max_downtime;
 }
 
-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,
                                  const QDict *status_dict)
 {
@@ -228,41 +154,42 @@
 void do_info_migrate(Monitor *mon, QObject **ret_data)
 {
     QDict *qdict;
-    MigrationState *s = current_migration;
+    MigrationState *s = migrate_get_current();
 
-    if (s) {
-        switch (s->get_status(s)) {
-        case MIG_STATE_ACTIVE:
-            qdict = qdict_new();
-            qdict_put(qdict, "status", qstring_from_str("active"));
+    switch (s->state) {
+    case MIG_STATE_SETUP:
+        /* no migration has happened ever */
+        break;
+    case MIG_STATE_ACTIVE:
+        qdict = qdict_new();
+        qdict_put(qdict, "status", qstring_from_str("active"));
 
-            migrate_put_status(qdict, "ram", ram_bytes_transferred(),
-                               ram_bytes_remaining(), ram_bytes_total());
+        migrate_put_status(qdict, "ram", ram_bytes_transferred(),
+                           ram_bytes_remaining(), ram_bytes_total());
 
-            if (blk_mig_active()) {
-                migrate_put_status(qdict, "disk", blk_mig_bytes_transferred(),
-                                   blk_mig_bytes_remaining(),
-                                   blk_mig_bytes_total());
-            }
-
-            *ret_data = QOBJECT(qdict);
-            break;
-        case MIG_STATE_COMPLETED:
-            *ret_data = qobject_from_jsonf("{ 'status': 'completed' }");
-            break;
-        case MIG_STATE_ERROR:
-            *ret_data = qobject_from_jsonf("{ 'status': 'failed' }");
-            break;
-        case MIG_STATE_CANCELLED:
-            *ret_data = qobject_from_jsonf("{ 'status': 'cancelled' }");
-            break;
+        if (blk_mig_active()) {
+            migrate_put_status(qdict, "disk", blk_mig_bytes_transferred(),
+                               blk_mig_bytes_remaining(),
+                               blk_mig_bytes_total());
         }
+
+        *ret_data = QOBJECT(qdict);
+        break;
+    case MIG_STATE_COMPLETED:
+        *ret_data = qobject_from_jsonf("{ 'status': 'completed' }");
+        break;
+    case MIG_STATE_ERROR:
+        *ret_data = qobject_from_jsonf("{ 'status': 'failed' }");
+        break;
+    case MIG_STATE_CANCELLED:
+        *ret_data = qobject_from_jsonf("{ 'status': 'cancelled' }");
+        break;
     }
 }
 
 /* shared migration helpers */
 
-void migrate_fd_monitor_suspend(FdMigrationState *s, Monitor *mon)
+static void migrate_fd_monitor_suspend(MigrationState *s, Monitor *mon)
 {
     s->mon = mon;
     if (monitor_suspend(mon) == 0) {
@@ -273,15 +200,7 @@
     }
 }
 
-void migrate_fd_error(FdMigrationState *s)
-{
-    DPRINTF("setting error state\n");
-    s->state = MIG_STATE_ERROR;
-    notifier_list_notify(&migration_state_notifiers, NULL);
-    migrate_fd_cleanup(s);
-}
-
-int migrate_fd_cleanup(FdMigrationState *s)
+static int migrate_fd_cleanup(MigrationState *s)
 {
     int ret = 0;
 
@@ -307,19 +226,47 @@
     return ret;
 }
 
-void migrate_fd_put_notify(void *opaque)
+void migrate_fd_error(MigrationState *s)
 {
-    FdMigrationState *s = opaque;
+    DPRINTF("setting error state\n");
+    s->state = MIG_STATE_ERROR;
+    notifier_list_notify(&migration_state_notifiers, s);
+    migrate_fd_cleanup(s);
+}
+
+static void migrate_fd_completed(MigrationState *s)
+{
+    DPRINTF("setting completed state\n");
+    if (migrate_fd_cleanup(s) < 0) {
+        s->state = MIG_STATE_ERROR;
+    } else {
+        s->state = MIG_STATE_COMPLETED;
+        runstate_set(RUN_STATE_POSTMIGRATE);
+    }
+    notifier_list_notify(&migration_state_notifiers, s);
+}
+
+static void migrate_fd_put_notify(void *opaque)
+{
+    MigrationState *s = opaque;
 
     qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
     qemu_file_put_notify(s->file);
+    if (qemu_file_get_error(s->file)) {
+        migrate_fd_error(s);
+    }
 }
 
-ssize_t migrate_fd_put_buffer(void *opaque, const void *data, size_t size)
+static ssize_t migrate_fd_put_buffer(void *opaque, const void *data,
+                                     size_t size)
 {
-    FdMigrationState *s = opaque;
+    MigrationState *s = opaque;
     ssize_t ret;
 
+    if (s->state != MIG_STATE_ACTIVE) {
+        return -EIO;
+    }
+
     do {
         ret = s->write(s, data, size);
     } while (ret == -1 && ((s->get_error(s)) == EINTR));
@@ -329,115 +276,61 @@
 
     if (ret == -EAGAIN) {
         qemu_set_fd_handler2(s->fd, NULL, NULL, migrate_fd_put_notify, s);
-    } else if (ret < 0) {
-        s->state = MIG_STATE_ERROR;
-        notifier_list_notify(&migration_state_notifiers, NULL);
     }
 
     return ret;
 }
 
-void migrate_fd_connect(FdMigrationState *s)
+static void migrate_fd_put_ready(void *opaque)
 {
+    MigrationState *s = opaque;
     int ret;
 
-    s->file = qemu_fopen_ops_buffered(s,
-                                      s->bandwidth_limit,
-                                      migrate_fd_put_buffer,
-                                      migrate_fd_put_ready,
-                                      migrate_fd_wait_for_unfreeze,
-                                      migrate_fd_close);
-
-    DPRINTF("beginning savevm\n");
-    ret = qemu_savevm_state_begin(s->mon, s->file, s->mig_state.blk,
-                                  s->mig_state.shared);
-    if (ret < 0) {
-        DPRINTF("failed, %d\n", ret);
-        migrate_fd_error(s);
-        return;
-    }
-    
-    migrate_fd_put_ready(s);
-}
-
-void migrate_fd_put_ready(void *opaque)
-{
-    FdMigrationState *s = opaque;
-
     if (s->state != MIG_STATE_ACTIVE) {
         DPRINTF("put_ready returning because of non-active state\n");
         return;
     }
 
     DPRINTF("iterate\n");
-    if (qemu_savevm_state_iterate(s->mon, s->file) == 1) {
-        int state;
+    ret = qemu_savevm_state_iterate(s->mon, s->file);
+    if (ret < 0) {
+        migrate_fd_error(s);
+    } else if (ret == 1) {
         int old_vm_running = runstate_is_running();
 
         DPRINTF("done iterating\n");
-        vm_stop(RUN_STATE_FINISH_MIGRATE);
+        vm_stop_force_state(RUN_STATE_FINISH_MIGRATE);
 
-        if ((qemu_savevm_state_complete(s->mon, s->file)) < 0) {
-            if (old_vm_running) {
-                vm_start();
-            }
-            state = MIG_STATE_ERROR;
+        if (qemu_savevm_state_complete(s->mon, s->file) < 0) {
+            migrate_fd_error(s);
         } else {
-            state = MIG_STATE_COMPLETED;
+            migrate_fd_completed(s);
         }
-        if (migrate_fd_cleanup(s) < 0) {
+        if (s->state != MIG_STATE_COMPLETED) {
             if (old_vm_running) {
                 vm_start();
             }
-            state = MIG_STATE_ERROR;
         }
-        if (state == MIG_STATE_COMPLETED) {
-            runstate_set(RUN_STATE_POSTMIGRATE);
-        }
-        s->state = state;
-        notifier_list_notify(&migration_state_notifiers, NULL);
     }
 }
 
-int migrate_fd_get_status(MigrationState *mig_state)
+static void migrate_fd_cancel(MigrationState *s)
 {
-    FdMigrationState *s = migrate_to_fms(mig_state);
-    return s->state;
-}
-
-void migrate_fd_cancel(MigrationState *mig_state)
-{
-    FdMigrationState *s = migrate_to_fms(mig_state);
-
     if (s->state != MIG_STATE_ACTIVE)
         return;
 
     DPRINTF("cancelling migration\n");
 
     s->state = MIG_STATE_CANCELLED;
-    notifier_list_notify(&migration_state_notifiers, NULL);
+    notifier_list_notify(&migration_state_notifiers, s);
     qemu_savevm_state_cancel(s->mon, s->file);
 
     migrate_fd_cleanup(s);
 }
 
-void migrate_fd_release(MigrationState *mig_state)
+static void migrate_fd_wait_for_unfreeze(void *opaque)
 {
-    FdMigrationState *s = migrate_to_fms(mig_state);
-
-    DPRINTF("releasing state\n");
-   
-    if (s->state == MIG_STATE_ACTIVE) {
-        s->state = MIG_STATE_CANCELLED;
-        notifier_list_notify(&migration_state_notifiers, NULL);
-        migrate_fd_cleanup(s);
-    }
-    g_free(s);
-}
-
-void migrate_fd_wait_for_unfreeze(void *opaque)
-{
-    FdMigrationState *s = opaque;
+    MigrationState *s = opaque;
     int ret;
 
     DPRINTF("wait for unfreeze\n");
@@ -452,11 +345,15 @@
 
         ret = select(s->fd + 1, NULL, &wfds, NULL, NULL);
     } while (ret == -1 && (s->get_error(s)) == EINTR);
+
+    if (ret == -1) {
+        qemu_file_set_error(s->file, -s->get_error(s));
+    }
 }
 
-int migrate_fd_close(void *opaque)
+static int migrate_fd_close(void *opaque)
 {
-    FdMigrationState *s = opaque;
+    MigrationState *s = opaque;
 
     if (s->mon) {
         monitor_resume(s->mon);
@@ -475,11 +372,129 @@
     notifier_list_remove(&migration_state_notifiers, notify);
 }
 
-int get_migration_state(void)
+bool migration_has_finished(MigrationState *s)
 {
-    if (current_migration) {
-        return migrate_fd_get_status(current_migration);
-    } else {
-        return MIG_STATE_ERROR;
+    return s->state == MIG_STATE_COMPLETED;
+}
+
+void migrate_fd_connect(MigrationState *s)
+{
+    int ret;
+
+    s->state = MIG_STATE_ACTIVE;
+    s->file = qemu_fopen_ops_buffered(s,
+                                      s->bandwidth_limit,
+                                      migrate_fd_put_buffer,
+                                      migrate_fd_put_ready,
+                                      migrate_fd_wait_for_unfreeze,
+                                      migrate_fd_close);
+
+    DPRINTF("beginning savevm\n");
+    ret = qemu_savevm_state_begin(s->mon, s->file, s->blk, s->shared);
+    if (ret < 0) {
+        DPRINTF("failed, %d\n", ret);
+        migrate_fd_error(s);
+        return;
     }
+    migrate_fd_put_ready(s);
+}
+
+static MigrationState *migrate_init(Monitor *mon, int detach, int blk, int inc)
+{
+    MigrationState *s = migrate_get_current();
+    int64_t bandwidth_limit = s->bandwidth_limit;
+
+    memset(s, 0, sizeof(*s));
+    s->bandwidth_limit = bandwidth_limit;
+    s->blk = blk;
+    s->shared = inc;
+    s->mon = NULL;
+    s->bandwidth_limit = bandwidth_limit;
+    s->state = MIG_STATE_SETUP;
+
+    if (!detach) {
+        migrate_fd_monitor_suspend(s, mon);
+    }
+
+    return s;
+}
+
+int do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    MigrationState *s = migrate_get_current();
+    const char *p;
+    int detach = qdict_get_try_bool(qdict, "detach", 0);
+    int blk = qdict_get_try_bool(qdict, "blk", 0);
+    int inc = qdict_get_try_bool(qdict, "inc", 0);
+    const char *uri = qdict_get_str(qdict, "uri");
+    int ret;
+
+    if (s->state == MIG_STATE_ACTIVE) {
+        monitor_printf(mon, "migration already in progress\n");
+        return -1;
+    }
+
+    if (qemu_savevm_state_blocked(mon)) {
+        return -1;
+    }
+
+    s = migrate_init(mon, detach, blk, inc);
+
+    if (strstart(uri, "tcp:", &p)) {
+        ret = tcp_start_outgoing_migration(s, p);
+#if !defined(WIN32)
+    } else if (strstart(uri, "exec:", &p)) {
+        ret = exec_start_outgoing_migration(s, p);
+    } else if (strstart(uri, "unix:", &p)) {
+        ret = unix_start_outgoing_migration(s, p);
+    } else if (strstart(uri, "fd:", &p)) {
+        ret = fd_start_outgoing_migration(s, p);
+#endif
+    } else {
+        monitor_printf(mon, "unknown migration protocol: %s\n", uri);
+        ret  = -EINVAL;
+    }
+
+    if (ret < 0) {
+        monitor_printf(mon, "migration failed: %s\n", strerror(-ret));
+        return ret;
+    }
+
+    notifier_list_notify(&migration_state_notifiers, s);
+    return 0;
+}
+
+int do_migrate_cancel(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    migrate_fd_cancel(migrate_get_current());
+    return 0;
+}
+
+int do_migrate_set_speed(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    int64_t d;
+    MigrationState *s;
+
+    d = qdict_get_int(qdict, "value");
+    if (d < 0) {
+        d = 0;
+    }
+
+    s = migrate_get_current();
+    s->bandwidth_limit = d;
+    qemu_file_set_rate_limit(s->file, s->bandwidth_limit);
+
+    return 0;
+}
+
+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;
 }
diff --git a/migration.h b/migration.h
index 050c56c..a1f80d0 100644
--- a/migration.h
+++ b/migration.h
@@ -18,37 +18,21 @@
 #include "qemu-common.h"
 #include "notify.h"
 
-#define MIG_STATE_ERROR		-1
-#define MIG_STATE_COMPLETED	0
-#define MIG_STATE_CANCELLED	1
-#define MIG_STATE_ACTIVE	2
-
 typedef struct MigrationState MigrationState;
 
 struct MigrationState
 {
-    /* FIXME: add more accessors to print migration info */
-    void (*cancel)(MigrationState *s);
-    int (*get_status)(MigrationState *s);
-    void (*release)(MigrationState *s);
-    int blk;
-    int shared;
-};
-
-typedef struct FdMigrationState FdMigrationState;
-
-struct FdMigrationState
-{
-    MigrationState mig_state;
     int64_t bandwidth_limit;
     QEMUFile *file;
     int fd;
     Monitor *mon;
     int state;
-    int (*get_error)(struct FdMigrationState*);
-    int (*close)(struct FdMigrationState*);
-    int (*write)(struct FdMigrationState*, const void *, size_t);
+    int (*get_error)(MigrationState *s);
+    int (*close)(MigrationState *s);
+    int (*write)(MigrationState *s, const void *buff, size_t size);
     void *opaque;
+    int blk;
+    int shared;
 };
 
 void process_incoming_migration(QEMUFile *f);
@@ -72,72 +56,27 @@
 
 int exec_start_incoming_migration(const char *host_port);
 
-MigrationState *exec_start_outgoing_migration(Monitor *mon,
-                                              const char *host_port,
-					      int64_t bandwidth_limit,
-					      int detach,
-					      int blk,
-					      int inc);
+int exec_start_outgoing_migration(MigrationState *s, const char *host_port);
 
 int tcp_start_incoming_migration(const char *host_port);
 
-MigrationState *tcp_start_outgoing_migration(Monitor *mon,
-                                             const char *host_port,
-					     int64_t bandwidth_limit,
-					     int detach,
-					     int blk,
-					     int inc);
+int tcp_start_outgoing_migration(MigrationState *s, const char *host_port);
 
 int unix_start_incoming_migration(const char *path);
 
-MigrationState *unix_start_outgoing_migration(Monitor *mon,
-                                              const char *path,
-					      int64_t bandwidth_limit,
-					      int detach,
-					      int blk,
-					      int inc);
+int unix_start_outgoing_migration(MigrationState *s, const char *path);
 
 int fd_start_incoming_migration(const char *path);
 
-MigrationState *fd_start_outgoing_migration(Monitor *mon,
-					    const char *fdname,
-					    int64_t bandwidth_limit,
-					    int detach,
-					    int blk,
-					    int inc);
+int fd_start_outgoing_migration(MigrationState *s, const char *fdname);
 
-void migrate_fd_monitor_suspend(FdMigrationState *s, Monitor *mon);
+void migrate_fd_error(MigrationState *s);
 
-void migrate_fd_error(FdMigrationState *s);
-
-int migrate_fd_cleanup(FdMigrationState *s);
-
-void migrate_fd_put_notify(void *opaque);
-
-ssize_t migrate_fd_put_buffer(void *opaque, const void *data, size_t size);
-
-void migrate_fd_connect(FdMigrationState *s);
-
-void migrate_fd_put_ready(void *opaque);
-
-int migrate_fd_get_status(MigrationState *mig_state);
-
-void migrate_fd_cancel(MigrationState *mig_state);
-
-void migrate_fd_release(MigrationState *mig_state);
-
-void migrate_fd_wait_for_unfreeze(void *opaque);
-
-int migrate_fd_close(void *opaque);
-
-static inline FdMigrationState *migrate_to_fms(MigrationState *mig_state)
-{
-    return container_of(mig_state, FdMigrationState, mig_state);
-}
+void migrate_fd_connect(MigrationState *s);
 
 void add_migration_state_change_notifier(Notifier *notify);
 void remove_migration_state_change_notifier(Notifier *notify);
-int get_migration_state(void);
+bool migration_has_finished(MigrationState *);
 
 uint64_t ram_bytes_remaining(void);
 uint64_t ram_bytes_transferred(void);
diff --git a/os-win32.c b/os-win32.c
index f09f01f..7909401 100644
--- a/os-win32.c
+++ b/os-win32.c
@@ -48,129 +48,6 @@
     return result;
 }
 
-/***********************************************************/
-/* Polling handling */
-
-typedef struct PollingEntry {
-    PollingFunc *func;
-    void *opaque;
-    struct PollingEntry *next;
-} PollingEntry;
-
-static PollingEntry *first_polling_entry;
-
-int qemu_add_polling_cb(PollingFunc *func, void *opaque)
-{
-    PollingEntry **ppe, *pe;
-    pe = g_malloc0(sizeof(PollingEntry));
-    pe->func = func;
-    pe->opaque = opaque;
-    for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next);
-    *ppe = pe;
-    return 0;
-}
-
-void qemu_del_polling_cb(PollingFunc *func, void *opaque)
-{
-    PollingEntry **ppe, *pe;
-    for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next) {
-        pe = *ppe;
-        if (pe->func == func && pe->opaque == opaque) {
-            *ppe = pe->next;
-            g_free(pe);
-            break;
-        }
-    }
-}
-
-/***********************************************************/
-/* Wait objects support */
-typedef struct WaitObjects {
-    int num;
-    HANDLE events[MAXIMUM_WAIT_OBJECTS + 1];
-    WaitObjectFunc *func[MAXIMUM_WAIT_OBJECTS + 1];
-    void *opaque[MAXIMUM_WAIT_OBJECTS + 1];
-} WaitObjects;
-
-static WaitObjects wait_objects = {0};
-
-int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
-{
-    WaitObjects *w = &wait_objects;
-
-    if (w->num >= MAXIMUM_WAIT_OBJECTS)
-        return -1;
-    w->events[w->num] = handle;
-    w->func[w->num] = func;
-    w->opaque[w->num] = opaque;
-    w->num++;
-    return 0;
-}
-
-void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
-{
-    int i, found;
-    WaitObjects *w = &wait_objects;
-
-    found = 0;
-    for (i = 0; i < w->num; i++) {
-        if (w->events[i] == handle)
-            found = 1;
-        if (found) {
-            w->events[i] = w->events[i + 1];
-            w->func[i] = w->func[i + 1];
-            w->opaque[i] = w->opaque[i + 1];
-        }
-    }
-    if (found)
-        w->num--;
-}
-
-void os_host_main_loop_wait(int *timeout)
-{
-    int ret, ret2, i;
-    PollingEntry *pe;
-
-    /* XXX: need to suppress polling by better using win32 events */
-    ret = 0;
-    for(pe = first_polling_entry; pe != NULL; pe = pe->next) {
-        ret |= pe->func(pe->opaque);
-    }
-    if (ret == 0) {
-        int err;
-        WaitObjects *w = &wait_objects;
-
-        qemu_mutex_unlock_iothread();
-        ret = WaitForMultipleObjects(w->num, w->events, FALSE, *timeout);
-        qemu_mutex_lock_iothread();
-        if (WAIT_OBJECT_0 + 0 <= ret && ret <= WAIT_OBJECT_0 + w->num - 1) {
-            if (w->func[ret - WAIT_OBJECT_0])
-                w->func[ret - WAIT_OBJECT_0](w->opaque[ret - WAIT_OBJECT_0]);
-
-            /* Check for additional signaled events */
-            for(i = (ret - WAIT_OBJECT_0 + 1); i < w->num; i++) {
-
-                /* Check if event is signaled */
-                ret2 = WaitForSingleObject(w->events[i], 0);
-                if(ret2 == WAIT_OBJECT_0) {
-                    if (w->func[i])
-                        w->func[i](w->opaque[i]);
-                } else if (ret2 == WAIT_TIMEOUT) {
-                } else {
-                    err = GetLastError();
-                    fprintf(stderr, "WaitForSingleObject error %d %d\n", i, err);
-                }
-            }
-        } else if (ret == WAIT_TIMEOUT) {
-        } else {
-            err = GetLastError();
-            fprintf(stderr, "WaitForMultipleObjects error %d %d\n", ret, err);
-        }
-    }
-
-    *timeout = 0;
-}
-
 static BOOL WINAPI qemu_ctrl_handler(DWORD type)
 {
     exit(STATUS_CONTROL_C_EXIT);
diff --git a/oslib-posix.c b/oslib-posix.c
index a304fb0..dbc8ee8 100644
--- a/oslib-posix.c
+++ b/oslib-posix.c
@@ -103,6 +103,13 @@
     free(ptr);
 }
 
+void socket_set_block(int fd)
+{
+    int f;
+    f = fcntl(fd, F_GETFL);
+    fcntl(fd, F_SETFL, f & ~O_NONBLOCK);
+}
+
 void socket_set_nonblock(int fd)
 {
     int f;
diff --git a/oslib-win32.c b/oslib-win32.c
index 5f0759f..5e3de7d 100644
--- a/oslib-win32.c
+++ b/oslib-win32.c
@@ -73,6 +73,12 @@
     VirtualFree(ptr, 0, MEM_RELEASE);
 }
 
+void socket_set_block(int fd)
+{
+    unsigned long opt = 0;
+    ioctlsocket(fd, FIONBIO, &opt);
+}
+
 void socket_set_nonblock(int fd)
 {
     unsigned long opt = 1;
diff --git a/qemu-char.c b/qemu-char.c
index fb9e058..9fd94d1 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -538,6 +538,9 @@
 }
 #endif /* !_WIN32 */
 
+#define STDIO_MAX_CLIENTS 1
+static int stdio_nb_clients;
+
 #ifndef _WIN32
 
 typedef struct {
@@ -545,8 +548,6 @@
     int max_size;
 } FDCharDriver;
 
-#define STDIO_MAX_CLIENTS 1
-static int stdio_nb_clients = 0;
 
 static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 {
@@ -1451,6 +1452,8 @@
 
 #else /* _WIN32 */
 
+static CharDriverState *stdio_clients[STDIO_MAX_CLIENTS];
+
 typedef struct {
     int max_size;
     HANDLE hcom, hrecv, hsend;
@@ -1459,6 +1462,14 @@
     DWORD len;
 } WinCharState;
 
+typedef struct {
+    HANDLE  hStdIn;
+    HANDLE  hInputReadyEvent;
+    HANDLE  hInputDoneEvent;
+    HANDLE  hInputThread;
+    uint8_t win_stdio_buf;
+} WinStdioCharState;
+
 #define NSENDBUF 2048
 #define NRECVBUF 2048
 #define MAXCONNECT 1
@@ -1809,6 +1820,217 @@
 
     return qemu_chr_open_win_file(fd_out, _chr);
 }
+
+static int win_stdio_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    HANDLE  hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
+    DWORD   dwSize;
+    int     len1;
+
+    len1 = len;
+
+    while (len1 > 0) {
+        if (!WriteFile(hStdOut, buf, len1, &dwSize, NULL)) {
+            break;
+        }
+        buf  += dwSize;
+        len1 -= dwSize;
+    }
+
+    return len - len1;
+}
+
+static void win_stdio_wait_func(void *opaque)
+{
+    CharDriverState   *chr   = opaque;
+    WinStdioCharState *stdio = chr->opaque;
+    INPUT_RECORD       buf[4];
+    int                ret;
+    DWORD              dwSize;
+    int                i;
+
+    ret = ReadConsoleInput(stdio->hStdIn, buf, sizeof(buf) / sizeof(*buf),
+                           &dwSize);
+
+    if (!ret) {
+        /* Avoid error storm */
+        qemu_del_wait_object(stdio->hStdIn, NULL, NULL);
+        return;
+    }
+
+    for (i = 0; i < dwSize; i++) {
+        KEY_EVENT_RECORD *kev = &buf[i].Event.KeyEvent;
+
+        if (buf[i].EventType == KEY_EVENT && kev->bKeyDown) {
+            int j;
+            if (kev->uChar.AsciiChar != 0) {
+                for (j = 0; j < kev->wRepeatCount; j++) {
+                    if (qemu_chr_be_can_write(chr)) {
+                        uint8_t c = kev->uChar.AsciiChar;
+                        qemu_chr_be_write(chr, &c, 1);
+                    }
+                }
+            }
+        }
+    }
+}
+
+static DWORD WINAPI win_stdio_thread(LPVOID param)
+{
+    CharDriverState   *chr   = param;
+    WinStdioCharState *stdio = chr->opaque;
+    int                ret;
+    DWORD              dwSize;
+
+    while (1) {
+
+        /* Wait for one byte */
+        ret = ReadFile(stdio->hStdIn, &stdio->win_stdio_buf, 1, &dwSize, NULL);
+
+        /* Exit in case of error, continue if nothing read */
+        if (!ret) {
+            break;
+        }
+        if (!dwSize) {
+            continue;
+        }
+
+        /* Some terminal emulator returns \r\n for Enter, just pass \n */
+        if (stdio->win_stdio_buf == '\r') {
+            continue;
+        }
+
+        /* Signal the main thread and wait until the byte was eaten */
+        if (!SetEvent(stdio->hInputReadyEvent)) {
+            break;
+        }
+        if (WaitForSingleObject(stdio->hInputDoneEvent, INFINITE)
+            != WAIT_OBJECT_0) {
+            break;
+        }
+    }
+
+    qemu_del_wait_object(stdio->hInputReadyEvent, NULL, NULL);
+    return 0;
+}
+
+static void win_stdio_thread_wait_func(void *opaque)
+{
+    CharDriverState   *chr   = opaque;
+    WinStdioCharState *stdio = chr->opaque;
+
+    if (qemu_chr_be_can_write(chr)) {
+        qemu_chr_be_write(chr, &stdio->win_stdio_buf, 1);
+    }
+
+    SetEvent(stdio->hInputDoneEvent);
+}
+
+static void qemu_chr_set_echo_win_stdio(CharDriverState *chr, bool echo)
+{
+    WinStdioCharState *stdio  = chr->opaque;
+    DWORD              dwMode = 0;
+
+    GetConsoleMode(stdio->hStdIn, &dwMode);
+
+    if (echo) {
+        SetConsoleMode(stdio->hStdIn, dwMode | ENABLE_ECHO_INPUT);
+    } else {
+        SetConsoleMode(stdio->hStdIn, dwMode & ~ENABLE_ECHO_INPUT);
+    }
+}
+
+static void win_stdio_close(CharDriverState *chr)
+{
+    WinStdioCharState *stdio = chr->opaque;
+
+    if (stdio->hInputReadyEvent != INVALID_HANDLE_VALUE) {
+        CloseHandle(stdio->hInputReadyEvent);
+    }
+    if (stdio->hInputDoneEvent != INVALID_HANDLE_VALUE) {
+        CloseHandle(stdio->hInputDoneEvent);
+    }
+    if (stdio->hInputThread != INVALID_HANDLE_VALUE) {
+        TerminateThread(stdio->hInputThread, 0);
+    }
+
+    g_free(chr->opaque);
+    g_free(chr);
+    stdio_nb_clients--;
+}
+
+static int qemu_chr_open_win_stdio(QemuOpts *opts, CharDriverState **_chr)
+{
+    CharDriverState   *chr;
+    WinStdioCharState *stdio;
+    DWORD              dwMode;
+    int                is_console = 0;
+
+    if (stdio_nb_clients >= STDIO_MAX_CLIENTS
+        || ((display_type != DT_NOGRAPHIC) && (stdio_nb_clients != 0))) {
+        return -EIO;
+    }
+
+    chr   = g_malloc0(sizeof(CharDriverState));
+    stdio = g_malloc0(sizeof(WinStdioCharState));
+
+    stdio->hStdIn = GetStdHandle(STD_INPUT_HANDLE);
+    if (stdio->hStdIn == INVALID_HANDLE_VALUE) {
+        fprintf(stderr, "cannot open stdio: invalid handle\n");
+        exit(1);
+    }
+
+    is_console = GetConsoleMode(stdio->hStdIn, &dwMode) != 0;
+
+    chr->opaque    = stdio;
+    chr->chr_write = win_stdio_write;
+    chr->chr_close = win_stdio_close;
+
+    if (stdio_nb_clients == 0) {
+        if (is_console) {
+            if (qemu_add_wait_object(stdio->hStdIn,
+                                     win_stdio_wait_func, chr)) {
+                fprintf(stderr, "qemu_add_wait_object: failed\n");
+            }
+        } else {
+            DWORD   dwId;
+
+            stdio->hInputReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+            stdio->hInputDoneEvent  = CreateEvent(NULL, FALSE, FALSE, NULL);
+            stdio->hInputThread     = CreateThread(NULL, 0, win_stdio_thread,
+                                            chr, 0, &dwId);
+
+            if (stdio->hInputThread == INVALID_HANDLE_VALUE
+                || stdio->hInputReadyEvent == INVALID_HANDLE_VALUE
+                || stdio->hInputDoneEvent == INVALID_HANDLE_VALUE) {
+                fprintf(stderr, "cannot create stdio thread or event\n");
+                exit(1);
+            }
+            if (qemu_add_wait_object(stdio->hInputReadyEvent,
+                                     win_stdio_thread_wait_func, chr)) {
+                fprintf(stderr, "qemu_add_wait_object: failed\n");
+            }
+        }
+    }
+
+    dwMode |= ENABLE_LINE_INPUT;
+
+    stdio_clients[stdio_nb_clients++] = chr;
+    if (stdio_nb_clients == 1 && is_console) {
+        /* set the terminal in raw mode */
+        /* ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS */
+        dwMode |= ENABLE_PROCESSED_INPUT;
+    }
+
+    SetConsoleMode(stdio->hStdIn, dwMode);
+
+    chr->chr_set_echo = qemu_chr_set_echo_win_stdio;
+    qemu_chr_fe_set_echo(chr, false);
+
+    *_chr = chr;
+
+    return 0;
+}
 #endif /* !_WIN32 */
 
 /***********************************************************/
@@ -2519,6 +2741,7 @@
     { .name = "pipe",      .open = qemu_chr_open_win_pipe },
     { .name = "console",   .open = qemu_chr_open_win_con },
     { .name = "serial",    .open = qemu_chr_open_win },
+    { .name = "stdio",     .open = qemu_chr_open_win_stdio },
 #else
     { .name = "file",      .open = qemu_chr_open_file_out },
     { .name = "pipe",      .open = qemu_chr_open_pipe },
diff --git a/qemu-char.h b/qemu-char.h
index eebbdd8..7efcf99 100644
--- a/qemu-char.h
+++ b/qemu-char.h
@@ -7,6 +7,7 @@
 #include "qemu-config.h"
 #include "qobject.h"
 #include "qstring.h"
+#include "main-loop.h"
 
 /* character device */
 
@@ -237,15 +238,4 @@
 QString *qemu_chr_mem_to_qs(CharDriverState *chr);
 size_t qemu_chr_mem_osize(const CharDriverState *chr);
 
-/* async I/O support */
-
-int qemu_set_fd_handler2(int fd,
-                         IOCanReadHandler *fd_read_poll,
-                         IOHandler *fd_read,
-                         IOHandler *fd_write,
-                         void *opaque);
-int qemu_set_fd_handler(int fd,
-                        IOHandler *fd_read,
-                        IOHandler *fd_write,
-                        void *opaque);
 #endif
diff --git a/qemu-common.h b/qemu-common.h
index 5e87bdf..1c15cb1 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -13,7 +13,6 @@
 
 typedef struct QEMUTimer QEMUTimer;
 typedef struct QEMUFile QEMUFile;
-typedef struct QEMUBH QEMUBH;
 typedef struct DeviceState DeviceState;
 
 struct Monitor;
@@ -96,6 +95,10 @@
 }
 #endif
 
+/* icount */
+void configure_icount(const char *option);
+extern int use_icount;
+
 /* FIXME: Remove NEED_CPU_H.  */
 #ifndef NEED_CPU_H
 
@@ -113,23 +116,6 @@
 int qemu_main(int argc, char **argv, char **envp);
 #endif
 
-/* bottom halves */
-typedef void QEMUBHFunc(void *opaque);
-
-QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque);
-void qemu_bh_schedule(QEMUBH *bh);
-/* Bottom halfs that are scheduled from a bottom half handler are instantly
- * invoked.  This can create an infinite loop if a bottom half handler
- * schedules itself.  qemu_bh_schedule_idle() avoids this infinite loop by
- * ensuring that the bottom half isn't executed until the next main loop
- * iteration.
- */
-void qemu_bh_schedule_idle(QEMUBH *bh);
-void qemu_bh_cancel(QEMUBH *bh);
-void qemu_bh_delete(QEMUBH *bh);
-int qemu_bh_poll(void);
-void qemu_bh_update_timeout(int *timeout);
-
 void qemu_get_timedate(struct tm *tm, int offset);
 int qemu_timedate_diff(struct tm *tm);
 
@@ -183,16 +169,12 @@
 
 void *qemu_oom_check(void *ptr);
 
-void qemu_mutex_lock_iothread(void);
-void qemu_mutex_unlock_iothread(void);
-
 int qemu_open(const char *name, int flags, ...);
 ssize_t qemu_write_full(int fd, const void *buf, size_t count)
     QEMU_WARN_UNUSED_RESULT;
 void qemu_set_cloexec(int fd);
 
 #ifndef _WIN32
-int qemu_add_child_watch(pid_t pid);
 int qemu_eventfd(int pipefd[2]);
 int qemu_pipe(int pipefd[2]);
 #endif
@@ -207,14 +189,6 @@
 
 void QEMU_NORETURN hw_error(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
 
-/* IO callbacks.  */
-typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size);
-typedef int IOCanReadHandler(void *opaque);
-typedef void IOHandler(void *opaque);
-
-void qemu_iohandler_fill(int *pnfds, fd_set *readfds, fd_set *writefds, fd_set *xfds);
-void qemu_iohandler_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds, int rc);
-
 struct ParallelIOArg {
     void *buffer;
     int count;
@@ -276,9 +250,6 @@
 void cpu_save(QEMUFile *f, void *opaque);
 int cpu_load(QEMUFile *f, void *opaque, int version_id);
 
-/* Force QEMU to process pending events */
-void qemu_notify_event(void);
-
 /* Unblock cpu */
 void qemu_cpu_kick(void *env);
 void qemu_cpu_kick_self(void);
diff --git a/qemu-config.c b/qemu-config.c
index 7a7854f..90b6b3e 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -165,11 +165,11 @@
 
 QemuOptsList qemu_fsdev_opts = {
     .name = "fsdev",
-    .implied_opt_name = "fstype",
+    .implied_opt_name = "fsdriver",
     .head = QTAILQ_HEAD_INITIALIZER(qemu_fsdev_opts.head),
     .desc = {
         {
-            .name = "fstype",
+            .name = "fsdriver",
             .type = QEMU_OPT_STRING,
         }, {
             .name = "path",
@@ -177,6 +177,9 @@
         }, {
             .name = "security_model",
             .type = QEMU_OPT_STRING,
+        }, {
+            .name = "writeout",
+            .type = QEMU_OPT_STRING,
         },
         { /*End of list */ }
     },
@@ -184,11 +187,11 @@
 
 QemuOptsList qemu_virtfs_opts = {
     .name = "virtfs",
-    .implied_opt_name = "fstype",
+    .implied_opt_name = "fsdriver",
     .head = QTAILQ_HEAD_INITIALIZER(qemu_virtfs_opts.head),
     .desc = {
         {
-            .name = "fstype",
+            .name = "fsdriver",
             .type = QEMU_OPT_STRING,
         }, {
             .name = "path",
@@ -199,6 +202,9 @@
         }, {
             .name = "security_model",
             .type = QEMU_OPT_STRING,
+        }, {
+            .name = "writeout",
+            .type = QEMU_OPT_STRING,
         },
 
         { /*End of list */ }
diff --git a/qemu-coroutine-lock.c b/qemu-coroutine-lock.c
index 2a385a3..6b58160 100644
--- a/qemu-coroutine-lock.c
+++ b/qemu-coroutine-lock.c
@@ -26,6 +26,7 @@
 #include "qemu-coroutine.h"
 #include "qemu-coroutine-int.h"
 #include "qemu-queue.h"
+#include "main-loop.h"
 #include "trace.h"
 
 static QTAILQ_HEAD(, Coroutine) unlock_bh_queue =
diff --git a/qemu-img.c b/qemu-img.c
index 6a39731..86127f0 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -824,6 +824,8 @@
     if (compress) {
         QEMUOptionParameter *encryption =
             get_option_parameter(param, BLOCK_OPT_ENCRYPT);
+        QEMUOptionParameter *preallocation =
+            get_option_parameter(param, BLOCK_OPT_PREALLOC);
 
         if (!drv->bdrv_write_compressed) {
             error_report("Compression not supported for this file format");
@@ -837,6 +839,15 @@
             ret = -1;
             goto out;
         }
+
+        if (preallocation && preallocation->value.s
+            && strcmp(preallocation->value.s, "off"))
+        {
+            error_report("Compression and preallocation not supported at "
+                         "the same time");
+            ret = -1;
+            goto out;
+        }
     }
 
     /* Create the new image */
diff --git a/qemu-io.c b/qemu-io.c
index e91af37..c45a413 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -1248,6 +1248,7 @@
         case 'P':
             pattern = parse_pattern(optarg);
             if (pattern < 0) {
+                free(ctx);
                 return 0;
             }
             break;
diff --git a/qemu-options.hx b/qemu-options.hx
index d4fe990..5d2a776 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -522,73 +522,103 @@
 @code{-device @var{driver},?}.
 ETEXI
 
+DEFHEADING()
+
 DEFHEADING(File system options:)
 
 DEF("fsdev", HAS_ARG, QEMU_OPTION_fsdev,
-    "-fsdev local,id=id,path=path,security_model=[mapped|passthrough|none]\n",
+    "-fsdev fsdriver,id=id,path=path,[security_model={mapped|passthrough|none}]\n"
+    "       [,writeout=immediate]\n",
     QEMU_ARCH_ALL)
 
 STEXI
 
-The general form of a File system device option is:
-@table @option
-
-@item -fsdev @var{fstype} ,id=@var{id} [,@var{options}]
+@item -fsdev @var{fsdriver},id=@var{id},path=@var{path},[security_model=@var{security_model}][,writeout=@var{writeout}]
 @findex -fsdev
-Fstype is one of:
-@option{local},
-The specific Fstype will determine the applicable options.
-
-Options to each backend are described below.
-
-@item -fsdev local ,id=@var{id} ,path=@var{path} ,security_model=@var{security_model}
-
-Create a file-system-"device" for local-filesystem.
-
-@option{local} is only available on Linux.
-
-@option{path} specifies the path to be exported. @option{path} is required.
-
-@option{security_model} specifies the security model to be followed.
-@option{security_model} is required.
-
+Define a new file system device. Valid options are:
+@table @option
+@item @var{fsdriver}
+This option specifies the fs driver backend to use.
+Currently "local" and "handle" file system drivers are supported.
+@item id=@var{id}
+Specifies identifier for this device
+@item path=@var{path}
+Specifies the export path for the file system device. Files under
+this path will be available to the 9p client on the guest.
+@item security_model=@var{security_model}
+Specifies the security model to be used for this export path.
+Supported security models are "passthrough", "mapped" and "none".
+In "passthrough" security model, files are stored using the same
+credentials as they are created on the guest. This requires qemu
+to run as root. In "mapped" security model, some of the file
+attributes like uid, gid, mode bits and link target are stored as
+file attributes. Directories exported by this security model cannot
+interact with other unix tools. "none" security model is same as
+passthrough except the sever won't report failures if it fails to
+set file attributes like ownership. Security model is mandatory
+only for local fsdriver. Other fsdrivers (like handle) don't take
+security model as a parameter.
+@item writeout=@var{writeout}
+This is an optional argument. The only supported value is "immediate".
+This means that host page cache will be used to read and write data but
+write notification will be sent to the guest only when the data has been
+reported as written by the storage subsystem.
 @end table
+
+-fsdev option is used along with -device driver "virtio-9p-pci".
+@item -device virtio-9p-pci,fsdev=@var{id},mount_tag=@var{mount_tag}
+Options for virtio-9p-pci driver are:
+@table @option
+@item fsdev=@var{id}
+Specifies the id value specified along with -fsdev option
+@item mount_tag=@var{mount_tag}
+Specifies the tag name to be used by the guest to mount this export point
+@end table
+
 ETEXI
 
+DEFHEADING()
+
 DEFHEADING(Virtual File system pass-through options:)
 
 DEF("virtfs", HAS_ARG, QEMU_OPTION_virtfs,
-    "-virtfs local,path=path,mount_tag=tag,security_model=[mapped|passthrough|none]\n",
+    "-virtfs local,path=path,mount_tag=tag,security_model=[mapped|passthrough|none]\n"
+    "        [,writeout=immediate]\n",
     QEMU_ARCH_ALL)
 
 STEXI
 
-The general form of a Virtual File system pass-through option is:
-@table @option
-
-@item -virtfs @var{fstype} [,@var{options}]
+@item -virtfs @var{fsdriver},path=@var{path},mount_tag=@var{mount_tag},security_model=@var{security_model}[,writeout=@var{writeout}]
 @findex -virtfs
-Fstype is one of:
-@option{local},
-The specific Fstype will determine the applicable options.
 
-Options to each backend are described below.
-
-@item -virtfs local ,path=@var{path} ,mount_tag=@var{mount_tag} ,security_model=@var{security_model}
-
-Create a Virtual file-system-pass through for local-filesystem.
-
-@option{local} is only available on Linux.
-
-@option{path} specifies the path to be exported. @option{path} is required.
-
-@option{security_model} specifies the security model to be followed.
-@option{security_model} is required.
-
-
-@option{mount_tag} specifies the tag with which the exported file is mounted.
-@option{mount_tag} is required.
-
+The general form of a Virtual File system pass-through options are:
+@table @option
+@item @var{fsdriver}
+This option specifies the fs driver backend to use.
+Currently "local" and "handle" file system drivers are supported.
+@item id=@var{id}
+Specifies identifier for this device
+@item path=@var{path}
+Specifies the export path for the file system device. Files under
+this path will be available to the 9p client on the guest.
+@item security_model=@var{security_model}
+Specifies the security model to be used for this export path.
+Supported security models are "passthrough", "mapped" and "none".
+In "passthrough" security model, files are stored using the same
+credentials as they are created on the guest. This requires qemu
+to run as root. In "mapped" security model, some of the file
+attributes like uid, gid, mode bits and link target are stored as
+file attributes. Directories exported by this security model cannot
+interact with other unix tools. "none" security model is same as
+passthrough except the sever won't report failures if it fails to
+set file attributes like ownership. Security model is mandatory only
+for local fsdriver. Other fsdrivers (like handle) don't take security
+model as a parameter.
+@item writeout=@var{writeout}
+This is an optional argument. The only supported value is "immediate".
+This means that host page cache will be used to read and write data but
+write notification will be sent to the guest only when the data has been
+reported as written by the storage subsystem.
 @end table
 ETEXI
 
diff --git a/qemu-os-posix.h b/qemu-os-posix.h
index 81fd9ab..920499d 100644
--- a/qemu-os-posix.h
+++ b/qemu-os-posix.h
@@ -26,10 +26,6 @@
 #ifndef QEMU_OS_POSIX_H
 #define QEMU_OS_POSIX_H
 
-static inline void os_host_main_loop_wait(int *timeout)
-{
-}
-
 void os_set_line_buffering(void);
 void os_set_proc_name(const char *s);
 void os_setup_signal_handling(void);
diff --git a/qemu-os-win32.h b/qemu-os-win32.h
index 8a069d7..8eda4bd 100644
--- a/qemu-os-win32.h
+++ b/qemu-os-win32.h
@@ -28,26 +28,11 @@
 
 #include <windows.h>
 #include <winsock2.h>
+#include "main-loop.h"
 
 /* Declaration of ffs() is missing in MinGW's strings.h. */
 int ffs(int i);
 
-/* Polling handling */
-
-/* return TRUE if no sleep should be done afterwards */
-typedef int PollingFunc(void *opaque);
-
-int qemu_add_polling_cb(PollingFunc *func, void *opaque);
-void qemu_del_polling_cb(PollingFunc *func, void *opaque);
-
-/* Wait objects handling */
-typedef void WaitObjectFunc(void *opaque);
-
-int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque);
-void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque);
-
-void os_host_main_loop_wait(int *timeout);
-
 static inline void os_setup_signal_handling(void) {}
 static inline void os_daemonize(void) {}
 static inline void os_setup_post(void) {}
diff --git a/qemu-timer.c b/qemu-timer.c
index ad1fc8b..f11a28d 100644
--- a/qemu-timer.c
+++ b/qemu-timer.c
@@ -46,82 +46,6 @@
 
 #include "qemu-timer.h"
 
-/* Conversion factor from emulated instructions to virtual clock ticks.  */
-int icount_time_shift;
-/* Arbitrarily pick 1MIPS as the minimum allowable speed.  */
-#define MAX_ICOUNT_SHIFT 10
-/* Compensate for varying guest execution speed.  */
-int64_t qemu_icount_bias;
-static QEMUTimer *icount_rt_timer;
-static QEMUTimer *icount_vm_timer;
-
-/***********************************************************/
-/* guest cycle counter */
-
-typedef struct TimersState {
-    int64_t cpu_ticks_prev;
-    int64_t cpu_ticks_offset;
-    int64_t cpu_clock_offset;
-    int32_t cpu_ticks_enabled;
-    int64_t dummy;
-} TimersState;
-
-TimersState timers_state;
-
-/* return the host CPU cycle counter and handle stop/restart */
-int64_t cpu_get_ticks(void)
-{
-    if (use_icount) {
-        return cpu_get_icount();
-    }
-    if (!timers_state.cpu_ticks_enabled) {
-        return timers_state.cpu_ticks_offset;
-    } else {
-        int64_t ticks;
-        ticks = cpu_get_real_ticks();
-        if (timers_state.cpu_ticks_prev > ticks) {
-            /* Note: non increasing ticks may happen if the host uses
-               software suspend */
-            timers_state.cpu_ticks_offset += timers_state.cpu_ticks_prev - ticks;
-        }
-        timers_state.cpu_ticks_prev = ticks;
-        return ticks + timers_state.cpu_ticks_offset;
-    }
-}
-
-/* return the host CPU monotonic timer and handle stop/restart */
-static int64_t cpu_get_clock(void)
-{
-    int64_t ti;
-    if (!timers_state.cpu_ticks_enabled) {
-        return timers_state.cpu_clock_offset;
-    } else {
-        ti = get_clock();
-        return ti + timers_state.cpu_clock_offset;
-    }
-}
-
-/* enable cpu_get_ticks() */
-void cpu_enable_ticks(void)
-{
-    if (!timers_state.cpu_ticks_enabled) {
-        timers_state.cpu_ticks_offset -= cpu_get_real_ticks();
-        timers_state.cpu_clock_offset -= get_clock();
-        timers_state.cpu_ticks_enabled = 1;
-    }
-}
-
-/* disable cpu_get_ticks() : the clock is stopped. You must not call
-   cpu_get_ticks() after that.  */
-void cpu_disable_ticks(void)
-{
-    if (timers_state.cpu_ticks_enabled) {
-        timers_state.cpu_ticks_offset = cpu_get_ticks();
-        timers_state.cpu_clock_offset = cpu_get_clock();
-        timers_state.cpu_ticks_enabled = 0;
-    }
-}
-
 /***********************************************************/
 /* timers */
 
@@ -133,7 +57,7 @@
     int type;
     int enabled;
 
-    QEMUTimer *warp_timer;
+    QEMUTimer *active_timers;
 
     NotifierList reset_notifiers;
     int64_t last;
@@ -152,7 +76,7 @@
     char const *name;
     int (*start)(struct qemu_alarm_timer *t);
     void (*stop)(struct qemu_alarm_timer *t);
-    void (*rearm)(struct qemu_alarm_timer *t);
+    void (*rearm)(struct qemu_alarm_timer *t, int64_t nearest_delta_ns);
 #if defined(__linux__)
     int fd;
     timer_t timer;
@@ -180,12 +104,46 @@
     return !!t->rearm;
 }
 
+static int64_t qemu_next_alarm_deadline(void)
+{
+    int64_t delta;
+    int64_t rtdelta;
+
+    if (!use_icount && vm_clock->active_timers) {
+        delta = vm_clock->active_timers->expire_time -
+                     qemu_get_clock_ns(vm_clock);
+    } else {
+        delta = INT32_MAX;
+    }
+    if (host_clock->active_timers) {
+        int64_t hdelta = host_clock->active_timers->expire_time -
+                 qemu_get_clock_ns(host_clock);
+        if (hdelta < delta) {
+            delta = hdelta;
+        }
+    }
+    if (rt_clock->active_timers) {
+        rtdelta = (rt_clock->active_timers->expire_time -
+                 qemu_get_clock_ns(rt_clock));
+        if (rtdelta < delta) {
+            delta = rtdelta;
+        }
+    }
+
+    return delta;
+}
+
 static void qemu_rearm_alarm_timer(struct qemu_alarm_timer *t)
 {
-    if (!alarm_has_dynticks(t))
+    int64_t nearest_delta_ns;
+    assert(alarm_has_dynticks(t));
+    if (!rt_clock->active_timers &&
+        !vm_clock->active_timers &&
+        !host_clock->active_timers) {
         return;
-
-    t->rearm(t);
+    }
+    nearest_delta_ns = qemu_next_alarm_deadline();
+    t->rearm(t, nearest_delta_ns);
 }
 
 /* TODO: MIN_TIMER_REARM_NS should be optimized */
@@ -195,83 +153,28 @@
 
 static int mm_start_timer(struct qemu_alarm_timer *t);
 static void mm_stop_timer(struct qemu_alarm_timer *t);
-static void mm_rearm_timer(struct qemu_alarm_timer *t);
+static void mm_rearm_timer(struct qemu_alarm_timer *t, int64_t delta);
 
 static int win32_start_timer(struct qemu_alarm_timer *t);
 static void win32_stop_timer(struct qemu_alarm_timer *t);
-static void win32_rearm_timer(struct qemu_alarm_timer *t);
+static void win32_rearm_timer(struct qemu_alarm_timer *t, int64_t delta);
 
 #else
 
 static int unix_start_timer(struct qemu_alarm_timer *t);
 static void unix_stop_timer(struct qemu_alarm_timer *t);
-static void unix_rearm_timer(struct qemu_alarm_timer *t);
+static void unix_rearm_timer(struct qemu_alarm_timer *t, int64_t delta);
 
 #ifdef __linux__
 
 static int dynticks_start_timer(struct qemu_alarm_timer *t);
 static void dynticks_stop_timer(struct qemu_alarm_timer *t);
-static void dynticks_rearm_timer(struct qemu_alarm_timer *t);
+static void dynticks_rearm_timer(struct qemu_alarm_timer *t, int64_t delta);
 
 #endif /* __linux__ */
 
 #endif /* _WIN32 */
 
-/* Correlation between real and virtual time is always going to be
-   fairly approximate, so ignore small variation.
-   When the guest is idle real and virtual time will be aligned in
-   the IO wait loop.  */
-#define ICOUNT_WOBBLE (get_ticks_per_sec() / 10)
-
-static void icount_adjust(void)
-{
-    int64_t cur_time;
-    int64_t cur_icount;
-    int64_t delta;
-    static int64_t last_delta;
-    /* If the VM is not running, then do nothing.  */
-    if (!runstate_is_running())
-        return;
-
-    cur_time = cpu_get_clock();
-    cur_icount = qemu_get_clock_ns(vm_clock);
-    delta = cur_icount - cur_time;
-    /* FIXME: This is a very crude algorithm, somewhat prone to oscillation.  */
-    if (delta > 0
-        && last_delta + ICOUNT_WOBBLE < delta * 2
-        && icount_time_shift > 0) {
-        /* The guest is getting too far ahead.  Slow time down.  */
-        icount_time_shift--;
-    }
-    if (delta < 0
-        && last_delta - ICOUNT_WOBBLE > delta * 2
-        && icount_time_shift < MAX_ICOUNT_SHIFT) {
-        /* The guest is getting too far behind.  Speed time up.  */
-        icount_time_shift++;
-    }
-    last_delta = delta;
-    qemu_icount_bias = cur_icount - (qemu_icount << icount_time_shift);
-}
-
-static void icount_adjust_rt(void * opaque)
-{
-    qemu_mod_timer(icount_rt_timer,
-                   qemu_get_clock_ms(rt_clock) + 1000);
-    icount_adjust();
-}
-
-static void icount_adjust_vm(void * opaque)
-{
-    qemu_mod_timer(icount_vm_timer,
-                   qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 10);
-    icount_adjust();
-}
-
-int64_t qemu_icount_round(int64_t count)
-{
-    return (count + (1 << icount_time_shift) - 1) >> icount_time_shift;
-}
-
 static struct qemu_alarm_timer alarm_timers[] = {
 #ifndef _WIN32
 #ifdef __linux__
@@ -352,14 +255,10 @@
     }
 }
 
-#define QEMU_NUM_CLOCKS 3
-
 QEMUClock *rt_clock;
 QEMUClock *vm_clock;
 QEMUClock *host_clock;
 
-static QEMUTimer *active_timers[QEMU_NUM_CLOCKS];
-
 static QEMUClock *qemu_new_clock(int type)
 {
     QEMUClock *clock;
@@ -367,101 +266,43 @@
     clock = g_malloc0(sizeof(QEMUClock));
     clock->type = type;
     clock->enabled = 1;
+    clock->last = INT64_MIN;
     notifier_list_init(&clock->reset_notifiers);
-    /* required to detect & report backward jumps */
-    if (type == QEMU_CLOCK_HOST) {
-        clock->last = get_clock_realtime();
-    }
     return clock;
 }
 
 void qemu_clock_enable(QEMUClock *clock, int enabled)
 {
+    bool old = clock->enabled;
     clock->enabled = enabled;
+    if (enabled && !old) {
+        qemu_rearm_alarm_timer(alarm_timer);
+    }
 }
 
-static int64_t vm_clock_warp_start;
-
-static void icount_warp_rt(void *opaque)
+int64_t qemu_clock_has_timers(QEMUClock *clock)
 {
-    if (vm_clock_warp_start == -1) {
-        return;
-    }
-
-    if (runstate_is_running()) {
-        int64_t clock = qemu_get_clock_ns(rt_clock);
-        int64_t warp_delta = clock - vm_clock_warp_start;
-        if (use_icount == 1) {
-            qemu_icount_bias += warp_delta;
-        } else {
-            /*
-             * In adaptive mode, do not let the vm_clock run too
-             * far ahead of real time.
-             */
-            int64_t cur_time = cpu_get_clock();
-            int64_t cur_icount = qemu_get_clock_ns(vm_clock);
-            int64_t delta = cur_time - cur_icount;
-            qemu_icount_bias += MIN(warp_delta, delta);
-        }
-        if (qemu_timer_expired(active_timers[QEMU_CLOCK_VIRTUAL],
-                               qemu_get_clock_ns(vm_clock))) {
-            qemu_notify_event();
-        }
-    }
-    vm_clock_warp_start = -1;
+    return !!clock->active_timers;
 }
 
-void qemu_clock_warp(QEMUClock *clock)
+int64_t qemu_clock_expired(QEMUClock *clock)
 {
-    int64_t deadline;
+    return (clock->active_timers &&
+            clock->active_timers->expire_time < qemu_get_clock_ns(clock));
+}
 
-    if (!clock->warp_timer) {
-        return;
+int64_t qemu_clock_deadline(QEMUClock *clock)
+{
+    /* To avoid problems with overflow limit this to 2^32.  */
+    int64_t delta = INT32_MAX;
+
+    if (clock->active_timers) {
+        delta = clock->active_timers->expire_time - qemu_get_clock_ns(clock);
     }
-
-    /*
-     * There are too many global variables to make the "warp" behavior
-     * applicable to other clocks.  But a clock argument removes the
-     * need for if statements all over the place.
-     */
-    assert(clock == vm_clock);
-
-    /*
-     * If the CPUs have been sleeping, advance the vm_clock timer now.  This
-     * ensures that the deadline for the timer is computed correctly below.
-     * This also makes sure that the insn counter is synchronized before the
-     * CPU starts running, in case the CPU is woken by an event other than
-     * the earliest vm_clock timer.
-     */
-    icount_warp_rt(NULL);
-    if (!all_cpu_threads_idle() || !active_timers[clock->type]) {
-        qemu_del_timer(clock->warp_timer);
-        return;
+    if (delta < 0) {
+        delta = 0;
     }
-
-    vm_clock_warp_start = qemu_get_clock_ns(rt_clock);
-    deadline = qemu_next_icount_deadline();
-    if (deadline > 0) {
-        /*
-         * Ensure the vm_clock proceeds even when the virtual CPU goes to
-         * sleep.  Otherwise, the CPU might be waiting for a future timer
-         * interrupt to wake it up, but the interrupt never comes because
-         * the vCPU isn't running any insns and thus doesn't advance the
-         * vm_clock.
-         *
-         * An extreme solution for this problem would be to never let VCPUs
-         * sleep in icount mode if there is a pending vm_clock timer; rather
-         * time could just advance to the next vm_clock event.  Instead, we
-         * do stop VCPUs and only advance vm_clock after some "real" time,
-         * (related to the time left until the next event) has passed.  This
-         * rt_clock timer will do this.  This avoids that the warps are too
-         * visible externally---for example, you will not be sending network
-         * packets continously instead of every 100ms.
-         */
-        qemu_mod_timer(clock->warp_timer, vm_clock_warp_start + deadline);
-    } else {
-        qemu_notify_event();
-    }
+    return delta;
 }
 
 QEMUTimer *qemu_new_timer(QEMUClock *clock, int scale,
@@ -489,7 +330,7 @@
 
     /* NOTE: this code must be signal safe because
        qemu_timer_expired() can be called from a signal. */
-    pt = &active_timers[ts->clock->type];
+    pt = &ts->clock->active_timers;
     for(;;) {
         t = *pt;
         if (!t)
@@ -504,7 +345,7 @@
 
 /* modify the current timer so that it will be fired when current_time
    >= expire_time. The corresponding callback will be called. */
-static void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time)
+void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time)
 {
     QEMUTimer **pt, *t;
 
@@ -513,7 +354,7 @@
     /* add the timer in the sorted list */
     /* NOTE: this code must be signal safe because
        qemu_timer_expired() can be called from a signal. */
-    pt = &active_timers[ts->clock->type];
+    pt = &ts->clock->active_timers;
     for(;;) {
         t = *pt;
         if (!qemu_timer_expired_ns(t, expire_time)) {
@@ -526,7 +367,7 @@
     *pt = ts;
 
     /* Rearm if necessary  */
-    if (pt == &active_timers[ts->clock->type]) {
+    if (pt == &ts->clock->active_timers) {
         if (!alarm_timer->pending) {
             qemu_rearm_alarm_timer(alarm_timer);
         }
@@ -538,8 +379,6 @@
     }
 }
 
-/* modify the current timer so that it will be fired when current_time
-   >= expire_time. The corresponding callback will be called. */
 void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time)
 {
     qemu_mod_timer_ns(ts, expire_time * ts->scale);
@@ -548,7 +387,7 @@
 int qemu_timer_pending(QEMUTimer *ts)
 {
     QEMUTimer *t;
-    for(t = active_timers[ts->clock->type]; t != NULL; t = t->next) {
+    for (t = ts->clock->active_timers; t != NULL; t = t->next) {
         if (t == ts)
             return 1;
     }
@@ -569,7 +408,7 @@
         return;
 
     current_time = qemu_get_clock_ns(clock);
-    ptimer_head = &active_timers[clock->type];
+    ptimer_head = &clock->active_timers;
     for(;;) {
         ts = *ptimer_head;
         if (!qemu_timer_expired_ns(ts, current_time)) {
@@ -624,79 +463,11 @@
     rt_clock = qemu_new_clock(QEMU_CLOCK_REALTIME);
     vm_clock = qemu_new_clock(QEMU_CLOCK_VIRTUAL);
     host_clock = qemu_new_clock(QEMU_CLOCK_HOST);
-
-    rtc_clock = host_clock;
 }
 
-/* save a timer */
-void qemu_put_timer(QEMUFile *f, QEMUTimer *ts)
+uint64_t qemu_timer_expire_time_ns(QEMUTimer *ts)
 {
-    uint64_t expire_time;
-
-    if (qemu_timer_pending(ts)) {
-        expire_time = ts->expire_time;
-    } else {
-        expire_time = -1;
-    }
-    qemu_put_be64(f, expire_time);
-}
-
-void qemu_get_timer(QEMUFile *f, QEMUTimer *ts)
-{
-    uint64_t expire_time;
-
-    expire_time = qemu_get_be64(f);
-    if (expire_time != -1) {
-        qemu_mod_timer_ns(ts, expire_time);
-    } else {
-        qemu_del_timer(ts);
-    }
-}
-
-static const VMStateDescription vmstate_timers = {
-    .name = "timer",
-    .version_id = 2,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField []) {
-        VMSTATE_INT64(cpu_ticks_offset, TimersState),
-        VMSTATE_INT64(dummy, TimersState),
-        VMSTATE_INT64_V(cpu_clock_offset, TimersState, 2),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-void configure_icount(const char *option)
-{
-    vmstate_register(NULL, 0, &vmstate_timers, &timers_state);
-    if (!option)
-        return;
-
-    vm_clock->warp_timer = qemu_new_timer_ns(rt_clock, icount_warp_rt, NULL);
-
-    if (strcmp(option, "auto") != 0) {
-        icount_time_shift = strtol(option, NULL, 0);
-        use_icount = 1;
-        return;
-    }
-
-    use_icount = 2;
-
-    /* 125MIPS seems a reasonable initial guess at the guest speed.
-       It will be corrected fairly quickly anyway.  */
-    icount_time_shift = 3;
-
-    /* Have both realtime and virtual time triggers for speed adjustment.
-       The realtime trigger catches emulated time passing too slowly,
-       the virtual time trigger catches emulated time passing too fast.
-       Realtime triggers occur even when idle, so use them less frequently
-       than VM triggers.  */
-    icount_rt_timer = qemu_new_timer_ms(rt_clock, icount_adjust_rt, NULL);
-    qemu_mod_timer(icount_rt_timer,
-                   qemu_get_clock_ms(rt_clock) + 1000);
-    icount_vm_timer = qemu_new_timer_ns(vm_clock, icount_adjust_vm, NULL);
-    qemu_mod_timer(icount_vm_timer,
-                   qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 10);
+    return qemu_timer_pending(ts) ? ts->expire_time : -1;
 }
 
 void qemu_run_all_timers(void)
@@ -710,16 +481,11 @@
     }
 
     /* vm time timers */
-    if (runstate_is_running()) {
-        qemu_run_timers(vm_clock);
-    }
-
+    qemu_run_timers(vm_clock);
     qemu_run_timers(rt_clock);
     qemu_run_timers(host_clock);
 }
 
-static int64_t qemu_next_alarm_deadline(void);
-
 #ifdef _WIN32
 static void CALLBACK host_alarm_handler(PVOID lpParam, BOOLEAN unused)
 #else
@@ -767,50 +533,6 @@
     }
 }
 
-int64_t qemu_next_icount_deadline(void)
-{
-    /* To avoid problems with overflow limit this to 2^32.  */
-    int64_t delta = INT32_MAX;
-
-    assert(use_icount);
-    if (active_timers[QEMU_CLOCK_VIRTUAL]) {
-        delta = active_timers[QEMU_CLOCK_VIRTUAL]->expire_time -
-                     qemu_get_clock_ns(vm_clock);
-    }
-
-    if (delta < 0)
-        delta = 0;
-
-    return delta;
-}
-
-static int64_t qemu_next_alarm_deadline(void)
-{
-    int64_t delta;
-    int64_t rtdelta;
-
-    if (!use_icount && active_timers[QEMU_CLOCK_VIRTUAL]) {
-        delta = active_timers[QEMU_CLOCK_VIRTUAL]->expire_time -
-                     qemu_get_clock_ns(vm_clock);
-    } else {
-        delta = INT32_MAX;
-    }
-    if (active_timers[QEMU_CLOCK_HOST]) {
-        int64_t hdelta = active_timers[QEMU_CLOCK_HOST]->expire_time -
-                 qemu_get_clock_ns(host_clock);
-        if (hdelta < delta)
-            delta = hdelta;
-    }
-    if (active_timers[QEMU_CLOCK_REALTIME]) {
-        rtdelta = (active_timers[QEMU_CLOCK_REALTIME]->expire_time -
-                 qemu_get_clock_ns(rt_clock));
-        if (rtdelta < delta)
-            delta = rtdelta;
-    }
-
-    return delta;
-}
-
 #if defined(__linux__)
 
 #include "compatfd.h"
@@ -863,20 +585,13 @@
     timer_delete(host_timer);
 }
 
-static void dynticks_rearm_timer(struct qemu_alarm_timer *t)
+static void dynticks_rearm_timer(struct qemu_alarm_timer *t,
+                                 int64_t nearest_delta_ns)
 {
     timer_t host_timer = t->timer;
     struct itimerspec timeout;
-    int64_t nearest_delta_ns = INT64_MAX;
     int64_t current_ns;
 
-    assert(alarm_has_dynticks(t));
-    if (!active_timers[QEMU_CLOCK_REALTIME] &&
-        !active_timers[QEMU_CLOCK_VIRTUAL] &&
-        !active_timers[QEMU_CLOCK_HOST])
-        return;
-
-    nearest_delta_ns = qemu_next_alarm_deadline();
     if (nearest_delta_ns < MIN_TIMER_REARM_NS)
         nearest_delta_ns = MIN_TIMER_REARM_NS;
 
@@ -918,19 +633,12 @@
     return 0;
 }
 
-static void unix_rearm_timer(struct qemu_alarm_timer *t)
+static void unix_rearm_timer(struct qemu_alarm_timer *t,
+                             int64_t nearest_delta_ns)
 {
     struct itimerval itv;
-    int64_t nearest_delta_ns = INT64_MAX;
     int err;
 
-    assert(alarm_has_dynticks(t));
-    if (!active_timers[QEMU_CLOCK_REALTIME] &&
-        !active_timers[QEMU_CLOCK_VIRTUAL] &&
-        !active_timers[QEMU_CLOCK_HOST])
-        return;
-
-    nearest_delta_ns = qemu_next_alarm_deadline();
     if (nearest_delta_ns < MIN_TIMER_REARM_NS)
         nearest_delta_ns = MIN_TIMER_REARM_NS;
 
@@ -1017,23 +725,14 @@
     timeEndPeriod(mm_period);
 }
 
-static void mm_rearm_timer(struct qemu_alarm_timer *t)
+static void mm_rearm_timer(struct qemu_alarm_timer *t, int64_t delta)
 {
-    int nearest_delta_ms;
-
-    assert(alarm_has_dynticks(t));
-    if (!active_timers[QEMU_CLOCK_REALTIME] &&
-        !active_timers[QEMU_CLOCK_VIRTUAL] &&
-        !active_timers[QEMU_CLOCK_HOST]) {
-        return;
-    }
-
-    timeKillEvent(mm_timer);
-
-    nearest_delta_ms = (qemu_next_alarm_deadline() + 999999) / 1000000;
+    int nearest_delta_ms = (delta + 999999) / 1000000;
     if (nearest_delta_ms < 1) {
         nearest_delta_ms = 1;
     }
+
+    timeKillEvent(mm_timer);
     mm_timer = timeSetEvent(nearest_delta_ms,
                             mm_period,
                             mm_alarm_handler,
@@ -1085,19 +784,14 @@
     }
 }
 
-static void win32_rearm_timer(struct qemu_alarm_timer *t)
+static void win32_rearm_timer(struct qemu_alarm_timer *t,
+                              int64_t nearest_delta_ns)
 {
     HANDLE hTimer = t->timer;
     int nearest_delta_ms;
     BOOLEAN success;
 
-    assert(alarm_has_dynticks(t));
-    if (!active_timers[QEMU_CLOCK_REALTIME] &&
-        !active_timers[QEMU_CLOCK_VIRTUAL] &&
-        !active_timers[QEMU_CLOCK_HOST])
-        return;
-
-    nearest_delta_ms = (qemu_next_alarm_deadline() + 999999) / 1000000;
+    nearest_delta_ms = (nearest_delta_ns + 999999) / 1000000;
     if (nearest_delta_ms < 1) {
         nearest_delta_ms = 1;
     }
@@ -1116,11 +810,11 @@
 
 #endif /* _WIN32 */
 
-static void alarm_timer_on_change_state_rearm(void *opaque, int running,
-                                              RunState state)
+static void quit_timers(void)
 {
-    if (running)
-        qemu_rearm_alarm_timer((struct qemu_alarm_timer *) opaque);
+    struct qemu_alarm_timer *t = alarm_timer;
+    alarm_timer = NULL;
+    t->stop(t);
 }
 
 int init_timer_alarm(void)
@@ -1142,9 +836,9 @@
     }
 
     /* first event is at time 0 */
+    atexit(quit_timers);
     t->pending = 1;
     alarm_timer = t;
-    qemu_add_vm_change_state_handler(alarm_timer_on_change_state_rearm, t);
 
     return 0;
 
@@ -1152,13 +846,6 @@
     return err;
 }
 
-void quit_timers(void)
-{
-    struct qemu_alarm_timer *t = alarm_timer;
-    alarm_timer = NULL;
-    t->stop(t);
-}
-
 int qemu_calculate_timeout(void)
 {
     return 1000;
diff --git a/qemu-timer.h b/qemu-timer.h
index 0a43469..67ca72e 100644
--- a/qemu-timer.h
+++ b/qemu-timer.h
@@ -2,6 +2,7 @@
 #define QEMU_TIMER_H
 
 #include "qemu-common.h"
+#include "main-loop.h"
 #include "notify.h"
 #include <time.h>
 #include <sys/time.h>
@@ -38,6 +39,9 @@
 extern QEMUClock *host_clock;
 
 int64_t qemu_get_clock_ns(QEMUClock *clock);
+int64_t qemu_clock_has_timers(QEMUClock *clock);
+int64_t qemu_clock_expired(QEMUClock *clock);
+int64_t qemu_clock_deadline(QEMUClock *clock);
 void qemu_clock_enable(QEMUClock *clock, int enabled);
 void qemu_clock_warp(QEMUClock *clock);
 
@@ -49,19 +53,18 @@
                           QEMUTimerCB *cb, void *opaque);
 void qemu_free_timer(QEMUTimer *ts);
 void qemu_del_timer(QEMUTimer *ts);
+void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time);
 void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time);
 int qemu_timer_pending(QEMUTimer *ts);
 int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time);
+uint64_t qemu_timer_expire_time_ns(QEMUTimer *ts);
 
 void qemu_run_all_timers(void);
 int qemu_alarm_pending(void);
-int64_t qemu_next_icount_deadline(void);
 void configure_alarms(char const *opt);
-void configure_icount(const char *option);
 int qemu_calculate_timeout(void);
 void init_clocks(void);
 int init_timer_alarm(void);
-void quit_timers(void);
 
 int64_t cpu_get_ticks(void);
 void cpu_enable_ticks(void);
@@ -150,12 +153,8 @@
 void ptimer_stop(ptimer_state *s);
 
 /* icount */
-int64_t qemu_icount_round(int64_t count);
-extern int64_t qemu_icount;
-extern int use_icount;
-extern int icount_time_shift;
-extern int64_t qemu_icount_bias;
 int64_t cpu_get_icount(void);
+int64_t cpu_get_clock(void);
 
 /*******************************************/
 /* host CPU ticks (if available) */
@@ -311,22 +310,6 @@
 }
 #endif
 
-#ifdef NEED_CPU_H
-/* Deterministic execution requires that IO only be performed on the last
-   instruction of a TB so that interrupts take effect immediately.  */
-static inline int can_do_io(CPUState *env)
-{
-    if (!use_icount)
-        return 1;
-
-    /* If not executing code then assume we are ok.  */
-    if (!env->current_tb)
-        return 1;
-
-    return env->can_do_io != 0;
-}
-#endif
-
 #ifdef CONFIG_PROFILER
 static inline int64_t profile_getclock(void)
 {
diff --git a/qemu_socket.h b/qemu_socket.h
index 180e4db..9e32fac 100644
--- a/qemu_socket.h
+++ b/qemu_socket.h
@@ -35,6 +35,7 @@
 /* misc helpers */
 int qemu_socket(int domain, int type, int protocol);
 int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
+void socket_set_block(int fd);
 void socket_set_nonblock(int fd);
 int send_all(int fd, const void *buf, int len1);
 
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 9c11e87..4328e8b 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -710,10 +710,10 @@
 
 Example:
 
--> { "execute": "blockdev-snapshot", "arguments": { "device": "ide-hd0",
-                                                    "snapshot-file":
-                                                    "/some/place/my-image",
-                                                    "format": "qcow2" } }
+-> { "execute": "blockdev-snapshot-sync", "arguments": { "device": "ide-hd0",
+                                                         "snapshot-file":
+                                                        "/some/place/my-image",
+                                                        "format": "qcow2" } }
 <- { "return": {} }
 
 EQMP
diff --git a/savevm.c b/savevm.c
index bf4d0e7..f01838f 100644
--- a/savevm.c
+++ b/savevm.c
@@ -81,6 +81,7 @@
 #include "migration.h"
 #include "qemu_socket.h"
 #include "qemu-queue.h"
+#include "qemu-timer.h"
 #include "cpus.h"
 
 #define SELF_ANNOUNCE_ROUNDS 5
@@ -173,7 +174,7 @@
     int buf_size; /* 0 when writing */
     uint8_t buf[IO_BUF_SIZE];
 
-    int has_error;
+    int last_error;
 };
 
 typedef struct QEMUFileStdio
@@ -425,14 +426,14 @@
     return f;
 }
 
-int qemu_file_has_error(QEMUFile *f)
+int qemu_file_get_error(QEMUFile *f)
 {
-    return f->has_error;
+    return f->last_error;
 }
 
-void qemu_file_set_error(QEMUFile *f)
+void qemu_file_set_error(QEMUFile *f, int ret)
 {
-    f->has_error = 1;
+    f->last_error = ret;
 }
 
 void qemu_fflush(QEMUFile *f)
@@ -447,7 +448,7 @@
         if (len > 0)
             f->buf_offset += f->buf_index;
         else
-            f->has_error = 1;
+            f->last_error = -EINVAL;
         f->buf_index = 0;
     }
 }
@@ -455,6 +456,7 @@
 static void qemu_fill_buffer(QEMUFile *f)
 {
     int len;
+    int pending;
 
     if (!f->get_buffer)
         return;
@@ -462,13 +464,20 @@
     if (f->is_write)
         abort();
 
-    len = f->get_buffer(f->opaque, f->buf, f->buf_offset, IO_BUF_SIZE);
+    pending = f->buf_size - f->buf_index;
+    if (pending > 0) {
+        memmove(f->buf, f->buf + f->buf_index, pending);
+    }
+    f->buf_index = 0;
+    f->buf_size = pending;
+
+    len = f->get_buffer(f->opaque, f->buf + pending, f->buf_offset,
+                        IO_BUF_SIZE - pending);
     if (len > 0) {
-        f->buf_index = 0;
-        f->buf_size = len;
+        f->buf_size += len;
         f->buf_offset += len;
     } else if (len != -EAGAIN)
-        f->has_error = 1;
+        f->last_error = len;
 }
 
 int qemu_fclose(QEMUFile *f)
@@ -490,13 +499,13 @@
 {
     int l;
 
-    if (!f->has_error && f->is_write == 0 && f->buf_index > 0) {
+    if (!f->last_error && f->is_write == 0 && f->buf_index > 0) {
         fprintf(stderr,
                 "Attempted to write to buffer while read buffer is not empty\n");
         abort();
     }
 
-    while (!f->has_error && size > 0) {
+    while (!f->last_error && size > 0) {
         l = IO_BUF_SIZE - f->buf_index;
         if (l > size)
             l = size;
@@ -512,7 +521,7 @@
 
 void qemu_put_byte(QEMUFile *f, int v)
 {
-    if (!f->has_error && f->is_write == 0 && f->buf_index > 0) {
+    if (!f->last_error && f->is_write == 0 && f->buf_index > 0) {
         fprintf(stderr,
                 "Attempted to write to buffer while read buffer is not empty\n");
         abort();
@@ -524,56 +533,86 @@
         qemu_fflush(f);
 }
 
-int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size1)
+static void qemu_file_skip(QEMUFile *f, int size)
 {
-    int size, l;
-
-    if (f->is_write)
-        abort();
-
-    size = size1;
-    while (size > 0) {
-        l = f->buf_size - f->buf_index;
-        if (l == 0) {
-            qemu_fill_buffer(f);
-            l = f->buf_size - f->buf_index;
-            if (l == 0)
-                break;
-        }
-        if (l > size)
-            l = size;
-        memcpy(buf, f->buf + f->buf_index, l);
-        f->buf_index += l;
-        buf += l;
-        size -= l;
+    if (f->buf_index + size <= f->buf_size) {
+        f->buf_index += size;
     }
-    return size1 - size;
 }
 
-static int qemu_peek_byte(QEMUFile *f)
+static int qemu_peek_buffer(QEMUFile *f, uint8_t *buf, int size, size_t offset)
 {
-    if (f->is_write)
-        abort();
+    int pending;
+    int index;
 
-    if (f->buf_index >= f->buf_size) {
-        qemu_fill_buffer(f);
-        if (f->buf_index >= f->buf_size)
-            return 0;
+    if (f->is_write) {
+        abort();
     }
-    return f->buf[f->buf_index];
+
+    index = f->buf_index + offset;
+    pending = f->buf_size - index;
+    if (pending < size) {
+        qemu_fill_buffer(f);
+        index = f->buf_index + offset;
+        pending = f->buf_size - index;
+    }
+
+    if (pending <= 0) {
+        return 0;
+    }
+    if (size > pending) {
+        size = pending;
+    }
+
+    memcpy(buf, f->buf + index, size);
+    return size;
+}
+
+int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size)
+{
+    int pending = size;
+    int done = 0;
+
+    while (pending > 0) {
+        int res;
+
+        res = qemu_peek_buffer(f, buf, pending, 0);
+        if (res == 0) {
+            return done;
+        }
+        qemu_file_skip(f, res);
+        buf += res;
+        pending -= res;
+        done += res;
+    }
+    return done;
+}
+
+static int qemu_peek_byte(QEMUFile *f, int offset)
+{
+    int index = f->buf_index + offset;
+
+    if (f->is_write) {
+        abort();
+    }
+
+    if (index >= f->buf_size) {
+        qemu_fill_buffer(f);
+        index = f->buf_index + offset;
+        if (index >= f->buf_size) {
+            return 0;
+        }
+    }
+    return f->buf[index];
 }
 
 int qemu_get_byte(QEMUFile *f)
 {
-    if (f->is_write)
-        abort();
+    int result;
 
-    if (f->buf_index >= f->buf_size) {
-        qemu_fill_buffer(f);
-        if (f->buf_index >= f->buf_size)
-            return 0;
-    }
-    return f->buf[f->buf_index++];
+    result = qemu_peek_byte(f, 0);
+    qemu_file_skip(f, 1);
+    return result;
 }
 
 int64_t qemu_ftell(QEMUFile *f)
@@ -674,6 +713,30 @@
     return v;
 }
 
+
+/* timer */
+
+void qemu_put_timer(QEMUFile *f, QEMUTimer *ts)
+{
+    uint64_t expire_time;
+
+    expire_time = qemu_timer_expire_time_ns(ts);
+    qemu_put_be64(f, expire_time);
+}
+
+void qemu_get_timer(QEMUFile *f, QEMUTimer *ts)
+{
+    uint64_t expire_time;
+
+    expire_time = qemu_get_be64(f);
+    if (expire_time != -1) {
+        qemu_mod_timer_ns(ts, expire_time);
+    } else {
+        qemu_del_timer(ts);
+    }
+}
+
+
 /* bool */
 
 static int get_bool(QEMUFile *f, void *pv, size_t size)
@@ -1466,6 +1529,7 @@
                             int shared)
 {
     SaveStateEntry *se;
+    int ret;
 
     QTAILQ_FOREACH(se, &savevm_handlers, entry) {
         if(se->set_params == NULL) {
@@ -1495,17 +1559,27 @@
         qemu_put_be32(f, se->instance_id);
         qemu_put_be32(f, se->version_id);
 
-        se->save_live_state(mon, f, QEMU_VM_SECTION_START, se->opaque);
+        ret = se->save_live_state(mon, f, QEMU_VM_SECTION_START, se->opaque);
+        if (ret < 0) {
+            qemu_savevm_state_cancel(mon, f);
+            return ret;
+        }
     }
-
-    if (qemu_file_has_error(f)) {
+    ret = qemu_file_get_error(f);
+    if (ret != 0) {
         qemu_savevm_state_cancel(mon, f);
-        return -EIO;
     }
 
-    return 0;
+    return ret;
+
 }
 
+/*
+ * this funtion has three return values:
+ *   negative: there was one error, and we have -errno.
+ *   0 : We haven't finished, caller have to go again
+ *   1 : We have finished, we can go to complete phase
+ */
 int qemu_savevm_state_iterate(Monitor *mon, QEMUFile *f)
 {
     SaveStateEntry *se;
@@ -1520,7 +1594,7 @@
         qemu_put_be32(f, se->section_id);
 
         ret = se->save_live_state(mon, f, QEMU_VM_SECTION_PART, se->opaque);
-        if (!ret) {
+        if (ret <= 0) {
             /* Do not proceed to the next vmstate before this one reported
                completion of the current stage. This serializes the migration
                and reduces the probability that a faster changing state is
@@ -1528,21 +1602,20 @@
             break;
         }
     }
-
-    if (ret)
-        return 1;
-
-    if (qemu_file_has_error(f)) {
-        qemu_savevm_state_cancel(mon, f);
-        return -EIO;
+    if (ret != 0) {
+        return ret;
     }
-
-    return 0;
+    ret = qemu_file_get_error(f);
+    if (ret != 0) {
+        qemu_savevm_state_cancel(mon, f);
+    }
+    return ret;
 }
 
 int qemu_savevm_state_complete(Monitor *mon, QEMUFile *f)
 {
     SaveStateEntry *se;
+    int ret;
 
     cpu_synchronize_all_states();
 
@@ -1554,7 +1627,10 @@
         qemu_put_byte(f, QEMU_VM_SECTION_END);
         qemu_put_be32(f, se->section_id);
 
-        se->save_live_state(mon, f, QEMU_VM_SECTION_END, se->opaque);
+        ret = se->save_live_state(mon, f, QEMU_VM_SECTION_END, se->opaque);
+        if (ret < 0) {
+            return ret;
+        }
     }
 
     QTAILQ_FOREACH(se, &savevm_handlers, entry) {
@@ -1580,10 +1656,7 @@
 
     qemu_put_byte(f, QEMU_VM_EOF);
 
-    if (qemu_file_has_error(f))
-        return -EIO;
-
-    return 0;
+    return qemu_file_get_error(f);
 }
 
 void qemu_savevm_state_cancel(Monitor *mon, QEMUFile *f)
@@ -1599,12 +1672,8 @@
 
 static int qemu_savevm_state(Monitor *mon, QEMUFile *f)
 {
-    int saved_vm_running;
     int ret;
 
-    saved_vm_running = runstate_is_running();
-    vm_stop(RUN_STATE_SAVE_VM);
-
     if (qemu_savevm_state_blocked(mon)) {
         ret = -EINVAL;
         goto out;
@@ -1623,11 +1692,9 @@
     ret = qemu_savevm_state_complete(mon, f);
 
 out:
-    if (qemu_file_has_error(f))
-        ret = -EIO;
-
-    if (!ret && saved_vm_running)
-        vm_start();
+    if (ret == 0) {
+        ret = qemu_file_get_error(f);
+    }
 
     return ret;
 }
@@ -1666,29 +1733,36 @@
 static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
                                    void *opaque)
 {
-    const VMStateSubsection *sub = vmsd->subsections;
-
-    if (!sub || !sub->needed) {
-        return 0;
-    }
-
-    while (qemu_peek_byte(f) == QEMU_VM_SUBSECTION) {
+    while (qemu_peek_byte(f, 0) == QEMU_VM_SUBSECTION) {
         char idstr[256];
         int ret;
-        uint8_t version_id, len;
+        uint8_t version_id, len, size;
         const VMStateDescription *sub_vmsd;
 
-        qemu_get_byte(f); /* subsection */
-        len = qemu_get_byte(f);
-        qemu_get_buffer(f, (uint8_t *)idstr, len);
-        idstr[len] = 0;
-        version_id = qemu_get_be32(f);
+        len = qemu_peek_byte(f, 1);
+        if (len < strlen(vmsd->name) + 1) {
+            /* subsection name has be be "section_name/a" */
+            return 0;
+        }
+        size = qemu_peek_buffer(f, (uint8_t *)idstr, len, 2);
+        if (size != len) {
+            return 0;
+        }
+        idstr[size] = 0;
 
-        sub_vmsd = vmstate_get_subsection(sub, idstr);
+        if (strncmp(vmsd->name, idstr, strlen(vmsd->name)) != 0) {
+            /* it don't have a valid subsection name */
+            return 0;
+        }
+        sub_vmsd = vmstate_get_subsection(vmsd->subsections, idstr);
         if (sub_vmsd == NULL) {
             return -ENOENT;
         }
-        assert(!sub_vmsd->subsections);
+        qemu_file_skip(f, 1); /* subsection */
+        qemu_file_skip(f, 1); /* len */
+        qemu_file_skip(f, len); /* idstr */
+        version_id = qemu_get_be32(f);
+
         ret = vmstate_load_state(f, sub_vmsd, opaque, version_id);
         if (ret) {
             return ret;
@@ -1712,7 +1786,6 @@
             qemu_put_byte(f, len);
             qemu_put_buffer(f, (uint8_t *)vmsd->name, len);
             qemu_put_be32(f, vmsd->version_id);
-            assert(!vmsd->subsections);
             vmstate_save_state(f, vmsd, opaque);
         }
         sub++;
@@ -1838,8 +1911,9 @@
         g_free(le);
     }
 
-    if (qemu_file_has_error(f))
-        ret = -EIO;
+    if (ret == 0) {
+        ret = qemu_file_get_error(f);
+    }
 
     return ret;
 }
diff --git a/scripts/analyse-9p-simpletrace.py b/scripts/analyse-9p-simpletrace.py
new file mode 100755
index 0000000..4358d6b
--- /dev/null
+++ b/scripts/analyse-9p-simpletrace.py
@@ -0,0 +1,142 @@
+#!/usr/bin/env python
+# Pretty print 9p simpletrace log
+# Usage: ./analyse-9p-simpletrace <trace-events> <trace-pid>
+#
+# Author: Harsh Prateek Bora
+
+import simpletrace
+
+class VirtFSRequestTracker(simpletrace.Analyzer):
+	def begin(self):
+		print "Pretty printing 9p simpletrace log ..."
+
+        def complete_pdu(self, tag, id, err):
+                print "ERROR (tag =", tag, ", id =", id, ",err =", err, ")"
+
+        def v9fs_version(self, tag, id, msize, version):
+                print "TVERSION (tag =", tag, ", msize =", msize, ", version =", version, ")"
+
+        def v9fs_version_return(self, tag, id, msize, version):
+                print "RVERSION (tag =", tag, ", msize =", msize, ", version =", version, ")"
+
+        def v9fs_attach(self, tag, id, fid, afid, uname, aname):
+                print "TATTACH (tag =", tag, ", fid =", fid, ", afid =", afid, ", uname =", uname, ", aname =", aname, ")"
+
+	def v9fs_attach_return(self, tag, id, type, verison, path):
+		print "RATTACH (tag =", tag, ", qid={type =", type, ", version =", version, ", path =", path, "})"
+
+	def v9fs_stat(self, tag, id, fid):
+		print "TSTAT (tag =", tag, ", fid =", fid, ")"
+
+	def v9fs_stat_return(self, tag, id, mode, atime, mtime, length):
+		print "RSTAT (tag =", tag, ", mode =", mode, ", atime =", atime, ", mtime =", mtime, ", length =", length, ")"
+
+	def v9fs_getattr(self, tag, id, fid, request_mask):
+		print "TGETATTR (tag =", tag, ", fid =", fid, ", request_mask =", hex(request_mask), ")"
+
+	def v9fs_getattr_return(self, tag, id, result_mask, mode, uid, gid):
+		print "RGETATTR (tag =", tag, ", result_mask =", hex(result_mask), ", mode =", oct(mode), ", uid =", uid, ", gid =", gid, ")"
+
+	def v9fs_walk(self, tag, id, fid, newfid, nwnames):
+		print "TWALK (tag =", tag, ", fid =", fid, ", newfid =", newfid, ", nwnames =", nwnames, ")"
+
+	def v9fs_walk_return(self, tag, id, nwnames, qids):
+		print "RWALK (tag =", tag, ", nwnames =", nwnames, ", qids =", hex(qids), ")"
+
+	def v9fs_open(self, tag, id, fid, mode):
+		print "TOPEN (tag =", tag, ", fid =", fid, ", mode =", oct(mode), ")"
+
+	def v9fs_open_return(self, tag, id, type, version, path, iounit):
+		print "ROPEN (tag =", tag,  ", qid={type =", type, ", version =", version, ", path =", path, "}, iounit =", iounit, ")"
+
+	def v9fs_lcreate(self, tag, id, dfid, flags, mode, gid):
+		print "TLCREATE (tag =", tag, ", dfid =", dfid, ", flags =", oct(flags), ", mode =", oct(mode), ", gid =", gid, ")"
+
+	def v9fs_lcreate_return(self, id, type, version, path, iounit):
+		print "RLCREATE (tag =", tag,  ", qid={type =", type, ", version =", version, ", path =", path, "}, iounit =", iounit, ")"
+
+	def v9fs_fsync(self, tag, id, fid, datasync):
+		print "TFSYNC (tag =", tag, ", fid =", fid, ", datasync =", datasync, ")"
+
+	def v9fs_clunk(self, tag, id, fid):
+		print "TCLUNK (tag =", tag, ", fid =", fid, ")"
+
+	def v9fs_read(self, tag, id, fid, off, max_count):
+		print "TREAD (tag =", tag, ", fid =", fid, ", off =", off, ", max_count =", max_count, ")"
+
+	def v9fs_read_return(self, tag, id, count, err):
+		print "RREAD (tag =", tag, ", count =", count, ", err =", err, ")"
+
+	def v9fs_readdir(self, tag, id, fid, offset, max_count):
+		print "TREADDIR (tag =", tag, ", fid =", fid, ", offset =", offset, ", max_count =", max_count, ")"
+
+	def v9fs_readdir_return(self, tag, id, count, retval):
+		print "RREADDIR (tag =", tag, ", count =", count, ", retval =", retval, ")"
+
+	def v9fs_write(self, tag, id, fid, off, count, cnt):
+		print "TWRITE (tag =", tag, ", fid =", fid, ", off =", off, ", count =", count, ", cnt =", cnt, ")"
+
+	def v9fs_write_return(self, tag, id, total, err):
+		print "RWRITE (tag =", tag, ", total =", total, ", err =", err, ")"
+
+	def v9fs_create(self, tag, id, fid, perm, name, mode):
+		print "TCREATE (tag =", tag, ", fid =", fid, ", perm =", oct(perm), ", name =", name, ", mode =", oct(mode), ")"
+
+	def v9fs_create_return(self, tag, id, type, verison, path, iounit):
+		print "RCREATE (tag =", tag,  ", qid={type =", type, ", version =", version, ", path =", path, "}, iounit =", iounit, ")"
+
+	def v9fs_symlink(self, tag, id, fid, name, symname, gid):
+		print "TSYMLINK (tag =", tag, ", fid =", fid, ", name =", name, ", symname =", symname, ", gid =", gid, ")"
+
+	def v9fs_symlink_return(self, tag, id, type, version, path):
+		print "RSYMLINK (tag =", tag,  ", qid={type =", type, ", version =", version, ", path =", path, "})"
+
+	def v9fs_flush(self, tag, id, flush_tag):
+		print "TFLUSH (tag =", tag, ", flush_tag =", flush_tag, ")"
+
+	def v9fs_link(self, tag, id, dfid, oldfid, name):
+		print "TLINK (tag =", tag, ", dfid =", dfid, ", oldfid =", oldfid, ", name =", name, ")"
+
+	def v9fs_remove(self, tag, id, fid):
+		print "TREMOVE (tag =", tag, ", fid =", fid, ")"
+
+	def v9fs_wstat(self, tag, id, fid, mode, atime, mtime):
+		print "TWSTAT (tag =", tag, ", fid =", fid, ", mode =", oct(mode), ", atime =", atime, "mtime =", mtime, ")"
+
+	def v9fs_mknod(self, tag, id, fid, mode, major, minor):
+		print "TMKNOD (tag =", tag, ", fid =", fid, ", mode =", oct(mode), ", major =", major, ", minor =", minor, ")"
+
+	def v9fs_lock(self, tag, id, fid, type, start, length):
+		print "TLOCK (tag =", tag, ", fid =", fid, "type =", type, ", start =", start, ", length =", length, ")"
+
+	def v9fs_lock_return(self, tag, id, status):
+		print "RLOCK (tag =", tag, ", status =", status, ")"
+
+	def v9fs_getlock(self, tag, id, fid, type, start, length):
+		print "TGETLOCK (tag =", tag, ", fid =", fid, "type =", type, ", start =", start, ", length =", length, ")"
+
+	def v9fs_getlock_return(self, tag, id, type, start, length, proc_id):
+		print "RGETLOCK (tag =", tag, "type =", type, ", start =", start, ", length =", length, ", proc_id =", proc_id,  ")"
+
+	def v9fs_mkdir(self, tag, id, fid, name, mode, gid):
+		print "TMKDIR (tag =", tag, ", fid =", fid, ", name =", name, ", mode =", mode, ", gid =", gid, ")"
+
+	def v9fs_mkdir_return(self, tag, id, type, version, path, err):
+		print "RMKDIR (tag =", tag,  ", qid={type =", type, ", version =", version, ", path =", path, "}, err =", err, ")"
+
+	def v9fs_xattrwalk(self, tag, id, fid, newfid, name):
+		print "TXATTRWALK (tag =", tag, ", fid =", fid, ", newfid =", newfid, ", xattr name =", name, ")"
+
+	def v9fs_xattrwalk_return(self, tag, id, size):
+		print "RXATTRWALK (tag =", tag, ", xattrsize  =", size, ")"
+
+	def v9fs_xattrcreate(self, tag, id, fid, name, size, flags):
+		print "TXATTRCREATE (tag =", tag, ", fid =", fid, ", name =", name, ", xattrsize =", size, ", flags =", flags, ")"
+
+	def v9fs_readlink(self, tag, id, fid):
+		print "TREADLINK (tag =", tag, ", fid =", fid, ")"
+
+	def v9fs_readlink_return(self, tag, id, target):
+		print "RREADLINK (tag =", tag, ", target =", target, ")"
+
+simpletrace.run(VirtFSRequestTracker())
diff --git a/slirp/libslirp.h b/slirp/libslirp.h
index a755123..890fd86 100644
--- a/slirp/libslirp.h
+++ b/slirp/libslirp.h
@@ -3,8 +3,6 @@
 
 #include "qemu-common.h"
 
-#ifdef CONFIG_SLIRP
-
 struct Slirp;
 typedef struct Slirp Slirp;
 
@@ -44,13 +42,4 @@
 size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr guest_addr,
                              int guest_port);
 
-#else /* !CONFIG_SLIRP */
-
-static inline void slirp_select_fill(int *pnfds, fd_set *readfds,
-                                     fd_set *writefds, fd_set *xfds) { }
-
-static inline void slirp_select_poll(fd_set *readfds, fd_set *writefds,
-                                     fd_set *xfds, int select_error) { }
-#endif /* !CONFIG_SLIRP */
-
 #endif
diff --git a/sysemu.h b/sysemu.h
index a889d90..22cd720 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -8,6 +8,7 @@
 #include "qemu-timer.h"
 #include "qapi-types.h"
 #include "notify.h"
+#include "main-loop.h"
 
 /* vl.c */
 
@@ -35,6 +36,7 @@
 
 void vm_start(void);
 void vm_stop(RunState state);
+void vm_stop_force_state(RunState state);
 
 void qemu_system_reset_request(void);
 void qemu_system_shutdown_request(void);
@@ -63,8 +65,6 @@
 
 void qemu_announce_self(void);
 
-int main_loop_wait(int nonblocking);
-
 bool qemu_savevm_state_blocked(Monitor *mon);
 int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f, int blk_enable,
                             int shared);
diff --git a/target-sparc/cc_helper.c b/target-sparc/cc_helper.c
new file mode 100644
index 0000000..04bd2cf
--- /dev/null
+++ b/target-sparc/cc_helper.c
@@ -0,0 +1,485 @@
+/*
+ * Helpers for lazy condition code handling
+ *
+ *  Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * 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/>.
+ */
+
+#include "cpu.h"
+#include "helper.h"
+
+static uint32_t compute_all_flags(CPUState *env)
+{
+    return env->psr & PSR_ICC;
+}
+
+static uint32_t compute_C_flags(CPUState *env)
+{
+    return env->psr & PSR_CARRY;
+}
+
+static inline uint32_t get_NZ_icc(int32_t dst)
+{
+    uint32_t ret = 0;
+
+    if (dst == 0) {
+        ret = PSR_ZERO;
+    } else if (dst < 0) {
+        ret = PSR_NEG;
+    }
+    return ret;
+}
+
+#ifdef TARGET_SPARC64
+static uint32_t compute_all_flags_xcc(CPUState *env)
+{
+    return env->xcc & PSR_ICC;
+}
+
+static uint32_t compute_C_flags_xcc(CPUState *env)
+{
+    return env->xcc & PSR_CARRY;
+}
+
+static inline uint32_t get_NZ_xcc(target_long dst)
+{
+    uint32_t ret = 0;
+
+    if (!dst) {
+        ret = PSR_ZERO;
+    } else if (dst < 0) {
+        ret = PSR_NEG;
+    }
+    return ret;
+}
+#endif
+
+static inline uint32_t get_V_div_icc(target_ulong src2)
+{
+    uint32_t ret = 0;
+
+    if (src2 != 0) {
+        ret = PSR_OVF;
+    }
+    return ret;
+}
+
+static uint32_t compute_all_div(CPUState *env)
+{
+    uint32_t ret;
+
+    ret = get_NZ_icc(CC_DST);
+    ret |= get_V_div_icc(CC_SRC2);
+    return ret;
+}
+
+static uint32_t compute_C_div(CPUState *env)
+{
+    return 0;
+}
+
+static inline uint32_t get_C_add_icc(uint32_t dst, uint32_t src1)
+{
+    uint32_t ret = 0;
+
+    if (dst < src1) {
+        ret = PSR_CARRY;
+    }
+    return ret;
+}
+
+static inline uint32_t get_C_addx_icc(uint32_t dst, uint32_t src1,
+                                      uint32_t src2)
+{
+    uint32_t ret = 0;
+
+    if (((src1 & src2) | (~dst & (src1 | src2))) & (1U << 31)) {
+        ret = PSR_CARRY;
+    }
+    return ret;
+}
+
+static inline uint32_t get_V_add_icc(uint32_t dst, uint32_t src1,
+                                     uint32_t src2)
+{
+    uint32_t ret = 0;
+
+    if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1U << 31)) {
+        ret = PSR_OVF;
+    }
+    return ret;
+}
+
+#ifdef TARGET_SPARC64
+static inline uint32_t get_C_add_xcc(target_ulong dst, target_ulong src1)
+{
+    uint32_t ret = 0;
+
+    if (dst < src1) {
+        ret = PSR_CARRY;
+    }
+    return ret;
+}
+
+static inline uint32_t get_C_addx_xcc(target_ulong dst, target_ulong src1,
+                                      target_ulong src2)
+{
+    uint32_t ret = 0;
+
+    if (((src1 & src2) | (~dst & (src1 | src2))) & (1ULL << 63)) {
+        ret = PSR_CARRY;
+    }
+    return ret;
+}
+
+static inline uint32_t get_V_add_xcc(target_ulong dst, target_ulong src1,
+                                     target_ulong src2)
+{
+    uint32_t ret = 0;
+
+    if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1ULL << 63)) {
+        ret = PSR_OVF;
+    }
+    return ret;
+}
+
+static uint32_t compute_all_add_xcc(CPUState *env)
+{
+    uint32_t ret;
+
+    ret = get_NZ_xcc(CC_DST);
+    ret |= get_C_add_xcc(CC_DST, CC_SRC);
+    ret |= get_V_add_xcc(CC_DST, CC_SRC, CC_SRC2);
+    return ret;
+}
+
+static uint32_t compute_C_add_xcc(CPUState *env)
+{
+    return get_C_add_xcc(CC_DST, CC_SRC);
+}
+#endif
+
+static uint32_t compute_all_add(CPUState *env)
+{
+    uint32_t ret;
+
+    ret = get_NZ_icc(CC_DST);
+    ret |= get_C_add_icc(CC_DST, CC_SRC);
+    ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
+    return ret;
+}
+
+static uint32_t compute_C_add(CPUState *env)
+{
+    return get_C_add_icc(CC_DST, CC_SRC);
+}
+
+#ifdef TARGET_SPARC64
+static uint32_t compute_all_addx_xcc(CPUState *env)
+{
+    uint32_t ret;
+
+    ret = get_NZ_xcc(CC_DST);
+    ret |= get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2);
+    ret |= get_V_add_xcc(CC_DST, CC_SRC, CC_SRC2);
+    return ret;
+}
+
+static uint32_t compute_C_addx_xcc(CPUState *env)
+{
+    uint32_t ret;
+
+    ret = get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2);
+    return ret;
+}
+#endif
+
+static uint32_t compute_all_addx(CPUState *env)
+{
+    uint32_t ret;
+
+    ret = get_NZ_icc(CC_DST);
+    ret |= get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2);
+    ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
+    return ret;
+}
+
+static uint32_t compute_C_addx(CPUState *env)
+{
+    uint32_t ret;
+
+    ret = get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2);
+    return ret;
+}
+
+static inline uint32_t get_V_tag_icc(target_ulong src1, target_ulong src2)
+{
+    uint32_t ret = 0;
+
+    if ((src1 | src2) & 0x3) {
+        ret = PSR_OVF;
+    }
+    return ret;
+}
+
+static uint32_t compute_all_tadd(CPUState *env)
+{
+    uint32_t ret;
+
+    ret = get_NZ_icc(CC_DST);
+    ret |= get_C_add_icc(CC_DST, CC_SRC);
+    ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
+    ret |= get_V_tag_icc(CC_SRC, CC_SRC2);
+    return ret;
+}
+
+static uint32_t compute_all_taddtv(CPUState *env)
+{
+    uint32_t ret;
+
+    ret = get_NZ_icc(CC_DST);
+    ret |= get_C_add_icc(CC_DST, CC_SRC);
+    return ret;
+}
+
+static inline uint32_t get_C_sub_icc(uint32_t src1, uint32_t src2)
+{
+    uint32_t ret = 0;
+
+    if (src1 < src2) {
+        ret = PSR_CARRY;
+    }
+    return ret;
+}
+
+static inline uint32_t get_C_subx_icc(uint32_t dst, uint32_t src1,
+                                      uint32_t src2)
+{
+    uint32_t ret = 0;
+
+    if (((~src1 & src2) | (dst & (~src1 | src2))) & (1U << 31)) {
+        ret = PSR_CARRY;
+    }
+    return ret;
+}
+
+static inline uint32_t get_V_sub_icc(uint32_t dst, uint32_t src1,
+                                     uint32_t src2)
+{
+    uint32_t ret = 0;
+
+    if (((src1 ^ src2) & (src1 ^ dst)) & (1U << 31)) {
+        ret = PSR_OVF;
+    }
+    return ret;
+}
+
+
+#ifdef TARGET_SPARC64
+static inline uint32_t get_C_sub_xcc(target_ulong src1, target_ulong src2)
+{
+    uint32_t ret = 0;
+
+    if (src1 < src2) {
+        ret = PSR_CARRY;
+    }
+    return ret;
+}
+
+static inline uint32_t get_C_subx_xcc(target_ulong dst, target_ulong src1,
+                                      target_ulong src2)
+{
+    uint32_t ret = 0;
+
+    if (((~src1 & src2) | (dst & (~src1 | src2))) & (1ULL << 63)) {
+        ret = PSR_CARRY;
+    }
+    return ret;
+}
+
+static inline uint32_t get_V_sub_xcc(target_ulong dst, target_ulong src1,
+                                     target_ulong src2)
+{
+    uint32_t ret = 0;
+
+    if (((src1 ^ src2) & (src1 ^ dst)) & (1ULL << 63)) {
+        ret = PSR_OVF;
+    }
+    return ret;
+}
+
+static uint32_t compute_all_sub_xcc(CPUState *env)
+{
+    uint32_t ret;
+
+    ret = get_NZ_xcc(CC_DST);
+    ret |= get_C_sub_xcc(CC_SRC, CC_SRC2);
+    ret |= get_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2);
+    return ret;
+}
+
+static uint32_t compute_C_sub_xcc(CPUState *env)
+{
+    return get_C_sub_xcc(CC_SRC, CC_SRC2);
+}
+#endif
+
+static uint32_t compute_all_sub(CPUState *env)
+{
+    uint32_t ret;
+
+    ret = get_NZ_icc(CC_DST);
+    ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
+    ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
+    return ret;
+}
+
+static uint32_t compute_C_sub(CPUState *env)
+{
+    return get_C_sub_icc(CC_SRC, CC_SRC2);
+}
+
+#ifdef TARGET_SPARC64
+static uint32_t compute_all_subx_xcc(CPUState *env)
+{
+    uint32_t ret;
+
+    ret = get_NZ_xcc(CC_DST);
+    ret |= get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2);
+    ret |= get_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2);
+    return ret;
+}
+
+static uint32_t compute_C_subx_xcc(CPUState *env)
+{
+    uint32_t ret;
+
+    ret = get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2);
+    return ret;
+}
+#endif
+
+static uint32_t compute_all_subx(CPUState *env)
+{
+    uint32_t ret;
+
+    ret = get_NZ_icc(CC_DST);
+    ret |= get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2);
+    ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
+    return ret;
+}
+
+static uint32_t compute_C_subx(CPUState *env)
+{
+    uint32_t ret;
+
+    ret = get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2);
+    return ret;
+}
+
+static uint32_t compute_all_tsub(CPUState *env)
+{
+    uint32_t ret;
+
+    ret = get_NZ_icc(CC_DST);
+    ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
+    ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
+    ret |= get_V_tag_icc(CC_SRC, CC_SRC2);
+    return ret;
+}
+
+static uint32_t compute_all_tsubtv(CPUState *env)
+{
+    uint32_t ret;
+
+    ret = get_NZ_icc(CC_DST);
+    ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
+    return ret;
+}
+
+static uint32_t compute_all_logic(CPUState *env)
+{
+    return get_NZ_icc(CC_DST);
+}
+
+static uint32_t compute_C_logic(CPUState *env)
+{
+    return 0;
+}
+
+#ifdef TARGET_SPARC64
+static uint32_t compute_all_logic_xcc(CPUState *env)
+{
+    return get_NZ_xcc(CC_DST);
+}
+#endif
+
+typedef struct CCTable {
+    uint32_t (*compute_all)(CPUState *env); /* return all the flags */
+    uint32_t (*compute_c)(CPUState *env);  /* return the C flag */
+} CCTable;
+
+static const CCTable icc_table[CC_OP_NB] = {
+    /* CC_OP_DYNAMIC should never happen */
+    [CC_OP_FLAGS] = { compute_all_flags, compute_C_flags },
+    [CC_OP_DIV] = { compute_all_div, compute_C_div },
+    [CC_OP_ADD] = { compute_all_add, compute_C_add },
+    [CC_OP_ADDX] = { compute_all_addx, compute_C_addx },
+    [CC_OP_TADD] = { compute_all_tadd, compute_C_add },
+    [CC_OP_TADDTV] = { compute_all_taddtv, compute_C_add },
+    [CC_OP_SUB] = { compute_all_sub, compute_C_sub },
+    [CC_OP_SUBX] = { compute_all_subx, compute_C_subx },
+    [CC_OP_TSUB] = { compute_all_tsub, compute_C_sub },
+    [CC_OP_TSUBTV] = { compute_all_tsubtv, compute_C_sub },
+    [CC_OP_LOGIC] = { compute_all_logic, compute_C_logic },
+};
+
+#ifdef TARGET_SPARC64
+static const CCTable xcc_table[CC_OP_NB] = {
+    /* CC_OP_DYNAMIC should never happen */
+    [CC_OP_FLAGS] = { compute_all_flags_xcc, compute_C_flags_xcc },
+    [CC_OP_DIV] = { compute_all_logic_xcc, compute_C_logic },
+    [CC_OP_ADD] = { compute_all_add_xcc, compute_C_add_xcc },
+    [CC_OP_ADDX] = { compute_all_addx_xcc, compute_C_addx_xcc },
+    [CC_OP_TADD] = { compute_all_add_xcc, compute_C_add_xcc },
+    [CC_OP_TADDTV] = { compute_all_add_xcc, compute_C_add_xcc },
+    [CC_OP_SUB] = { compute_all_sub_xcc, compute_C_sub_xcc },
+    [CC_OP_SUBX] = { compute_all_subx_xcc, compute_C_subx_xcc },
+    [CC_OP_TSUB] = { compute_all_sub_xcc, compute_C_sub_xcc },
+    [CC_OP_TSUBTV] = { compute_all_sub_xcc, compute_C_sub_xcc },
+    [CC_OP_LOGIC] = { compute_all_logic_xcc, compute_C_logic },
+};
+#endif
+
+void helper_compute_psr(CPUState *env)
+{
+    uint32_t new_psr;
+
+    new_psr = icc_table[CC_OP].compute_all(env);
+    env->psr = new_psr;
+#ifdef TARGET_SPARC64
+    new_psr = xcc_table[CC_OP].compute_all(env);
+    env->xcc = new_psr;
+#endif
+    CC_OP = CC_OP_FLAGS;
+}
+
+uint32_t helper_compute_C_icc(CPUState *env)
+{
+    uint32_t ret;
+
+    ret = icc_table[CC_OP].compute_c(env) >> PSR_CARRY_SHIFT;
+    return ret;
+}
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index 19de5ba..25b4f1a 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -335,6 +335,27 @@
 #define SFSR_CT_NOTRANS     (3ULL <<  4)
 #define SFSR_CT_MASK        (3ULL <<  4)
 
+/* Leon3 cache control */
+
+/* Cache control: emulate the behavior of cache control registers but without
+   any effect on the emulated */
+
+#define CACHE_STATE_MASK 0x3
+#define CACHE_DISABLED   0x0
+#define CACHE_FROZEN     0x1
+#define CACHE_ENABLED    0x3
+
+/* Cache Control register fields */
+
+#define CACHE_CTRL_IF (1 <<  4)  /* Instruction Cache Freeze on Interrupt */
+#define CACHE_CTRL_DF (1 <<  5)  /* Data Cache Freeze on Interrupt */
+#define CACHE_CTRL_DP (1 << 14)  /* Data cache flush pending */
+#define CACHE_CTRL_IP (1 << 15)  /* Instruction cache flush pending */
+#define CACHE_CTRL_IB (1 << 16)  /* Instruction burst fetch */
+#define CACHE_CTRL_FI (1 << 21)  /* Flush Instruction cache (Write only) */
+#define CACHE_CTRL_FD (1 << 22)  /* Flush Data cache (Write only) */
+#define CACHE_CTRL_DS (1 << 23)  /* Data cache snoop enable */
+
 typedef struct SparcTLBEntry {
     uint64_t tag;
     uint64_t tte;
@@ -478,17 +499,18 @@
     sparc_def_t *def;
 
     void *irq_manager;
-    void (*qemu_irq_ack) (void *irq_manager, int intno);
+    void (*qemu_irq_ack)(CPUState *env, void *irq_manager, int intno);
 
     /* Leon3 cache control */
     uint32_t cache_control;
 } CPUSPARCState;
 
 #ifndef NO_CPU_IO_DEFS
-/* helper.c */
+/* cpu_init.c */
 CPUSPARCState *cpu_sparc_init(const char *cpu_model);
 void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu);
 void sparc_cpu_list(FILE *f, fprintf_function cpu_fprintf);
+/* mmu_helper.c */
 int cpu_sparc_handle_mmu_fault(CPUSPARCState *env1, target_ulong address, int rw,
                                int mmu_idx);
 #define cpu_handle_mmu_fault cpu_sparc_handle_mmu_fault
@@ -508,7 +530,7 @@
 /* cpu-exec.c */
 int cpu_sparc_exec(CPUSPARCState *s);
 
-/* op_helper.c */
+/* win_helper.c */
 target_ulong cpu_get_psr(CPUState *env1);
 void cpu_put_psr(CPUState *env1, target_ulong val);
 #ifdef TARGET_SPARC64
@@ -521,7 +543,10 @@
 int cpu_cwp_inc(CPUState *env1, int cwp);
 int cpu_cwp_dec(CPUState *env1, int cwp);
 void cpu_set_cwp(CPUState *env1, int new_cwp);
-void leon3_irq_manager(void *irq_manager, int intno);
+
+/* int_helper.c */
+void do_interrupt(CPUState *env);
+void leon3_irq_manager(CPUState *env, void *irq_manager, int intno);
 
 /* sun4m.c, sun4u.c */
 void cpu_check_irqs(CPUSPARCState *env);
@@ -718,9 +743,6 @@
 #endif
 }
 
-/* helper.c */
-void do_interrupt(CPUState *env);
-
 static inline bool cpu_has_work(CPUState *env1)
 {
     return (env1->interrupt_request & CPU_INTERRUPT_HARD) &&
diff --git a/target-sparc/cpu_init.c b/target-sparc/cpu_init.c
new file mode 100644
index 0000000..6954800
--- /dev/null
+++ b/target-sparc/cpu_init.c
@@ -0,0 +1,848 @@
+/*
+ * Sparc CPU init helpers
+ *
+ *  Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * 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/>.
+ */
+
+#include "cpu.h"
+
+//#define DEBUG_FEATURES
+
+static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model);
+
+void cpu_reset(CPUSPARCState *env)
+{
+    if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+        qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+        log_cpu_state(env, 0);
+    }
+
+    tlb_flush(env, 1);
+    env->cwp = 0;
+#ifndef TARGET_SPARC64
+    env->wim = 1;
+#endif
+    env->regwptr = env->regbase + (env->cwp * 16);
+    CC_OP = CC_OP_FLAGS;
+#if defined(CONFIG_USER_ONLY)
+#ifdef TARGET_SPARC64
+    env->cleanwin = env->nwindows - 2;
+    env->cansave = env->nwindows - 2;
+    env->pstate = PS_RMO | PS_PEF | PS_IE;
+    env->asi = 0x82; /* Primary no-fault */
+#endif
+#else
+#if !defined(TARGET_SPARC64)
+    env->psret = 0;
+    env->psrs = 1;
+    env->psrps = 1;
+#endif
+#ifdef TARGET_SPARC64
+    env->pstate = PS_PRIV|PS_RED|PS_PEF|PS_AG;
+    env->hpstate = cpu_has_hypervisor(env) ? HS_PRIV : 0;
+    env->tl = env->maxtl;
+    cpu_tsptr(env)->tt = TT_POWER_ON_RESET;
+    env->lsu = 0;
+#else
+    env->mmuregs[0] &= ~(MMU_E | MMU_NF);
+    env->mmuregs[0] |= env->def->mmu_bm;
+#endif
+    env->pc = 0;
+    env->npc = env->pc + 4;
+#endif
+    env->cache_control = 0;
+}
+
+static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model)
+{
+    sparc_def_t def1, *def = &def1;
+
+    if (cpu_sparc_find_by_name(def, cpu_model) < 0) {
+        return -1;
+    }
+
+    env->def = g_new0(sparc_def_t, 1);
+    memcpy(env->def, def, sizeof(*def));
+#if defined(CONFIG_USER_ONLY)
+    if ((env->def->features & CPU_FEATURE_FLOAT)) {
+        env->def->features |= CPU_FEATURE_FLOAT128;
+    }
+#endif
+    env->cpu_model_str = cpu_model;
+    env->version = def->iu_version;
+    env->fsr = def->fpu_version;
+    env->nwindows = def->nwindows;
+#if !defined(TARGET_SPARC64)
+    env->mmuregs[0] |= def->mmu_version;
+    cpu_sparc_set_id(env, 0);
+    env->mxccregs[7] |= def->mxcc_version;
+#else
+    env->mmu_version = def->mmu_version;
+    env->maxtl = def->maxtl;
+    env->version |= def->maxtl << 8;
+    env->version |= def->nwindows - 1;
+#endif
+    return 0;
+}
+
+static void cpu_sparc_close(CPUSPARCState *env)
+{
+    g_free(env->def);
+    g_free(env);
+}
+
+CPUSPARCState *cpu_sparc_init(const char *cpu_model)
+{
+    CPUSPARCState *env;
+
+    env = g_new0(CPUSPARCState, 1);
+    cpu_exec_init(env);
+
+    gen_intermediate_code_init(env);
+
+    if (cpu_sparc_register(env, cpu_model) < 0) {
+        cpu_sparc_close(env);
+        return NULL;
+    }
+    qemu_init_vcpu(env);
+
+    return env;
+}
+
+void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu)
+{
+#if !defined(TARGET_SPARC64)
+    env->mxccregs[7] = ((cpu + 8) & 0xf) << 24;
+#endif
+}
+
+static const sparc_def_t sparc_defs[] = {
+#ifdef TARGET_SPARC64
+    {
+        .name = "Fujitsu Sparc64",
+        .iu_version = ((0x04ULL << 48) | (0x02ULL << 32) | (0ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_12,
+        .nwindows = 4,
+        .maxtl = 4,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "Fujitsu Sparc64 III",
+        .iu_version = ((0x04ULL << 48) | (0x03ULL << 32) | (0ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_12,
+        .nwindows = 5,
+        .maxtl = 4,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "Fujitsu Sparc64 IV",
+        .iu_version = ((0x04ULL << 48) | (0x04ULL << 32) | (0ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_12,
+        .nwindows = 8,
+        .maxtl = 5,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "Fujitsu Sparc64 V",
+        .iu_version = ((0x04ULL << 48) | (0x05ULL << 32) | (0x51ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_12,
+        .nwindows = 8,
+        .maxtl = 5,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "TI UltraSparc I",
+        .iu_version = ((0x17ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_12,
+        .nwindows = 8,
+        .maxtl = 5,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "TI UltraSparc II",
+        .iu_version = ((0x17ULL << 48) | (0x11ULL << 32) | (0x20ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_12,
+        .nwindows = 8,
+        .maxtl = 5,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "TI UltraSparc IIi",
+        .iu_version = ((0x17ULL << 48) | (0x12ULL << 32) | (0x91ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_12,
+        .nwindows = 8,
+        .maxtl = 5,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "TI UltraSparc IIe",
+        .iu_version = ((0x17ULL << 48) | (0x13ULL << 32) | (0x14ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_12,
+        .nwindows = 8,
+        .maxtl = 5,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "Sun UltraSparc III",
+        .iu_version = ((0x3eULL << 48) | (0x14ULL << 32) | (0x34ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_12,
+        .nwindows = 8,
+        .maxtl = 5,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "Sun UltraSparc III Cu",
+        .iu_version = ((0x3eULL << 48) | (0x15ULL << 32) | (0x41ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_3,
+        .nwindows = 8,
+        .maxtl = 5,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "Sun UltraSparc IIIi",
+        .iu_version = ((0x3eULL << 48) | (0x16ULL << 32) | (0x34ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_12,
+        .nwindows = 8,
+        .maxtl = 5,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "Sun UltraSparc IV",
+        .iu_version = ((0x3eULL << 48) | (0x18ULL << 32) | (0x31ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_4,
+        .nwindows = 8,
+        .maxtl = 5,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "Sun UltraSparc IV+",
+        .iu_version = ((0x3eULL << 48) | (0x19ULL << 32) | (0x22ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_12,
+        .nwindows = 8,
+        .maxtl = 5,
+        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_CMT,
+    },
+    {
+        .name = "Sun UltraSparc IIIi+",
+        .iu_version = ((0x3eULL << 48) | (0x22ULL << 32) | (0ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_3,
+        .nwindows = 8,
+        .maxtl = 5,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "Sun UltraSparc T1",
+        /* defined in sparc_ifu_fdp.v and ctu.h */
+        .iu_version = ((0x3eULL << 48) | (0x23ULL << 32) | (0x02ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_sun4v,
+        .nwindows = 8,
+        .maxtl = 6,
+        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
+        | CPU_FEATURE_GL,
+    },
+    {
+        .name = "Sun UltraSparc T2",
+        /* defined in tlu_asi_ctl.v and n2_revid_cust.v */
+        .iu_version = ((0x3eULL << 48) | (0x24ULL << 32) | (0x02ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_sun4v,
+        .nwindows = 8,
+        .maxtl = 6,
+        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
+        | CPU_FEATURE_GL,
+    },
+    {
+        .name = "NEC UltraSparc I",
+        .iu_version = ((0x22ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_12,
+        .nwindows = 8,
+        .maxtl = 5,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+#else
+    {
+        .name = "Fujitsu MB86900",
+        .iu_version = 0x00 << 24, /* Impl 0, ver 0 */
+        .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
+        .mmu_version = 0x00 << 24, /* Impl 0, ver 0 */
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x007ffff0,
+        .mmu_cxr_mask = 0x0000003f,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 7,
+        .features = CPU_FEATURE_FLOAT | CPU_FEATURE_FSMULD,
+    },
+    {
+        .name = "Fujitsu MB86904",
+        .iu_version = 0x04 << 24, /* Impl 0, ver 4 */
+        .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
+        .mmu_version = 0x04 << 24, /* Impl 0, ver 4 */
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x00ffffc0,
+        .mmu_cxr_mask = 0x000000ff,
+        .mmu_sfsr_mask = 0x00016fff,
+        .mmu_trcr_mask = 0x00ffffff,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "Fujitsu MB86907",
+        .iu_version = 0x05 << 24, /* Impl 0, ver 5 */
+        .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
+        .mmu_version = 0x05 << 24, /* Impl 0, ver 5 */
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0xffffffc0,
+        .mmu_cxr_mask = 0x000000ff,
+        .mmu_sfsr_mask = 0x00016fff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "LSI L64811",
+        .iu_version = 0x10 << 24, /* Impl 1, ver 0 */
+        .fpu_version = 1 << 17, /* FPU version 1 (LSI L64814) */
+        .mmu_version = 0x10 << 24,
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x007ffff0,
+        .mmu_cxr_mask = 0x0000003f,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
+        CPU_FEATURE_FSMULD,
+    },
+    {
+        .name = "Cypress CY7C601",
+        .iu_version = 0x11 << 24, /* Impl 1, ver 1 */
+        .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
+        .mmu_version = 0x10 << 24,
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x007ffff0,
+        .mmu_cxr_mask = 0x0000003f,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
+        CPU_FEATURE_FSMULD,
+    },
+    {
+        .name = "Cypress CY7C611",
+        .iu_version = 0x13 << 24, /* Impl 1, ver 3 */
+        .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
+        .mmu_version = 0x10 << 24,
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x007ffff0,
+        .mmu_cxr_mask = 0x0000003f,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
+        CPU_FEATURE_FSMULD,
+    },
+    {
+        .name = "TI MicroSparc I",
+        .iu_version = 0x41000000,
+        .fpu_version = 4 << 17,
+        .mmu_version = 0x41000000,
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x007ffff0,
+        .mmu_cxr_mask = 0x0000003f,
+        .mmu_sfsr_mask = 0x00016fff,
+        .mmu_trcr_mask = 0x0000003f,
+        .nwindows = 7,
+        .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_MUL |
+        CPU_FEATURE_DIV | CPU_FEATURE_FLUSH | CPU_FEATURE_FSQRT |
+        CPU_FEATURE_FMUL,
+    },
+    {
+        .name = "TI MicroSparc II",
+        .iu_version = 0x42000000,
+        .fpu_version = 4 << 17,
+        .mmu_version = 0x02000000,
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x00ffffc0,
+        .mmu_cxr_mask = 0x000000ff,
+        .mmu_sfsr_mask = 0x00016fff,
+        .mmu_trcr_mask = 0x00ffffff,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "TI MicroSparc IIep",
+        .iu_version = 0x42000000,
+        .fpu_version = 4 << 17,
+        .mmu_version = 0x04000000,
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x00ffffc0,
+        .mmu_cxr_mask = 0x000000ff,
+        .mmu_sfsr_mask = 0x00016bff,
+        .mmu_trcr_mask = 0x00ffffff,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "TI SuperSparc 40", /* STP1020NPGA */
+        .iu_version = 0x41000000, /* SuperSPARC 2.x */
+        .fpu_version = 0 << 17,
+        .mmu_version = 0x00000800, /* SuperSPARC 2.x, no MXCC */
+        .mmu_bm = 0x00002000,
+        .mmu_ctpr_mask = 0xffffffc0,
+        .mmu_cxr_mask = 0x0000ffff,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "TI SuperSparc 50", /* STP1020PGA */
+        .iu_version = 0x40000000, /* SuperSPARC 3.x */
+        .fpu_version = 0 << 17,
+        .mmu_version = 0x01000800, /* SuperSPARC 3.x, no MXCC */
+        .mmu_bm = 0x00002000,
+        .mmu_ctpr_mask = 0xffffffc0,
+        .mmu_cxr_mask = 0x0000ffff,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "TI SuperSparc 51",
+        .iu_version = 0x40000000, /* SuperSPARC 3.x */
+        .fpu_version = 0 << 17,
+        .mmu_version = 0x01000000, /* SuperSPARC 3.x, MXCC */
+        .mmu_bm = 0x00002000,
+        .mmu_ctpr_mask = 0xffffffc0,
+        .mmu_cxr_mask = 0x0000ffff,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .mxcc_version = 0x00000104,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "TI SuperSparc 60", /* STP1020APGA */
+        .iu_version = 0x40000000, /* SuperSPARC 3.x */
+        .fpu_version = 0 << 17,
+        .mmu_version = 0x01000800, /* SuperSPARC 3.x, no MXCC */
+        .mmu_bm = 0x00002000,
+        .mmu_ctpr_mask = 0xffffffc0,
+        .mmu_cxr_mask = 0x0000ffff,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "TI SuperSparc 61",
+        .iu_version = 0x44000000, /* SuperSPARC 3.x */
+        .fpu_version = 0 << 17,
+        .mmu_version = 0x01000000, /* SuperSPARC 3.x, MXCC */
+        .mmu_bm = 0x00002000,
+        .mmu_ctpr_mask = 0xffffffc0,
+        .mmu_cxr_mask = 0x0000ffff,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .mxcc_version = 0x00000104,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "TI SuperSparc II",
+        .iu_version = 0x40000000, /* SuperSPARC II 1.x */
+        .fpu_version = 0 << 17,
+        .mmu_version = 0x08000000, /* SuperSPARC II 1.x, MXCC */
+        .mmu_bm = 0x00002000,
+        .mmu_ctpr_mask = 0xffffffc0,
+        .mmu_cxr_mask = 0x0000ffff,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .mxcc_version = 0x00000104,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "Ross RT625",
+        .iu_version = 0x1e000000,
+        .fpu_version = 1 << 17,
+        .mmu_version = 0x1e000000,
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x007ffff0,
+        .mmu_cxr_mask = 0x0000003f,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "Ross RT620",
+        .iu_version = 0x1f000000,
+        .fpu_version = 1 << 17,
+        .mmu_version = 0x1f000000,
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x007ffff0,
+        .mmu_cxr_mask = 0x0000003f,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "BIT B5010",
+        .iu_version = 0x20000000,
+        .fpu_version = 0 << 17, /* B5010/B5110/B5120/B5210 */
+        .mmu_version = 0x20000000,
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x007ffff0,
+        .mmu_cxr_mask = 0x0000003f,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
+        CPU_FEATURE_FSMULD,
+    },
+    {
+        .name = "Matsushita MN10501",
+        .iu_version = 0x50000000,
+        .fpu_version = 0 << 17,
+        .mmu_version = 0x50000000,
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x007ffff0,
+        .mmu_cxr_mask = 0x0000003f,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_FEATURE_FLOAT | CPU_FEATURE_MUL | CPU_FEATURE_FSQRT |
+        CPU_FEATURE_FSMULD,
+    },
+    {
+        .name = "Weitek W8601",
+        .iu_version = 0x90 << 24, /* Impl 9, ver 0 */
+        .fpu_version = 3 << 17, /* FPU version 3 (Weitek WTL3170/2) */
+        .mmu_version = 0x10 << 24,
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x007ffff0,
+        .mmu_cxr_mask = 0x0000003f,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "LEON2",
+        .iu_version = 0xf2000000,
+        .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
+        .mmu_version = 0xf2000000,
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x007ffff0,
+        .mmu_cxr_mask = 0x0000003f,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
+    },
+    {
+        .name = "LEON3",
+        .iu_version = 0xf3000000,
+        .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
+        .mmu_version = 0xf3000000,
+        .mmu_bm = 0x00000000,
+        .mmu_ctpr_mask = 0x007ffff0,
+        .mmu_cxr_mask = 0x0000003f,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN |
+        CPU_FEATURE_ASR17 | CPU_FEATURE_CACHE_CTRL,
+    },
+#endif
+};
+
+static const char * const feature_name[] = {
+    "float",
+    "float128",
+    "swap",
+    "mul",
+    "div",
+    "flush",
+    "fsqrt",
+    "fmul",
+    "vis1",
+    "vis2",
+    "fsmuld",
+    "hypv",
+    "cmt",
+    "gl",
+};
+
+static void print_features(FILE *f, fprintf_function cpu_fprintf,
+                           uint32_t features, const char *prefix)
+{
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(feature_name); i++) {
+        if (feature_name[i] && (features & (1 << i))) {
+            if (prefix) {
+                (*cpu_fprintf)(f, "%s", prefix);
+            }
+            (*cpu_fprintf)(f, "%s ", feature_name[i]);
+        }
+    }
+}
+
+static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features)
+{
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(feature_name); i++) {
+        if (feature_name[i] && !strcmp(flagname, feature_name[i])) {
+            *features |= 1 << i;
+            return;
+        }
+    }
+    fprintf(stderr, "CPU feature %s not found\n", flagname);
+}
+
+static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model)
+{
+    unsigned int i;
+    const sparc_def_t *def = NULL;
+    char *s = strdup(cpu_model);
+    char *featurestr, *name = strtok(s, ",");
+    uint32_t plus_features = 0;
+    uint32_t minus_features = 0;
+    uint64_t iu_version;
+    uint32_t fpu_version, mmu_version, nwindows;
+
+    for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
+        if (strcasecmp(name, sparc_defs[i].name) == 0) {
+            def = &sparc_defs[i];
+        }
+    }
+    if (!def) {
+        goto error;
+    }
+    memcpy(cpu_def, def, sizeof(*def));
+
+    featurestr = strtok(NULL, ",");
+    while (featurestr) {
+        char *val;
+
+        if (featurestr[0] == '+') {
+            add_flagname_to_bitmaps(featurestr + 1, &plus_features);
+        } else if (featurestr[0] == '-') {
+            add_flagname_to_bitmaps(featurestr + 1, &minus_features);
+        } else if ((val = strchr(featurestr, '='))) {
+            *val = 0; val++;
+            if (!strcmp(featurestr, "iu_version")) {
+                char *err;
+
+                iu_version = strtoll(val, &err, 0);
+                if (!*val || *err) {
+                    fprintf(stderr, "bad numerical value %s\n", val);
+                    goto error;
+                }
+                cpu_def->iu_version = iu_version;
+#ifdef DEBUG_FEATURES
+                fprintf(stderr, "iu_version %" PRIx64 "\n", iu_version);
+#endif
+            } else if (!strcmp(featurestr, "fpu_version")) {
+                char *err;
+
+                fpu_version = strtol(val, &err, 0);
+                if (!*val || *err) {
+                    fprintf(stderr, "bad numerical value %s\n", val);
+                    goto error;
+                }
+                cpu_def->fpu_version = fpu_version;
+#ifdef DEBUG_FEATURES
+                fprintf(stderr, "fpu_version %x\n", fpu_version);
+#endif
+            } else if (!strcmp(featurestr, "mmu_version")) {
+                char *err;
+
+                mmu_version = strtol(val, &err, 0);
+                if (!*val || *err) {
+                    fprintf(stderr, "bad numerical value %s\n", val);
+                    goto error;
+                }
+                cpu_def->mmu_version = mmu_version;
+#ifdef DEBUG_FEATURES
+                fprintf(stderr, "mmu_version %x\n", mmu_version);
+#endif
+            } else if (!strcmp(featurestr, "nwindows")) {
+                char *err;
+
+                nwindows = strtol(val, &err, 0);
+                if (!*val || *err || nwindows > MAX_NWINDOWS ||
+                    nwindows < MIN_NWINDOWS) {
+                    fprintf(stderr, "bad numerical value %s\n", val);
+                    goto error;
+                }
+                cpu_def->nwindows = nwindows;
+#ifdef DEBUG_FEATURES
+                fprintf(stderr, "nwindows %d\n", nwindows);
+#endif
+            } else {
+                fprintf(stderr, "unrecognized feature %s\n", featurestr);
+                goto error;
+            }
+        } else {
+            fprintf(stderr, "feature string `%s' not in format "
+                    "(+feature|-feature|feature=xyz)\n", featurestr);
+            goto error;
+        }
+        featurestr = strtok(NULL, ",");
+    }
+    cpu_def->features |= plus_features;
+    cpu_def->features &= ~minus_features;
+#ifdef DEBUG_FEATURES
+    print_features(stderr, fprintf, cpu_def->features, NULL);
+#endif
+    free(s);
+    return 0;
+
+ error:
+    free(s);
+    return -1;
+}
+
+void sparc_cpu_list(FILE *f, fprintf_function cpu_fprintf)
+{
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
+        (*cpu_fprintf)(f, "Sparc %16s IU " TARGET_FMT_lx
+                       " FPU %08x MMU %08x NWINS %d ",
+                       sparc_defs[i].name,
+                       sparc_defs[i].iu_version,
+                       sparc_defs[i].fpu_version,
+                       sparc_defs[i].mmu_version,
+                       sparc_defs[i].nwindows);
+        print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES &
+                       ~sparc_defs[i].features, "-");
+        print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES &
+                       sparc_defs[i].features, "+");
+        (*cpu_fprintf)(f, "\n");
+    }
+    (*cpu_fprintf)(f, "Default CPU feature flags (use '-' to remove): ");
+    print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES, NULL);
+    (*cpu_fprintf)(f, "\n");
+    (*cpu_fprintf)(f, "Available CPU feature flags (use '+' to add): ");
+    print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES, NULL);
+    (*cpu_fprintf)(f, "\n");
+    (*cpu_fprintf)(f, "Numerical features (use '=' to set): iu_version "
+                   "fpu_version mmu_version nwindows\n");
+}
+
+static void cpu_print_cc(FILE *f, fprintf_function cpu_fprintf,
+                         uint32_t cc)
+{
+    cpu_fprintf(f, "%c%c%c%c", cc & PSR_NEG ? 'N' : '-',
+                cc & PSR_ZERO ? 'Z' : '-', cc & PSR_OVF ? 'V' : '-',
+                cc & PSR_CARRY ? 'C' : '-');
+}
+
+#ifdef TARGET_SPARC64
+#define REGS_PER_LINE 4
+#else
+#define REGS_PER_LINE 8
+#endif
+
+void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
+                    int flags)
+{
+    int i, x;
+
+    cpu_fprintf(f, "pc: " TARGET_FMT_lx "  npc: " TARGET_FMT_lx "\n", env->pc,
+                env->npc);
+    cpu_fprintf(f, "General Registers:\n");
+
+    for (i = 0; i < 8; i++) {
+        if (i % REGS_PER_LINE == 0) {
+            cpu_fprintf(f, "%%g%d-%d:", i, i + REGS_PER_LINE - 1);
+        }
+        cpu_fprintf(f, " " TARGET_FMT_lx, env->gregs[i]);
+        if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
+            cpu_fprintf(f, "\n");
+        }
+    }
+    cpu_fprintf(f, "\nCurrent Register Window:\n");
+    for (x = 0; x < 3; x++) {
+        for (i = 0; i < 8; i++) {
+            if (i % REGS_PER_LINE == 0) {
+                cpu_fprintf(f, "%%%c%d-%d: ",
+                            x == 0 ? 'o' : (x == 1 ? 'l' : 'i'),
+                            i, i + REGS_PER_LINE - 1);
+            }
+            cpu_fprintf(f, TARGET_FMT_lx " ", env->regwptr[i + x * 8]);
+            if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
+                cpu_fprintf(f, "\n");
+            }
+        }
+    }
+    cpu_fprintf(f, "\nFloating Point Registers:\n");
+    for (i = 0; i < TARGET_FPREGS; i++) {
+        if ((i & 3) == 0) {
+            cpu_fprintf(f, "%%f%02d:", i);
+        }
+        cpu_fprintf(f, " %016f", *(float *)&env->fpr[i]);
+        if ((i & 3) == 3) {
+            cpu_fprintf(f, "\n");
+        }
+    }
+#ifdef TARGET_SPARC64
+    cpu_fprintf(f, "pstate: %08x ccr: %02x (icc: ", env->pstate,
+                (unsigned)cpu_get_ccr(env));
+    cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << PSR_CARRY_SHIFT);
+    cpu_fprintf(f, " xcc: ");
+    cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << (PSR_CARRY_SHIFT - 4));
+    cpu_fprintf(f, ") asi: %02x tl: %d pil: %x\n", env->asi, env->tl,
+                env->psrpil);
+    cpu_fprintf(f, "cansave: %d canrestore: %d otherwin: %d wstate: %d "
+                "cleanwin: %d cwp: %d\n",
+                env->cansave, env->canrestore, env->otherwin, env->wstate,
+                env->cleanwin, env->nwindows - 1 - env->cwp);
+    cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx " fprs: "
+                TARGET_FMT_lx "\n", env->fsr, env->y, env->fprs);
+#else
+    cpu_fprintf(f, "psr: %08x (icc: ", cpu_get_psr(env));
+    cpu_print_cc(f, cpu_fprintf, cpu_get_psr(env));
+    cpu_fprintf(f, " SPE: %c%c%c) wim: %08x\n", env->psrs ? 'S' : '-',
+                env->psrps ? 'P' : '-', env->psret ? 'E' : '-',
+                env->wim);
+    cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx "\n",
+                env->fsr, env->y);
+#endif
+}
diff --git a/target-sparc/fop_helper.c b/target-sparc/fop_helper.c
new file mode 100644
index 0000000..23502f3
--- /dev/null
+++ b/target-sparc/fop_helper.c
@@ -0,0 +1,394 @@
+/*
+ * FPU op helpers
+ *
+ *  Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * 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/>.
+ */
+
+#include "cpu.h"
+#include "helper.h"
+
+#define DT0 (env->dt0)
+#define DT1 (env->dt1)
+#define QT0 (env->qt0)
+#define QT1 (env->qt1)
+
+#define F_HELPER(name, p) void helper_f##name##p(CPUState *env)
+
+#define F_BINOP(name)                                           \
+    float32 helper_f ## name ## s (CPUState * env, float32 src1,\
+                                   float32 src2)                \
+    {                                                           \
+        return float32_ ## name (src1, src2, &env->fp_status);  \
+    }                                                           \
+    F_HELPER(name, d)                                           \
+    {                                                           \
+        DT0 = float64_ ## name (DT0, DT1, &env->fp_status);     \
+    }                                                           \
+    F_HELPER(name, q)                                           \
+    {                                                           \
+        QT0 = float128_ ## name (QT0, QT1, &env->fp_status);    \
+    }
+
+F_BINOP(add);
+F_BINOP(sub);
+F_BINOP(mul);
+F_BINOP(div);
+#undef F_BINOP
+
+void helper_fsmuld(CPUState *env, float32 src1, float32 src2)
+{
+    DT0 = float64_mul(float32_to_float64(src1, &env->fp_status),
+                      float32_to_float64(src2, &env->fp_status),
+                      &env->fp_status);
+}
+
+void helper_fdmulq(CPUState *env)
+{
+    QT0 = float128_mul(float64_to_float128(DT0, &env->fp_status),
+                       float64_to_float128(DT1, &env->fp_status),
+                       &env->fp_status);
+}
+
+float32 helper_fnegs(float32 src)
+{
+    return float32_chs(src);
+}
+
+#ifdef TARGET_SPARC64
+F_HELPER(neg, d)
+{
+    DT0 = float64_chs(DT1);
+}
+
+F_HELPER(neg, q)
+{
+    QT0 = float128_chs(QT1);
+}
+#endif
+
+/* Integer to float conversion.  */
+float32 helper_fitos(CPUState *env, int32_t src)
+{
+    return int32_to_float32(src, &env->fp_status);
+}
+
+void helper_fitod(CPUState *env, int32_t src)
+{
+    DT0 = int32_to_float64(src, &env->fp_status);
+}
+
+void helper_fitoq(CPUState *env, int32_t src)
+{
+    QT0 = int32_to_float128(src, &env->fp_status);
+}
+
+#ifdef TARGET_SPARC64
+float32 helper_fxtos(CPUState *env)
+{
+    return int64_to_float32(*((int64_t *)&DT1), &env->fp_status);
+}
+
+F_HELPER(xto, d)
+{
+    DT0 = int64_to_float64(*((int64_t *)&DT1), &env->fp_status);
+}
+
+F_HELPER(xto, q)
+{
+    QT0 = int64_to_float128(*((int64_t *)&DT1), &env->fp_status);
+}
+#endif
+#undef F_HELPER
+
+/* floating point conversion */
+float32 helper_fdtos(CPUState *env)
+{
+    return float64_to_float32(DT1, &env->fp_status);
+}
+
+void helper_fstod(CPUState *env, float32 src)
+{
+    DT0 = float32_to_float64(src, &env->fp_status);
+}
+
+float32 helper_fqtos(CPUState *env)
+{
+    return float128_to_float32(QT1, &env->fp_status);
+}
+
+void helper_fstoq(CPUState *env, float32 src)
+{
+    QT0 = float32_to_float128(src, &env->fp_status);
+}
+
+void helper_fqtod(CPUState *env)
+{
+    DT0 = float128_to_float64(QT1, &env->fp_status);
+}
+
+void helper_fdtoq(CPUState *env)
+{
+    QT0 = float64_to_float128(DT1, &env->fp_status);
+}
+
+/* Float to integer conversion.  */
+int32_t helper_fstoi(CPUState *env, float32 src)
+{
+    return float32_to_int32_round_to_zero(src, &env->fp_status);
+}
+
+int32_t helper_fdtoi(CPUState *env)
+{
+    return float64_to_int32_round_to_zero(DT1, &env->fp_status);
+}
+
+int32_t helper_fqtoi(CPUState *env)
+{
+    return float128_to_int32_round_to_zero(QT1, &env->fp_status);
+}
+
+#ifdef TARGET_SPARC64
+void helper_fstox(CPUState *env, float32 src)
+{
+    *((int64_t *)&DT0) = float32_to_int64_round_to_zero(src, &env->fp_status);
+}
+
+void helper_fdtox(CPUState *env)
+{
+    *((int64_t *)&DT0) = float64_to_int64_round_to_zero(DT1, &env->fp_status);
+}
+
+void helper_fqtox(CPUState *env)
+{
+    *((int64_t *)&DT0) = float128_to_int64_round_to_zero(QT1, &env->fp_status);
+}
+#endif
+
+float32 helper_fabss(float32 src)
+{
+    return float32_abs(src);
+}
+
+#ifdef TARGET_SPARC64
+void helper_fabsd(CPUState *env)
+{
+    DT0 = float64_abs(DT1);
+}
+
+void helper_fabsq(CPUState *env)
+{
+    QT0 = float128_abs(QT1);
+}
+#endif
+
+float32 helper_fsqrts(CPUState *env, float32 src)
+{
+    return float32_sqrt(src, &env->fp_status);
+}
+
+void helper_fsqrtd(CPUState *env)
+{
+    DT0 = float64_sqrt(DT1, &env->fp_status);
+}
+
+void helper_fsqrtq(CPUState *env)
+{
+    QT0 = float128_sqrt(QT1, &env->fp_status);
+}
+
+#define GEN_FCMP(name, size, reg1, reg2, FS, E)                         \
+    void glue(helper_, name) (CPUState *env)                            \
+    {                                                                   \
+        env->fsr &= FSR_FTT_NMASK;                                      \
+        if (E && (glue(size, _is_any_nan)(reg1) ||                      \
+                  glue(size, _is_any_nan)(reg2)) &&                     \
+            (env->fsr & FSR_NVM)) {                                     \
+            env->fsr |= FSR_NVC;                                        \
+            env->fsr |= FSR_FTT_IEEE_EXCP;                              \
+            helper_raise_exception(env, TT_FP_EXCP);                    \
+        }                                                               \
+        switch (glue(size, _compare) (reg1, reg2, &env->fp_status)) {   \
+        case float_relation_unordered:                                  \
+            if ((env->fsr & FSR_NVM)) {                                 \
+                env->fsr |= FSR_NVC;                                    \
+                env->fsr |= FSR_FTT_IEEE_EXCP;                          \
+                helper_raise_exception(env, TT_FP_EXCP);                \
+            } else {                                                    \
+                env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);             \
+                env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS;                \
+                env->fsr |= FSR_NVA;                                    \
+            }                                                           \
+            break;                                                      \
+        case float_relation_less:                                       \
+            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
+            env->fsr |= FSR_FCC0 << FS;                                 \
+            break;                                                      \
+        case float_relation_greater:                                    \
+            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
+            env->fsr |= FSR_FCC1 << FS;                                 \
+            break;                                                      \
+        default:                                                        \
+            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
+            break;                                                      \
+        }                                                               \
+    }
+#define GEN_FCMPS(name, size, FS, E)                                    \
+    void glue(helper_, name)(CPUState *env, float32 src1, float32 src2) \
+    {                                                                   \
+        env->fsr &= FSR_FTT_NMASK;                                      \
+        if (E && (glue(size, _is_any_nan)(src1) ||                      \
+                  glue(size, _is_any_nan)(src2)) &&                     \
+            (env->fsr & FSR_NVM)) {                                     \
+            env->fsr |= FSR_NVC;                                        \
+            env->fsr |= FSR_FTT_IEEE_EXCP;                              \
+            helper_raise_exception(env, TT_FP_EXCP);                    \
+        }                                                               \
+        switch (glue(size, _compare) (src1, src2, &env->fp_status)) {   \
+        case float_relation_unordered:                                  \
+            if ((env->fsr & FSR_NVM)) {                                 \
+                env->fsr |= FSR_NVC;                                    \
+                env->fsr |= FSR_FTT_IEEE_EXCP;                          \
+                helper_raise_exception(env, TT_FP_EXCP);                \
+            } else {                                                    \
+                env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);             \
+                env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS;                \
+                env->fsr |= FSR_NVA;                                    \
+            }                                                           \
+            break;                                                      \
+        case float_relation_less:                                       \
+            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
+            env->fsr |= FSR_FCC0 << FS;                                 \
+            break;                                                      \
+        case float_relation_greater:                                    \
+            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
+            env->fsr |= FSR_FCC1 << FS;                                 \
+            break;                                                      \
+        default:                                                        \
+            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
+            break;                                                      \
+        }                                                               \
+    }
+
+GEN_FCMPS(fcmps, float32, 0, 0);
+GEN_FCMP(fcmpd, float64, DT0, DT1, 0, 0);
+
+GEN_FCMPS(fcmpes, float32, 0, 1);
+GEN_FCMP(fcmped, float64, DT0, DT1, 0, 1);
+
+GEN_FCMP(fcmpq, float128, QT0, QT1, 0, 0);
+GEN_FCMP(fcmpeq, float128, QT0, QT1, 0, 1);
+
+#ifdef TARGET_SPARC64
+GEN_FCMPS(fcmps_fcc1, float32, 22, 0);
+GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22, 0);
+GEN_FCMP(fcmpq_fcc1, float128, QT0, QT1, 22, 0);
+
+GEN_FCMPS(fcmps_fcc2, float32, 24, 0);
+GEN_FCMP(fcmpd_fcc2, float64, DT0, DT1, 24, 0);
+GEN_FCMP(fcmpq_fcc2, float128, QT0, QT1, 24, 0);
+
+GEN_FCMPS(fcmps_fcc3, float32, 26, 0);
+GEN_FCMP(fcmpd_fcc3, float64, DT0, DT1, 26, 0);
+GEN_FCMP(fcmpq_fcc3, float128, QT0, QT1, 26, 0);
+
+GEN_FCMPS(fcmpes_fcc1, float32, 22, 1);
+GEN_FCMP(fcmped_fcc1, float64, DT0, DT1, 22, 1);
+GEN_FCMP(fcmpeq_fcc1, float128, QT0, QT1, 22, 1);
+
+GEN_FCMPS(fcmpes_fcc2, float32, 24, 1);
+GEN_FCMP(fcmped_fcc2, float64, DT0, DT1, 24, 1);
+GEN_FCMP(fcmpeq_fcc2, float128, QT0, QT1, 24, 1);
+
+GEN_FCMPS(fcmpes_fcc3, float32, 26, 1);
+GEN_FCMP(fcmped_fcc3, float64, DT0, DT1, 26, 1);
+GEN_FCMP(fcmpeq_fcc3, float128, QT0, QT1, 26, 1);
+#endif
+#undef GEN_FCMPS
+
+void helper_check_ieee_exceptions(CPUState *env)
+{
+    target_ulong status;
+
+    status = get_float_exception_flags(&env->fp_status);
+    if (status) {
+        /* Copy IEEE 754 flags into FSR */
+        if (status & float_flag_invalid) {
+            env->fsr |= FSR_NVC;
+        }
+        if (status & float_flag_overflow) {
+            env->fsr |= FSR_OFC;
+        }
+        if (status & float_flag_underflow) {
+            env->fsr |= FSR_UFC;
+        }
+        if (status & float_flag_divbyzero) {
+            env->fsr |= FSR_DZC;
+        }
+        if (status & float_flag_inexact) {
+            env->fsr |= FSR_NXC;
+        }
+
+        if ((env->fsr & FSR_CEXC_MASK) & ((env->fsr & FSR_TEM_MASK) >> 23)) {
+            /* Unmasked exception, generate a trap */
+            env->fsr |= FSR_FTT_IEEE_EXCP;
+            helper_raise_exception(env, TT_FP_EXCP);
+        } else {
+            /* Accumulate exceptions */
+            env->fsr |= (env->fsr & FSR_CEXC_MASK) << 5;
+        }
+    }
+}
+
+void helper_clear_float_exceptions(CPUState *env)
+{
+    set_float_exception_flags(0, &env->fp_status);
+}
+
+static inline void set_fsr(CPUState *env)
+{
+    int rnd_mode;
+
+    switch (env->fsr & FSR_RD_MASK) {
+    case FSR_RD_NEAREST:
+        rnd_mode = float_round_nearest_even;
+        break;
+    default:
+    case FSR_RD_ZERO:
+        rnd_mode = float_round_to_zero;
+        break;
+    case FSR_RD_POS:
+        rnd_mode = float_round_up;
+        break;
+    case FSR_RD_NEG:
+        rnd_mode = float_round_down;
+        break;
+    }
+    set_float_rounding_mode(rnd_mode, &env->fp_status);
+}
+
+void helper_ldfsr(CPUState *env, uint32_t new_fsr)
+{
+    env->fsr = (new_fsr & FSR_LDFSR_MASK) | (env->fsr & FSR_LDFSR_OLDMASK);
+    set_fsr(env);
+}
+
+#ifdef TARGET_SPARC64
+void helper_ldxfsr(CPUState *env, uint64_t new_fsr)
+{
+    env->fsr = (new_fsr & FSR_LDXFSR_MASK) | (env->fsr & FSR_LDXFSR_OLDMASK);
+    set_fsr(env);
+}
+#endif
diff --git a/target-sparc/helper.c b/target-sparc/helper.c
index c80531a..18609c4 100644
--- a/target-sparc/helper.c
+++ b/target-sparc/helper.c
@@ -1,5 +1,5 @@
 /*
- *  sparc helpers
+ *  Misc Sparc helpers
  *
  *  Copyright (c) 2003-2005 Fabrice Bellard
  *
@@ -16,1926 +16,133 @@
  * 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/>.
  */
-#include <stdarg.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <inttypes.h>
 
 #include "cpu.h"
-#include "qemu-common.h"
+#include "host-utils.h"
+#include "helper.h"
+#include "sysemu.h"
 
-//#define DEBUG_MMU
-//#define DEBUG_FEATURES
+void helper_raise_exception(CPUState *env, int tt)
+{
+    env->exception_index = tt;
+    cpu_loop_exit(env);
+}
 
-#ifdef DEBUG_MMU
-#define DPRINTF_MMU(fmt, ...) \
-    do { printf("MMU: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF_MMU(fmt, ...) do {} while (0)
+void helper_debug(CPUState *env)
+{
+    env->exception_index = EXCP_DEBUG;
+    cpu_loop_exit(env);
+}
+
+void helper_shutdown(void)
+{
+#if !defined(CONFIG_USER_ONLY)
+    qemu_system_shutdown_request();
 #endif
-
-static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model);
-
-/* Sparc MMU emulation */
-
-#if defined(CONFIG_USER_ONLY)
-
-int cpu_sparc_handle_mmu_fault(CPUState *env1, target_ulong address, int rw,
-                               int mmu_idx)
-{
-    if (rw & 2)
-        env1->exception_index = TT_TFAULT;
-    else
-        env1->exception_index = TT_DFAULT;
-    return 1;
 }
 
-#else
-
-#ifndef TARGET_SPARC64
-/*
- * Sparc V8 Reference MMU (SRMMU)
- */
-static const int access_table[8][8] = {
-    { 0, 0, 0, 0, 8, 0, 12, 12 },
-    { 0, 0, 0, 0, 8, 0, 0, 0 },
-    { 8, 8, 0, 0, 0, 8, 12, 12 },
-    { 8, 8, 0, 0, 0, 8, 0, 0 },
-    { 8, 0, 8, 0, 8, 8, 12, 12 },
-    { 8, 0, 8, 0, 8, 0, 8, 0 },
-    { 8, 8, 8, 0, 8, 8, 12, 12 },
-    { 8, 8, 8, 0, 8, 8, 8, 0 }
-};
-
-static const int perm_table[2][8] = {
-    {
-        PAGE_READ,
-        PAGE_READ | PAGE_WRITE,
-        PAGE_READ | PAGE_EXEC,
-        PAGE_READ | PAGE_WRITE | PAGE_EXEC,
-        PAGE_EXEC,
-        PAGE_READ | PAGE_WRITE,
-        PAGE_READ | PAGE_EXEC,
-        PAGE_READ | PAGE_WRITE | PAGE_EXEC
-    },
-    {
-        PAGE_READ,
-        PAGE_READ | PAGE_WRITE,
-        PAGE_READ | PAGE_EXEC,
-        PAGE_READ | PAGE_WRITE | PAGE_EXEC,
-        PAGE_EXEC,
-        PAGE_READ,
-        0,
-        0,
-    }
-};
-
-static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
-                                int *prot, int *access_index,
-                                target_ulong address, int rw, int mmu_idx,
-                                target_ulong *page_size)
+#ifdef TARGET_SPARC64
+target_ulong helper_popc(target_ulong val)
 {
-    int access_perms = 0;
-    target_phys_addr_t pde_ptr;
-    uint32_t pde;
-    int error_code = 0, is_dirty, is_user;
-    unsigned long page_offset;
-
-    is_user = mmu_idx == MMU_USER_IDX;
-
-    if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
-        *page_size = TARGET_PAGE_SIZE;
-        // Boot mode: instruction fetches are taken from PROM
-        if (rw == 2 && (env->mmuregs[0] & env->def->mmu_bm)) {
-            *physical = env->prom_addr | (address & 0x7ffffULL);
-            *prot = PAGE_READ | PAGE_EXEC;
-            return 0;
-        }
-        *physical = address;
-        *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
-        return 0;
-    }
-
-    *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1);
-    *physical = 0xffffffffffff0000ULL;
-
-    /* SPARC reference MMU table walk: Context table->L1->L2->PTE */
-    /* Context base + context number */
-    pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
-    pde = ldl_phys(pde_ptr);
-
-    /* Ctx pde */
-    switch (pde & PTE_ENTRYTYPE_MASK) {
-    default:
-    case 0: /* Invalid */
-        return 1 << 2;
-    case 2: /* L0 PTE, maybe should not happen? */
-    case 3: /* Reserved */
-        return 4 << 2;
-    case 1: /* L0 PDE */
-        pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
-        pde = ldl_phys(pde_ptr);
-
-        switch (pde & PTE_ENTRYTYPE_MASK) {
-        default:
-        case 0: /* Invalid */
-            return (1 << 8) | (1 << 2);
-        case 3: /* Reserved */
-            return (1 << 8) | (4 << 2);
-        case 1: /* L1 PDE */
-            pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
-            pde = ldl_phys(pde_ptr);
-
-            switch (pde & PTE_ENTRYTYPE_MASK) {
-            default:
-            case 0: /* Invalid */
-                return (2 << 8) | (1 << 2);
-            case 3: /* Reserved */
-                return (2 << 8) | (4 << 2);
-            case 1: /* L2 PDE */
-                pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
-                pde = ldl_phys(pde_ptr);
-
-                switch (pde & PTE_ENTRYTYPE_MASK) {
-                default:
-                case 0: /* Invalid */
-                    return (3 << 8) | (1 << 2);
-                case 1: /* PDE, should not happen */
-                case 3: /* Reserved */
-                    return (3 << 8) | (4 << 2);
-                case 2: /* L3 PTE */
-                    page_offset = (address & TARGET_PAGE_MASK) &
-                        (TARGET_PAGE_SIZE - 1);
-                }
-                *page_size = TARGET_PAGE_SIZE;
-                break;
-            case 2: /* L2 PTE */
-                page_offset = address & 0x3ffff;
-                *page_size = 0x40000;
-            }
-            break;
-        case 2: /* L1 PTE */
-            page_offset = address & 0xffffff;
-            *page_size = 0x1000000;
-        }
-    }
-
-    /* check access */
-    access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT;
-    error_code = access_table[*access_index][access_perms];
-    if (error_code && !((env->mmuregs[0] & MMU_NF) && is_user))
-        return error_code;
-
-    /* update page modified and dirty bits */
-    is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK);
-    if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
-        pde |= PG_ACCESSED_MASK;
-        if (is_dirty)
-            pde |= PG_MODIFIED_MASK;
-        stl_phys_notdirty(pde_ptr, pde);
-    }
-
-    /* the page can be put in the TLB */
-    *prot = perm_table[is_user][access_perms];
-    if (!(pde & PG_MODIFIED_MASK)) {
-        /* only set write access if already dirty... otherwise wait
-           for dirty access */
-        *prot &= ~PAGE_WRITE;
-    }
-
-    /* Even if large ptes, we map only one 4KB page in the cache to
-       avoid filling it too fast */
-    *physical = ((target_phys_addr_t)(pde & PTE_ADDR_MASK) << 4) + page_offset;
-    return error_code;
+    return ctpop64(val);
 }
 
-/* Perform address translation */
-int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
-                              int mmu_idx)
+void helper_tick_set_count(void *opaque, uint64_t count)
 {
-    target_phys_addr_t paddr;
-    target_ulong vaddr;
-    target_ulong page_size;
-    int error_code = 0, prot, access_index;
-
-    error_code = get_physical_address(env, &paddr, &prot, &access_index,
-                                      address, rw, mmu_idx, &page_size);
-    if (error_code == 0) {
-        vaddr = address & TARGET_PAGE_MASK;
-        paddr &= TARGET_PAGE_MASK;
-#ifdef DEBUG_MMU
-        printf("Translate at " TARGET_FMT_lx " -> " TARGET_FMT_plx ", vaddr "
-               TARGET_FMT_lx "\n", address, paddr, vaddr);
+#if !defined(CONFIG_USER_ONLY)
+    cpu_tick_set_count(opaque, count);
 #endif
-        tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
-        return 0;
-    }
-
-    if (env->mmuregs[3]) /* Fault status register */
-        env->mmuregs[3] = 1; /* overflow (not read before another fault) */
-    env->mmuregs[3] |= (access_index << 5) | error_code | 2;
-    env->mmuregs[4] = address; /* Fault address register */
-
-    if ((env->mmuregs[0] & MMU_NF) || env->psret == 0)  {
-        // No fault mode: if a mapping is available, just override
-        // permissions. If no mapping is available, redirect accesses to
-        // neverland. Fake/overridden mappings will be flushed when
-        // switching to normal mode.
-        vaddr = address & TARGET_PAGE_MASK;
-        prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
-        tlb_set_page(env, vaddr, paddr, prot, mmu_idx, TARGET_PAGE_SIZE);
-        return 0;
-    } else {
-        if (rw & 2)
-            env->exception_index = TT_TFAULT;
-        else
-            env->exception_index = TT_DFAULT;
-        return 1;
-    }
 }
 
-target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev)
+uint64_t helper_tick_get_count(void *opaque)
 {
-    target_phys_addr_t pde_ptr;
-    uint32_t pde;
-
-    /* Context base + context number */
-    pde_ptr = (target_phys_addr_t)(env->mmuregs[1] << 4) +
-        (env->mmuregs[2] << 2);
-    pde = ldl_phys(pde_ptr);
-
-    switch (pde & PTE_ENTRYTYPE_MASK) {
-    default:
-    case 0: /* Invalid */
-    case 2: /* PTE, maybe should not happen? */
-    case 3: /* Reserved */
-        return 0;
-    case 1: /* L1 PDE */
-        if (mmulev == 3)
-            return pde;
-        pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
-        pde = ldl_phys(pde_ptr);
-
-        switch (pde & PTE_ENTRYTYPE_MASK) {
-        default:
-        case 0: /* Invalid */
-        case 3: /* Reserved */
-            return 0;
-        case 2: /* L1 PTE */
-            return pde;
-        case 1: /* L2 PDE */
-            if (mmulev == 2)
-                return pde;
-            pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
-            pde = ldl_phys(pde_ptr);
-
-            switch (pde & PTE_ENTRYTYPE_MASK) {
-            default:
-            case 0: /* Invalid */
-            case 3: /* Reserved */
-                return 0;
-            case 2: /* L2 PTE */
-                return pde;
-            case 1: /* L3 PDE */
-                if (mmulev == 1)
-                    return pde;
-                pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
-                pde = ldl_phys(pde_ptr);
-
-                switch (pde & PTE_ENTRYTYPE_MASK) {
-                default:
-                case 0: /* Invalid */
-                case 1: /* PDE, should not happen */
-                case 3: /* Reserved */
-                    return 0;
-                case 2: /* L3 PTE */
-                    return pde;
-                }
-            }
-        }
-    }
+#if !defined(CONFIG_USER_ONLY)
+    return cpu_tick_get_count(opaque);
+#else
     return 0;
+#endif
 }
 
-void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
+void helper_tick_set_limit(void *opaque, uint64_t limit)
 {
-    target_ulong va, va1, va2;
-    unsigned int n, m, o;
-    target_phys_addr_t pde_ptr, pa;
-    uint32_t pde;
-
-    pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
-    pde = ldl_phys(pde_ptr);
-    (*cpu_fprintf)(f, "Root ptr: " TARGET_FMT_plx ", ctx: %d\n",
-                   (target_phys_addr_t)env->mmuregs[1] << 4, env->mmuregs[2]);
-    for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) {
-        pde = mmu_probe(env, va, 2);
-        if (pde) {
-            pa = cpu_get_phys_page_debug(env, va);
-            (*cpu_fprintf)(f, "VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx
-                           " PDE: " TARGET_FMT_lx "\n", va, pa, pde);
-            for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) {
-                pde = mmu_probe(env, va1, 1);
-                if (pde) {
-                    pa = cpu_get_phys_page_debug(env, va1);
-                    (*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: "
-                                   TARGET_FMT_plx " PDE: " TARGET_FMT_lx "\n",
-                                   va1, pa, pde);
-                    for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) {
-                        pde = mmu_probe(env, va2, 0);
-                        if (pde) {
-                            pa = cpu_get_phys_page_debug(env, va2);
-                            (*cpu_fprintf)(f, "  VA: " TARGET_FMT_lx ", PA: "
-                                           TARGET_FMT_plx " PTE: "
-                                           TARGET_FMT_lx "\n",
-                                           va2, pa, pde);
-                        }
-                    }
-                }
-            }
-        }
-    }
-}
-
 #if !defined(CONFIG_USER_ONLY)
-
-/* Gdb expects all registers windows to be flushed in ram. This function handles
- * reads (and only reads) in stack frames as if windows were flushed. We assume
- * that the sparc ABI is followed.
- */
-int target_memory_rw_debug(CPUState *env, target_ulong addr,
-                           uint8_t *buf, int len, int is_write)
-{
-    int i;
-    int len1;
-    int cwp = env->cwp;
-
-    if (!is_write) {
-        for (i = 0; i < env->nwindows; i++) {
-            int off;
-            target_ulong fp = env->regbase[cwp * 16 + 22];
-
-            /* Assume fp == 0 means end of frame.  */
-            if (fp == 0) {
-                break;
-            }
-
-            cwp = cpu_cwp_inc(env, cwp + 1);
-
-            /* Invalid window ? */
-            if (env->wim & (1 << cwp)) {
-                break;
-            }
-
-            /* According to the ABI, the stack is growing downward.  */
-            if (addr + len < fp) {
-                break;
-            }
-
-            /* Not in this frame.  */
-            if (addr > fp + 64) {
-                continue;
-            }
-
-            /* Handle access before this window.  */
-            if (addr < fp) {
-                len1 = fp - addr;
-                if (cpu_memory_rw_debug(env, addr, buf, len1, is_write) != 0) {
-                    return -1;
-                }
-                addr += len1;
-                len -= len1;
-                buf += len1;
-            }
-
-            /* Access byte per byte to registers. Not very efficient but speed
-             * is not critical.
-             */
-            off = addr - fp;
-            len1 = 64 - off;
-
-            if (len1 > len) {
-                len1 = len;
-            }
-
-            for (; len1; len1--) {
-                int reg = cwp * 16 + 8 + (off >> 2);
-                union {
-                    uint32_t v;
-                    uint8_t c[4];
-                } u;
-                u.v = cpu_to_be32(env->regbase[reg]);
-                *buf++ = u.c[off & 3];
-                addr++;
-                len--;
-                off++;
-            }
-
-            if (len == 0) {
-                return 0;
-            }
-        }
-    }
-    return cpu_memory_rw_debug(env, addr, buf, len, is_write);
-}
-
-#endif  /* !defined(CONFIG_USER_ONLY) */
-
-#else /* !TARGET_SPARC64 */
-
-// 41 bit physical address space
-static inline target_phys_addr_t ultrasparc_truncate_physical(uint64_t x)
-{
-    return x & 0x1ffffffffffULL;
-}
-
-/*
- * UltraSparc IIi I/DMMUs
- */
-
-// Returns true if TTE tag is valid and matches virtual address value in context
-// requires virtual address mask value calculated from TTE entry size
-static inline int ultrasparc_tag_match(SparcTLBEntry *tlb,
-                                       uint64_t address, uint64_t context,
-                                       target_phys_addr_t *physical)
-{
-    uint64_t mask;
-
-    switch (TTE_PGSIZE(tlb->tte)) {
-    default:
-    case 0x0: // 8k
-        mask = 0xffffffffffffe000ULL;
-        break;
-    case 0x1: // 64k
-        mask = 0xffffffffffff0000ULL;
-        break;
-    case 0x2: // 512k
-        mask = 0xfffffffffff80000ULL;
-        break;
-    case 0x3: // 4M
-        mask = 0xffffffffffc00000ULL;
-        break;
-    }
-
-    // valid, context match, virtual address match?
-    if (TTE_IS_VALID(tlb->tte) &&
-        (TTE_IS_GLOBAL(tlb->tte) || tlb_compare_context(tlb, context))
-        && compare_masked(address, tlb->tag, mask))
-    {
-        // decode physical address
-        *physical = ((tlb->tte & mask) | (address & ~mask)) & 0x1ffffffe000ULL;
-        return 1;
-    }
-
-    return 0;
-}
-
-static int get_physical_address_data(CPUState *env,
-                                     target_phys_addr_t *physical, int *prot,
-                                     target_ulong address, int rw, int mmu_idx)
-{
-    unsigned int i;
-    uint64_t context;
-    uint64_t sfsr = 0;
-
-    int is_user = (mmu_idx == MMU_USER_IDX ||
-                   mmu_idx == MMU_USER_SECONDARY_IDX);
-
-    if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */
-        *physical = ultrasparc_truncate_physical(address);
-        *prot = PAGE_READ | PAGE_WRITE;
-        return 0;
-    }
-
-    switch(mmu_idx) {
-    case MMU_USER_IDX:
-    case MMU_KERNEL_IDX:
-        context = env->dmmu.mmu_primary_context & 0x1fff;
-        sfsr |= SFSR_CT_PRIMARY;
-        break;
-    case MMU_USER_SECONDARY_IDX:
-    case MMU_KERNEL_SECONDARY_IDX:
-        context = env->dmmu.mmu_secondary_context & 0x1fff;
-        sfsr |= SFSR_CT_SECONDARY;
-        break;
-    case MMU_NUCLEUS_IDX:
-        sfsr |= SFSR_CT_NUCLEUS;
-        /* FALLTHRU */
-    default:
-        context = 0;
-        break;
-    }
-
-    if (rw == 1) {
-        sfsr |= SFSR_WRITE_BIT;
-    } else if (rw == 4) {
-        sfsr |= SFSR_NF_BIT;
-    }
-
-    for (i = 0; i < 64; i++) {
-        // ctx match, vaddr match, valid?
-        if (ultrasparc_tag_match(&env->dtlb[i], address, context, physical)) {
-            int do_fault = 0;
-
-            // access ok?
-            /* multiple bits in SFSR.FT may be set on TT_DFAULT */
-            if (TTE_IS_PRIV(env->dtlb[i].tte) && is_user) {
-                do_fault = 1;
-                sfsr |= SFSR_FT_PRIV_BIT; /* privilege violation */
-
-                DPRINTF_MMU("DFAULT at %" PRIx64 " context %" PRIx64
-                            " mmu_idx=%d tl=%d\n",
-                            address, context, mmu_idx, env->tl);
-            }
-            if (rw == 4) {
-                if (TTE_IS_SIDEEFFECT(env->dtlb[i].tte)) {
-                    do_fault = 1;
-                    sfsr |= SFSR_FT_NF_E_BIT;
-                }
-            } else {
-                if (TTE_IS_NFO(env->dtlb[i].tte)) {
-                    do_fault = 1;
-                    sfsr |= SFSR_FT_NFO_BIT;
-                }
-            }
-
-            if (do_fault) {
-                /* faults above are reported with TT_DFAULT. */
-                env->exception_index = TT_DFAULT;
-            } else if (!TTE_IS_W_OK(env->dtlb[i].tte) && (rw == 1)) {
-                do_fault = 1;
-                env->exception_index = TT_DPROT;
-
-                DPRINTF_MMU("DPROT at %" PRIx64 " context %" PRIx64
-                            " mmu_idx=%d tl=%d\n",
-                            address, context, mmu_idx, env->tl);
-            }
-
-            if (!do_fault) {
-                *prot = PAGE_READ;
-                if (TTE_IS_W_OK(env->dtlb[i].tte)) {
-                    *prot |= PAGE_WRITE;
-                }
-
-                TTE_SET_USED(env->dtlb[i].tte);
-
-                return 0;
-            }
-
-            if (env->dmmu.sfsr & SFSR_VALID_BIT) { /* Fault status register */
-                sfsr |= SFSR_OW_BIT; /* overflow (not read before
-                                        another fault) */
-            }
-
-            if (env->pstate & PS_PRIV) {
-                sfsr |= SFSR_PR_BIT;
-            }
-
-            /* FIXME: ASI field in SFSR must be set */
-            env->dmmu.sfsr = sfsr | SFSR_VALID_BIT;
-
-            env->dmmu.sfar = address; /* Fault address register */
-
-            env->dmmu.tag_access = (address & ~0x1fffULL) | context;
-
-            return 1;
-        }
-    }
-
-    DPRINTF_MMU("DMISS at %" PRIx64 " context %" PRIx64 "\n",
-                address, context);
-
-    /*
-     * On MMU misses:
-     * - UltraSPARC IIi: SFSR and SFAR unmodified
-     * - JPS1: SFAR updated and some fields of SFSR updated
-     */
-    env->dmmu.tag_access = (address & ~0x1fffULL) | context;
-    env->exception_index = TT_DMISS;
-    return 1;
-}
-
-static int get_physical_address_code(CPUState *env,
-                                     target_phys_addr_t *physical, int *prot,
-                                     target_ulong address, int mmu_idx)
-{
-    unsigned int i;
-    uint64_t context;
-
-    int is_user = (mmu_idx == MMU_USER_IDX ||
-                   mmu_idx == MMU_USER_SECONDARY_IDX);
-
-    if ((env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0) {
-        /* IMMU disabled */
-        *physical = ultrasparc_truncate_physical(address);
-        *prot = PAGE_EXEC;
-        return 0;
-    }
-
-    if (env->tl == 0) {
-        /* PRIMARY context */
-        context = env->dmmu.mmu_primary_context & 0x1fff;
-    } else {
-        /* NUCLEUS context */
-        context = 0;
-    }
-
-    for (i = 0; i < 64; i++) {
-        // ctx match, vaddr match, valid?
-        if (ultrasparc_tag_match(&env->itlb[i],
-                                 address, context, physical)) {
-            // access ok?
-            if (TTE_IS_PRIV(env->itlb[i].tte) && is_user) {
-                /* Fault status register */
-                if (env->immu.sfsr & SFSR_VALID_BIT) {
-                    env->immu.sfsr = SFSR_OW_BIT; /* overflow (not read before
-                                                     another fault) */
-                } else {
-                    env->immu.sfsr = 0;
-                }
-                if (env->pstate & PS_PRIV) {
-                    env->immu.sfsr |= SFSR_PR_BIT;
-                }
-                if (env->tl > 0) {
-                    env->immu.sfsr |= SFSR_CT_NUCLEUS;
-                }
-
-                /* FIXME: ASI field in SFSR must be set */
-                env->immu.sfsr |= SFSR_FT_PRIV_BIT | SFSR_VALID_BIT;
-                env->exception_index = TT_TFAULT;
-
-                env->immu.tag_access = (address & ~0x1fffULL) | context;
-
-                DPRINTF_MMU("TFAULT at %" PRIx64 " context %" PRIx64 "\n",
-                            address, context);
-
-                return 1;
-            }
-            *prot = PAGE_EXEC;
-            TTE_SET_USED(env->itlb[i].tte);
-            return 0;
-        }
-    }
-
-    DPRINTF_MMU("TMISS at %" PRIx64 " context %" PRIx64 "\n",
-                address, context);
-
-    /* Context is stored in DMMU (dmmuregs[1]) also for IMMU */
-    env->immu.tag_access = (address & ~0x1fffULL) | context;
-    env->exception_index = TT_TMISS;
-    return 1;
-}
-
-static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
-                                int *prot, int *access_index,
-                                target_ulong address, int rw, int mmu_idx,
-                                target_ulong *page_size)
-{
-    /* ??? We treat everything as a small page, then explicitly flush
-       everything when an entry is evicted.  */
-    *page_size = TARGET_PAGE_SIZE;
-
-#if defined (DEBUG_MMU)
-    /* safety net to catch wrong softmmu index use from dynamic code */
-    if (env->tl > 0 && mmu_idx != MMU_NUCLEUS_IDX) {
-        DPRINTF_MMU("get_physical_address %s tl=%d mmu_idx=%d"
-                    " primary context=%" PRIx64
-                    " secondary context=%" PRIx64
-                " address=%" PRIx64
-                "\n",
-                (rw == 2 ? "CODE" : "DATA"),
-                env->tl, mmu_idx,
-                env->dmmu.mmu_primary_context,
-                env->dmmu.mmu_secondary_context,
-                address);
-    }
-#endif
-
-    if (rw == 2)
-        return get_physical_address_code(env, physical, prot, address,
-                                         mmu_idx);
-    else
-        return get_physical_address_data(env, physical, prot, address, rw,
-                                         mmu_idx);
-}
-
-/* Perform address translation */
-int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
-                              int mmu_idx)
-{
-    target_ulong virt_addr, vaddr;
-    target_phys_addr_t paddr;
-    target_ulong page_size;
-    int error_code = 0, prot, access_index;
-
-    error_code = get_physical_address(env, &paddr, &prot, &access_index,
-                                      address, rw, mmu_idx, &page_size);
-    if (error_code == 0) {
-        virt_addr = address & TARGET_PAGE_MASK;
-        vaddr = virt_addr + ((address & TARGET_PAGE_MASK) &
-                             (TARGET_PAGE_SIZE - 1));
-
-        DPRINTF_MMU("Translate at %" PRIx64 " -> %" PRIx64 ","
-                    " vaddr %" PRIx64
-                    " mmu_idx=%d"
-                    " tl=%d"
-                    " primary context=%" PRIx64
-                    " secondary context=%" PRIx64
-                    "\n",
-                    address, paddr, vaddr, mmu_idx, env->tl,
-                    env->dmmu.mmu_primary_context,
-                    env->dmmu.mmu_secondary_context);
-
-        tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
-        return 0;
-    }
-    // XXX
-    return 1;
-}
-
-void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
-{
-    unsigned int i;
-    const char *mask;
-
-    (*cpu_fprintf)(f, "MMU contexts: Primary: %" PRId64 ", Secondary: %"
-                   PRId64 "\n",
-                   env->dmmu.mmu_primary_context,
-                   env->dmmu.mmu_secondary_context);
-    if ((env->lsu & DMMU_E) == 0) {
-        (*cpu_fprintf)(f, "DMMU disabled\n");
-    } else {
-        (*cpu_fprintf)(f, "DMMU dump\n");
-        for (i = 0; i < 64; i++) {
-            switch (TTE_PGSIZE(env->dtlb[i].tte)) {
-            default:
-            case 0x0:
-                mask = "  8k";
-                break;
-            case 0x1:
-                mask = " 64k";
-                break;
-            case 0x2:
-                mask = "512k";
-                break;
-            case 0x3:
-                mask = "  4M";
-                break;
-            }
-            if (TTE_IS_VALID(env->dtlb[i].tte)) {
-                (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx"
-                               ", %s, %s, %s, %s, ctx %" PRId64 " %s\n",
-                               i,
-                               env->dtlb[i].tag & (uint64_t)~0x1fffULL,
-                               TTE_PA(env->dtlb[i].tte),
-                               mask,
-                               TTE_IS_PRIV(env->dtlb[i].tte) ? "priv" : "user",
-                               TTE_IS_W_OK(env->dtlb[i].tte) ? "RW" : "RO",
-                               TTE_IS_LOCKED(env->dtlb[i].tte) ?
-                               "locked" : "unlocked",
-                               env->dtlb[i].tag & (uint64_t)0x1fffULL,
-                               TTE_IS_GLOBAL(env->dtlb[i].tte)?
-                               "global" : "local");
-            }
-        }
-    }
-    if ((env->lsu & IMMU_E) == 0) {
-        (*cpu_fprintf)(f, "IMMU disabled\n");
-    } else {
-        (*cpu_fprintf)(f, "IMMU dump\n");
-        for (i = 0; i < 64; i++) {
-            switch (TTE_PGSIZE(env->itlb[i].tte)) {
-            default:
-            case 0x0:
-                mask = "  8k";
-                break;
-            case 0x1:
-                mask = " 64k";
-                break;
-            case 0x2:
-                mask = "512k";
-                break;
-            case 0x3:
-                mask = "  4M";
-                break;
-            }
-            if (TTE_IS_VALID(env->itlb[i].tte)) {
-                (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx"
-                               ", %s, %s, %s, ctx %" PRId64 " %s\n",
-                               i,
-                               env->itlb[i].tag & (uint64_t)~0x1fffULL,
-                               TTE_PA(env->itlb[i].tte),
-                               mask,
-                               TTE_IS_PRIV(env->itlb[i].tte) ? "priv" : "user",
-                               TTE_IS_LOCKED(env->itlb[i].tte) ?
-                               "locked" : "unlocked",
-                               env->itlb[i].tag & (uint64_t)0x1fffULL,
-                               TTE_IS_GLOBAL(env->itlb[i].tte)?
-                               "global" : "local");
-            }
-        }
-    }
-}
-
-#endif /* TARGET_SPARC64 */
-#endif /* !CONFIG_USER_ONLY */
-
-
-#if !defined(CONFIG_USER_ONLY)
-static int cpu_sparc_get_phys_page(CPUState *env, target_phys_addr_t *phys,
-                                   target_ulong addr, int rw, int mmu_idx)
-{
-    target_ulong page_size;
-    int prot, access_index;
-
-    return get_physical_address(env, phys, &prot, &access_index, addr, rw,
-                                mmu_idx, &page_size);
-}
-
-#if defined(TARGET_SPARC64)
-target_phys_addr_t cpu_get_phys_page_nofault(CPUState *env, target_ulong addr,
-                                           int mmu_idx)
-{
-    target_phys_addr_t phys_addr;
-
-    if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 4, mmu_idx) != 0) {
-        return -1;
-    }
-    return phys_addr;
-}
-#endif
-
-target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
-{
-    target_phys_addr_t phys_addr;
-    int mmu_idx = cpu_mmu_index(env);
-
-    if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 2, mmu_idx) != 0) {
-        if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 0, mmu_idx) != 0) {
-            return -1;
-        }
-    }
-    if (cpu_get_physical_page_desc(phys_addr) == IO_MEM_UNASSIGNED) {
-        return -1;
-    }
-    return phys_addr;
-}
-#endif
-
-#ifdef TARGET_SPARC64
-#ifdef DEBUG_PCALL
-static const char * const excp_names[0x80] = {
-    [TT_TFAULT] = "Instruction Access Fault",
-    [TT_TMISS] = "Instruction Access MMU Miss",
-    [TT_CODE_ACCESS] = "Instruction Access Error",
-    [TT_ILL_INSN] = "Illegal Instruction",
-    [TT_PRIV_INSN] = "Privileged Instruction",
-    [TT_NFPU_INSN] = "FPU Disabled",
-    [TT_FP_EXCP] = "FPU Exception",
-    [TT_TOVF] = "Tag Overflow",
-    [TT_CLRWIN] = "Clean Windows",
-    [TT_DIV_ZERO] = "Division By Zero",
-    [TT_DFAULT] = "Data Access Fault",
-    [TT_DMISS] = "Data Access MMU Miss",
-    [TT_DATA_ACCESS] = "Data Access Error",
-    [TT_DPROT] = "Data Protection Error",
-    [TT_UNALIGNED] = "Unaligned Memory Access",
-    [TT_PRIV_ACT] = "Privileged Action",
-    [TT_EXTINT | 0x1] = "External Interrupt 1",
-    [TT_EXTINT | 0x2] = "External Interrupt 2",
-    [TT_EXTINT | 0x3] = "External Interrupt 3",
-    [TT_EXTINT | 0x4] = "External Interrupt 4",
-    [TT_EXTINT | 0x5] = "External Interrupt 5",
-    [TT_EXTINT | 0x6] = "External Interrupt 6",
-    [TT_EXTINT | 0x7] = "External Interrupt 7",
-    [TT_EXTINT | 0x8] = "External Interrupt 8",
-    [TT_EXTINT | 0x9] = "External Interrupt 9",
-    [TT_EXTINT | 0xa] = "External Interrupt 10",
-    [TT_EXTINT | 0xb] = "External Interrupt 11",
-    [TT_EXTINT | 0xc] = "External Interrupt 12",
-    [TT_EXTINT | 0xd] = "External Interrupt 13",
-    [TT_EXTINT | 0xe] = "External Interrupt 14",
-    [TT_EXTINT | 0xf] = "External Interrupt 15",
-};
-#endif
-
-void do_interrupt(CPUState *env)
-{
-    int intno = env->exception_index;
-    trap_state *tsptr;
-
-#ifdef DEBUG_PCALL
-    if (qemu_loglevel_mask(CPU_LOG_INT)) {
-        static int count;
-        const char *name;
-
-        if (intno < 0 || intno >= 0x180) {
-            name = "Unknown";
-        } else if (intno >= 0x100) {
-            name = "Trap Instruction";
-        } else if (intno >= 0xc0) {
-            name = "Window Fill";
-        } else if (intno >= 0x80) {
-            name = "Window Spill";
-        } else {
-            name = excp_names[intno];
-            if (!name) {
-                name = "Unknown";
-            }
-        }
-
-        qemu_log("%6d: %s (v=%04x) pc=%016" PRIx64 " npc=%016" PRIx64
-                " SP=%016" PRIx64 "\n",
-                count, name, intno,
-                env->pc,
-                env->npc, env->regwptr[6]);
-        log_cpu_state(env, 0);
-#if 0
-        {
-            int i;
-            uint8_t *ptr;
-
-            qemu_log("       code=");
-            ptr = (uint8_t *)env->pc;
-            for (i = 0; i < 16; i++) {
-                qemu_log(" %02x", ldub(ptr + i));
-            }
-            qemu_log("\n");
-        }
-#endif
-        count++;
-    }
-#endif
-#if !defined(CONFIG_USER_ONLY)
-    if (env->tl >= env->maxtl) {
-        cpu_abort(env, "Trap 0x%04x while trap level (%d) >= MAXTL (%d),"
-                  " Error state", env->exception_index, env->tl, env->maxtl);
-        return;
-    }
-#endif
-    if (env->tl < env->maxtl - 1) {
-        env->tl++;
-    } else {
-        env->pstate |= PS_RED;
-        if (env->tl < env->maxtl) {
-            env->tl++;
-        }
-    }
-    tsptr = cpu_tsptr(env);
-
-    tsptr->tstate = (cpu_get_ccr(env) << 32) |
-        ((env->asi & 0xff) << 24) | ((env->pstate & 0xf3f) << 8) |
-        cpu_get_cwp64(env);
-    tsptr->tpc = env->pc;
-    tsptr->tnpc = env->npc;
-    tsptr->tt = intno;
-
-    switch (intno) {
-    case TT_IVEC:
-        cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_IG);
-        break;
-    case TT_TFAULT:
-    case TT_DFAULT:
-    case TT_TMISS ... TT_TMISS + 3:
-    case TT_DMISS ... TT_DMISS + 3:
-    case TT_DPROT ... TT_DPROT + 3:
-        cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_MG);
-        break;
-    default:
-        cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_AG);
-        break;
-    }
-
-    if (intno == TT_CLRWIN) {
-        cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - 1));
-    } else if ((intno & 0x1c0) == TT_SPILL) {
-        cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - env->cansave - 2));
-    } else if ((intno & 0x1c0) == TT_FILL) {
-        cpu_set_cwp(env, cpu_cwp_inc(env, env->cwp + 1));
-    }
-    env->tbr &= ~0x7fffULL;
-    env->tbr |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5);
-    env->pc = env->tbr;
-    env->npc = env->pc + 4;
-    env->exception_index = -1;
-}
-#else
-#ifdef DEBUG_PCALL
-static const char * const excp_names[0x80] = {
-    [TT_TFAULT] = "Instruction Access Fault",
-    [TT_ILL_INSN] = "Illegal Instruction",
-    [TT_PRIV_INSN] = "Privileged Instruction",
-    [TT_NFPU_INSN] = "FPU Disabled",
-    [TT_WIN_OVF] = "Window Overflow",
-    [TT_WIN_UNF] = "Window Underflow",
-    [TT_UNALIGNED] = "Unaligned Memory Access",
-    [TT_FP_EXCP] = "FPU Exception",
-    [TT_DFAULT] = "Data Access Fault",
-    [TT_TOVF] = "Tag Overflow",
-    [TT_EXTINT | 0x1] = "External Interrupt 1",
-    [TT_EXTINT | 0x2] = "External Interrupt 2",
-    [TT_EXTINT | 0x3] = "External Interrupt 3",
-    [TT_EXTINT | 0x4] = "External Interrupt 4",
-    [TT_EXTINT | 0x5] = "External Interrupt 5",
-    [TT_EXTINT | 0x6] = "External Interrupt 6",
-    [TT_EXTINT | 0x7] = "External Interrupt 7",
-    [TT_EXTINT | 0x8] = "External Interrupt 8",
-    [TT_EXTINT | 0x9] = "External Interrupt 9",
-    [TT_EXTINT | 0xa] = "External Interrupt 10",
-    [TT_EXTINT | 0xb] = "External Interrupt 11",
-    [TT_EXTINT | 0xc] = "External Interrupt 12",
-    [TT_EXTINT | 0xd] = "External Interrupt 13",
-    [TT_EXTINT | 0xe] = "External Interrupt 14",
-    [TT_EXTINT | 0xf] = "External Interrupt 15",
-    [TT_TOVF] = "Tag Overflow",
-    [TT_CODE_ACCESS] = "Instruction Access Error",
-    [TT_DATA_ACCESS] = "Data Access Error",
-    [TT_DIV_ZERO] = "Division By Zero",
-    [TT_NCP_INSN] = "Coprocessor Disabled",
-};
-#endif
-
-void do_interrupt(CPUState *env)
-{
-    int cwp, intno = env->exception_index;
-
-#ifdef DEBUG_PCALL
-    if (qemu_loglevel_mask(CPU_LOG_INT)) {
-        static int count;
-        const char *name;
-
-        if (intno < 0 || intno >= 0x100) {
-            name = "Unknown";
-        } else if (intno >= 0x80) {
-            name = "Trap Instruction";
-        } else {
-            name = excp_names[intno];
-            if (!name) {
-                name = "Unknown";
-            }
-        }
-
-        qemu_log("%6d: %s (v=%02x) pc=%08x npc=%08x SP=%08x\n",
-                count, name, intno,
-                env->pc,
-                env->npc, env->regwptr[6]);
-        log_cpu_state(env, 0);
-#if 0
-        {
-            int i;
-            uint8_t *ptr;
-
-            qemu_log("       code=");
-            ptr = (uint8_t *)env->pc;
-            for (i = 0; i < 16; i++) {
-                qemu_log(" %02x", ldub(ptr + i));
-            }
-            qemu_log("\n");
-        }
-#endif
-        count++;
-    }
-#endif
-#if !defined(CONFIG_USER_ONLY)
-    if (env->psret == 0) {
-        cpu_abort(env, "Trap 0x%02x while interrupts disabled, Error state",
-                  env->exception_index);
-        return;
-    }
-#endif
-    env->psret = 0;
-    cwp = cpu_cwp_dec(env, env->cwp - 1);
-    cpu_set_cwp(env, cwp);
-    env->regwptr[9] = env->pc;
-    env->regwptr[10] = env->npc;
-    env->psrps = env->psrs;
-    env->psrs = 1;
-    env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4);
-    env->pc = env->tbr;
-    env->npc = env->pc + 4;
-    env->exception_index = -1;
-
-#if !defined(CONFIG_USER_ONLY)
-    /* IRQ acknowledgment */
-    if ((intno & ~15) == TT_EXTINT && env->qemu_irq_ack != NULL) {
-        env->qemu_irq_ack(env->irq_manager, intno);
-    }
+    cpu_tick_set_limit(opaque, limit);
 #endif
 }
 #endif
 
-void cpu_reset(CPUSPARCState *env)
+static target_ulong helper_udiv_common(CPUState *env, target_ulong a,
+                                       target_ulong b, int cc)
 {
-    if (qemu_loglevel_mask(CPU_LOG_RESET)) {
-        qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
-        log_cpu_state(env, 0);
+    int overflow = 0;
+    uint64_t x0;
+    uint32_t x1;
+
+    x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
+    x1 = (b & 0xffffffff);
+
+    if (x1 == 0) {
+        helper_raise_exception(env, TT_DIV_ZERO);
     }
 
-    tlb_flush(env, 1);
-    env->cwp = 0;
-#ifndef TARGET_SPARC64
-    env->wim = 1;
-#endif
-    env->regwptr = env->regbase + (env->cwp * 16);
-    CC_OP = CC_OP_FLAGS;
-#if defined(CONFIG_USER_ONLY)
-#ifdef TARGET_SPARC64
-    env->cleanwin = env->nwindows - 2;
-    env->cansave = env->nwindows - 2;
-    env->pstate = PS_RMO | PS_PEF | PS_IE;
-    env->asi = 0x82; // Primary no-fault
-#endif
-#else
-#if !defined(TARGET_SPARC64)
-    env->psret = 0;
-    env->psrs = 1;
-    env->psrps = 1;
-#endif
-#ifdef TARGET_SPARC64
-    env->pstate = PS_PRIV|PS_RED|PS_PEF|PS_AG;
-    env->hpstate = cpu_has_hypervisor(env) ? HS_PRIV : 0;
-    env->tl = env->maxtl;
-    cpu_tsptr(env)->tt = TT_POWER_ON_RESET;
-    env->lsu = 0;
-#else
-    env->mmuregs[0] &= ~(MMU_E | MMU_NF);
-    env->mmuregs[0] |= env->def->mmu_bm;
-#endif
-    env->pc = 0;
-    env->npc = env->pc + 4;
-#endif
-    env->cache_control = 0;
-}
-
-static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model)
-{
-    sparc_def_t def1, *def = &def1;
-
-    if (cpu_sparc_find_by_name(def, cpu_model) < 0)
-        return -1;
-
-    env->def = g_malloc0(sizeof(*def));
-    memcpy(env->def, def, sizeof(*def));
-#if defined(CONFIG_USER_ONLY)
-    if ((env->def->features & CPU_FEATURE_FLOAT))
-        env->def->features |= CPU_FEATURE_FLOAT128;
-#endif
-    env->cpu_model_str = cpu_model;
-    env->version = def->iu_version;
-    env->fsr = def->fpu_version;
-    env->nwindows = def->nwindows;
-#if !defined(TARGET_SPARC64)
-    env->mmuregs[0] |= def->mmu_version;
-    cpu_sparc_set_id(env, 0);
-    env->mxccregs[7] |= def->mxcc_version;
-#else
-    env->mmu_version = def->mmu_version;
-    env->maxtl = def->maxtl;
-    env->version |= def->maxtl << 8;
-    env->version |= def->nwindows - 1;
-#endif
-    return 0;
-}
-
-static void cpu_sparc_close(CPUSPARCState *env)
-{
-    free(env->def);
-    free(env);
-}
-
-CPUSPARCState *cpu_sparc_init(const char *cpu_model)
-{
-    CPUSPARCState *env;
-
-    env = g_malloc0(sizeof(CPUSPARCState));
-    cpu_exec_init(env);
-
-    gen_intermediate_code_init(env);
-
-    if (cpu_sparc_register(env, cpu_model) < 0) {
-        cpu_sparc_close(env);
-        return NULL;
+    x0 = x0 / x1;
+    if (x0 > 0xffffffff) {
+        x0 = 0xffffffff;
+        overflow = 1;
     }
-    qemu_init_vcpu(env);
 
-    return env;
-}
-
-void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu)
-{
-#if !defined(TARGET_SPARC64)
-    env->mxccregs[7] = ((cpu + 8) & 0xf) << 24;
-#endif
-}
-
-static const sparc_def_t sparc_defs[] = {
-#ifdef TARGET_SPARC64
-    {
-        .name = "Fujitsu Sparc64",
-        .iu_version = ((0x04ULL << 48) | (0x02ULL << 32) | (0ULL << 24)),
-        .fpu_version = 0x00000000,
-        .mmu_version = mmu_us_12,
-        .nwindows = 4,
-        .maxtl = 4,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "Fujitsu Sparc64 III",
-        .iu_version = ((0x04ULL << 48) | (0x03ULL << 32) | (0ULL << 24)),
-        .fpu_version = 0x00000000,
-        .mmu_version = mmu_us_12,
-        .nwindows = 5,
-        .maxtl = 4,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "Fujitsu Sparc64 IV",
-        .iu_version = ((0x04ULL << 48) | (0x04ULL << 32) | (0ULL << 24)),
-        .fpu_version = 0x00000000,
-        .mmu_version = mmu_us_12,
-        .nwindows = 8,
-        .maxtl = 5,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "Fujitsu Sparc64 V",
-        .iu_version = ((0x04ULL << 48) | (0x05ULL << 32) | (0x51ULL << 24)),
-        .fpu_version = 0x00000000,
-        .mmu_version = mmu_us_12,
-        .nwindows = 8,
-        .maxtl = 5,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "TI UltraSparc I",
-        .iu_version = ((0x17ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
-        .fpu_version = 0x00000000,
-        .mmu_version = mmu_us_12,
-        .nwindows = 8,
-        .maxtl = 5,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "TI UltraSparc II",
-        .iu_version = ((0x17ULL << 48) | (0x11ULL << 32) | (0x20ULL << 24)),
-        .fpu_version = 0x00000000,
-        .mmu_version = mmu_us_12,
-        .nwindows = 8,
-        .maxtl = 5,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "TI UltraSparc IIi",
-        .iu_version = ((0x17ULL << 48) | (0x12ULL << 32) | (0x91ULL << 24)),
-        .fpu_version = 0x00000000,
-        .mmu_version = mmu_us_12,
-        .nwindows = 8,
-        .maxtl = 5,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "TI UltraSparc IIe",
-        .iu_version = ((0x17ULL << 48) | (0x13ULL << 32) | (0x14ULL << 24)),
-        .fpu_version = 0x00000000,
-        .mmu_version = mmu_us_12,
-        .nwindows = 8,
-        .maxtl = 5,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "Sun UltraSparc III",
-        .iu_version = ((0x3eULL << 48) | (0x14ULL << 32) | (0x34ULL << 24)),
-        .fpu_version = 0x00000000,
-        .mmu_version = mmu_us_12,
-        .nwindows = 8,
-        .maxtl = 5,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "Sun UltraSparc III Cu",
-        .iu_version = ((0x3eULL << 48) | (0x15ULL << 32) | (0x41ULL << 24)),
-        .fpu_version = 0x00000000,
-        .mmu_version = mmu_us_3,
-        .nwindows = 8,
-        .maxtl = 5,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "Sun UltraSparc IIIi",
-        .iu_version = ((0x3eULL << 48) | (0x16ULL << 32) | (0x34ULL << 24)),
-        .fpu_version = 0x00000000,
-        .mmu_version = mmu_us_12,
-        .nwindows = 8,
-        .maxtl = 5,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "Sun UltraSparc IV",
-        .iu_version = ((0x3eULL << 48) | (0x18ULL << 32) | (0x31ULL << 24)),
-        .fpu_version = 0x00000000,
-        .mmu_version = mmu_us_4,
-        .nwindows = 8,
-        .maxtl = 5,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "Sun UltraSparc IV+",
-        .iu_version = ((0x3eULL << 48) | (0x19ULL << 32) | (0x22ULL << 24)),
-        .fpu_version = 0x00000000,
-        .mmu_version = mmu_us_12,
-        .nwindows = 8,
-        .maxtl = 5,
-        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_CMT,
-    },
-    {
-        .name = "Sun UltraSparc IIIi+",
-        .iu_version = ((0x3eULL << 48) | (0x22ULL << 32) | (0ULL << 24)),
-        .fpu_version = 0x00000000,
-        .mmu_version = mmu_us_3,
-        .nwindows = 8,
-        .maxtl = 5,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "Sun UltraSparc T1",
-        // defined in sparc_ifu_fdp.v and ctu.h
-        .iu_version = ((0x3eULL << 48) | (0x23ULL << 32) | (0x02ULL << 24)),
-        .fpu_version = 0x00000000,
-        .mmu_version = mmu_sun4v,
-        .nwindows = 8,
-        .maxtl = 6,
-        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
-        | CPU_FEATURE_GL,
-    },
-    {
-        .name = "Sun UltraSparc T2",
-        // defined in tlu_asi_ctl.v and n2_revid_cust.v
-        .iu_version = ((0x3eULL << 48) | (0x24ULL << 32) | (0x02ULL << 24)),
-        .fpu_version = 0x00000000,
-        .mmu_version = mmu_sun4v,
-        .nwindows = 8,
-        .maxtl = 6,
-        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
-        | CPU_FEATURE_GL,
-    },
-    {
-        .name = "NEC UltraSparc I",
-        .iu_version = ((0x22ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
-        .fpu_version = 0x00000000,
-        .mmu_version = mmu_us_12,
-        .nwindows = 8,
-        .maxtl = 5,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-#else
-    {
-        .name = "Fujitsu MB86900",
-        .iu_version = 0x00 << 24, /* Impl 0, ver 0 */
-        .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
-        .mmu_version = 0x00 << 24, /* Impl 0, ver 0 */
-        .mmu_bm = 0x00004000,
-        .mmu_ctpr_mask = 0x007ffff0,
-        .mmu_cxr_mask = 0x0000003f,
-        .mmu_sfsr_mask = 0xffffffff,
-        .mmu_trcr_mask = 0xffffffff,
-        .nwindows = 7,
-        .features = CPU_FEATURE_FLOAT | CPU_FEATURE_FSMULD,
-    },
-    {
-        .name = "Fujitsu MB86904",
-        .iu_version = 0x04 << 24, /* Impl 0, ver 4 */
-        .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
-        .mmu_version = 0x04 << 24, /* Impl 0, ver 4 */
-        .mmu_bm = 0x00004000,
-        .mmu_ctpr_mask = 0x00ffffc0,
-        .mmu_cxr_mask = 0x000000ff,
-        .mmu_sfsr_mask = 0x00016fff,
-        .mmu_trcr_mask = 0x00ffffff,
-        .nwindows = 8,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "Fujitsu MB86907",
-        .iu_version = 0x05 << 24, /* Impl 0, ver 5 */
-        .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
-        .mmu_version = 0x05 << 24, /* Impl 0, ver 5 */
-        .mmu_bm = 0x00004000,
-        .mmu_ctpr_mask = 0xffffffc0,
-        .mmu_cxr_mask = 0x000000ff,
-        .mmu_sfsr_mask = 0x00016fff,
-        .mmu_trcr_mask = 0xffffffff,
-        .nwindows = 8,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "LSI L64811",
-        .iu_version = 0x10 << 24, /* Impl 1, ver 0 */
-        .fpu_version = 1 << 17, /* FPU version 1 (LSI L64814) */
-        .mmu_version = 0x10 << 24,
-        .mmu_bm = 0x00004000,
-        .mmu_ctpr_mask = 0x007ffff0,
-        .mmu_cxr_mask = 0x0000003f,
-        .mmu_sfsr_mask = 0xffffffff,
-        .mmu_trcr_mask = 0xffffffff,
-        .nwindows = 8,
-        .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
-        CPU_FEATURE_FSMULD,
-    },
-    {
-        .name = "Cypress CY7C601",
-        .iu_version = 0x11 << 24, /* Impl 1, ver 1 */
-        .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
-        .mmu_version = 0x10 << 24,
-        .mmu_bm = 0x00004000,
-        .mmu_ctpr_mask = 0x007ffff0,
-        .mmu_cxr_mask = 0x0000003f,
-        .mmu_sfsr_mask = 0xffffffff,
-        .mmu_trcr_mask = 0xffffffff,
-        .nwindows = 8,
-        .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
-        CPU_FEATURE_FSMULD,
-    },
-    {
-        .name = "Cypress CY7C611",
-        .iu_version = 0x13 << 24, /* Impl 1, ver 3 */
-        .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
-        .mmu_version = 0x10 << 24,
-        .mmu_bm = 0x00004000,
-        .mmu_ctpr_mask = 0x007ffff0,
-        .mmu_cxr_mask = 0x0000003f,
-        .mmu_sfsr_mask = 0xffffffff,
-        .mmu_trcr_mask = 0xffffffff,
-        .nwindows = 8,
-        .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
-        CPU_FEATURE_FSMULD,
-    },
-    {
-        .name = "TI MicroSparc I",
-        .iu_version = 0x41000000,
-        .fpu_version = 4 << 17,
-        .mmu_version = 0x41000000,
-        .mmu_bm = 0x00004000,
-        .mmu_ctpr_mask = 0x007ffff0,
-        .mmu_cxr_mask = 0x0000003f,
-        .mmu_sfsr_mask = 0x00016fff,
-        .mmu_trcr_mask = 0x0000003f,
-        .nwindows = 7,
-        .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_MUL |
-        CPU_FEATURE_DIV | CPU_FEATURE_FLUSH | CPU_FEATURE_FSQRT |
-        CPU_FEATURE_FMUL,
-    },
-    {
-        .name = "TI MicroSparc II",
-        .iu_version = 0x42000000,
-        .fpu_version = 4 << 17,
-        .mmu_version = 0x02000000,
-        .mmu_bm = 0x00004000,
-        .mmu_ctpr_mask = 0x00ffffc0,
-        .mmu_cxr_mask = 0x000000ff,
-        .mmu_sfsr_mask = 0x00016fff,
-        .mmu_trcr_mask = 0x00ffffff,
-        .nwindows = 8,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "TI MicroSparc IIep",
-        .iu_version = 0x42000000,
-        .fpu_version = 4 << 17,
-        .mmu_version = 0x04000000,
-        .mmu_bm = 0x00004000,
-        .mmu_ctpr_mask = 0x00ffffc0,
-        .mmu_cxr_mask = 0x000000ff,
-        .mmu_sfsr_mask = 0x00016bff,
-        .mmu_trcr_mask = 0x00ffffff,
-        .nwindows = 8,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "TI SuperSparc 40", // STP1020NPGA
-        .iu_version = 0x41000000, // SuperSPARC 2.x
-        .fpu_version = 0 << 17,
-        .mmu_version = 0x00000800, // SuperSPARC 2.x, no MXCC
-        .mmu_bm = 0x00002000,
-        .mmu_ctpr_mask = 0xffffffc0,
-        .mmu_cxr_mask = 0x0000ffff,
-        .mmu_sfsr_mask = 0xffffffff,
-        .mmu_trcr_mask = 0xffffffff,
-        .nwindows = 8,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "TI SuperSparc 50", // STP1020PGA
-        .iu_version = 0x40000000, // SuperSPARC 3.x
-        .fpu_version = 0 << 17,
-        .mmu_version = 0x01000800, // SuperSPARC 3.x, no MXCC
-        .mmu_bm = 0x00002000,
-        .mmu_ctpr_mask = 0xffffffc0,
-        .mmu_cxr_mask = 0x0000ffff,
-        .mmu_sfsr_mask = 0xffffffff,
-        .mmu_trcr_mask = 0xffffffff,
-        .nwindows = 8,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "TI SuperSparc 51",
-        .iu_version = 0x40000000, // SuperSPARC 3.x
-        .fpu_version = 0 << 17,
-        .mmu_version = 0x01000000, // SuperSPARC 3.x, MXCC
-        .mmu_bm = 0x00002000,
-        .mmu_ctpr_mask = 0xffffffc0,
-        .mmu_cxr_mask = 0x0000ffff,
-        .mmu_sfsr_mask = 0xffffffff,
-        .mmu_trcr_mask = 0xffffffff,
-        .mxcc_version = 0x00000104,
-        .nwindows = 8,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "TI SuperSparc 60", // STP1020APGA
-        .iu_version = 0x40000000, // SuperSPARC 3.x
-        .fpu_version = 0 << 17,
-        .mmu_version = 0x01000800, // SuperSPARC 3.x, no MXCC
-        .mmu_bm = 0x00002000,
-        .mmu_ctpr_mask = 0xffffffc0,
-        .mmu_cxr_mask = 0x0000ffff,
-        .mmu_sfsr_mask = 0xffffffff,
-        .mmu_trcr_mask = 0xffffffff,
-        .nwindows = 8,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "TI SuperSparc 61",
-        .iu_version = 0x44000000, // SuperSPARC 3.x
-        .fpu_version = 0 << 17,
-        .mmu_version = 0x01000000, // SuperSPARC 3.x, MXCC
-        .mmu_bm = 0x00002000,
-        .mmu_ctpr_mask = 0xffffffc0,
-        .mmu_cxr_mask = 0x0000ffff,
-        .mmu_sfsr_mask = 0xffffffff,
-        .mmu_trcr_mask = 0xffffffff,
-        .mxcc_version = 0x00000104,
-        .nwindows = 8,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "TI SuperSparc II",
-        .iu_version = 0x40000000, // SuperSPARC II 1.x
-        .fpu_version = 0 << 17,
-        .mmu_version = 0x08000000, // SuperSPARC II 1.x, MXCC
-        .mmu_bm = 0x00002000,
-        .mmu_ctpr_mask = 0xffffffc0,
-        .mmu_cxr_mask = 0x0000ffff,
-        .mmu_sfsr_mask = 0xffffffff,
-        .mmu_trcr_mask = 0xffffffff,
-        .mxcc_version = 0x00000104,
-        .nwindows = 8,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "Ross RT625",
-        .iu_version = 0x1e000000,
-        .fpu_version = 1 << 17,
-        .mmu_version = 0x1e000000,
-        .mmu_bm = 0x00004000,
-        .mmu_ctpr_mask = 0x007ffff0,
-        .mmu_cxr_mask = 0x0000003f,
-        .mmu_sfsr_mask = 0xffffffff,
-        .mmu_trcr_mask = 0xffffffff,
-        .nwindows = 8,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "Ross RT620",
-        .iu_version = 0x1f000000,
-        .fpu_version = 1 << 17,
-        .mmu_version = 0x1f000000,
-        .mmu_bm = 0x00004000,
-        .mmu_ctpr_mask = 0x007ffff0,
-        .mmu_cxr_mask = 0x0000003f,
-        .mmu_sfsr_mask = 0xffffffff,
-        .mmu_trcr_mask = 0xffffffff,
-        .nwindows = 8,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "BIT B5010",
-        .iu_version = 0x20000000,
-        .fpu_version = 0 << 17, /* B5010/B5110/B5120/B5210 */
-        .mmu_version = 0x20000000,
-        .mmu_bm = 0x00004000,
-        .mmu_ctpr_mask = 0x007ffff0,
-        .mmu_cxr_mask = 0x0000003f,
-        .mmu_sfsr_mask = 0xffffffff,
-        .mmu_trcr_mask = 0xffffffff,
-        .nwindows = 8,
-        .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
-        CPU_FEATURE_FSMULD,
-    },
-    {
-        .name = "Matsushita MN10501",
-        .iu_version = 0x50000000,
-        .fpu_version = 0 << 17,
-        .mmu_version = 0x50000000,
-        .mmu_bm = 0x00004000,
-        .mmu_ctpr_mask = 0x007ffff0,
-        .mmu_cxr_mask = 0x0000003f,
-        .mmu_sfsr_mask = 0xffffffff,
-        .mmu_trcr_mask = 0xffffffff,
-        .nwindows = 8,
-        .features = CPU_FEATURE_FLOAT | CPU_FEATURE_MUL | CPU_FEATURE_FSQRT |
-        CPU_FEATURE_FSMULD,
-    },
-    {
-        .name = "Weitek W8601",
-        .iu_version = 0x90 << 24, /* Impl 9, ver 0 */
-        .fpu_version = 3 << 17, /* FPU version 3 (Weitek WTL3170/2) */
-        .mmu_version = 0x10 << 24,
-        .mmu_bm = 0x00004000,
-        .mmu_ctpr_mask = 0x007ffff0,
-        .mmu_cxr_mask = 0x0000003f,
-        .mmu_sfsr_mask = 0xffffffff,
-        .mmu_trcr_mask = 0xffffffff,
-        .nwindows = 8,
-        .features = CPU_DEFAULT_FEATURES,
-    },
-    {
-        .name = "LEON2",
-        .iu_version = 0xf2000000,
-        .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
-        .mmu_version = 0xf2000000,
-        .mmu_bm = 0x00004000,
-        .mmu_ctpr_mask = 0x007ffff0,
-        .mmu_cxr_mask = 0x0000003f,
-        .mmu_sfsr_mask = 0xffffffff,
-        .mmu_trcr_mask = 0xffffffff,
-        .nwindows = 8,
-        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
-    },
-    {
-        .name = "LEON3",
-        .iu_version = 0xf3000000,
-        .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
-        .mmu_version = 0xf3000000,
-        .mmu_bm = 0x00000000,
-        .mmu_ctpr_mask = 0x007ffff0,
-        .mmu_cxr_mask = 0x0000003f,
-        .mmu_sfsr_mask = 0xffffffff,
-        .mmu_trcr_mask = 0xffffffff,
-        .nwindows = 8,
-        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN |
-        CPU_FEATURE_ASR17 | CPU_FEATURE_CACHE_CTRL,
-    },
-#endif
-};
-
-static const char * const feature_name[] = {
-    "float",
-    "float128",
-    "swap",
-    "mul",
-    "div",
-    "flush",
-    "fsqrt",
-    "fmul",
-    "vis1",
-    "vis2",
-    "fsmuld",
-    "hypv",
-    "cmt",
-    "gl",
-};
-
-static void print_features(FILE *f, fprintf_function cpu_fprintf,
-                           uint32_t features, const char *prefix)
-{
-    unsigned int i;
-
-    for (i = 0; i < ARRAY_SIZE(feature_name); i++)
-        if (feature_name[i] && (features & (1 << i))) {
-            if (prefix)
-                (*cpu_fprintf)(f, "%s", prefix);
-            (*cpu_fprintf)(f, "%s ", feature_name[i]);
-        }
-}
-
-static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features)
-{
-    unsigned int i;
-
-    for (i = 0; i < ARRAY_SIZE(feature_name); i++)
-        if (feature_name[i] && !strcmp(flagname, feature_name[i])) {
-            *features |= 1 << i;
-            return;
-        }
-    fprintf(stderr, "CPU feature %s not found\n", flagname);
-}
-
-static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model)
-{
-    unsigned int i;
-    const sparc_def_t *def = NULL;
-    char *s = strdup(cpu_model);
-    char *featurestr, *name = strtok(s, ",");
-    uint32_t plus_features = 0;
-    uint32_t minus_features = 0;
-    uint64_t iu_version;
-    uint32_t fpu_version, mmu_version, nwindows;
-
-    for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
-        if (strcasecmp(name, sparc_defs[i].name) == 0) {
-            def = &sparc_defs[i];
-        }
+    if (cc) {
+        env->cc_dst = x0;
+        env->cc_src2 = overflow;
+        env->cc_op = CC_OP_DIV;
     }
-    if (!def)
-        goto error;
-    memcpy(cpu_def, def, sizeof(*def));
-
-    featurestr = strtok(NULL, ",");
-    while (featurestr) {
-        char *val;
-
-        if (featurestr[0] == '+') {
-            add_flagname_to_bitmaps(featurestr + 1, &plus_features);
-        } else if (featurestr[0] == '-') {
-            add_flagname_to_bitmaps(featurestr + 1, &minus_features);
-        } else if ((val = strchr(featurestr, '='))) {
-            *val = 0; val++;
-            if (!strcmp(featurestr, "iu_version")) {
-                char *err;
-
-                iu_version = strtoll(val, &err, 0);
-                if (!*val || *err) {
-                    fprintf(stderr, "bad numerical value %s\n", val);
-                    goto error;
-                }
-                cpu_def->iu_version = iu_version;
-#ifdef DEBUG_FEATURES
-                fprintf(stderr, "iu_version %" PRIx64 "\n", iu_version);
-#endif
-            } else if (!strcmp(featurestr, "fpu_version")) {
-                char *err;
-
-                fpu_version = strtol(val, &err, 0);
-                if (!*val || *err) {
-                    fprintf(stderr, "bad numerical value %s\n", val);
-                    goto error;
-                }
-                cpu_def->fpu_version = fpu_version;
-#ifdef DEBUG_FEATURES
-                fprintf(stderr, "fpu_version %x\n", fpu_version);
-#endif
-            } else if (!strcmp(featurestr, "mmu_version")) {
-                char *err;
-
-                mmu_version = strtol(val, &err, 0);
-                if (!*val || *err) {
-                    fprintf(stderr, "bad numerical value %s\n", val);
-                    goto error;
-                }
-                cpu_def->mmu_version = mmu_version;
-#ifdef DEBUG_FEATURES
-                fprintf(stderr, "mmu_version %x\n", mmu_version);
-#endif
-            } else if (!strcmp(featurestr, "nwindows")) {
-                char *err;
-
-                nwindows = strtol(val, &err, 0);
-                if (!*val || *err || nwindows > MAX_NWINDOWS ||
-                    nwindows < MIN_NWINDOWS) {
-                    fprintf(stderr, "bad numerical value %s\n", val);
-                    goto error;
-                }
-                cpu_def->nwindows = nwindows;
-#ifdef DEBUG_FEATURES
-                fprintf(stderr, "nwindows %d\n", nwindows);
-#endif
-            } else {
-                fprintf(stderr, "unrecognized feature %s\n", featurestr);
-                goto error;
-            }
-        } else {
-            fprintf(stderr, "feature string `%s' not in format "
-                    "(+feature|-feature|feature=xyz)\n", featurestr);
-            goto error;
-        }
-        featurestr = strtok(NULL, ",");
-    }
-    cpu_def->features |= plus_features;
-    cpu_def->features &= ~minus_features;
-#ifdef DEBUG_FEATURES
-    print_features(stderr, fprintf, cpu_def->features, NULL);
-#endif
-    free(s);
-    return 0;
-
- error:
-    free(s);
-    return -1;
+    return x0;
 }
 
-void sparc_cpu_list(FILE *f, fprintf_function cpu_fprintf)
+target_ulong helper_udiv(CPUState *env, target_ulong a, target_ulong b)
 {
-    unsigned int i;
-
-    for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
-        (*cpu_fprintf)(f, "Sparc %16s IU " TARGET_FMT_lx " FPU %08x MMU %08x NWINS %d ",
-                       sparc_defs[i].name,
-                       sparc_defs[i].iu_version,
-                       sparc_defs[i].fpu_version,
-                       sparc_defs[i].mmu_version,
-                       sparc_defs[i].nwindows);
-        print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES &
-                       ~sparc_defs[i].features, "-");
-        print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES &
-                       sparc_defs[i].features, "+");
-        (*cpu_fprintf)(f, "\n");
-    }
-    (*cpu_fprintf)(f, "Default CPU feature flags (use '-' to remove): ");
-    print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES, NULL);
-    (*cpu_fprintf)(f, "\n");
-    (*cpu_fprintf)(f, "Available CPU feature flags (use '+' to add): ");
-    print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES, NULL);
-    (*cpu_fprintf)(f, "\n");
-    (*cpu_fprintf)(f, "Numerical features (use '=' to set): iu_version "
-                   "fpu_version mmu_version nwindows\n");
+    return helper_udiv_common(env, a, b, 0);
 }
 
-static void cpu_print_cc(FILE *f, fprintf_function cpu_fprintf,
-                         uint32_t cc)
+target_ulong helper_udiv_cc(CPUState *env, target_ulong a, target_ulong b)
 {
-    cpu_fprintf(f, "%c%c%c%c", cc & PSR_NEG? 'N' : '-',
-                cc & PSR_ZERO? 'Z' : '-', cc & PSR_OVF? 'V' : '-',
-                cc & PSR_CARRY? 'C' : '-');
+    return helper_udiv_common(env, a, b, 1);
 }
 
-#ifdef TARGET_SPARC64
-#define REGS_PER_LINE 4
-#else
-#define REGS_PER_LINE 8
-#endif
-
-void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
-                    int flags)
+static target_ulong helper_sdiv_common(CPUState *env, target_ulong a,
+                                       target_ulong b, int cc)
 {
-    int i, x;
+    int overflow = 0;
+    int64_t x0;
+    int32_t x1;
 
-    cpu_fprintf(f, "pc: " TARGET_FMT_lx "  npc: " TARGET_FMT_lx "\n", env->pc,
-                env->npc);
-    cpu_fprintf(f, "General Registers:\n");
+    x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
+    x1 = (b & 0xffffffff);
 
-    for (i = 0; i < 8; i++) {
-        if (i % REGS_PER_LINE == 0) {
-            cpu_fprintf(f, "%%g%d-%d:", i, i + REGS_PER_LINE - 1);
-        }
-        cpu_fprintf(f, " " TARGET_FMT_lx, env->gregs[i]);
-        if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
-            cpu_fprintf(f, "\n");
-        }
+    if (x1 == 0) {
+        helper_raise_exception(env, TT_DIV_ZERO);
     }
-    cpu_fprintf(f, "\nCurrent Register Window:\n");
-    for (x = 0; x < 3; x++) {
-        for (i = 0; i < 8; i++) {
-            if (i % REGS_PER_LINE == 0) {
-                cpu_fprintf(f, "%%%c%d-%d: ",
-                            x == 0 ? 'o' : (x == 1 ? 'l' : 'i'),
-                            i, i + REGS_PER_LINE - 1);
-            }
-            cpu_fprintf(f, TARGET_FMT_lx " ", env->regwptr[i + x * 8]);
-            if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
-                cpu_fprintf(f, "\n");
-            }
-        }
+
+    x0 = x0 / x1;
+    if ((int32_t) x0 != x0) {
+        x0 = x0 < 0 ? 0x80000000 : 0x7fffffff;
+        overflow = 1;
     }
-    cpu_fprintf(f, "\nFloating Point Registers:\n");
-    for (i = 0; i < TARGET_FPREGS; i++) {
-        if ((i & 3) == 0)
-            cpu_fprintf(f, "%%f%02d:", i);
-        cpu_fprintf(f, " %016f", *(float *)&env->fpr[i]);
-        if ((i & 3) == 3)
-            cpu_fprintf(f, "\n");
+
+    if (cc) {
+        env->cc_dst = x0;
+        env->cc_src2 = overflow;
+        env->cc_op = CC_OP_DIV;
     }
-#ifdef TARGET_SPARC64
-    cpu_fprintf(f, "pstate: %08x ccr: %02x (icc: ", env->pstate,
-                (unsigned)cpu_get_ccr(env));
-    cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << PSR_CARRY_SHIFT);
-    cpu_fprintf(f, " xcc: ");
-    cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << (PSR_CARRY_SHIFT - 4));
-    cpu_fprintf(f, ") asi: %02x tl: %d pil: %x\n", env->asi, env->tl,
-                env->psrpil);
-    cpu_fprintf(f, "cansave: %d canrestore: %d otherwin: %d wstate: %d "
-                "cleanwin: %d cwp: %d\n",
-                env->cansave, env->canrestore, env->otherwin, env->wstate,
-                env->cleanwin, env->nwindows - 1 - env->cwp);
-    cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx " fprs: "
-                TARGET_FMT_lx "\n", env->fsr, env->y, env->fprs);
-#else
-    cpu_fprintf(f, "psr: %08x (icc: ", cpu_get_psr(env));
-    cpu_print_cc(f, cpu_fprintf, cpu_get_psr(env));
-    cpu_fprintf(f, " SPE: %c%c%c) wim: %08x\n", env->psrs? 'S' : '-',
-                env->psrps? 'P' : '-', env->psret? 'E' : '-',
-                env->wim);
-    cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx "\n",
-                env->fsr, env->y);
-#endif
+    return x0;
+}
+
+target_ulong helper_sdiv(CPUState *env, target_ulong a, target_ulong b)
+{
+    return helper_sdiv_common(env, a, b, 0);
+}
+
+target_ulong helper_sdiv_cc(CPUState *env, target_ulong a, target_ulong b)
+{
+    return helper_sdiv_common(env, a, b, 1);
 }
diff --git a/target-sparc/helper.h b/target-sparc/helper.h
index 2d36af3..615ddef 100644
--- a/target-sparc/helper.h
+++ b/target-sparc/helper.h
@@ -1,44 +1,44 @@
 #include "def-helper.h"
 
 #ifndef TARGET_SPARC64
-DEF_HELPER_0(rett, void)
-DEF_HELPER_1(wrpsr, void, tl)
-DEF_HELPER_0(rdpsr, tl)
+DEF_HELPER_1(rett, void, env)
+DEF_HELPER_2(wrpsr, void, env, tl)
+DEF_HELPER_1(rdpsr, tl, env)
 #else
-DEF_HELPER_1(wrpil, void, tl)
-DEF_HELPER_1(wrpstate, void, tl)
-DEF_HELPER_0(done, void)
-DEF_HELPER_0(retry, void)
-DEF_HELPER_0(flushw, void)
-DEF_HELPER_0(saved, void)
-DEF_HELPER_0(restored, void)
-DEF_HELPER_0(rdccr, tl)
-DEF_HELPER_1(wrccr, void, tl)
-DEF_HELPER_0(rdcwp, tl)
-DEF_HELPER_1(wrcwp, void, tl)
-DEF_HELPER_2(array8, tl, tl, tl)
-DEF_HELPER_2(alignaddr, tl, tl, tl)
+DEF_HELPER_2(wrpil, void, env, tl)
+DEF_HELPER_2(wrpstate, void, env, tl)
+DEF_HELPER_1(done, void, env)
+DEF_HELPER_1(retry, void, env)
+DEF_HELPER_1(flushw, void, env)
+DEF_HELPER_1(saved, void, env)
+DEF_HELPER_1(restored, void, env)
+DEF_HELPER_1(rdccr, tl, env)
+DEF_HELPER_2(wrccr, void, env, tl)
+DEF_HELPER_1(rdcwp, tl, env)
+DEF_HELPER_2(wrcwp, void, env, tl)
+DEF_HELPER_3(array8, tl, env, tl, tl)
+DEF_HELPER_3(alignaddr, tl, env, tl, tl)
 DEF_HELPER_1(popc, tl, tl)
 DEF_HELPER_3(ldda_asi, void, tl, int, int)
 DEF_HELPER_4(ldf_asi, void, tl, int, int, int)
 DEF_HELPER_4(stf_asi, void, tl, int, int, int)
 DEF_HELPER_4(cas_asi, tl, tl, tl, tl, i32)
 DEF_HELPER_4(casx_asi, tl, tl, tl, tl, i32)
-DEF_HELPER_1(set_softint, void, i64)
-DEF_HELPER_1(clear_softint, void, i64)
-DEF_HELPER_1(write_softint, void, i64)
+DEF_HELPER_2(set_softint, void, env, i64)
+DEF_HELPER_2(clear_softint, void, env, i64)
+DEF_HELPER_2(write_softint, void, env, i64)
 DEF_HELPER_2(tick_set_count, void, ptr, i64)
 DEF_HELPER_1(tick_get_count, i64, ptr)
 DEF_HELPER_2(tick_set_limit, void, ptr, i64)
 #endif
 DEF_HELPER_2(check_align, void, tl, i32)
-DEF_HELPER_0(debug, void)
-DEF_HELPER_0(save, void)
-DEF_HELPER_0(restore, void)
-DEF_HELPER_2(udiv, tl, tl, tl)
-DEF_HELPER_2(udiv_cc, tl, tl, tl)
-DEF_HELPER_2(sdiv, tl, tl, tl)
-DEF_HELPER_2(sdiv_cc, tl, tl, tl)
+DEF_HELPER_1(debug, void, env)
+DEF_HELPER_1(save, void, env)
+DEF_HELPER_1(restore, void, env)
+DEF_HELPER_3(udiv, tl, env, tl, tl)
+DEF_HELPER_3(udiv_cc, tl, env, tl, tl)
+DEF_HELPER_3(sdiv, tl, env, tl, tl)
+DEF_HELPER_3(sdiv_cc, tl, env, tl, tl)
 DEF_HELPER_2(stdf, void, tl, int)
 DEF_HELPER_2(lddf, void, tl, int)
 DEF_HELPER_2(ldqf, void, tl, int)
@@ -47,119 +47,119 @@
 DEF_HELPER_4(ld_asi, i64, tl, int, int, int)
 DEF_HELPER_4(st_asi, void, tl, i64, int, int)
 #endif
-DEF_HELPER_1(ldfsr, void, i32)
-DEF_HELPER_0(check_ieee_exceptions, void)
-DEF_HELPER_0(clear_float_exceptions, void)
+DEF_HELPER_2(ldfsr, void, env, i32)
+DEF_HELPER_1(check_ieee_exceptions, void, env)
+DEF_HELPER_1(clear_float_exceptions, void, env)
 DEF_HELPER_1(fabss, f32, f32)
-DEF_HELPER_1(fsqrts, f32, f32)
-DEF_HELPER_0(fsqrtd, void)
-DEF_HELPER_2(fcmps, void, f32, f32)
-DEF_HELPER_0(fcmpd, void)
-DEF_HELPER_2(fcmpes, void, f32, f32)
-DEF_HELPER_0(fcmped, void)
-DEF_HELPER_0(fsqrtq, void)
-DEF_HELPER_0(fcmpq, void)
-DEF_HELPER_0(fcmpeq, void)
+DEF_HELPER_2(fsqrts, f32, env, f32)
+DEF_HELPER_1(fsqrtd, void, env)
+DEF_HELPER_3(fcmps, void, env, f32, f32)
+DEF_HELPER_1(fcmpd, void, env)
+DEF_HELPER_3(fcmpes, void, env, f32, f32)
+DEF_HELPER_1(fcmped, void, env)
+DEF_HELPER_1(fsqrtq, void, env)
+DEF_HELPER_1(fcmpq, void, env)
+DEF_HELPER_1(fcmpeq, void, env)
 #ifdef TARGET_SPARC64
-DEF_HELPER_1(ldxfsr, void, i64)
-DEF_HELPER_0(fabsd, void)
-DEF_HELPER_2(fcmps_fcc1, void, f32, f32)
-DEF_HELPER_2(fcmps_fcc2, void, f32, f32)
-DEF_HELPER_2(fcmps_fcc3, void, f32, f32)
-DEF_HELPER_0(fcmpd_fcc1, void)
-DEF_HELPER_0(fcmpd_fcc2, void)
-DEF_HELPER_0(fcmpd_fcc3, void)
-DEF_HELPER_2(fcmpes_fcc1, void, f32, f32)
-DEF_HELPER_2(fcmpes_fcc2, void, f32, f32)
-DEF_HELPER_2(fcmpes_fcc3, void, f32, f32)
-DEF_HELPER_0(fcmped_fcc1, void)
-DEF_HELPER_0(fcmped_fcc2, void)
-DEF_HELPER_0(fcmped_fcc3, void)
-DEF_HELPER_0(fabsq, void)
-DEF_HELPER_0(fcmpq_fcc1, void)
-DEF_HELPER_0(fcmpq_fcc2, void)
-DEF_HELPER_0(fcmpq_fcc3, void)
-DEF_HELPER_0(fcmpeq_fcc1, void)
-DEF_HELPER_0(fcmpeq_fcc2, void)
-DEF_HELPER_0(fcmpeq_fcc3, void)
+DEF_HELPER_2(ldxfsr, void, env, i64)
+DEF_HELPER_1(fabsd, void, env)
+DEF_HELPER_3(fcmps_fcc1, void, env, f32, f32)
+DEF_HELPER_3(fcmps_fcc2, void, env, f32, f32)
+DEF_HELPER_3(fcmps_fcc3, void, env, f32, f32)
+DEF_HELPER_1(fcmpd_fcc1, void, env)
+DEF_HELPER_1(fcmpd_fcc2, void, env)
+DEF_HELPER_1(fcmpd_fcc3, void, env)
+DEF_HELPER_3(fcmpes_fcc1, void, env, f32, f32)
+DEF_HELPER_3(fcmpes_fcc2, void, env, f32, f32)
+DEF_HELPER_3(fcmpes_fcc3, void, env, f32, f32)
+DEF_HELPER_1(fcmped_fcc1, void, env)
+DEF_HELPER_1(fcmped_fcc2, void, env)
+DEF_HELPER_1(fcmped_fcc3, void, env)
+DEF_HELPER_1(fabsq, void, env)
+DEF_HELPER_1(fcmpq_fcc1, void, env)
+DEF_HELPER_1(fcmpq_fcc2, void, env)
+DEF_HELPER_1(fcmpq_fcc3, void, env)
+DEF_HELPER_1(fcmpeq_fcc1, void, env)
+DEF_HELPER_1(fcmpeq_fcc2, void, env)
+DEF_HELPER_1(fcmpeq_fcc3, void, env)
 #endif
-DEF_HELPER_1(raise_exception, void, int)
+DEF_HELPER_2(raise_exception, void, env, int)
 DEF_HELPER_0(shutdown, void)
-#define F_HELPER_0_0(name) DEF_HELPER_0(f ## name, void)
-#define F_HELPER_DQ_0_0(name)                   \
-    F_HELPER_0_0(name ## d);                    \
-    F_HELPER_0_0(name ## q)
+#define F_HELPER_0_1(name) DEF_HELPER_1(f ## name, void, env)
+#define F_HELPER_DQ_0_1(name)                   \
+    F_HELPER_0_1(name ## d);                    \
+    F_HELPER_0_1(name ## q)
 
-F_HELPER_DQ_0_0(add);
-F_HELPER_DQ_0_0(sub);
-F_HELPER_DQ_0_0(mul);
-F_HELPER_DQ_0_0(div);
+F_HELPER_DQ_0_1(add);
+F_HELPER_DQ_0_1(sub);
+F_HELPER_DQ_0_1(mul);
+F_HELPER_DQ_0_1(div);
 
-DEF_HELPER_2(fadds, f32, f32, f32)
-DEF_HELPER_2(fsubs, f32, f32, f32)
-DEF_HELPER_2(fmuls, f32, f32, f32)
-DEF_HELPER_2(fdivs, f32, f32, f32)
+DEF_HELPER_3(fadds, f32, env, f32, f32)
+DEF_HELPER_3(fsubs, f32, env, f32, f32)
+DEF_HELPER_3(fmuls, f32, env, f32, f32)
+DEF_HELPER_3(fdivs, f32, env, f32, f32)
 
-DEF_HELPER_2(fsmuld, void, f32, f32)
-F_HELPER_0_0(dmulq);
+DEF_HELPER_3(fsmuld, void, env, f32, f32)
+F_HELPER_0_1(dmulq);
 
 DEF_HELPER_1(fnegs, f32, f32)
-DEF_HELPER_1(fitod, void, s32)
-DEF_HELPER_1(fitoq, void, s32)
+DEF_HELPER_2(fitod, void, env, s32)
+DEF_HELPER_2(fitoq, void, env, s32)
 
-DEF_HELPER_1(fitos, f32, s32)
+DEF_HELPER_2(fitos, f32, env, s32)
 
 #ifdef TARGET_SPARC64
-DEF_HELPER_0(fnegd, void)
-DEF_HELPER_0(fnegq, void)
-DEF_HELPER_0(fxtos, i32)
-F_HELPER_DQ_0_0(xto);
+DEF_HELPER_1(fnegd, void, env)
+DEF_HELPER_1(fnegq, void, env)
+DEF_HELPER_1(fxtos, i32, env)
+F_HELPER_DQ_0_1(xto);
 #endif
-DEF_HELPER_0(fdtos, f32)
-DEF_HELPER_1(fstod, void, f32)
-DEF_HELPER_0(fqtos, f32)
-DEF_HELPER_1(fstoq, void, f32)
-F_HELPER_0_0(qtod);
-F_HELPER_0_0(dtoq);
-DEF_HELPER_1(fstoi, s32, f32)
-DEF_HELPER_0(fdtoi, s32)
-DEF_HELPER_0(fqtoi, s32)
+DEF_HELPER_1(fdtos, f32, env)
+DEF_HELPER_2(fstod, void, env, f32)
+DEF_HELPER_1(fqtos, f32, env)
+DEF_HELPER_2(fstoq, void, env, f32)
+F_HELPER_0_1(qtod);
+F_HELPER_0_1(dtoq);
+DEF_HELPER_2(fstoi, s32, env, f32)
+DEF_HELPER_1(fdtoi, s32, env)
+DEF_HELPER_1(fqtoi, s32, env)
 #ifdef TARGET_SPARC64
-DEF_HELPER_1(fstox, void, i32)
-F_HELPER_0_0(dtox);
-F_HELPER_0_0(qtox);
-F_HELPER_0_0(aligndata);
+DEF_HELPER_2(fstox, void, env, i32)
+F_HELPER_0_1(dtox);
+F_HELPER_0_1(qtox);
+F_HELPER_0_1(aligndata);
 
-F_HELPER_0_0(pmerge);
-F_HELPER_0_0(mul8x16);
-F_HELPER_0_0(mul8x16al);
-F_HELPER_0_0(mul8x16au);
-F_HELPER_0_0(mul8sux16);
-F_HELPER_0_0(mul8ulx16);
-F_HELPER_0_0(muld8sux16);
-F_HELPER_0_0(muld8ulx16);
-F_HELPER_0_0(expand);
+F_HELPER_0_1(pmerge);
+F_HELPER_0_1(mul8x16);
+F_HELPER_0_1(mul8x16al);
+F_HELPER_0_1(mul8x16au);
+F_HELPER_0_1(mul8sux16);
+F_HELPER_0_1(mul8ulx16);
+F_HELPER_0_1(muld8sux16);
+F_HELPER_0_1(muld8ulx16);
+F_HELPER_0_1(expand);
 #define VIS_HELPER(name)                                 \
-    F_HELPER_0_0(name##16);                              \
-    DEF_HELPER_2(f ## name ## 16s, i32, i32, i32) \
-    F_HELPER_0_0(name##32);                              \
-    DEF_HELPER_2(f ## name ## 32s, i32, i32, i32)
+    F_HELPER_0_1(name##16);                              \
+    DEF_HELPER_3(f ## name ## 16s, i32, env, i32, i32)   \
+    F_HELPER_0_1(name##32);                              \
+    DEF_HELPER_3(f ## name ## 32s, i32, env, i32, i32)
 
 VIS_HELPER(padd);
 VIS_HELPER(psub);
 #define VIS_CMPHELPER(name)                              \
-    DEF_HELPER_0(f##name##16, i64);                      \
-    DEF_HELPER_0(f##name##32, i64)
+    DEF_HELPER_1(f##name##16, i64, env);                 \
+    DEF_HELPER_1(f##name##32, i64, env)
 VIS_CMPHELPER(cmpgt);
 VIS_CMPHELPER(cmpeq);
 VIS_CMPHELPER(cmple);
 VIS_CMPHELPER(cmpne);
 #endif
-#undef F_HELPER_0_0
-#undef F_HELPER_DQ_0_0
+#undef F_HELPER_0_1
+#undef F_HELPER_DQ_0_1
 #undef VIS_HELPER
 #undef VIS_CMPHELPER
-DEF_HELPER_0(compute_psr, void);
-DEF_HELPER_0(compute_C_icc, i32);
+DEF_HELPER_1(compute_psr, void, env);
+DEF_HELPER_1(compute_C_icc, i32, env);
 
 #include "def-helper.h"
diff --git a/target-sparc/int32_helper.c b/target-sparc/int32_helper.c
new file mode 100644
index 0000000..3a749bf
--- /dev/null
+++ b/target-sparc/int32_helper.c
@@ -0,0 +1,163 @@
+/*
+ * Sparc32 interrupt helpers
+ *
+ *  Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * 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/>.
+ */
+
+#include "cpu.h"
+#include "trace.h"
+
+//#define DEBUG_PCALL
+
+#ifdef DEBUG_PCALL
+static const char * const excp_names[0x80] = {
+    [TT_TFAULT] = "Instruction Access Fault",
+    [TT_ILL_INSN] = "Illegal Instruction",
+    [TT_PRIV_INSN] = "Privileged Instruction",
+    [TT_NFPU_INSN] = "FPU Disabled",
+    [TT_WIN_OVF] = "Window Overflow",
+    [TT_WIN_UNF] = "Window Underflow",
+    [TT_UNALIGNED] = "Unaligned Memory Access",
+    [TT_FP_EXCP] = "FPU Exception",
+    [TT_DFAULT] = "Data Access Fault",
+    [TT_TOVF] = "Tag Overflow",
+    [TT_EXTINT | 0x1] = "External Interrupt 1",
+    [TT_EXTINT | 0x2] = "External Interrupt 2",
+    [TT_EXTINT | 0x3] = "External Interrupt 3",
+    [TT_EXTINT | 0x4] = "External Interrupt 4",
+    [TT_EXTINT | 0x5] = "External Interrupt 5",
+    [TT_EXTINT | 0x6] = "External Interrupt 6",
+    [TT_EXTINT | 0x7] = "External Interrupt 7",
+    [TT_EXTINT | 0x8] = "External Interrupt 8",
+    [TT_EXTINT | 0x9] = "External Interrupt 9",
+    [TT_EXTINT | 0xa] = "External Interrupt 10",
+    [TT_EXTINT | 0xb] = "External Interrupt 11",
+    [TT_EXTINT | 0xc] = "External Interrupt 12",
+    [TT_EXTINT | 0xd] = "External Interrupt 13",
+    [TT_EXTINT | 0xe] = "External Interrupt 14",
+    [TT_EXTINT | 0xf] = "External Interrupt 15",
+    [TT_TOVF] = "Tag Overflow",
+    [TT_CODE_ACCESS] = "Instruction Access Error",
+    [TT_DATA_ACCESS] = "Data Access Error",
+    [TT_DIV_ZERO] = "Division By Zero",
+    [TT_NCP_INSN] = "Coprocessor Disabled",
+};
+#endif
+
+void do_interrupt(CPUState *env)
+{
+    int cwp, intno = env->exception_index;
+
+#ifdef DEBUG_PCALL
+    if (qemu_loglevel_mask(CPU_LOG_INT)) {
+        static int count;
+        const char *name;
+
+        if (intno < 0 || intno >= 0x100) {
+            name = "Unknown";
+        } else if (intno >= 0x80) {
+            name = "Trap Instruction";
+        } else {
+            name = excp_names[intno];
+            if (!name) {
+                name = "Unknown";
+            }
+        }
+
+        qemu_log("%6d: %s (v=%02x) pc=%08x npc=%08x SP=%08x\n",
+                count, name, intno,
+                env->pc,
+                env->npc, env->regwptr[6]);
+        log_cpu_state(env, 0);
+#if 0
+        {
+            int i;
+            uint8_t *ptr;
+
+            qemu_log("       code=");
+            ptr = (uint8_t *)env->pc;
+            for (i = 0; i < 16; i++) {
+                qemu_log(" %02x", ldub(ptr + i));
+            }
+            qemu_log("\n");
+        }
+#endif
+        count++;
+    }
+#endif
+#if !defined(CONFIG_USER_ONLY)
+    if (env->psret == 0) {
+        cpu_abort(env, "Trap 0x%02x while interrupts disabled, Error state",
+                  env->exception_index);
+        return;
+    }
+#endif
+    env->psret = 0;
+    cwp = cpu_cwp_dec(env, env->cwp - 1);
+    cpu_set_cwp(env, cwp);
+    env->regwptr[9] = env->pc;
+    env->regwptr[10] = env->npc;
+    env->psrps = env->psrs;
+    env->psrs = 1;
+    env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4);
+    env->pc = env->tbr;
+    env->npc = env->pc + 4;
+    env->exception_index = -1;
+
+#if !defined(CONFIG_USER_ONLY)
+    /* IRQ acknowledgment */
+    if ((intno & ~15) == TT_EXTINT && env->qemu_irq_ack != NULL) {
+        env->qemu_irq_ack(env, env->irq_manager, intno);
+    }
+#endif
+}
+
+#if !defined(CONFIG_USER_ONLY)
+static void leon3_cache_control_int(CPUState *env)
+{
+    uint32_t state = 0;
+
+    if (env->cache_control & CACHE_CTRL_IF) {
+        /* Instruction cache state */
+        state = env->cache_control & CACHE_STATE_MASK;
+        if (state == CACHE_ENABLED) {
+            state = CACHE_FROZEN;
+            trace_int_helper_icache_freeze();
+        }
+
+        env->cache_control &= ~CACHE_STATE_MASK;
+        env->cache_control |= state;
+    }
+
+    if (env->cache_control & CACHE_CTRL_DF) {
+        /* Data cache state */
+        state = (env->cache_control >> 2) & CACHE_STATE_MASK;
+        if (state == CACHE_ENABLED) {
+            state = CACHE_FROZEN;
+            trace_int_helper_dcache_freeze();
+        }
+
+        env->cache_control &= ~(CACHE_STATE_MASK << 2);
+        env->cache_control |= (state << 2);
+    }
+}
+
+void leon3_irq_manager(CPUState *env, void *irq_manager, int intno)
+{
+    leon3_irq_ack(irq_manager, intno);
+    leon3_cache_control_int(env);
+}
+#endif
diff --git a/target-sparc/int64_helper.c b/target-sparc/int64_helper.c
new file mode 100644
index 0000000..1d471db
--- /dev/null
+++ b/target-sparc/int64_helper.c
@@ -0,0 +1,201 @@
+/*
+ * Sparc64 interrupt helpers
+ *
+ *  Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * 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/>.
+ */
+
+#include "cpu.h"
+#include "helper.h"
+#include "trace.h"
+
+//#define DEBUG_PCALL
+
+#ifdef DEBUG_PCALL
+static const char * const excp_names[0x80] = {
+    [TT_TFAULT] = "Instruction Access Fault",
+    [TT_TMISS] = "Instruction Access MMU Miss",
+    [TT_CODE_ACCESS] = "Instruction Access Error",
+    [TT_ILL_INSN] = "Illegal Instruction",
+    [TT_PRIV_INSN] = "Privileged Instruction",
+    [TT_NFPU_INSN] = "FPU Disabled",
+    [TT_FP_EXCP] = "FPU Exception",
+    [TT_TOVF] = "Tag Overflow",
+    [TT_CLRWIN] = "Clean Windows",
+    [TT_DIV_ZERO] = "Division By Zero",
+    [TT_DFAULT] = "Data Access Fault",
+    [TT_DMISS] = "Data Access MMU Miss",
+    [TT_DATA_ACCESS] = "Data Access Error",
+    [TT_DPROT] = "Data Protection Error",
+    [TT_UNALIGNED] = "Unaligned Memory Access",
+    [TT_PRIV_ACT] = "Privileged Action",
+    [TT_EXTINT | 0x1] = "External Interrupt 1",
+    [TT_EXTINT | 0x2] = "External Interrupt 2",
+    [TT_EXTINT | 0x3] = "External Interrupt 3",
+    [TT_EXTINT | 0x4] = "External Interrupt 4",
+    [TT_EXTINT | 0x5] = "External Interrupt 5",
+    [TT_EXTINT | 0x6] = "External Interrupt 6",
+    [TT_EXTINT | 0x7] = "External Interrupt 7",
+    [TT_EXTINT | 0x8] = "External Interrupt 8",
+    [TT_EXTINT | 0x9] = "External Interrupt 9",
+    [TT_EXTINT | 0xa] = "External Interrupt 10",
+    [TT_EXTINT | 0xb] = "External Interrupt 11",
+    [TT_EXTINT | 0xc] = "External Interrupt 12",
+    [TT_EXTINT | 0xd] = "External Interrupt 13",
+    [TT_EXTINT | 0xe] = "External Interrupt 14",
+    [TT_EXTINT | 0xf] = "External Interrupt 15",
+};
+#endif
+
+void do_interrupt(CPUState *env)
+{
+    int intno = env->exception_index;
+    trap_state *tsptr;
+
+#ifdef DEBUG_PCALL
+    if (qemu_loglevel_mask(CPU_LOG_INT)) {
+        static int count;
+        const char *name;
+
+        if (intno < 0 || intno >= 0x180) {
+            name = "Unknown";
+        } else if (intno >= 0x100) {
+            name = "Trap Instruction";
+        } else if (intno >= 0xc0) {
+            name = "Window Fill";
+        } else if (intno >= 0x80) {
+            name = "Window Spill";
+        } else {
+            name = excp_names[intno];
+            if (!name) {
+                name = "Unknown";
+            }
+        }
+
+        qemu_log("%6d: %s (v=%04x) pc=%016" PRIx64 " npc=%016" PRIx64
+                " SP=%016" PRIx64 "\n",
+                count, name, intno,
+                env->pc,
+                env->npc, env->regwptr[6]);
+        log_cpu_state(env, 0);
+#if 0
+        {
+            int i;
+            uint8_t *ptr;
+
+            qemu_log("       code=");
+            ptr = (uint8_t *)env->pc;
+            for (i = 0; i < 16; i++) {
+                qemu_log(" %02x", ldub(ptr + i));
+            }
+            qemu_log("\n");
+        }
+#endif
+        count++;
+    }
+#endif
+#if !defined(CONFIG_USER_ONLY)
+    if (env->tl >= env->maxtl) {
+        cpu_abort(env, "Trap 0x%04x while trap level (%d) >= MAXTL (%d),"
+                  " Error state", env->exception_index, env->tl, env->maxtl);
+        return;
+    }
+#endif
+    if (env->tl < env->maxtl - 1) {
+        env->tl++;
+    } else {
+        env->pstate |= PS_RED;
+        if (env->tl < env->maxtl) {
+            env->tl++;
+        }
+    }
+    tsptr = cpu_tsptr(env);
+
+    tsptr->tstate = (cpu_get_ccr(env) << 32) |
+        ((env->asi & 0xff) << 24) | ((env->pstate & 0xf3f) << 8) |
+        cpu_get_cwp64(env);
+    tsptr->tpc = env->pc;
+    tsptr->tnpc = env->npc;
+    tsptr->tt = intno;
+
+    switch (intno) {
+    case TT_IVEC:
+        cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_IG);
+        break;
+    case TT_TFAULT:
+    case TT_DFAULT:
+    case TT_TMISS ... TT_TMISS + 3:
+    case TT_DMISS ... TT_DMISS + 3:
+    case TT_DPROT ... TT_DPROT + 3:
+        cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_MG);
+        break;
+    default:
+        cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_AG);
+        break;
+    }
+
+    if (intno == TT_CLRWIN) {
+        cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - 1));
+    } else if ((intno & 0x1c0) == TT_SPILL) {
+        cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - env->cansave - 2));
+    } else if ((intno & 0x1c0) == TT_FILL) {
+        cpu_set_cwp(env, cpu_cwp_inc(env, env->cwp + 1));
+    }
+    env->tbr &= ~0x7fffULL;
+    env->tbr |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5);
+    env->pc = env->tbr;
+    env->npc = env->pc + 4;
+    env->exception_index = -1;
+}
+
+trap_state *cpu_tsptr(CPUState* env)
+{
+    return &env->ts[env->tl & MAXTL_MASK];
+}
+
+static bool do_modify_softint(CPUState *env, uint32_t value)
+{
+    if (env->softint != value) {
+        env->softint = value;
+#if !defined(CONFIG_USER_ONLY)
+        if (cpu_interrupts_enabled(env)) {
+            cpu_check_irqs(env);
+        }
+#endif
+        return true;
+    }
+    return false;
+}
+
+void helper_set_softint(CPUState *env, uint64_t value)
+{
+    if (do_modify_softint(env, env->softint | (uint32_t)value)) {
+        trace_int_helper_set_softint(env->softint);
+    }
+}
+
+void helper_clear_softint(CPUState *env, uint64_t value)
+{
+    if (do_modify_softint(env, env->softint & (uint32_t)~value)) {
+        trace_int_helper_clear_softint(env->softint);
+    }
+}
+
+void helper_write_softint(CPUState *env, uint64_t value)
+{
+    if (do_modify_softint(env, (uint32_t)value)) {
+        trace_int_helper_write_softint(env->softint);
+    }
+}
diff --git a/target-sparc/ldst_helper.c b/target-sparc/ldst_helper.c
new file mode 100644
index 0000000..1fb3996
--- /dev/null
+++ b/target-sparc/ldst_helper.c
@@ -0,0 +1,2434 @@
+/*
+ * Helpers for loads and stores
+ *
+ *  Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * 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/>.
+ */
+
+#include "cpu.h"
+#include "dyngen-exec.h"
+#include "helper.h"
+
+#if !defined(CONFIG_USER_ONLY)
+#include "softmmu_exec.h"
+#endif
+
+//#define DEBUG_MMU
+//#define DEBUG_MXCC
+//#define DEBUG_UNALIGNED
+//#define DEBUG_UNASSIGNED
+//#define DEBUG_ASI
+//#define DEBUG_CACHE_CONTROL
+
+#ifdef DEBUG_MMU
+#define DPRINTF_MMU(fmt, ...)                                   \
+    do { printf("MMU: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF_MMU(fmt, ...) do {} while (0)
+#endif
+
+#ifdef DEBUG_MXCC
+#define DPRINTF_MXCC(fmt, ...)                                  \
+    do { printf("MXCC: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF_MXCC(fmt, ...) do {} while (0)
+#endif
+
+#ifdef DEBUG_ASI
+#define DPRINTF_ASI(fmt, ...)                                   \
+    do { printf("ASI: " fmt , ## __VA_ARGS__); } while (0)
+#endif
+
+#ifdef DEBUG_CACHE_CONTROL
+#define DPRINTF_CACHE_CONTROL(fmt, ...)                                 \
+    do { printf("CACHE_CONTROL: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF_CACHE_CONTROL(fmt, ...) do {} while (0)
+#endif
+
+#ifdef TARGET_SPARC64
+#ifndef TARGET_ABI32
+#define AM_CHECK(env1) ((env1)->pstate & PS_AM)
+#else
+#define AM_CHECK(env1) (1)
+#endif
+#endif
+
+#define DT0 (env->dt0)
+#define DT1 (env->dt1)
+#define QT0 (env->qt0)
+#define QT1 (env->qt1)
+
+#if !defined(CONFIG_USER_ONLY)
+static void do_unassigned_access(target_phys_addr_t addr, int is_write,
+                                 int is_exec, int is_asi, int size);
+#else
+#ifdef TARGET_SPARC64
+static void do_unassigned_access(target_ulong addr, int is_write, int is_exec,
+                                 int is_asi, int size);
+#endif
+#endif
+
+#if defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
+/* Calculates TSB pointer value for fault page size 8k or 64k */
+static uint64_t ultrasparc_tsb_pointer(uint64_t tsb_register,
+                                       uint64_t tag_access_register,
+                                       int page_size)
+{
+    uint64_t tsb_base = tsb_register & ~0x1fffULL;
+    int tsb_split = (tsb_register & 0x1000ULL) ? 1 : 0;
+    int tsb_size  = tsb_register & 0xf;
+
+    /* discard lower 13 bits which hold tag access context */
+    uint64_t tag_access_va = tag_access_register & ~0x1fffULL;
+
+    /* now reorder bits */
+    uint64_t tsb_base_mask = ~0x1fffULL;
+    uint64_t va = tag_access_va;
+
+    /* move va bits to correct position */
+    if (page_size == 8*1024) {
+        va >>= 9;
+    } else if (page_size == 64*1024) {
+        va >>= 12;
+    }
+
+    if (tsb_size) {
+        tsb_base_mask <<= tsb_size;
+    }
+
+    /* calculate tsb_base mask and adjust va if split is in use */
+    if (tsb_split) {
+        if (page_size == 8*1024) {
+            va &= ~(1ULL << (13 + tsb_size));
+        } else if (page_size == 64*1024) {
+            va |= (1ULL << (13 + tsb_size));
+        }
+        tsb_base_mask <<= 1;
+    }
+
+    return ((tsb_base & tsb_base_mask) | (va & ~tsb_base_mask)) & ~0xfULL;
+}
+
+/* Calculates tag target register value by reordering bits
+   in tag access register */
+static uint64_t ultrasparc_tag_target(uint64_t tag_access_register)
+{
+    return ((tag_access_register & 0x1fff) << 48) | (tag_access_register >> 22);
+}
+
+static void replace_tlb_entry(SparcTLBEntry *tlb,
+                              uint64_t tlb_tag, uint64_t tlb_tte,
+                              CPUState *env1)
+{
+    target_ulong mask, size, va, offset;
+
+    /* flush page range if translation is valid */
+    if (TTE_IS_VALID(tlb->tte)) {
+
+        mask = 0xffffffffffffe000ULL;
+        mask <<= 3 * ((tlb->tte >> 61) & 3);
+        size = ~mask + 1;
+
+        va = tlb->tag & mask;
+
+        for (offset = 0; offset < size; offset += TARGET_PAGE_SIZE) {
+            tlb_flush_page(env1, va + offset);
+        }
+    }
+
+    tlb->tag = tlb_tag;
+    tlb->tte = tlb_tte;
+}
+
+static void demap_tlb(SparcTLBEntry *tlb, target_ulong demap_addr,
+                      const char *strmmu, CPUState *env1)
+{
+    unsigned int i;
+    target_ulong mask;
+    uint64_t context;
+
+    int is_demap_context = (demap_addr >> 6) & 1;
+
+    /* demap context */
+    switch ((demap_addr >> 4) & 3) {
+    case 0: /* primary */
+        context = env1->dmmu.mmu_primary_context;
+        break;
+    case 1: /* secondary */
+        context = env1->dmmu.mmu_secondary_context;
+        break;
+    case 2: /* nucleus */
+        context = 0;
+        break;
+    case 3: /* reserved */
+    default:
+        return;
+    }
+
+    for (i = 0; i < 64; i++) {
+        if (TTE_IS_VALID(tlb[i].tte)) {
+
+            if (is_demap_context) {
+                /* will remove non-global entries matching context value */
+                if (TTE_IS_GLOBAL(tlb[i].tte) ||
+                    !tlb_compare_context(&tlb[i], context)) {
+                    continue;
+                }
+            } else {
+                /* demap page
+                   will remove any entry matching VA */
+                mask = 0xffffffffffffe000ULL;
+                mask <<= 3 * ((tlb[i].tte >> 61) & 3);
+
+                if (!compare_masked(demap_addr, tlb[i].tag, mask)) {
+                    continue;
+                }
+
+                /* entry should be global or matching context value */
+                if (!TTE_IS_GLOBAL(tlb[i].tte) &&
+                    !tlb_compare_context(&tlb[i], context)) {
+                    continue;
+                }
+            }
+
+            replace_tlb_entry(&tlb[i], 0, 0, env1);
+#ifdef DEBUG_MMU
+            DPRINTF_MMU("%s demap invalidated entry [%02u]\n", strmmu, i);
+            dump_mmu(stdout, fprintf, env1);
+#endif
+        }
+    }
+}
+
+static void replace_tlb_1bit_lru(SparcTLBEntry *tlb,
+                                 uint64_t tlb_tag, uint64_t tlb_tte,
+                                 const char *strmmu, CPUState *env1)
+{
+    unsigned int i, replace_used;
+
+    /* Try replacing invalid entry */
+    for (i = 0; i < 64; i++) {
+        if (!TTE_IS_VALID(tlb[i].tte)) {
+            replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1);
+#ifdef DEBUG_MMU
+            DPRINTF_MMU("%s lru replaced invalid entry [%i]\n", strmmu, i);
+            dump_mmu(stdout, fprintf, env1);
+#endif
+            return;
+        }
+    }
+
+    /* All entries are valid, try replacing unlocked entry */
+
+    for (replace_used = 0; replace_used < 2; ++replace_used) {
+
+        /* Used entries are not replaced on first pass */
+
+        for (i = 0; i < 64; i++) {
+            if (!TTE_IS_LOCKED(tlb[i].tte) && !TTE_IS_USED(tlb[i].tte)) {
+
+                replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1);
+#ifdef DEBUG_MMU
+                DPRINTF_MMU("%s lru replaced unlocked %s entry [%i]\n",
+                            strmmu, (replace_used ? "used" : "unused"), i);
+                dump_mmu(stdout, fprintf, env1);
+#endif
+                return;
+            }
+        }
+
+        /* Now reset used bit and search for unused entries again */
+
+        for (i = 0; i < 64; i++) {
+            TTE_SET_UNUSED(tlb[i].tte);
+        }
+    }
+
+#ifdef DEBUG_MMU
+    DPRINTF_MMU("%s lru replacement failed: no entries available\n", strmmu);
+#endif
+    /* error state? */
+}
+
+#endif
+
+static inline target_ulong address_mask(CPUState *env1, target_ulong addr)
+{
+#ifdef TARGET_SPARC64
+    if (AM_CHECK(env1)) {
+        addr &= 0xffffffffULL;
+    }
+#endif
+    return addr;
+}
+
+/* returns true if access using this ASI is to have address translated by MMU
+   otherwise access is to raw physical address */
+static inline int is_translating_asi(int asi)
+{
+#ifdef TARGET_SPARC64
+    /* Ultrasparc IIi translating asi
+       - note this list is defined by cpu implementation
+    */
+    switch (asi) {
+    case 0x04 ... 0x11:
+    case 0x16 ... 0x19:
+    case 0x1E ... 0x1F:
+    case 0x24 ... 0x2C:
+    case 0x70 ... 0x73:
+    case 0x78 ... 0x79:
+    case 0x80 ... 0xFF:
+        return 1;
+
+    default:
+        return 0;
+    }
+#else
+    /* TODO: check sparc32 bits */
+    return 0;
+#endif
+}
+
+static inline target_ulong asi_address_mask(CPUState *env1,
+                                            int asi, target_ulong addr)
+{
+    if (is_translating_asi(asi)) {
+        return address_mask(env, addr);
+    } else {
+        return addr;
+    }
+}
+
+void helper_check_align(target_ulong addr, uint32_t align)
+{
+    if (addr & align) {
+#ifdef DEBUG_UNALIGNED
+        printf("Unaligned access to 0x" TARGET_FMT_lx " from 0x" TARGET_FMT_lx
+               "\n", addr, env->pc);
+#endif
+        helper_raise_exception(env, TT_UNALIGNED);
+    }
+}
+
+#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) &&   \
+    defined(DEBUG_MXCC)
+static void dump_mxcc(CPUState *env)
+{
+    printf("mxccdata: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64
+           "\n",
+           env->mxccdata[0], env->mxccdata[1],
+           env->mxccdata[2], env->mxccdata[3]);
+    printf("mxccregs: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64
+           "\n"
+           "          %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64
+           "\n",
+           env->mxccregs[0], env->mxccregs[1],
+           env->mxccregs[2], env->mxccregs[3],
+           env->mxccregs[4], env->mxccregs[5],
+           env->mxccregs[6], env->mxccregs[7]);
+}
+#endif
+
+#if (defined(TARGET_SPARC64) || !defined(CONFIG_USER_ONLY))     \
+    && defined(DEBUG_ASI)
+static void dump_asi(const char *txt, target_ulong addr, int asi, int size,
+                     uint64_t r1)
+{
+    switch (size) {
+    case 1:
+        DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %02" PRIx64 "\n", txt,
+                    addr, asi, r1 & 0xff);
+        break;
+    case 2:
+        DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %04" PRIx64 "\n", txt,
+                    addr, asi, r1 & 0xffff);
+        break;
+    case 4:
+        DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %08" PRIx64 "\n", txt,
+                    addr, asi, r1 & 0xffffffff);
+        break;
+    case 8:
+        DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %016" PRIx64 "\n", txt,
+                    addr, asi, r1);
+        break;
+    }
+}
+#endif
+
+#ifndef TARGET_SPARC64
+#ifndef CONFIG_USER_ONLY
+
+
+/* Leon3 cache control */
+
+static void leon3_cache_control_st(target_ulong addr, uint64_t val, int size)
+{
+    DPRINTF_CACHE_CONTROL("st addr:%08x, val:%" PRIx64 ", size:%d\n",
+                          addr, val, size);
+
+    if (size != 4) {
+        DPRINTF_CACHE_CONTROL("32bits only\n");
+        return;
+    }
+
+    switch (addr) {
+    case 0x00:              /* Cache control */
+
+        /* These values must always be read as zeros */
+        val &= ~CACHE_CTRL_FD;
+        val &= ~CACHE_CTRL_FI;
+        val &= ~CACHE_CTRL_IB;
+        val &= ~CACHE_CTRL_IP;
+        val &= ~CACHE_CTRL_DP;
+
+        env->cache_control = val;
+        break;
+    case 0x04:              /* Instruction cache configuration */
+    case 0x08:              /* Data cache configuration */
+        /* Read Only */
+        break;
+    default:
+        DPRINTF_CACHE_CONTROL("write unknown register %08x\n", addr);
+        break;
+    };
+}
+
+static uint64_t leon3_cache_control_ld(target_ulong addr, int size)
+{
+    uint64_t ret = 0;
+
+    if (size != 4) {
+        DPRINTF_CACHE_CONTROL("32bits only\n");
+        return 0;
+    }
+
+    switch (addr) {
+    case 0x00:              /* Cache control */
+        ret = env->cache_control;
+        break;
+
+        /* Configuration registers are read and only always keep those
+           predefined values */
+
+    case 0x04:              /* Instruction cache configuration */
+        ret = 0x10220000;
+        break;
+    case 0x08:              /* Data cache configuration */
+        ret = 0x18220000;
+        break;
+    default:
+        DPRINTF_CACHE_CONTROL("read unknown register %08x\n", addr);
+        break;
+    };
+    DPRINTF_CACHE_CONTROL("ld addr:%08x, ret:0x%" PRIx64 ", size:%d\n",
+                          addr, ret, size);
+    return ret;
+}
+
+uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
+{
+    uint64_t ret = 0;
+#if defined(DEBUG_MXCC) || defined(DEBUG_ASI)
+    uint32_t last_addr = addr;
+#endif
+
+    helper_check_align(addr, size - 1);
+    switch (asi) {
+    case 2: /* SuperSparc MXCC registers and Leon3 cache control */
+        switch (addr) {
+        case 0x00:          /* Leon3 Cache Control */
+        case 0x08:          /* Leon3 Instruction Cache config */
+        case 0x0C:          /* Leon3 Date Cache config */
+            if (env->def->features & CPU_FEATURE_CACHE_CTRL) {
+                ret = leon3_cache_control_ld(addr, size);
+            }
+            break;
+        case 0x01c00a00: /* MXCC control register */
+            if (size == 8) {
+                ret = env->mxccregs[3];
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            break;
+        case 0x01c00a04: /* MXCC control register */
+            if (size == 4) {
+                ret = env->mxccregs[3];
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            break;
+        case 0x01c00c00: /* Module reset register */
+            if (size == 8) {
+                ret = env->mxccregs[5];
+                /* should we do something here? */
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            break;
+        case 0x01c00f00: /* MBus port address register */
+            if (size == 8) {
+                ret = env->mxccregs[7];
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            break;
+        default:
+            DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", addr,
+                         size);
+            break;
+        }
+        DPRINTF_MXCC("asi = %d, size = %d, sign = %d, "
+                     "addr = %08x -> ret = %" PRIx64 ","
+                     "addr = %08x\n", asi, size, sign, last_addr, ret, addr);
+#ifdef DEBUG_MXCC
+        dump_mxcc(env);
+#endif
+        break;
+    case 3: /* MMU probe */
+        {
+            int mmulev;
+
+            mmulev = (addr >> 8) & 15;
+            if (mmulev > 4) {
+                ret = 0;
+            } else {
+                ret = mmu_probe(env, addr, mmulev);
+            }
+            DPRINTF_MMU("mmu_probe: 0x%08x (lev %d) -> 0x%08" PRIx64 "\n",
+                        addr, mmulev, ret);
+        }
+        break;
+    case 4: /* read MMU regs */
+        {
+            int reg = (addr >> 8) & 0x1f;
+
+            ret = env->mmuregs[reg];
+            if (reg == 3) { /* Fault status cleared on read */
+                env->mmuregs[3] = 0;
+            } else if (reg == 0x13) { /* Fault status read */
+                ret = env->mmuregs[3];
+            } else if (reg == 0x14) { /* Fault address read */
+                ret = env->mmuregs[4];
+            }
+            DPRINTF_MMU("mmu_read: reg[%d] = 0x%08" PRIx64 "\n", reg, ret);
+        }
+        break;
+    case 5: /* Turbosparc ITLB Diagnostic */
+    case 6: /* Turbosparc DTLB Diagnostic */
+    case 7: /* Turbosparc IOTLB Diagnostic */
+        break;
+    case 9: /* Supervisor code access */
+        switch (size) {
+        case 1:
+            ret = ldub_code(addr);
+            break;
+        case 2:
+            ret = lduw_code(addr);
+            break;
+        default:
+        case 4:
+            ret = ldl_code(addr);
+            break;
+        case 8:
+            ret = ldq_code(addr);
+            break;
+        }
+        break;
+    case 0xa: /* User data access */
+        switch (size) {
+        case 1:
+            ret = ldub_user(addr);
+            break;
+        case 2:
+            ret = lduw_user(addr);
+            break;
+        default:
+        case 4:
+            ret = ldl_user(addr);
+            break;
+        case 8:
+            ret = ldq_user(addr);
+            break;
+        }
+        break;
+    case 0xb: /* Supervisor data access */
+        switch (size) {
+        case 1:
+            ret = ldub_kernel(addr);
+            break;
+        case 2:
+            ret = lduw_kernel(addr);
+            break;
+        default:
+        case 4:
+            ret = ldl_kernel(addr);
+            break;
+        case 8:
+            ret = ldq_kernel(addr);
+            break;
+        }
+        break;
+    case 0xc: /* I-cache tag */
+    case 0xd: /* I-cache data */
+    case 0xe: /* D-cache tag */
+    case 0xf: /* D-cache data */
+        break;
+    case 0x20: /* MMU passthrough */
+        switch (size) {
+        case 1:
+            ret = ldub_phys(addr);
+            break;
+        case 2:
+            ret = lduw_phys(addr);
+            break;
+        default:
+        case 4:
+            ret = ldl_phys(addr);
+            break;
+        case 8:
+            ret = ldq_phys(addr);
+            break;
+        }
+        break;
+    case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */
+        switch (size) {
+        case 1:
+            ret = ldub_phys((target_phys_addr_t)addr
+                            | ((target_phys_addr_t)(asi & 0xf) << 32));
+            break;
+        case 2:
+            ret = lduw_phys((target_phys_addr_t)addr
+                            | ((target_phys_addr_t)(asi & 0xf) << 32));
+            break;
+        default:
+        case 4:
+            ret = ldl_phys((target_phys_addr_t)addr
+                           | ((target_phys_addr_t)(asi & 0xf) << 32));
+            break;
+        case 8:
+            ret = ldq_phys((target_phys_addr_t)addr
+                           | ((target_phys_addr_t)(asi & 0xf) << 32));
+            break;
+        }
+        break;
+    case 0x30: /* Turbosparc secondary cache diagnostic */
+    case 0x31: /* Turbosparc RAM snoop */
+    case 0x32: /* Turbosparc page table descriptor diagnostic */
+    case 0x39: /* data cache diagnostic register */
+        ret = 0;
+        break;
+    case 0x38: /* SuperSPARC MMU Breakpoint Control Registers */
+        {
+            int reg = (addr >> 8) & 3;
+
+            switch (reg) {
+            case 0: /* Breakpoint Value (Addr) */
+                ret = env->mmubpregs[reg];
+                break;
+            case 1: /* Breakpoint Mask */
+                ret = env->mmubpregs[reg];
+                break;
+            case 2: /* Breakpoint Control */
+                ret = env->mmubpregs[reg];
+                break;
+            case 3: /* Breakpoint Status */
+                ret = env->mmubpregs[reg];
+                env->mmubpregs[reg] = 0ULL;
+                break;
+            }
+            DPRINTF_MMU("read breakpoint reg[%d] 0x%016" PRIx64 "\n", reg,
+                        ret);
+        }
+        break;
+    case 0x49: /* SuperSPARC MMU Counter Breakpoint Value */
+        ret = env->mmubpctrv;
+        break;
+    case 0x4a: /* SuperSPARC MMU Counter Breakpoint Control */
+        ret = env->mmubpctrc;
+        break;
+    case 0x4b: /* SuperSPARC MMU Counter Breakpoint Status */
+        ret = env->mmubpctrs;
+        break;
+    case 0x4c: /* SuperSPARC MMU Breakpoint Action */
+        ret = env->mmubpaction;
+        break;
+    case 8: /* User code access, XXX */
+    default:
+        do_unassigned_access(addr, 0, 0, asi, size);
+        ret = 0;
+        break;
+    }
+    if (sign) {
+        switch (size) {
+        case 1:
+            ret = (int8_t) ret;
+            break;
+        case 2:
+            ret = (int16_t) ret;
+            break;
+        case 4:
+            ret = (int32_t) ret;
+            break;
+        default:
+            break;
+        }
+    }
+#ifdef DEBUG_ASI
+    dump_asi("read ", last_addr, asi, size, ret);
+#endif
+    return ret;
+}
+
+void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
+{
+    helper_check_align(addr, size - 1);
+    switch (asi) {
+    case 2: /* SuperSparc MXCC registers and Leon3 cache control */
+        switch (addr) {
+        case 0x00:          /* Leon3 Cache Control */
+        case 0x08:          /* Leon3 Instruction Cache config */
+        case 0x0C:          /* Leon3 Date Cache config */
+            if (env->def->features & CPU_FEATURE_CACHE_CTRL) {
+                leon3_cache_control_st(addr, val, size);
+            }
+            break;
+
+        case 0x01c00000: /* MXCC stream data register 0 */
+            if (size == 8) {
+                env->mxccdata[0] = val;
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            break;
+        case 0x01c00008: /* MXCC stream data register 1 */
+            if (size == 8) {
+                env->mxccdata[1] = val;
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            break;
+        case 0x01c00010: /* MXCC stream data register 2 */
+            if (size == 8) {
+                env->mxccdata[2] = val;
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            break;
+        case 0x01c00018: /* MXCC stream data register 3 */
+            if (size == 8) {
+                env->mxccdata[3] = val;
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            break;
+        case 0x01c00100: /* MXCC stream source */
+            if (size == 8) {
+                env->mxccregs[0] = val;
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            env->mxccdata[0] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
+                                        0);
+            env->mxccdata[1] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
+                                        8);
+            env->mxccdata[2] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
+                                        16);
+            env->mxccdata[3] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
+                                        24);
+            break;
+        case 0x01c00200: /* MXCC stream destination */
+            if (size == 8) {
+                env->mxccregs[1] = val;
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            stq_phys((env->mxccregs[1] & 0xffffffffULL) +  0,
+                     env->mxccdata[0]);
+            stq_phys((env->mxccregs[1] & 0xffffffffULL) +  8,
+                     env->mxccdata[1]);
+            stq_phys((env->mxccregs[1] & 0xffffffffULL) + 16,
+                     env->mxccdata[2]);
+            stq_phys((env->mxccregs[1] & 0xffffffffULL) + 24,
+                     env->mxccdata[3]);
+            break;
+        case 0x01c00a00: /* MXCC control register */
+            if (size == 8) {
+                env->mxccregs[3] = val;
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            break;
+        case 0x01c00a04: /* MXCC control register */
+            if (size == 4) {
+                env->mxccregs[3] = (env->mxccregs[3] & 0xffffffff00000000ULL)
+                    | val;
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            break;
+        case 0x01c00e00: /* MXCC error register  */
+            /* writing a 1 bit clears the error */
+            if (size == 8) {
+                env->mxccregs[6] &= ~val;
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            break;
+        case 0x01c00f00: /* MBus port address register */
+            if (size == 8) {
+                env->mxccregs[7] = val;
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            break;
+        default:
+            DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", addr,
+                         size);
+            break;
+        }
+        DPRINTF_MXCC("asi = %d, size = %d, addr = %08x, val = %" PRIx64 "\n",
+                     asi, size, addr, val);
+#ifdef DEBUG_MXCC
+        dump_mxcc(env);
+#endif
+        break;
+    case 3: /* MMU flush */
+        {
+            int mmulev;
+
+            mmulev = (addr >> 8) & 15;
+            DPRINTF_MMU("mmu flush level %d\n", mmulev);
+            switch (mmulev) {
+            case 0: /* flush page */
+                tlb_flush_page(env, addr & 0xfffff000);
+                break;
+            case 1: /* flush segment (256k) */
+            case 2: /* flush region (16M) */
+            case 3: /* flush context (4G) */
+            case 4: /* flush entire */
+                tlb_flush(env, 1);
+                break;
+            default:
+                break;
+            }
+#ifdef DEBUG_MMU
+            dump_mmu(stdout, fprintf, env);
+#endif
+        }
+        break;
+    case 4: /* write MMU regs */
+        {
+            int reg = (addr >> 8) & 0x1f;
+            uint32_t oldreg;
+
+            oldreg = env->mmuregs[reg];
+            switch (reg) {
+            case 0: /* Control Register */
+                env->mmuregs[reg] = (env->mmuregs[reg] & 0xff000000) |
+                    (val & 0x00ffffff);
+                /* Mappings generated during no-fault mode or MMU
+                   disabled mode are invalid in normal mode */
+                if ((oldreg & (MMU_E | MMU_NF | env->def->mmu_bm)) !=
+                    (env->mmuregs[reg] & (MMU_E | MMU_NF | env->def->mmu_bm))) {
+                    tlb_flush(env, 1);
+                }
+                break;
+            case 1: /* Context Table Pointer Register */
+                env->mmuregs[reg] = val & env->def->mmu_ctpr_mask;
+                break;
+            case 2: /* Context Register */
+                env->mmuregs[reg] = val & env->def->mmu_cxr_mask;
+                if (oldreg != env->mmuregs[reg]) {
+                    /* we flush when the MMU context changes because
+                       QEMU has no MMU context support */
+                    tlb_flush(env, 1);
+                }
+                break;
+            case 3: /* Synchronous Fault Status Register with Clear */
+            case 4: /* Synchronous Fault Address Register */
+                break;
+            case 0x10: /* TLB Replacement Control Register */
+                env->mmuregs[reg] = val & env->def->mmu_trcr_mask;
+                break;
+            case 0x13: /* Synchronous Fault Status Register with Read
+                          and Clear */
+                env->mmuregs[3] = val & env->def->mmu_sfsr_mask;
+                break;
+            case 0x14: /* Synchronous Fault Address Register */
+                env->mmuregs[4] = val;
+                break;
+            default:
+                env->mmuregs[reg] = val;
+                break;
+            }
+            if (oldreg != env->mmuregs[reg]) {
+                DPRINTF_MMU("mmu change reg[%d]: 0x%08x -> 0x%08x\n",
+                            reg, oldreg, env->mmuregs[reg]);
+            }
+#ifdef DEBUG_MMU
+            dump_mmu(stdout, fprintf, env);
+#endif
+        }
+        break;
+    case 5: /* Turbosparc ITLB Diagnostic */
+    case 6: /* Turbosparc DTLB Diagnostic */
+    case 7: /* Turbosparc IOTLB Diagnostic */
+        break;
+    case 0xa: /* User data access */
+        switch (size) {
+        case 1:
+            stb_user(addr, val);
+            break;
+        case 2:
+            stw_user(addr, val);
+            break;
+        default:
+        case 4:
+            stl_user(addr, val);
+            break;
+        case 8:
+            stq_user(addr, val);
+            break;
+        }
+        break;
+    case 0xb: /* Supervisor data access */
+        switch (size) {
+        case 1:
+            stb_kernel(addr, val);
+            break;
+        case 2:
+            stw_kernel(addr, val);
+            break;
+        default:
+        case 4:
+            stl_kernel(addr, val);
+            break;
+        case 8:
+            stq_kernel(addr, val);
+            break;
+        }
+        break;
+    case 0xc: /* I-cache tag */
+    case 0xd: /* I-cache data */
+    case 0xe: /* D-cache tag */
+    case 0xf: /* D-cache data */
+    case 0x10: /* I/D-cache flush page */
+    case 0x11: /* I/D-cache flush segment */
+    case 0x12: /* I/D-cache flush region */
+    case 0x13: /* I/D-cache flush context */
+    case 0x14: /* I/D-cache flush user */
+        break;
+    case 0x17: /* Block copy, sta access */
+        {
+            /* val = src
+               addr = dst
+               copy 32 bytes */
+            unsigned int i;
+            uint32_t src = val & ~3, dst = addr & ~3, temp;
+
+            for (i = 0; i < 32; i += 4, src += 4, dst += 4) {
+                temp = ldl_kernel(src);
+                stl_kernel(dst, temp);
+            }
+        }
+        break;
+    case 0x1f: /* Block fill, stda access */
+        {
+            /* addr = dst
+               fill 32 bytes with val */
+            unsigned int i;
+            uint32_t dst = addr & 7;
+
+            for (i = 0; i < 32; i += 8, dst += 8) {
+                stq_kernel(dst, val);
+            }
+        }
+        break;
+    case 0x20: /* MMU passthrough */
+        {
+            switch (size) {
+            case 1:
+                stb_phys(addr, val);
+                break;
+            case 2:
+                stw_phys(addr, val);
+                break;
+            case 4:
+            default:
+                stl_phys(addr, val);
+                break;
+            case 8:
+                stq_phys(addr, val);
+                break;
+            }
+        }
+        break;
+    case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */
+        {
+            switch (size) {
+            case 1:
+                stb_phys((target_phys_addr_t)addr
+                         | ((target_phys_addr_t)(asi & 0xf) << 32), val);
+                break;
+            case 2:
+                stw_phys((target_phys_addr_t)addr
+                         | ((target_phys_addr_t)(asi & 0xf) << 32), val);
+                break;
+            case 4:
+            default:
+                stl_phys((target_phys_addr_t)addr
+                         | ((target_phys_addr_t)(asi & 0xf) << 32), val);
+                break;
+            case 8:
+                stq_phys((target_phys_addr_t)addr
+                         | ((target_phys_addr_t)(asi & 0xf) << 32), val);
+                break;
+            }
+        }
+        break;
+    case 0x30: /* store buffer tags or Turbosparc secondary cache diagnostic */
+    case 0x31: /* store buffer data, Ross RT620 I-cache flush or
+                  Turbosparc snoop RAM */
+    case 0x32: /* store buffer control or Turbosparc page table
+                  descriptor diagnostic */
+    case 0x36: /* I-cache flash clear */
+    case 0x37: /* D-cache flash clear */
+        break;
+    case 0x38: /* SuperSPARC MMU Breakpoint Control Registers*/
+        {
+            int reg = (addr >> 8) & 3;
+
+            switch (reg) {
+            case 0: /* Breakpoint Value (Addr) */
+                env->mmubpregs[reg] = (val & 0xfffffffffULL);
+                break;
+            case 1: /* Breakpoint Mask */
+                env->mmubpregs[reg] = (val & 0xfffffffffULL);
+                break;
+            case 2: /* Breakpoint Control */
+                env->mmubpregs[reg] = (val & 0x7fULL);
+                break;
+            case 3: /* Breakpoint Status */
+                env->mmubpregs[reg] = (val & 0xfULL);
+                break;
+            }
+            DPRINTF_MMU("write breakpoint reg[%d] 0x%016x\n", reg,
+                        env->mmuregs[reg]);
+        }
+        break;
+    case 0x49: /* SuperSPARC MMU Counter Breakpoint Value */
+        env->mmubpctrv = val & 0xffffffff;
+        break;
+    case 0x4a: /* SuperSPARC MMU Counter Breakpoint Control */
+        env->mmubpctrc = val & 0x3;
+        break;
+    case 0x4b: /* SuperSPARC MMU Counter Breakpoint Status */
+        env->mmubpctrs = val & 0x3;
+        break;
+    case 0x4c: /* SuperSPARC MMU Breakpoint Action */
+        env->mmubpaction = val & 0x1fff;
+        break;
+    case 8: /* User code access, XXX */
+    case 9: /* Supervisor code access, XXX */
+    default:
+        do_unassigned_access(addr, 1, 0, asi, size);
+        break;
+    }
+#ifdef DEBUG_ASI
+    dump_asi("write", addr, asi, size, val);
+#endif
+}
+
+#endif /* CONFIG_USER_ONLY */
+#else /* TARGET_SPARC64 */
+
+#ifdef CONFIG_USER_ONLY
+uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
+{
+    uint64_t ret = 0;
+#if defined(DEBUG_ASI)
+    target_ulong last_addr = addr;
+#endif
+
+    if (asi < 0x80) {
+        helper_raise_exception(env, TT_PRIV_ACT);
+    }
+
+    helper_check_align(addr, size - 1);
+    addr = asi_address_mask(env, asi, addr);
+
+    switch (asi) {
+    case 0x82: /* Primary no-fault */
+    case 0x8a: /* Primary no-fault LE */
+        if (page_check_range(addr, size, PAGE_READ) == -1) {
+#ifdef DEBUG_ASI
+            dump_asi("read ", last_addr, asi, size, ret);
+#endif
+            return 0;
+        }
+        /* Fall through */
+    case 0x80: /* Primary */
+    case 0x88: /* Primary LE */
+        {
+            switch (size) {
+            case 1:
+                ret = ldub_raw(addr);
+                break;
+            case 2:
+                ret = lduw_raw(addr);
+                break;
+            case 4:
+                ret = ldl_raw(addr);
+                break;
+            default:
+            case 8:
+                ret = ldq_raw(addr);
+                break;
+            }
+        }
+        break;
+    case 0x83: /* Secondary no-fault */
+    case 0x8b: /* Secondary no-fault LE */
+        if (page_check_range(addr, size, PAGE_READ) == -1) {
+#ifdef DEBUG_ASI
+            dump_asi("read ", last_addr, asi, size, ret);
+#endif
+            return 0;
+        }
+        /* Fall through */
+    case 0x81: /* Secondary */
+    case 0x89: /* Secondary LE */
+        /* XXX */
+        break;
+    default:
+        break;
+    }
+
+    /* Convert from little endian */
+    switch (asi) {
+    case 0x88: /* Primary LE */
+    case 0x89: /* Secondary LE */
+    case 0x8a: /* Primary no-fault LE */
+    case 0x8b: /* Secondary no-fault LE */
+        switch (size) {
+        case 2:
+            ret = bswap16(ret);
+            break;
+        case 4:
+            ret = bswap32(ret);
+            break;
+        case 8:
+            ret = bswap64(ret);
+            break;
+        default:
+            break;
+        }
+    default:
+        break;
+    }
+
+    /* Convert to signed number */
+    if (sign) {
+        switch (size) {
+        case 1:
+            ret = (int8_t) ret;
+            break;
+        case 2:
+            ret = (int16_t) ret;
+            break;
+        case 4:
+            ret = (int32_t) ret;
+            break;
+        default:
+            break;
+        }
+    }
+#ifdef DEBUG_ASI
+    dump_asi("read ", last_addr, asi, size, ret);
+#endif
+    return ret;
+}
+
+void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
+{
+#ifdef DEBUG_ASI
+    dump_asi("write", addr, asi, size, val);
+#endif
+    if (asi < 0x80) {
+        helper_raise_exception(env, TT_PRIV_ACT);
+    }
+
+    helper_check_align(addr, size - 1);
+    addr = asi_address_mask(env, asi, addr);
+
+    /* Convert to little endian */
+    switch (asi) {
+    case 0x88: /* Primary LE */
+    case 0x89: /* Secondary LE */
+        switch (size) {
+        case 2:
+            val = bswap16(val);
+            break;
+        case 4:
+            val = bswap32(val);
+            break;
+        case 8:
+            val = bswap64(val);
+            break;
+        default:
+            break;
+        }
+    default:
+        break;
+    }
+
+    switch (asi) {
+    case 0x80: /* Primary */
+    case 0x88: /* Primary LE */
+        {
+            switch (size) {
+            case 1:
+                stb_raw(addr, val);
+                break;
+            case 2:
+                stw_raw(addr, val);
+                break;
+            case 4:
+                stl_raw(addr, val);
+                break;
+            case 8:
+            default:
+                stq_raw(addr, val);
+                break;
+            }
+        }
+        break;
+    case 0x81: /* Secondary */
+    case 0x89: /* Secondary LE */
+        /* XXX */
+        return;
+
+    case 0x82: /* Primary no-fault, RO */
+    case 0x83: /* Secondary no-fault, RO */
+    case 0x8a: /* Primary no-fault LE, RO */
+    case 0x8b: /* Secondary no-fault LE, RO */
+    default:
+        do_unassigned_access(addr, 1, 0, 1, size);
+        return;
+    }
+}
+
+#else /* CONFIG_USER_ONLY */
+
+uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
+{
+    uint64_t ret = 0;
+#if defined(DEBUG_ASI)
+    target_ulong last_addr = addr;
+#endif
+
+    asi &= 0xff;
+
+    if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
+        || (cpu_has_hypervisor(env)
+            && asi >= 0x30 && asi < 0x80
+            && !(env->hpstate & HS_PRIV))) {
+        helper_raise_exception(env, TT_PRIV_ACT);
+    }
+
+    helper_check_align(addr, size - 1);
+    addr = asi_address_mask(env, asi, addr);
+
+    /* process nonfaulting loads first */
+    if ((asi & 0xf6) == 0x82) {
+        int mmu_idx;
+
+        /* secondary space access has lowest asi bit equal to 1 */
+        if (env->pstate & PS_PRIV) {
+            mmu_idx = (asi & 1) ? MMU_KERNEL_SECONDARY_IDX : MMU_KERNEL_IDX;
+        } else {
+            mmu_idx = (asi & 1) ? MMU_USER_SECONDARY_IDX : MMU_USER_IDX;
+        }
+
+        if (cpu_get_phys_page_nofault(env, addr, mmu_idx) == -1ULL) {
+#ifdef DEBUG_ASI
+            dump_asi("read ", last_addr, asi, size, ret);
+#endif
+            /* env->exception_index is set in get_physical_address_data(). */
+            helper_raise_exception(env, env->exception_index);
+        }
+
+        /* convert nonfaulting load ASIs to normal load ASIs */
+        asi &= ~0x02;
+    }
+
+    switch (asi) {
+    case 0x10: /* As if user primary */
+    case 0x11: /* As if user secondary */
+    case 0x18: /* As if user primary LE */
+    case 0x19: /* As if user secondary LE */
+    case 0x80: /* Primary */
+    case 0x81: /* Secondary */
+    case 0x88: /* Primary LE */
+    case 0x89: /* Secondary LE */
+    case 0xe2: /* UA2007 Primary block init */
+    case 0xe3: /* UA2007 Secondary block init */
+        if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
+            if (cpu_hypervisor_mode(env)) {
+                switch (size) {
+                case 1:
+                    ret = ldub_hypv(addr);
+                    break;
+                case 2:
+                    ret = lduw_hypv(addr);
+                    break;
+                case 4:
+                    ret = ldl_hypv(addr);
+                    break;
+                default:
+                case 8:
+                    ret = ldq_hypv(addr);
+                    break;
+                }
+            } else {
+                /* secondary space access has lowest asi bit equal to 1 */
+                if (asi & 1) {
+                    switch (size) {
+                    case 1:
+                        ret = ldub_kernel_secondary(addr);
+                        break;
+                    case 2:
+                        ret = lduw_kernel_secondary(addr);
+                        break;
+                    case 4:
+                        ret = ldl_kernel_secondary(addr);
+                        break;
+                    default:
+                    case 8:
+                        ret = ldq_kernel_secondary(addr);
+                        break;
+                    }
+                } else {
+                    switch (size) {
+                    case 1:
+                        ret = ldub_kernel(addr);
+                        break;
+                    case 2:
+                        ret = lduw_kernel(addr);
+                        break;
+                    case 4:
+                        ret = ldl_kernel(addr);
+                        break;
+                    default:
+                    case 8:
+                        ret = ldq_kernel(addr);
+                        break;
+                    }
+                }
+            }
+        } else {
+            /* secondary space access has lowest asi bit equal to 1 */
+            if (asi & 1) {
+                switch (size) {
+                case 1:
+                    ret = ldub_user_secondary(addr);
+                    break;
+                case 2:
+                    ret = lduw_user_secondary(addr);
+                    break;
+                case 4:
+                    ret = ldl_user_secondary(addr);
+                    break;
+                default:
+                case 8:
+                    ret = ldq_user_secondary(addr);
+                    break;
+                }
+            } else {
+                switch (size) {
+                case 1:
+                    ret = ldub_user(addr);
+                    break;
+                case 2:
+                    ret = lduw_user(addr);
+                    break;
+                case 4:
+                    ret = ldl_user(addr);
+                    break;
+                default:
+                case 8:
+                    ret = ldq_user(addr);
+                    break;
+                }
+            }
+        }
+        break;
+    case 0x14: /* Bypass */
+    case 0x15: /* Bypass, non-cacheable */
+    case 0x1c: /* Bypass LE */
+    case 0x1d: /* Bypass, non-cacheable LE */
+        {
+            switch (size) {
+            case 1:
+                ret = ldub_phys(addr);
+                break;
+            case 2:
+                ret = lduw_phys(addr);
+                break;
+            case 4:
+                ret = ldl_phys(addr);
+                break;
+            default:
+            case 8:
+                ret = ldq_phys(addr);
+                break;
+            }
+            break;
+        }
+    case 0x24: /* Nucleus quad LDD 128 bit atomic */
+    case 0x2c: /* Nucleus quad LDD 128 bit atomic LE
+                  Only ldda allowed */
+        helper_raise_exception(env, TT_ILL_INSN);
+        return 0;
+    case 0x04: /* Nucleus */
+    case 0x0c: /* Nucleus Little Endian (LE) */
+        {
+            switch (size) {
+            case 1:
+                ret = ldub_nucleus(addr);
+                break;
+            case 2:
+                ret = lduw_nucleus(addr);
+                break;
+            case 4:
+                ret = ldl_nucleus(addr);
+                break;
+            default:
+            case 8:
+                ret = ldq_nucleus(addr);
+                break;
+            }
+            break;
+        }
+    case 0x4a: /* UPA config */
+        /* XXX */
+        break;
+    case 0x45: /* LSU */
+        ret = env->lsu;
+        break;
+    case 0x50: /* I-MMU regs */
+        {
+            int reg = (addr >> 3) & 0xf;
+
+            if (reg == 0) {
+                /* I-TSB Tag Target register */
+                ret = ultrasparc_tag_target(env->immu.tag_access);
+            } else {
+                ret = env->immuregs[reg];
+            }
+
+            break;
+        }
+    case 0x51: /* I-MMU 8k TSB pointer */
+        {
+            /* env->immuregs[5] holds I-MMU TSB register value
+               env->immuregs[6] holds I-MMU Tag Access register value */
+            ret = ultrasparc_tsb_pointer(env->immu.tsb, env->immu.tag_access,
+                                         8*1024);
+            break;
+        }
+    case 0x52: /* I-MMU 64k TSB pointer */
+        {
+            /* env->immuregs[5] holds I-MMU TSB register value
+               env->immuregs[6] holds I-MMU Tag Access register value */
+            ret = ultrasparc_tsb_pointer(env->immu.tsb, env->immu.tag_access,
+                                         64*1024);
+            break;
+        }
+    case 0x55: /* I-MMU data access */
+        {
+            int reg = (addr >> 3) & 0x3f;
+
+            ret = env->itlb[reg].tte;
+            break;
+        }
+    case 0x56: /* I-MMU tag read */
+        {
+            int reg = (addr >> 3) & 0x3f;
+
+            ret = env->itlb[reg].tag;
+            break;
+        }
+    case 0x58: /* D-MMU regs */
+        {
+            int reg = (addr >> 3) & 0xf;
+
+            if (reg == 0) {
+                /* D-TSB Tag Target register */
+                ret = ultrasparc_tag_target(env->dmmu.tag_access);
+            } else {
+                ret = env->dmmuregs[reg];
+            }
+            break;
+        }
+    case 0x59: /* D-MMU 8k TSB pointer */
+        {
+            /* env->dmmuregs[5] holds D-MMU TSB register value
+               env->dmmuregs[6] holds D-MMU Tag Access register value */
+            ret = ultrasparc_tsb_pointer(env->dmmu.tsb, env->dmmu.tag_access,
+                                         8*1024);
+            break;
+        }
+    case 0x5a: /* D-MMU 64k TSB pointer */
+        {
+            /* env->dmmuregs[5] holds D-MMU TSB register value
+               env->dmmuregs[6] holds D-MMU Tag Access register value */
+            ret = ultrasparc_tsb_pointer(env->dmmu.tsb, env->dmmu.tag_access,
+                                         64*1024);
+            break;
+        }
+    case 0x5d: /* D-MMU data access */
+        {
+            int reg = (addr >> 3) & 0x3f;
+
+            ret = env->dtlb[reg].tte;
+            break;
+        }
+    case 0x5e: /* D-MMU tag read */
+        {
+            int reg = (addr >> 3) & 0x3f;
+
+            ret = env->dtlb[reg].tag;
+            break;
+        }
+    case 0x46: /* D-cache data */
+    case 0x47: /* D-cache tag access */
+    case 0x4b: /* E-cache error enable */
+    case 0x4c: /* E-cache asynchronous fault status */
+    case 0x4d: /* E-cache asynchronous fault address */
+    case 0x4e: /* E-cache tag data */
+    case 0x66: /* I-cache instruction access */
+    case 0x67: /* I-cache tag access */
+    case 0x6e: /* I-cache predecode */
+    case 0x6f: /* I-cache LRU etc. */
+    case 0x76: /* E-cache tag */
+    case 0x7e: /* E-cache tag */
+        break;
+    case 0x5b: /* D-MMU data pointer */
+    case 0x48: /* Interrupt dispatch, RO */
+    case 0x49: /* Interrupt data receive */
+    case 0x7f: /* Incoming interrupt vector, RO */
+        /* XXX */
+        break;
+    case 0x54: /* I-MMU data in, WO */
+    case 0x57: /* I-MMU demap, WO */
+    case 0x5c: /* D-MMU data in, WO */
+    case 0x5f: /* D-MMU demap, WO */
+    case 0x77: /* Interrupt vector, WO */
+    default:
+        do_unassigned_access(addr, 0, 0, 1, size);
+        ret = 0;
+        break;
+    }
+
+    /* Convert from little endian */
+    switch (asi) {
+    case 0x0c: /* Nucleus Little Endian (LE) */
+    case 0x18: /* As if user primary LE */
+    case 0x19: /* As if user secondary LE */
+    case 0x1c: /* Bypass LE */
+    case 0x1d: /* Bypass, non-cacheable LE */
+    case 0x88: /* Primary LE */
+    case 0x89: /* Secondary LE */
+        switch(size) {
+        case 2:
+            ret = bswap16(ret);
+            break;
+        case 4:
+            ret = bswap32(ret);
+            break;
+        case 8:
+            ret = bswap64(ret);
+            break;
+        default:
+            break;
+        }
+    default:
+        break;
+    }
+
+    /* Convert to signed number */
+    if (sign) {
+        switch (size) {
+        case 1:
+            ret = (int8_t) ret;
+            break;
+        case 2:
+            ret = (int16_t) ret;
+            break;
+        case 4:
+            ret = (int32_t) ret;
+            break;
+        default:
+            break;
+        }
+    }
+#ifdef DEBUG_ASI
+    dump_asi("read ", last_addr, asi, size, ret);
+#endif
+    return ret;
+}
+
+void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
+{
+#ifdef DEBUG_ASI
+    dump_asi("write", addr, asi, size, val);
+#endif
+
+    asi &= 0xff;
+
+    if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
+        || (cpu_has_hypervisor(env)
+            && asi >= 0x30 && asi < 0x80
+            && !(env->hpstate & HS_PRIV))) {
+        helper_raise_exception(env, TT_PRIV_ACT);
+    }
+
+    helper_check_align(addr, size - 1);
+    addr = asi_address_mask(env, asi, addr);
+
+    /* Convert to little endian */
+    switch (asi) {
+    case 0x0c: /* Nucleus Little Endian (LE) */
+    case 0x18: /* As if user primary LE */
+    case 0x19: /* As if user secondary LE */
+    case 0x1c: /* Bypass LE */
+    case 0x1d: /* Bypass, non-cacheable LE */
+    case 0x88: /* Primary LE */
+    case 0x89: /* Secondary LE */
+        switch (size) {
+        case 2:
+            val = bswap16(val);
+            break;
+        case 4:
+            val = bswap32(val);
+            break;
+        case 8:
+            val = bswap64(val);
+            break;
+        default:
+            break;
+        }
+    default:
+        break;
+    }
+
+    switch (asi) {
+    case 0x10: /* As if user primary */
+    case 0x11: /* As if user secondary */
+    case 0x18: /* As if user primary LE */
+    case 0x19: /* As if user secondary LE */
+    case 0x80: /* Primary */
+    case 0x81: /* Secondary */
+    case 0x88: /* Primary LE */
+    case 0x89: /* Secondary LE */
+    case 0xe2: /* UA2007 Primary block init */
+    case 0xe3: /* UA2007 Secondary block init */
+        if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
+            if (cpu_hypervisor_mode(env)) {
+                switch (size) {
+                case 1:
+                    stb_hypv(addr, val);
+                    break;
+                case 2:
+                    stw_hypv(addr, val);
+                    break;
+                case 4:
+                    stl_hypv(addr, val);
+                    break;
+                case 8:
+                default:
+                    stq_hypv(addr, val);
+                    break;
+                }
+            } else {
+                /* secondary space access has lowest asi bit equal to 1 */
+                if (asi & 1) {
+                    switch (size) {
+                    case 1:
+                        stb_kernel_secondary(addr, val);
+                        break;
+                    case 2:
+                        stw_kernel_secondary(addr, val);
+                        break;
+                    case 4:
+                        stl_kernel_secondary(addr, val);
+                        break;
+                    case 8:
+                    default:
+                        stq_kernel_secondary(addr, val);
+                        break;
+                    }
+                } else {
+                    switch (size) {
+                    case 1:
+                        stb_kernel(addr, val);
+                        break;
+                    case 2:
+                        stw_kernel(addr, val);
+                        break;
+                    case 4:
+                        stl_kernel(addr, val);
+                        break;
+                    case 8:
+                    default:
+                        stq_kernel(addr, val);
+                        break;
+                    }
+                }
+            }
+        } else {
+            /* secondary space access has lowest asi bit equal to 1 */
+            if (asi & 1) {
+                switch (size) {
+                case 1:
+                    stb_user_secondary(addr, val);
+                    break;
+                case 2:
+                    stw_user_secondary(addr, val);
+                    break;
+                case 4:
+                    stl_user_secondary(addr, val);
+                    break;
+                case 8:
+                default:
+                    stq_user_secondary(addr, val);
+                    break;
+                }
+            } else {
+                switch (size) {
+                case 1:
+                    stb_user(addr, val);
+                    break;
+                case 2:
+                    stw_user(addr, val);
+                    break;
+                case 4:
+                    stl_user(addr, val);
+                    break;
+                case 8:
+                default:
+                    stq_user(addr, val);
+                    break;
+                }
+            }
+        }
+        break;
+    case 0x14: /* Bypass */
+    case 0x15: /* Bypass, non-cacheable */
+    case 0x1c: /* Bypass LE */
+    case 0x1d: /* Bypass, non-cacheable LE */
+        {
+            switch (size) {
+            case 1:
+                stb_phys(addr, val);
+                break;
+            case 2:
+                stw_phys(addr, val);
+                break;
+            case 4:
+                stl_phys(addr, val);
+                break;
+            case 8:
+            default:
+                stq_phys(addr, val);
+                break;
+            }
+        }
+        return;
+    case 0x24: /* Nucleus quad LDD 128 bit atomic */
+    case 0x2c: /* Nucleus quad LDD 128 bit atomic LE
+                  Only ldda allowed */
+        helper_raise_exception(env, TT_ILL_INSN);
+        return;
+    case 0x04: /* Nucleus */
+    case 0x0c: /* Nucleus Little Endian (LE) */
+        {
+            switch (size) {
+            case 1:
+                stb_nucleus(addr, val);
+                break;
+            case 2:
+                stw_nucleus(addr, val);
+                break;
+            case 4:
+                stl_nucleus(addr, val);
+                break;
+            default:
+            case 8:
+                stq_nucleus(addr, val);
+                break;
+            }
+            break;
+        }
+
+    case 0x4a: /* UPA config */
+        /* XXX */
+        return;
+    case 0x45: /* LSU */
+        {
+            uint64_t oldreg;
+
+            oldreg = env->lsu;
+            env->lsu = val & (DMMU_E | IMMU_E);
+            /* Mappings generated during D/I MMU disabled mode are
+               invalid in normal mode */
+            if (oldreg != env->lsu) {
+                DPRINTF_MMU("LSU change: 0x%" PRIx64 " -> 0x%" PRIx64 "\n",
+                            oldreg, env->lsu);
+#ifdef DEBUG_MMU
+                dump_mmu(stdout, fprintf, env1);
+#endif
+                tlb_flush(env, 1);
+            }
+            return;
+        }
+    case 0x50: /* I-MMU regs */
+        {
+            int reg = (addr >> 3) & 0xf;
+            uint64_t oldreg;
+
+            oldreg = env->immuregs[reg];
+            switch (reg) {
+            case 0: /* RO */
+                return;
+            case 1: /* Not in I-MMU */
+            case 2:
+                return;
+            case 3: /* SFSR */
+                if ((val & 1) == 0) {
+                    val = 0; /* Clear SFSR */
+                }
+                env->immu.sfsr = val;
+                break;
+            case 4: /* RO */
+                return;
+            case 5: /* TSB access */
+                DPRINTF_MMU("immu TSB write: 0x%016" PRIx64 " -> 0x%016"
+                            PRIx64 "\n", env->immu.tsb, val);
+                env->immu.tsb = val;
+                break;
+            case 6: /* Tag access */
+                env->immu.tag_access = val;
+                break;
+            case 7:
+            case 8:
+                return;
+            default:
+                break;
+            }
+
+            if (oldreg != env->immuregs[reg]) {
+                DPRINTF_MMU("immu change reg[%d]: 0x%016" PRIx64 " -> 0x%016"
+                            PRIx64 "\n", reg, oldreg, env->immuregs[reg]);
+            }
+#ifdef DEBUG_MMU
+            dump_mmu(stdout, fprintf, env);
+#endif
+            return;
+        }
+    case 0x54: /* I-MMU data in */
+        replace_tlb_1bit_lru(env->itlb, env->immu.tag_access, val, "immu", env);
+        return;
+    case 0x55: /* I-MMU data access */
+        {
+            /* TODO: auto demap */
+
+            unsigned int i = (addr >> 3) & 0x3f;
+
+            replace_tlb_entry(&env->itlb[i], env->immu.tag_access, val, env);
+
+#ifdef DEBUG_MMU
+            DPRINTF_MMU("immu data access replaced entry [%i]\n", i);
+            dump_mmu(stdout, fprintf, env);
+#endif
+            return;
+        }
+    case 0x57: /* I-MMU demap */
+        demap_tlb(env->itlb, addr, "immu", env);
+        return;
+    case 0x58: /* D-MMU regs */
+        {
+            int reg = (addr >> 3) & 0xf;
+            uint64_t oldreg;
+
+            oldreg = env->dmmuregs[reg];
+            switch (reg) {
+            case 0: /* RO */
+            case 4:
+                return;
+            case 3: /* SFSR */
+                if ((val & 1) == 0) {
+                    val = 0; /* Clear SFSR, Fault address */
+                    env->dmmu.sfar = 0;
+                }
+                env->dmmu.sfsr = val;
+                break;
+            case 1: /* Primary context */
+                env->dmmu.mmu_primary_context = val;
+                /* can be optimized to only flush MMU_USER_IDX
+                   and MMU_KERNEL_IDX entries */
+                tlb_flush(env, 1);
+                break;
+            case 2: /* Secondary context */
+                env->dmmu.mmu_secondary_context = val;
+                /* can be optimized to only flush MMU_USER_SECONDARY_IDX
+                   and MMU_KERNEL_SECONDARY_IDX entries */
+                tlb_flush(env, 1);
+                break;
+            case 5: /* TSB access */
+                DPRINTF_MMU("dmmu TSB write: 0x%016" PRIx64 " -> 0x%016"
+                            PRIx64 "\n", env->dmmu.tsb, val);
+                env->dmmu.tsb = val;
+                break;
+            case 6: /* Tag access */
+                env->dmmu.tag_access = val;
+                break;
+            case 7: /* Virtual Watchpoint */
+            case 8: /* Physical Watchpoint */
+            default:
+                env->dmmuregs[reg] = val;
+                break;
+            }
+
+            if (oldreg != env->dmmuregs[reg]) {
+                DPRINTF_MMU("dmmu change reg[%d]: 0x%016" PRIx64 " -> 0x%016"
+                            PRIx64 "\n", reg, oldreg, env->dmmuregs[reg]);
+            }
+#ifdef DEBUG_MMU
+            dump_mmu(stdout, fprintf, env);
+#endif
+            return;
+        }
+    case 0x5c: /* D-MMU data in */
+        replace_tlb_1bit_lru(env->dtlb, env->dmmu.tag_access, val, "dmmu", env);
+        return;
+    case 0x5d: /* D-MMU data access */
+        {
+            unsigned int i = (addr >> 3) & 0x3f;
+
+            replace_tlb_entry(&env->dtlb[i], env->dmmu.tag_access, val, env);
+
+#ifdef DEBUG_MMU
+            DPRINTF_MMU("dmmu data access replaced entry [%i]\n", i);
+            dump_mmu(stdout, fprintf, env);
+#endif
+            return;
+        }
+    case 0x5f: /* D-MMU demap */
+        demap_tlb(env->dtlb, addr, "dmmu", env);
+        return;
+    case 0x49: /* Interrupt data receive */
+        /* XXX */
+        return;
+    case 0x46: /* D-cache data */
+    case 0x47: /* D-cache tag access */
+    case 0x4b: /* E-cache error enable */
+    case 0x4c: /* E-cache asynchronous fault status */
+    case 0x4d: /* E-cache asynchronous fault address */
+    case 0x4e: /* E-cache tag data */
+    case 0x66: /* I-cache instruction access */
+    case 0x67: /* I-cache tag access */
+    case 0x6e: /* I-cache predecode */
+    case 0x6f: /* I-cache LRU etc. */
+    case 0x76: /* E-cache tag */
+    case 0x7e: /* E-cache tag */
+        return;
+    case 0x51: /* I-MMU 8k TSB pointer, RO */
+    case 0x52: /* I-MMU 64k TSB pointer, RO */
+    case 0x56: /* I-MMU tag read, RO */
+    case 0x59: /* D-MMU 8k TSB pointer, RO */
+    case 0x5a: /* D-MMU 64k TSB pointer, RO */
+    case 0x5b: /* D-MMU data pointer, RO */
+    case 0x5e: /* D-MMU tag read, RO */
+    case 0x48: /* Interrupt dispatch, RO */
+    case 0x7f: /* Incoming interrupt vector, RO */
+    case 0x82: /* Primary no-fault, RO */
+    case 0x83: /* Secondary no-fault, RO */
+    case 0x8a: /* Primary no-fault LE, RO */
+    case 0x8b: /* Secondary no-fault LE, RO */
+    default:
+        do_unassigned_access(addr, 1, 0, 1, size);
+        return;
+    }
+}
+#endif /* CONFIG_USER_ONLY */
+
+void helper_ldda_asi(target_ulong addr, int asi, int rd)
+{
+    if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
+        || (cpu_has_hypervisor(env)
+            && asi >= 0x30 && asi < 0x80
+            && !(env->hpstate & HS_PRIV))) {
+        helper_raise_exception(env, TT_PRIV_ACT);
+    }
+
+    addr = asi_address_mask(env, asi, addr);
+
+    switch (asi) {
+#if !defined(CONFIG_USER_ONLY)
+    case 0x24: /* Nucleus quad LDD 128 bit atomic */
+    case 0x2c: /* Nucleus quad LDD 128 bit atomic LE */
+        helper_check_align(addr, 0xf);
+        if (rd == 0) {
+            env->gregs[1] = ldq_nucleus(addr + 8);
+            if (asi == 0x2c) {
+                bswap64s(&env->gregs[1]);
+            }
+        } else if (rd < 8) {
+            env->gregs[rd] = ldq_nucleus(addr);
+            env->gregs[rd + 1] = ldq_nucleus(addr + 8);
+            if (asi == 0x2c) {
+                bswap64s(&env->gregs[rd]);
+                bswap64s(&env->gregs[rd + 1]);
+            }
+        } else {
+            env->regwptr[rd] = ldq_nucleus(addr);
+            env->regwptr[rd + 1] = ldq_nucleus(addr + 8);
+            if (asi == 0x2c) {
+                bswap64s(&env->regwptr[rd]);
+                bswap64s(&env->regwptr[rd + 1]);
+            }
+        }
+        break;
+#endif
+    default:
+        helper_check_align(addr, 0x3);
+        if (rd == 0) {
+            env->gregs[1] = helper_ld_asi(addr + 4, asi, 4, 0);
+        } else if (rd < 8) {
+            env->gregs[rd] = helper_ld_asi(addr, asi, 4, 0);
+            env->gregs[rd + 1] = helper_ld_asi(addr + 4, asi, 4, 0);
+        } else {
+            env->regwptr[rd] = helper_ld_asi(addr, asi, 4, 0);
+            env->regwptr[rd + 1] = helper_ld_asi(addr + 4, asi, 4, 0);
+        }
+        break;
+    }
+}
+
+void helper_ldf_asi(target_ulong addr, int asi, int size, int rd)
+{
+    unsigned int i;
+    CPU_DoubleU u;
+
+    helper_check_align(addr, 3);
+    addr = asi_address_mask(env, asi, addr);
+
+    switch (asi) {
+    case 0xf0: /* UA2007/JPS1 Block load primary */
+    case 0xf1: /* UA2007/JPS1 Block load secondary */
+    case 0xf8: /* UA2007/JPS1 Block load primary LE */
+    case 0xf9: /* UA2007/JPS1 Block load secondary LE */
+        if (rd & 7) {
+            helper_raise_exception(env, TT_ILL_INSN);
+            return;
+        }
+        helper_check_align(addr, 0x3f);
+        for (i = 0; i < 16; i++) {
+            *(uint32_t *)&env->fpr[rd++] = helper_ld_asi(addr, asi & 0x8f, 4,
+                                                         0);
+            addr += 4;
+        }
+
+        return;
+    case 0x16: /* UA2007 Block load primary, user privilege */
+    case 0x17: /* UA2007 Block load secondary, user privilege */
+    case 0x1e: /* UA2007 Block load primary LE, user privilege */
+    case 0x1f: /* UA2007 Block load secondary LE, user privilege */
+    case 0x70: /* JPS1 Block load primary, user privilege */
+    case 0x71: /* JPS1 Block load secondary, user privilege */
+    case 0x78: /* JPS1 Block load primary LE, user privilege */
+    case 0x79: /* JPS1 Block load secondary LE, user privilege */
+        if (rd & 7) {
+            helper_raise_exception(env, TT_ILL_INSN);
+            return;
+        }
+        helper_check_align(addr, 0x3f);
+        for (i = 0; i < 16; i++) {
+            *(uint32_t *)&env->fpr[rd++] = helper_ld_asi(addr, asi & 0x19, 4,
+                                                         0);
+            addr += 4;
+        }
+
+        return;
+    default:
+        break;
+    }
+
+    switch (size) {
+    default:
+    case 4:
+        *((uint32_t *)&env->fpr[rd]) = helper_ld_asi(addr, asi, size, 0);
+        break;
+    case 8:
+        u.ll = helper_ld_asi(addr, asi, size, 0);
+        *((uint32_t *)&env->fpr[rd++]) = u.l.upper;
+        *((uint32_t *)&env->fpr[rd++]) = u.l.lower;
+        break;
+    case 16:
+        u.ll = helper_ld_asi(addr, asi, 8, 0);
+        *((uint32_t *)&env->fpr[rd++]) = u.l.upper;
+        *((uint32_t *)&env->fpr[rd++]) = u.l.lower;
+        u.ll = helper_ld_asi(addr + 8, asi, 8, 0);
+        *((uint32_t *)&env->fpr[rd++]) = u.l.upper;
+        *((uint32_t *)&env->fpr[rd++]) = u.l.lower;
+        break;
+    }
+}
+
+void helper_stf_asi(target_ulong addr, int asi, int size, int rd)
+{
+    unsigned int i;
+    target_ulong val = 0;
+    CPU_DoubleU u;
+
+    helper_check_align(addr, 3);
+    addr = asi_address_mask(env, asi, addr);
+
+    switch (asi) {
+    case 0xe0: /* UA2007/JPS1 Block commit store primary (cache flush) */
+    case 0xe1: /* UA2007/JPS1 Block commit store secondary (cache flush) */
+    case 0xf0: /* UA2007/JPS1 Block store primary */
+    case 0xf1: /* UA2007/JPS1 Block store secondary */
+    case 0xf8: /* UA2007/JPS1 Block store primary LE */
+    case 0xf9: /* UA2007/JPS1 Block store secondary LE */
+        if (rd & 7) {
+            helper_raise_exception(env, TT_ILL_INSN);
+            return;
+        }
+        helper_check_align(addr, 0x3f);
+        for (i = 0; i < 16; i++) {
+            val = *(uint32_t *)&env->fpr[rd++];
+            helper_st_asi(addr, val, asi & 0x8f, 4);
+            addr += 4;
+        }
+
+        return;
+    case 0x16: /* UA2007 Block load primary, user privilege */
+    case 0x17: /* UA2007 Block load secondary, user privilege */
+    case 0x1e: /* UA2007 Block load primary LE, user privilege */
+    case 0x1f: /* UA2007 Block load secondary LE, user privilege */
+    case 0x70: /* JPS1 Block store primary, user privilege */
+    case 0x71: /* JPS1 Block store secondary, user privilege */
+    case 0x78: /* JPS1 Block load primary LE, user privilege */
+    case 0x79: /* JPS1 Block load secondary LE, user privilege */
+        if (rd & 7) {
+            helper_raise_exception(env, TT_ILL_INSN);
+            return;
+        }
+        helper_check_align(addr, 0x3f);
+        for (i = 0; i < 16; i++) {
+            val = *(uint32_t *)&env->fpr[rd++];
+            helper_st_asi(addr, val, asi & 0x19, 4);
+            addr += 4;
+        }
+
+        return;
+    default:
+        break;
+    }
+
+    switch (size) {
+    default:
+    case 4:
+        helper_st_asi(addr, *(uint32_t *)&env->fpr[rd], asi, size);
+        break;
+    case 8:
+        u.l.upper = *(uint32_t *)&env->fpr[rd++];
+        u.l.lower = *(uint32_t *)&env->fpr[rd++];
+        helper_st_asi(addr, u.ll, asi, size);
+        break;
+    case 16:
+        u.l.upper = *(uint32_t *)&env->fpr[rd++];
+        u.l.lower = *(uint32_t *)&env->fpr[rd++];
+        helper_st_asi(addr, u.ll, asi, 8);
+        u.l.upper = *(uint32_t *)&env->fpr[rd++];
+        u.l.lower = *(uint32_t *)&env->fpr[rd++];
+        helper_st_asi(addr + 8, u.ll, asi, 8);
+        break;
+    }
+}
+
+target_ulong helper_cas_asi(target_ulong addr, target_ulong val1,
+                            target_ulong val2, uint32_t asi)
+{
+    target_ulong ret;
+
+    val2 &= 0xffffffffUL;
+    ret = helper_ld_asi(addr, asi, 4, 0);
+    ret &= 0xffffffffUL;
+    if (val2 == ret) {
+        helper_st_asi(addr, val1 & 0xffffffffUL, asi, 4);
+    }
+    return ret;
+}
+
+target_ulong helper_casx_asi(target_ulong addr, target_ulong val1,
+                             target_ulong val2, uint32_t asi)
+{
+    target_ulong ret;
+
+    ret = helper_ld_asi(addr, asi, 8, 0);
+    if (val2 == ret) {
+        helper_st_asi(addr, val1, asi, 8);
+    }
+    return ret;
+}
+#endif /* TARGET_SPARC64 */
+
+void helper_stdf(target_ulong addr, int mem_idx)
+{
+    helper_check_align(addr, 7);
+#if !defined(CONFIG_USER_ONLY)
+    switch (mem_idx) {
+    case MMU_USER_IDX:
+        stfq_user(addr, DT0);
+        break;
+    case MMU_KERNEL_IDX:
+        stfq_kernel(addr, DT0);
+        break;
+#ifdef TARGET_SPARC64
+    case MMU_HYPV_IDX:
+        stfq_hypv(addr, DT0);
+        break;
+#endif
+    default:
+        DPRINTF_MMU("helper_stdf: need to check MMU idx %d\n", mem_idx);
+        break;
+    }
+#else
+    stfq_raw(address_mask(env, addr), DT0);
+#endif
+}
+
+void helper_lddf(target_ulong addr, int mem_idx)
+{
+    helper_check_align(addr, 7);
+#if !defined(CONFIG_USER_ONLY)
+    switch (mem_idx) {
+    case MMU_USER_IDX:
+        DT0 = ldfq_user(addr);
+        break;
+    case MMU_KERNEL_IDX:
+        DT0 = ldfq_kernel(addr);
+        break;
+#ifdef TARGET_SPARC64
+    case MMU_HYPV_IDX:
+        DT0 = ldfq_hypv(addr);
+        break;
+#endif
+    default:
+        DPRINTF_MMU("helper_lddf: need to check MMU idx %d\n", mem_idx);
+        break;
+    }
+#else
+    DT0 = ldfq_raw(address_mask(env, addr));
+#endif
+}
+
+void helper_ldqf(target_ulong addr, int mem_idx)
+{
+    /* XXX add 128 bit load */
+    CPU_QuadU u;
+
+    helper_check_align(addr, 7);
+#if !defined(CONFIG_USER_ONLY)
+    switch (mem_idx) {
+    case MMU_USER_IDX:
+        u.ll.upper = ldq_user(addr);
+        u.ll.lower = ldq_user(addr + 8);
+        QT0 = u.q;
+        break;
+    case MMU_KERNEL_IDX:
+        u.ll.upper = ldq_kernel(addr);
+        u.ll.lower = ldq_kernel(addr + 8);
+        QT0 = u.q;
+        break;
+#ifdef TARGET_SPARC64
+    case MMU_HYPV_IDX:
+        u.ll.upper = ldq_hypv(addr);
+        u.ll.lower = ldq_hypv(addr + 8);
+        QT0 = u.q;
+        break;
+#endif
+    default:
+        DPRINTF_MMU("helper_ldqf: need to check MMU idx %d\n", mem_idx);
+        break;
+    }
+#else
+    u.ll.upper = ldq_raw(address_mask(env, addr));
+    u.ll.lower = ldq_raw(address_mask(env, addr + 8));
+    QT0 = u.q;
+#endif
+}
+
+void helper_stqf(target_ulong addr, int mem_idx)
+{
+    /* XXX add 128 bit store */
+    CPU_QuadU u;
+
+    helper_check_align(addr, 7);
+#if !defined(CONFIG_USER_ONLY)
+    switch (mem_idx) {
+    case MMU_USER_IDX:
+        u.q = QT0;
+        stq_user(addr, u.ll.upper);
+        stq_user(addr + 8, u.ll.lower);
+        break;
+    case MMU_KERNEL_IDX:
+        u.q = QT0;
+        stq_kernel(addr, u.ll.upper);
+        stq_kernel(addr + 8, u.ll.lower);
+        break;
+#ifdef TARGET_SPARC64
+    case MMU_HYPV_IDX:
+        u.q = QT0;
+        stq_hypv(addr, u.ll.upper);
+        stq_hypv(addr + 8, u.ll.lower);
+        break;
+#endif
+    default:
+        DPRINTF_MMU("helper_stqf: need to check MMU idx %d\n", mem_idx);
+        break;
+    }
+#else
+    u.q = QT0;
+    stq_raw(address_mask(env, addr), u.ll.upper);
+    stq_raw(address_mask(env, addr + 8), u.ll.lower);
+#endif
+}
+
+#ifndef TARGET_SPARC64
+#if !defined(CONFIG_USER_ONLY)
+static void do_unassigned_access(target_phys_addr_t addr, int is_write,
+                                 int is_exec, int is_asi, int size)
+{
+    int fault_type;
+
+#ifdef DEBUG_UNASSIGNED
+    if (is_asi) {
+        printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx
+               " asi 0x%02x from " TARGET_FMT_lx "\n",
+               is_exec ? "exec" : is_write ? "write" : "read", size,
+               size == 1 ? "" : "s", addr, is_asi, env->pc);
+    } else {
+        printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx
+               " from " TARGET_FMT_lx "\n",
+               is_exec ? "exec" : is_write ? "write" : "read", size,
+               size == 1 ? "" : "s", addr, env->pc);
+    }
+#endif
+    /* Don't overwrite translation and access faults */
+    fault_type = (env->mmuregs[3] & 0x1c) >> 2;
+    if ((fault_type > 4) || (fault_type == 0)) {
+        env->mmuregs[3] = 0; /* Fault status register */
+        if (is_asi) {
+            env->mmuregs[3] |= 1 << 16;
+        }
+        if (env->psrs) {
+            env->mmuregs[3] |= 1 << 5;
+        }
+        if (is_exec) {
+            env->mmuregs[3] |= 1 << 6;
+        }
+        if (is_write) {
+            env->mmuregs[3] |= 1 << 7;
+        }
+        env->mmuregs[3] |= (5 << 2) | 2;
+        /* SuperSPARC will never place instruction fault addresses in the FAR */
+        if (!is_exec) {
+            env->mmuregs[4] = addr; /* Fault address register */
+        }
+    }
+    /* overflow (same type fault was not read before another fault) */
+    if (fault_type == ((env->mmuregs[3] & 0x1c)) >> 2) {
+        env->mmuregs[3] |= 1;
+    }
+
+    if ((env->mmuregs[0] & MMU_E) && !(env->mmuregs[0] & MMU_NF)) {
+        if (is_exec) {
+            helper_raise_exception(env, TT_CODE_ACCESS);
+        } else {
+            helper_raise_exception(env, TT_DATA_ACCESS);
+        }
+    }
+
+    /* flush neverland mappings created during no-fault mode,
+       so the sequential MMU faults report proper fault types */
+    if (env->mmuregs[0] & MMU_NF) {
+        tlb_flush(env, 1);
+    }
+}
+#endif
+#else
+#if defined(CONFIG_USER_ONLY)
+static void do_unassigned_access(target_ulong addr, int is_write, int is_exec,
+                                 int is_asi, int size)
+#else
+static void do_unassigned_access(target_phys_addr_t addr, int is_write,
+                                 int is_exec, int is_asi, int size)
+#endif
+{
+#ifdef DEBUG_UNASSIGNED
+    printf("Unassigned mem access to " TARGET_FMT_plx " from " TARGET_FMT_lx
+           "\n", addr, env->pc);
+#endif
+
+    if (is_exec) {
+        helper_raise_exception(env, TT_CODE_ACCESS);
+    } else {
+        helper_raise_exception(env, TT_DATA_ACCESS);
+    }
+}
+#endif
+
+#if !defined(CONFIG_USER_ONLY)
+void cpu_unassigned_access(CPUState *env1, target_phys_addr_t addr,
+                           int is_write, int is_exec, int is_asi, int size)
+{
+    CPUState *saved_env;
+
+    saved_env = env;
+    env = env1;
+    do_unassigned_access(addr, is_write, is_exec, is_asi, size);
+    env = saved_env;
+}
+#endif
diff --git a/target-sparc/mmu_helper.c b/target-sparc/mmu_helper.c
new file mode 100644
index 0000000..8cdc224
--- /dev/null
+++ b/target-sparc/mmu_helper.c
@@ -0,0 +1,853 @@
+/*
+ *  Sparc MMU helpers
+ *
+ *  Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * 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/>.
+ */
+
+#include "cpu.h"
+#include "trace.h"
+
+/* Sparc MMU emulation */
+
+#if defined(CONFIG_USER_ONLY)
+
+int cpu_sparc_handle_mmu_fault(CPUState *env1, target_ulong address, int rw,
+                               int mmu_idx)
+{
+    if (rw & 2) {
+        env1->exception_index = TT_TFAULT;
+    } else {
+        env1->exception_index = TT_DFAULT;
+    }
+    return 1;
+}
+
+#else
+
+#ifndef TARGET_SPARC64
+/*
+ * Sparc V8 Reference MMU (SRMMU)
+ */
+static const int access_table[8][8] = {
+    { 0, 0, 0, 0, 8, 0, 12, 12 },
+    { 0, 0, 0, 0, 8, 0, 0, 0 },
+    { 8, 8, 0, 0, 0, 8, 12, 12 },
+    { 8, 8, 0, 0, 0, 8, 0, 0 },
+    { 8, 0, 8, 0, 8, 8, 12, 12 },
+    { 8, 0, 8, 0, 8, 0, 8, 0 },
+    { 8, 8, 8, 0, 8, 8, 12, 12 },
+    { 8, 8, 8, 0, 8, 8, 8, 0 }
+};
+
+static const int perm_table[2][8] = {
+    {
+        PAGE_READ,
+        PAGE_READ | PAGE_WRITE,
+        PAGE_READ | PAGE_EXEC,
+        PAGE_READ | PAGE_WRITE | PAGE_EXEC,
+        PAGE_EXEC,
+        PAGE_READ | PAGE_WRITE,
+        PAGE_READ | PAGE_EXEC,
+        PAGE_READ | PAGE_WRITE | PAGE_EXEC
+    },
+    {
+        PAGE_READ,
+        PAGE_READ | PAGE_WRITE,
+        PAGE_READ | PAGE_EXEC,
+        PAGE_READ | PAGE_WRITE | PAGE_EXEC,
+        PAGE_EXEC,
+        PAGE_READ,
+        0,
+        0,
+    }
+};
+
+static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
+                                int *prot, int *access_index,
+                                target_ulong address, int rw, int mmu_idx,
+                                target_ulong *page_size)
+{
+    int access_perms = 0;
+    target_phys_addr_t pde_ptr;
+    uint32_t pde;
+    int error_code = 0, is_dirty, is_user;
+    unsigned long page_offset;
+
+    is_user = mmu_idx == MMU_USER_IDX;
+
+    if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
+        *page_size = TARGET_PAGE_SIZE;
+        /* Boot mode: instruction fetches are taken from PROM */
+        if (rw == 2 && (env->mmuregs[0] & env->def->mmu_bm)) {
+            *physical = env->prom_addr | (address & 0x7ffffULL);
+            *prot = PAGE_READ | PAGE_EXEC;
+            return 0;
+        }
+        *physical = address;
+        *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+        return 0;
+    }
+
+    *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user ? 0 : 1);
+    *physical = 0xffffffffffff0000ULL;
+
+    /* SPARC reference MMU table walk: Context table->L1->L2->PTE */
+    /* Context base + context number */
+    pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
+    pde = ldl_phys(pde_ptr);
+
+    /* Ctx pde */
+    switch (pde & PTE_ENTRYTYPE_MASK) {
+    default:
+    case 0: /* Invalid */
+        return 1 << 2;
+    case 2: /* L0 PTE, maybe should not happen? */
+    case 3: /* Reserved */
+        return 4 << 2;
+    case 1: /* L0 PDE */
+        pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
+        pde = ldl_phys(pde_ptr);
+
+        switch (pde & PTE_ENTRYTYPE_MASK) {
+        default:
+        case 0: /* Invalid */
+            return (1 << 8) | (1 << 2);
+        case 3: /* Reserved */
+            return (1 << 8) | (4 << 2);
+        case 1: /* L1 PDE */
+            pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
+            pde = ldl_phys(pde_ptr);
+
+            switch (pde & PTE_ENTRYTYPE_MASK) {
+            default:
+            case 0: /* Invalid */
+                return (2 << 8) | (1 << 2);
+            case 3: /* Reserved */
+                return (2 << 8) | (4 << 2);
+            case 1: /* L2 PDE */
+                pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
+                pde = ldl_phys(pde_ptr);
+
+                switch (pde & PTE_ENTRYTYPE_MASK) {
+                default:
+                case 0: /* Invalid */
+                    return (3 << 8) | (1 << 2);
+                case 1: /* PDE, should not happen */
+                case 3: /* Reserved */
+                    return (3 << 8) | (4 << 2);
+                case 2: /* L3 PTE */
+                    page_offset = (address & TARGET_PAGE_MASK) &
+                        (TARGET_PAGE_SIZE - 1);
+                }
+                *page_size = TARGET_PAGE_SIZE;
+                break;
+            case 2: /* L2 PTE */
+                page_offset = address & 0x3ffff;
+                *page_size = 0x40000;
+            }
+            break;
+        case 2: /* L1 PTE */
+            page_offset = address & 0xffffff;
+            *page_size = 0x1000000;
+        }
+    }
+
+    /* check access */
+    access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT;
+    error_code = access_table[*access_index][access_perms];
+    if (error_code && !((env->mmuregs[0] & MMU_NF) && is_user)) {
+        return error_code;
+    }
+
+    /* update page modified and dirty bits */
+    is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK);
+    if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
+        pde |= PG_ACCESSED_MASK;
+        if (is_dirty) {
+            pde |= PG_MODIFIED_MASK;
+        }
+        stl_phys_notdirty(pde_ptr, pde);
+    }
+
+    /* the page can be put in the TLB */
+    *prot = perm_table[is_user][access_perms];
+    if (!(pde & PG_MODIFIED_MASK)) {
+        /* only set write access if already dirty... otherwise wait
+           for dirty access */
+        *prot &= ~PAGE_WRITE;
+    }
+
+    /* Even if large ptes, we map only one 4KB page in the cache to
+       avoid filling it too fast */
+    *physical = ((target_phys_addr_t)(pde & PTE_ADDR_MASK) << 4) + page_offset;
+    return error_code;
+}
+
+/* Perform address translation */
+int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
+                               int mmu_idx)
+{
+    target_phys_addr_t paddr;
+    target_ulong vaddr;
+    target_ulong page_size;
+    int error_code = 0, prot, access_index;
+
+    error_code = get_physical_address(env, &paddr, &prot, &access_index,
+                                      address, rw, mmu_idx, &page_size);
+    if (error_code == 0) {
+        vaddr = address & TARGET_PAGE_MASK;
+        paddr &= TARGET_PAGE_MASK;
+#ifdef DEBUG_MMU
+        printf("Translate at " TARGET_FMT_lx " -> " TARGET_FMT_plx ", vaddr "
+               TARGET_FMT_lx "\n", address, paddr, vaddr);
+#endif
+        tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
+        return 0;
+    }
+
+    if (env->mmuregs[3]) { /* Fault status register */
+        env->mmuregs[3] = 1; /* overflow (not read before another fault) */
+    }
+    env->mmuregs[3] |= (access_index << 5) | error_code | 2;
+    env->mmuregs[4] = address; /* Fault address register */
+
+    if ((env->mmuregs[0] & MMU_NF) || env->psret == 0)  {
+        /* No fault mode: if a mapping is available, just override
+           permissions. If no mapping is available, redirect accesses to
+           neverland. Fake/overridden mappings will be flushed when
+           switching to normal mode. */
+        vaddr = address & TARGET_PAGE_MASK;
+        prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+        tlb_set_page(env, vaddr, paddr, prot, mmu_idx, TARGET_PAGE_SIZE);
+        return 0;
+    } else {
+        if (rw & 2) {
+            env->exception_index = TT_TFAULT;
+        } else {
+            env->exception_index = TT_DFAULT;
+        }
+        return 1;
+    }
+}
+
+target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev)
+{
+    target_phys_addr_t pde_ptr;
+    uint32_t pde;
+
+    /* Context base + context number */
+    pde_ptr = (target_phys_addr_t)(env->mmuregs[1] << 4) +
+        (env->mmuregs[2] << 2);
+    pde = ldl_phys(pde_ptr);
+
+    switch (pde & PTE_ENTRYTYPE_MASK) {
+    default:
+    case 0: /* Invalid */
+    case 2: /* PTE, maybe should not happen? */
+    case 3: /* Reserved */
+        return 0;
+    case 1: /* L1 PDE */
+        if (mmulev == 3) {
+            return pde;
+        }
+        pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
+        pde = ldl_phys(pde_ptr);
+
+        switch (pde & PTE_ENTRYTYPE_MASK) {
+        default:
+        case 0: /* Invalid */
+        case 3: /* Reserved */
+            return 0;
+        case 2: /* L1 PTE */
+            return pde;
+        case 1: /* L2 PDE */
+            if (mmulev == 2) {
+                return pde;
+            }
+            pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
+            pde = ldl_phys(pde_ptr);
+
+            switch (pde & PTE_ENTRYTYPE_MASK) {
+            default:
+            case 0: /* Invalid */
+            case 3: /* Reserved */
+                return 0;
+            case 2: /* L2 PTE */
+                return pde;
+            case 1: /* L3 PDE */
+                if (mmulev == 1) {
+                    return pde;
+                }
+                pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
+                pde = ldl_phys(pde_ptr);
+
+                switch (pde & PTE_ENTRYTYPE_MASK) {
+                default:
+                case 0: /* Invalid */
+                case 1: /* PDE, should not happen */
+                case 3: /* Reserved */
+                    return 0;
+                case 2: /* L3 PTE */
+                    return pde;
+                }
+            }
+        }
+    }
+    return 0;
+}
+
+void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
+{
+    target_ulong va, va1, va2;
+    unsigned int n, m, o;
+    target_phys_addr_t pde_ptr, pa;
+    uint32_t pde;
+
+    pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
+    pde = ldl_phys(pde_ptr);
+    (*cpu_fprintf)(f, "Root ptr: " TARGET_FMT_plx ", ctx: %d\n",
+                   (target_phys_addr_t)env->mmuregs[1] << 4, env->mmuregs[2]);
+    for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) {
+        pde = mmu_probe(env, va, 2);
+        if (pde) {
+            pa = cpu_get_phys_page_debug(env, va);
+            (*cpu_fprintf)(f, "VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx
+                           " PDE: " TARGET_FMT_lx "\n", va, pa, pde);
+            for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) {
+                pde = mmu_probe(env, va1, 1);
+                if (pde) {
+                    pa = cpu_get_phys_page_debug(env, va1);
+                    (*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: "
+                                   TARGET_FMT_plx " PDE: " TARGET_FMT_lx "\n",
+                                   va1, pa, pde);
+                    for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) {
+                        pde = mmu_probe(env, va2, 0);
+                        if (pde) {
+                            pa = cpu_get_phys_page_debug(env, va2);
+                            (*cpu_fprintf)(f, "  VA: " TARGET_FMT_lx ", PA: "
+                                           TARGET_FMT_plx " PTE: "
+                                           TARGET_FMT_lx "\n",
+                                           va2, pa, pde);
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+/* Gdb expects all registers windows to be flushed in ram. This function handles
+ * reads (and only reads) in stack frames as if windows were flushed. We assume
+ * that the sparc ABI is followed.
+ */
+int target_memory_rw_debug(CPUState *env, target_ulong addr,
+                           uint8_t *buf, int len, int is_write)
+{
+    int i;
+    int len1;
+    int cwp = env->cwp;
+
+    if (!is_write) {
+        for (i = 0; i < env->nwindows; i++) {
+            int off;
+            target_ulong fp = env->regbase[cwp * 16 + 22];
+
+            /* Assume fp == 0 means end of frame.  */
+            if (fp == 0) {
+                break;
+            }
+
+            cwp = cpu_cwp_inc(env, cwp + 1);
+
+            /* Invalid window ? */
+            if (env->wim & (1 << cwp)) {
+                break;
+            }
+
+            /* According to the ABI, the stack is growing downward.  */
+            if (addr + len < fp) {
+                break;
+            }
+
+            /* Not in this frame.  */
+            if (addr > fp + 64) {
+                continue;
+            }
+
+            /* Handle access before this window.  */
+            if (addr < fp) {
+                len1 = fp - addr;
+                if (cpu_memory_rw_debug(env, addr, buf, len1, is_write) != 0) {
+                    return -1;
+                }
+                addr += len1;
+                len -= len1;
+                buf += len1;
+            }
+
+            /* Access byte per byte to registers. Not very efficient but speed
+             * is not critical.
+             */
+            off = addr - fp;
+            len1 = 64 - off;
+
+            if (len1 > len) {
+                len1 = len;
+            }
+
+            for (; len1; len1--) {
+                int reg = cwp * 16 + 8 + (off >> 2);
+                union {
+                    uint32_t v;
+                    uint8_t c[4];
+                } u;
+                u.v = cpu_to_be32(env->regbase[reg]);
+                *buf++ = u.c[off & 3];
+                addr++;
+                len--;
+                off++;
+            }
+
+            if (len == 0) {
+                return 0;
+            }
+        }
+    }
+    return cpu_memory_rw_debug(env, addr, buf, len, is_write);
+}
+
+#else /* !TARGET_SPARC64 */
+
+/* 41 bit physical address space */
+static inline target_phys_addr_t ultrasparc_truncate_physical(uint64_t x)
+{
+    return x & 0x1ffffffffffULL;
+}
+
+/*
+ * UltraSparc IIi I/DMMUs
+ */
+
+/* Returns true if TTE tag is valid and matches virtual address value
+   in context requires virtual address mask value calculated from TTE
+   entry size */
+static inline int ultrasparc_tag_match(SparcTLBEntry *tlb,
+                                       uint64_t address, uint64_t context,
+                                       target_phys_addr_t *physical)
+{
+    uint64_t mask;
+
+    switch (TTE_PGSIZE(tlb->tte)) {
+    default:
+    case 0x0: /* 8k */
+        mask = 0xffffffffffffe000ULL;
+        break;
+    case 0x1: /* 64k */
+        mask = 0xffffffffffff0000ULL;
+        break;
+    case 0x2: /* 512k */
+        mask = 0xfffffffffff80000ULL;
+        break;
+    case 0x3: /* 4M */
+        mask = 0xffffffffffc00000ULL;
+        break;
+    }
+
+    /* valid, context match, virtual address match? */
+    if (TTE_IS_VALID(tlb->tte) &&
+        (TTE_IS_GLOBAL(tlb->tte) || tlb_compare_context(tlb, context))
+        && compare_masked(address, tlb->tag, mask)) {
+        /* decode physical address */
+        *physical = ((tlb->tte & mask) | (address & ~mask)) & 0x1ffffffe000ULL;
+        return 1;
+    }
+
+    return 0;
+}
+
+static int get_physical_address_data(CPUState *env,
+                                     target_phys_addr_t *physical, int *prot,
+                                     target_ulong address, int rw, int mmu_idx)
+{
+    unsigned int i;
+    uint64_t context;
+    uint64_t sfsr = 0;
+
+    int is_user = (mmu_idx == MMU_USER_IDX ||
+                   mmu_idx == MMU_USER_SECONDARY_IDX);
+
+    if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */
+        *physical = ultrasparc_truncate_physical(address);
+        *prot = PAGE_READ | PAGE_WRITE;
+        return 0;
+    }
+
+    switch (mmu_idx) {
+    case MMU_USER_IDX:
+    case MMU_KERNEL_IDX:
+        context = env->dmmu.mmu_primary_context & 0x1fff;
+        sfsr |= SFSR_CT_PRIMARY;
+        break;
+    case MMU_USER_SECONDARY_IDX:
+    case MMU_KERNEL_SECONDARY_IDX:
+        context = env->dmmu.mmu_secondary_context & 0x1fff;
+        sfsr |= SFSR_CT_SECONDARY;
+        break;
+    case MMU_NUCLEUS_IDX:
+        sfsr |= SFSR_CT_NUCLEUS;
+        /* FALLTHRU */
+    default:
+        context = 0;
+        break;
+    }
+
+    if (rw == 1) {
+        sfsr |= SFSR_WRITE_BIT;
+    } else if (rw == 4) {
+        sfsr |= SFSR_NF_BIT;
+    }
+
+    for (i = 0; i < 64; i++) {
+        /* ctx match, vaddr match, valid? */
+        if (ultrasparc_tag_match(&env->dtlb[i], address, context, physical)) {
+            int do_fault = 0;
+
+            /* access ok? */
+            /* multiple bits in SFSR.FT may be set on TT_DFAULT */
+            if (TTE_IS_PRIV(env->dtlb[i].tte) && is_user) {
+                do_fault = 1;
+                sfsr |= SFSR_FT_PRIV_BIT; /* privilege violation */
+                trace_mmu_helper_dfault(address, context, mmu_idx, env->tl);
+            }
+            if (rw == 4) {
+                if (TTE_IS_SIDEEFFECT(env->dtlb[i].tte)) {
+                    do_fault = 1;
+                    sfsr |= SFSR_FT_NF_E_BIT;
+                }
+            } else {
+                if (TTE_IS_NFO(env->dtlb[i].tte)) {
+                    do_fault = 1;
+                    sfsr |= SFSR_FT_NFO_BIT;
+                }
+            }
+
+            if (do_fault) {
+                /* faults above are reported with TT_DFAULT. */
+                env->exception_index = TT_DFAULT;
+            } else if (!TTE_IS_W_OK(env->dtlb[i].tte) && (rw == 1)) {
+                do_fault = 1;
+                env->exception_index = TT_DPROT;
+
+                trace_mmu_helper_dprot(address, context, mmu_idx, env->tl);
+            }
+
+            if (!do_fault) {
+                *prot = PAGE_READ;
+                if (TTE_IS_W_OK(env->dtlb[i].tte)) {
+                    *prot |= PAGE_WRITE;
+                }
+
+                TTE_SET_USED(env->dtlb[i].tte);
+
+                return 0;
+            }
+
+            if (env->dmmu.sfsr & SFSR_VALID_BIT) { /* Fault status register */
+                sfsr |= SFSR_OW_BIT; /* overflow (not read before
+                                        another fault) */
+            }
+
+            if (env->pstate & PS_PRIV) {
+                sfsr |= SFSR_PR_BIT;
+            }
+
+            /* FIXME: ASI field in SFSR must be set */
+            env->dmmu.sfsr = sfsr | SFSR_VALID_BIT;
+
+            env->dmmu.sfar = address; /* Fault address register */
+
+            env->dmmu.tag_access = (address & ~0x1fffULL) | context;
+
+            return 1;
+        }
+    }
+
+    trace_mmu_helper_dmiss(address, context);
+
+    /*
+     * On MMU misses:
+     * - UltraSPARC IIi: SFSR and SFAR unmodified
+     * - JPS1: SFAR updated and some fields of SFSR updated
+     */
+    env->dmmu.tag_access = (address & ~0x1fffULL) | context;
+    env->exception_index = TT_DMISS;
+    return 1;
+}
+
+static int get_physical_address_code(CPUState *env,
+                                     target_phys_addr_t *physical, int *prot,
+                                     target_ulong address, int mmu_idx)
+{
+    unsigned int i;
+    uint64_t context;
+
+    int is_user = (mmu_idx == MMU_USER_IDX ||
+                   mmu_idx == MMU_USER_SECONDARY_IDX);
+
+    if ((env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0) {
+        /* IMMU disabled */
+        *physical = ultrasparc_truncate_physical(address);
+        *prot = PAGE_EXEC;
+        return 0;
+    }
+
+    if (env->tl == 0) {
+        /* PRIMARY context */
+        context = env->dmmu.mmu_primary_context & 0x1fff;
+    } else {
+        /* NUCLEUS context */
+        context = 0;
+    }
+
+    for (i = 0; i < 64; i++) {
+        /* ctx match, vaddr match, valid? */
+        if (ultrasparc_tag_match(&env->itlb[i],
+                                 address, context, physical)) {
+            /* access ok? */
+            if (TTE_IS_PRIV(env->itlb[i].tte) && is_user) {
+                /* Fault status register */
+                if (env->immu.sfsr & SFSR_VALID_BIT) {
+                    env->immu.sfsr = SFSR_OW_BIT; /* overflow (not read before
+                                                     another fault) */
+                } else {
+                    env->immu.sfsr = 0;
+                }
+                if (env->pstate & PS_PRIV) {
+                    env->immu.sfsr |= SFSR_PR_BIT;
+                }
+                if (env->tl > 0) {
+                    env->immu.sfsr |= SFSR_CT_NUCLEUS;
+                }
+
+                /* FIXME: ASI field in SFSR must be set */
+                env->immu.sfsr |= SFSR_FT_PRIV_BIT | SFSR_VALID_BIT;
+                env->exception_index = TT_TFAULT;
+
+                env->immu.tag_access = (address & ~0x1fffULL) | context;
+
+                trace_mmu_helper_tfault(address, context);
+
+                return 1;
+            }
+            *prot = PAGE_EXEC;
+            TTE_SET_USED(env->itlb[i].tte);
+            return 0;
+        }
+    }
+
+    trace_mmu_helper_tmiss(address, context);
+
+    /* Context is stored in DMMU (dmmuregs[1]) also for IMMU */
+    env->immu.tag_access = (address & ~0x1fffULL) | context;
+    env->exception_index = TT_TMISS;
+    return 1;
+}
+
+static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
+                                int *prot, int *access_index,
+                                target_ulong address, int rw, int mmu_idx,
+                                target_ulong *page_size)
+{
+    /* ??? We treat everything as a small page, then explicitly flush
+       everything when an entry is evicted.  */
+    *page_size = TARGET_PAGE_SIZE;
+
+    /* safety net to catch wrong softmmu index use from dynamic code */
+    if (env->tl > 0 && mmu_idx != MMU_NUCLEUS_IDX) {
+        if (rw == 2) {
+            trace_mmu_helper_get_phys_addr_code(env->tl, mmu_idx,
+                                                env->dmmu.mmu_primary_context,
+                                                env->dmmu.mmu_secondary_context,
+                                                address);
+        } else {
+            trace_mmu_helper_get_phys_addr_data(env->tl, mmu_idx,
+                                                env->dmmu.mmu_primary_context,
+                                                env->dmmu.mmu_secondary_context,
+                                                address);
+        }
+    }
+
+    if (rw == 2) {
+        return get_physical_address_code(env, physical, prot, address,
+                                         mmu_idx);
+    } else {
+        return get_physical_address_data(env, physical, prot, address, rw,
+                                         mmu_idx);
+    }
+}
+
+/* Perform address translation */
+int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
+                               int mmu_idx)
+{
+    target_ulong virt_addr, vaddr;
+    target_phys_addr_t paddr;
+    target_ulong page_size;
+    int error_code = 0, prot, access_index;
+
+    error_code = get_physical_address(env, &paddr, &prot, &access_index,
+                                      address, rw, mmu_idx, &page_size);
+    if (error_code == 0) {
+        virt_addr = address & TARGET_PAGE_MASK;
+        vaddr = virt_addr + ((address & TARGET_PAGE_MASK) &
+                             (TARGET_PAGE_SIZE - 1));
+
+        trace_mmu_helper_mmu_fault(address, paddr, mmu_idx, env->tl,
+                                   env->dmmu.mmu_primary_context,
+                                   env->dmmu.mmu_secondary_context);
+
+        tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
+        return 0;
+    }
+    /* XXX */
+    return 1;
+}
+
+void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
+{
+    unsigned int i;
+    const char *mask;
+
+    (*cpu_fprintf)(f, "MMU contexts: Primary: %" PRId64 ", Secondary: %"
+                   PRId64 "\n",
+                   env->dmmu.mmu_primary_context,
+                   env->dmmu.mmu_secondary_context);
+    if ((env->lsu & DMMU_E) == 0) {
+        (*cpu_fprintf)(f, "DMMU disabled\n");
+    } else {
+        (*cpu_fprintf)(f, "DMMU dump\n");
+        for (i = 0; i < 64; i++) {
+            switch (TTE_PGSIZE(env->dtlb[i].tte)) {
+            default:
+            case 0x0:
+                mask = "  8k";
+                break;
+            case 0x1:
+                mask = " 64k";
+                break;
+            case 0x2:
+                mask = "512k";
+                break;
+            case 0x3:
+                mask = "  4M";
+                break;
+            }
+            if (TTE_IS_VALID(env->dtlb[i].tte)) {
+                (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx"
+                               ", %s, %s, %s, %s, ctx %" PRId64 " %s\n",
+                               i,
+                               env->dtlb[i].tag & (uint64_t)~0x1fffULL,
+                               TTE_PA(env->dtlb[i].tte),
+                               mask,
+                               TTE_IS_PRIV(env->dtlb[i].tte) ? "priv" : "user",
+                               TTE_IS_W_OK(env->dtlb[i].tte) ? "RW" : "RO",
+                               TTE_IS_LOCKED(env->dtlb[i].tte) ?
+                               "locked" : "unlocked",
+                               env->dtlb[i].tag & (uint64_t)0x1fffULL,
+                               TTE_IS_GLOBAL(env->dtlb[i].tte) ?
+                               "global" : "local");
+            }
+        }
+    }
+    if ((env->lsu & IMMU_E) == 0) {
+        (*cpu_fprintf)(f, "IMMU disabled\n");
+    } else {
+        (*cpu_fprintf)(f, "IMMU dump\n");
+        for (i = 0; i < 64; i++) {
+            switch (TTE_PGSIZE(env->itlb[i].tte)) {
+            default:
+            case 0x0:
+                mask = "  8k";
+                break;
+            case 0x1:
+                mask = " 64k";
+                break;
+            case 0x2:
+                mask = "512k";
+                break;
+            case 0x3:
+                mask = "  4M";
+                break;
+            }
+            if (TTE_IS_VALID(env->itlb[i].tte)) {
+                (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx"
+                               ", %s, %s, %s, ctx %" PRId64 " %s\n",
+                               i,
+                               env->itlb[i].tag & (uint64_t)~0x1fffULL,
+                               TTE_PA(env->itlb[i].tte),
+                               mask,
+                               TTE_IS_PRIV(env->itlb[i].tte) ? "priv" : "user",
+                               TTE_IS_LOCKED(env->itlb[i].tte) ?
+                               "locked" : "unlocked",
+                               env->itlb[i].tag & (uint64_t)0x1fffULL,
+                               TTE_IS_GLOBAL(env->itlb[i].tte) ?
+                               "global" : "local");
+            }
+        }
+    }
+}
+
+#endif /* TARGET_SPARC64 */
+
+static int cpu_sparc_get_phys_page(CPUState *env, target_phys_addr_t *phys,
+                                   target_ulong addr, int rw, int mmu_idx)
+{
+    target_ulong page_size;
+    int prot, access_index;
+
+    return get_physical_address(env, phys, &prot, &access_index, addr, rw,
+                                mmu_idx, &page_size);
+}
+
+#if defined(TARGET_SPARC64)
+target_phys_addr_t cpu_get_phys_page_nofault(CPUState *env, target_ulong addr,
+                                           int mmu_idx)
+{
+    target_phys_addr_t phys_addr;
+
+    if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 4, mmu_idx) != 0) {
+        return -1;
+    }
+    return phys_addr;
+}
+#endif
+
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+{
+    target_phys_addr_t phys_addr;
+    int mmu_idx = cpu_mmu_index(env);
+
+    if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 2, mmu_idx) != 0) {
+        if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 0, mmu_idx) != 0) {
+            return -1;
+        }
+    }
+    if (cpu_get_physical_page_desc(phys_addr) == IO_MEM_UNASSIGNED) {
+        return -1;
+    }
+    return phys_addr;
+}
+#endif
diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
index 1cb0636..02b660d 100644
--- a/target-sparc/op_helper.c
+++ b/target-sparc/op_helper.c
@@ -1,4179 +1,8 @@
 #include "cpu.h"
 #include "dyngen-exec.h"
-#include "host-utils.h"
 #include "helper.h"
-#include "sysemu.h"
 
 #if !defined(CONFIG_USER_ONLY)
-#include "softmmu_exec.h"
-#endif
-
-//#define DEBUG_MMU
-//#define DEBUG_MXCC
-//#define DEBUG_UNALIGNED
-//#define DEBUG_UNASSIGNED
-//#define DEBUG_ASI
-//#define DEBUG_PCALL
-//#define DEBUG_PSTATE
-//#define DEBUG_CACHE_CONTROL
-
-#ifdef DEBUG_MMU
-#define DPRINTF_MMU(fmt, ...)                                   \
-    do { printf("MMU: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF_MMU(fmt, ...) do {} while (0)
-#endif
-
-#ifdef DEBUG_MXCC
-#define DPRINTF_MXCC(fmt, ...)                                  \
-    do { printf("MXCC: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF_MXCC(fmt, ...) do {} while (0)
-#endif
-
-#ifdef DEBUG_ASI
-#define DPRINTF_ASI(fmt, ...)                                   \
-    do { printf("ASI: " fmt , ## __VA_ARGS__); } while (0)
-#endif
-
-#ifdef DEBUG_PSTATE
-#define DPRINTF_PSTATE(fmt, ...)                                   \
-    do { printf("PSTATE: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF_PSTATE(fmt, ...) do {} while (0)
-#endif
-
-#ifdef DEBUG_CACHE_CONTROL
-#define DPRINTF_CACHE_CONTROL(fmt, ...)                                   \
-    do { printf("CACHE_CONTROL: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF_CACHE_CONTROL(fmt, ...) do {} while (0)
-#endif
-
-#ifdef TARGET_SPARC64
-#ifndef TARGET_ABI32
-#define AM_CHECK(env1) ((env1)->pstate & PS_AM)
-#else
-#define AM_CHECK(env1) (1)
-#endif
-#endif
-
-#define DT0 (env->dt0)
-#define DT1 (env->dt1)
-#define QT0 (env->qt0)
-#define QT1 (env->qt1)
-
-/* Leon3 cache control */
-
-/* Cache control: emulate the behavior of cache control registers but without
-   any effect on the emulated */
-
-#define CACHE_STATE_MASK 0x3
-#define CACHE_DISABLED   0x0
-#define CACHE_FROZEN     0x1
-#define CACHE_ENABLED    0x3
-
-/* Cache Control register fields */
-
-#define CACHE_CTRL_IF (1 <<  4)  /* Instruction Cache Freeze on Interrupt */
-#define CACHE_CTRL_DF (1 <<  5)  /* Data Cache Freeze on Interrupt */
-#define CACHE_CTRL_DP (1 << 14)  /* Data cache flush pending */
-#define CACHE_CTRL_IP (1 << 15)  /* Instruction cache flush pending */
-#define CACHE_CTRL_IB (1 << 16)  /* Instruction burst fetch */
-#define CACHE_CTRL_FI (1 << 21)  /* Flush Instruction cache (Write only) */
-#define CACHE_CTRL_FD (1 << 22)  /* Flush Data cache (Write only) */
-#define CACHE_CTRL_DS (1 << 23)  /* Data cache snoop enable */
-
-#if !defined(CONFIG_USER_ONLY)
-static void do_unassigned_access(target_phys_addr_t addr, int is_write,
-                                 int is_exec, int is_asi, int size);
-#else
-#ifdef TARGET_SPARC64
-static void do_unassigned_access(target_ulong addr, int is_write, int is_exec,
-                                 int is_asi, int size);
-#endif
-#endif
-
-#if defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
-// Calculates TSB pointer value for fault page size 8k or 64k
-static uint64_t ultrasparc_tsb_pointer(uint64_t tsb_register,
-                                       uint64_t tag_access_register,
-                                       int page_size)
-{
-    uint64_t tsb_base = tsb_register & ~0x1fffULL;
-    int tsb_split = (tsb_register & 0x1000ULL) ? 1 : 0;
-    int tsb_size  = tsb_register & 0xf;
-
-    // discard lower 13 bits which hold tag access context
-    uint64_t tag_access_va = tag_access_register & ~0x1fffULL;
-
-    // now reorder bits
-    uint64_t tsb_base_mask = ~0x1fffULL;
-    uint64_t va = tag_access_va;
-
-    // move va bits to correct position
-    if (page_size == 8*1024) {
-        va >>= 9;
-    } else if (page_size == 64*1024) {
-        va >>= 12;
-    }
-
-    if (tsb_size) {
-        tsb_base_mask <<= tsb_size;
-    }
-
-    // calculate tsb_base mask and adjust va if split is in use
-    if (tsb_split) {
-        if (page_size == 8*1024) {
-            va &= ~(1ULL << (13 + tsb_size));
-        } else if (page_size == 64*1024) {
-            va |= (1ULL << (13 + tsb_size));
-        }
-        tsb_base_mask <<= 1;
-    }
-
-    return ((tsb_base & tsb_base_mask) | (va & ~tsb_base_mask)) & ~0xfULL;
-}
-
-// Calculates tag target register value by reordering bits
-// in tag access register
-static uint64_t ultrasparc_tag_target(uint64_t tag_access_register)
-{
-    return ((tag_access_register & 0x1fff) << 48) | (tag_access_register >> 22);
-}
-
-static void replace_tlb_entry(SparcTLBEntry *tlb,
-                              uint64_t tlb_tag, uint64_t tlb_tte,
-                              CPUState *env1)
-{
-    target_ulong mask, size, va, offset;
-
-    // flush page range if translation is valid
-    if (TTE_IS_VALID(tlb->tte)) {
-
-        mask = 0xffffffffffffe000ULL;
-        mask <<= 3 * ((tlb->tte >> 61) & 3);
-        size = ~mask + 1;
-
-        va = tlb->tag & mask;
-
-        for (offset = 0; offset < size; offset += TARGET_PAGE_SIZE) {
-            tlb_flush_page(env1, va + offset);
-        }
-    }
-
-    tlb->tag = tlb_tag;
-    tlb->tte = tlb_tte;
-}
-
-static void demap_tlb(SparcTLBEntry *tlb, target_ulong demap_addr,
-                      const char* strmmu, CPUState *env1)
-{
-    unsigned int i;
-    target_ulong mask;
-    uint64_t context;
-
-    int is_demap_context = (demap_addr >> 6) & 1;
-
-    // demap context
-    switch ((demap_addr >> 4) & 3) {
-    case 0: // primary
-        context = env1->dmmu.mmu_primary_context;
-        break;
-    case 1: // secondary
-        context = env1->dmmu.mmu_secondary_context;
-        break;
-    case 2: // nucleus
-        context = 0;
-        break;
-    case 3: // reserved
-    default:
-        return;
-    }
-
-    for (i = 0; i < 64; i++) {
-        if (TTE_IS_VALID(tlb[i].tte)) {
-
-            if (is_demap_context) {
-                // will remove non-global entries matching context value
-                if (TTE_IS_GLOBAL(tlb[i].tte) ||
-                    !tlb_compare_context(&tlb[i], context)) {
-                    continue;
-                }
-            } else {
-                // demap page
-                // will remove any entry matching VA
-                mask = 0xffffffffffffe000ULL;
-                mask <<= 3 * ((tlb[i].tte >> 61) & 3);
-
-                if (!compare_masked(demap_addr, tlb[i].tag, mask)) {
-                    continue;
-                }
-
-                // entry should be global or matching context value
-                if (!TTE_IS_GLOBAL(tlb[i].tte) &&
-                    !tlb_compare_context(&tlb[i], context)) {
-                    continue;
-                }
-            }
-
-            replace_tlb_entry(&tlb[i], 0, 0, env1);
-#ifdef DEBUG_MMU
-            DPRINTF_MMU("%s demap invalidated entry [%02u]\n", strmmu, i);
-            dump_mmu(stdout, fprintf, env1);
-#endif
-        }
-    }
-}
-
-static void replace_tlb_1bit_lru(SparcTLBEntry *tlb,
-                                 uint64_t tlb_tag, uint64_t tlb_tte,
-                                 const char* strmmu, CPUState *env1)
-{
-    unsigned int i, replace_used;
-
-    // Try replacing invalid entry
-    for (i = 0; i < 64; i++) {
-        if (!TTE_IS_VALID(tlb[i].tte)) {
-            replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1);
-#ifdef DEBUG_MMU
-            DPRINTF_MMU("%s lru replaced invalid entry [%i]\n", strmmu, i);
-            dump_mmu(stdout, fprintf, env1);
-#endif
-            return;
-        }
-    }
-
-    // All entries are valid, try replacing unlocked entry
-
-    for (replace_used = 0; replace_used < 2; ++replace_used) {
-
-        // Used entries are not replaced on first pass
-
-        for (i = 0; i < 64; i++) {
-            if (!TTE_IS_LOCKED(tlb[i].tte) && !TTE_IS_USED(tlb[i].tte)) {
-
-                replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1);
-#ifdef DEBUG_MMU
-                DPRINTF_MMU("%s lru replaced unlocked %s entry [%i]\n",
-                            strmmu, (replace_used?"used":"unused"), i);
-                dump_mmu(stdout, fprintf, env1);
-#endif
-                return;
-            }
-        }
-
-        // Now reset used bit and search for unused entries again
-
-        for (i = 0; i < 64; i++) {
-            TTE_SET_UNUSED(tlb[i].tte);
-        }
-    }
-
-#ifdef DEBUG_MMU
-    DPRINTF_MMU("%s lru replacement failed: no entries available\n", strmmu);
-#endif
-    // error state?
-}
-
-#endif
-
-static inline target_ulong address_mask(CPUState *env1, target_ulong addr)
-{
-#ifdef TARGET_SPARC64
-    if (AM_CHECK(env1))
-        addr &= 0xffffffffULL;
-#endif
-    return addr;
-}
-
-/* returns true if access using this ASI is to have address translated by MMU
-   otherwise access is to raw physical address */
-static inline int is_translating_asi(int asi)
-{
-#ifdef TARGET_SPARC64
-    /* Ultrasparc IIi translating asi
-       - note this list is defined by cpu implementation
-     */
-    switch (asi) {
-    case 0x04 ... 0x11:
-    case 0x16 ... 0x19:
-    case 0x1E ... 0x1F:
-    case 0x24 ... 0x2C:
-    case 0x70 ... 0x73:
-    case 0x78 ... 0x79:
-    case 0x80 ... 0xFF:
-        return 1;
-
-    default:
-        return 0;
-    }
-#else
-    /* TODO: check sparc32 bits */
-    return 0;
-#endif
-}
-
-static inline target_ulong asi_address_mask(CPUState *env1,
-                                            int asi, target_ulong addr)
-{
-    if (is_translating_asi(asi)) {
-        return address_mask(env, addr);
-    } else {
-        return addr;
-    }
-}
-
-static void raise_exception(int tt)
-{
-    env->exception_index = tt;
-    cpu_loop_exit(env);
-}
-
-void HELPER(raise_exception)(int tt)
-{
-    raise_exception(tt);
-}
-
-void helper_shutdown(void)
-{
-#if !defined(CONFIG_USER_ONLY)
-    qemu_system_shutdown_request();
-#endif
-}
-
-void helper_check_align(target_ulong addr, uint32_t align)
-{
-    if (addr & align) {
-#ifdef DEBUG_UNALIGNED
-    printf("Unaligned access to 0x" TARGET_FMT_lx " from 0x" TARGET_FMT_lx
-           "\n", addr, env->pc);
-#endif
-        raise_exception(TT_UNALIGNED);
-    }
-}
-
-#define F_HELPER(name, p) void helper_f##name##p(void)
-
-#define F_BINOP(name)                                           \
-    float32 helper_f ## name ## s (float32 src1, float32 src2)  \
-    {                                                           \
-        return float32_ ## name (src1, src2, &env->fp_status);  \
-    }                                                           \
-    F_HELPER(name, d)                                           \
-    {                                                           \
-        DT0 = float64_ ## name (DT0, DT1, &env->fp_status);     \
-    }                                                           \
-    F_HELPER(name, q)                                           \
-    {                                                           \
-        QT0 = float128_ ## name (QT0, QT1, &env->fp_status);    \
-    }
-
-F_BINOP(add);
-F_BINOP(sub);
-F_BINOP(mul);
-F_BINOP(div);
-#undef F_BINOP
-
-void helper_fsmuld(float32 src1, float32 src2)
-{
-    DT0 = float64_mul(float32_to_float64(src1, &env->fp_status),
-                      float32_to_float64(src2, &env->fp_status),
-                      &env->fp_status);
-}
-
-void helper_fdmulq(void)
-{
-    QT0 = float128_mul(float64_to_float128(DT0, &env->fp_status),
-                       float64_to_float128(DT1, &env->fp_status),
-                       &env->fp_status);
-}
-
-float32 helper_fnegs(float32 src)
-{
-    return float32_chs(src);
-}
-
-#ifdef TARGET_SPARC64
-F_HELPER(neg, d)
-{
-    DT0 = float64_chs(DT1);
-}
-
-F_HELPER(neg, q)
-{
-    QT0 = float128_chs(QT1);
-}
-#endif
-
-/* Integer to float conversion.  */
-float32 helper_fitos(int32_t src)
-{
-    return int32_to_float32(src, &env->fp_status);
-}
-
-void helper_fitod(int32_t src)
-{
-    DT0 = int32_to_float64(src, &env->fp_status);
-}
-
-void helper_fitoq(int32_t src)
-{
-    QT0 = int32_to_float128(src, &env->fp_status);
-}
-
-#ifdef TARGET_SPARC64
-float32 helper_fxtos(void)
-{
-    return int64_to_float32(*((int64_t *)&DT1), &env->fp_status);
-}
-
-F_HELPER(xto, d)
-{
-    DT0 = int64_to_float64(*((int64_t *)&DT1), &env->fp_status);
-}
-
-F_HELPER(xto, q)
-{
-    QT0 = int64_to_float128(*((int64_t *)&DT1), &env->fp_status);
-}
-#endif
-#undef F_HELPER
-
-/* floating point conversion */
-float32 helper_fdtos(void)
-{
-    return float64_to_float32(DT1, &env->fp_status);
-}
-
-void helper_fstod(float32 src)
-{
-    DT0 = float32_to_float64(src, &env->fp_status);
-}
-
-float32 helper_fqtos(void)
-{
-    return float128_to_float32(QT1, &env->fp_status);
-}
-
-void helper_fstoq(float32 src)
-{
-    QT0 = float32_to_float128(src, &env->fp_status);
-}
-
-void helper_fqtod(void)
-{
-    DT0 = float128_to_float64(QT1, &env->fp_status);
-}
-
-void helper_fdtoq(void)
-{
-    QT0 = float64_to_float128(DT1, &env->fp_status);
-}
-
-/* Float to integer conversion.  */
-int32_t helper_fstoi(float32 src)
-{
-    return float32_to_int32_round_to_zero(src, &env->fp_status);
-}
-
-int32_t helper_fdtoi(void)
-{
-    return float64_to_int32_round_to_zero(DT1, &env->fp_status);
-}
-
-int32_t helper_fqtoi(void)
-{
-    return float128_to_int32_round_to_zero(QT1, &env->fp_status);
-}
-
-#ifdef TARGET_SPARC64
-void helper_fstox(float32 src)
-{
-    *((int64_t *)&DT0) = float32_to_int64_round_to_zero(src, &env->fp_status);
-}
-
-void helper_fdtox(void)
-{
-    *((int64_t *)&DT0) = float64_to_int64_round_to_zero(DT1, &env->fp_status);
-}
-
-void helper_fqtox(void)
-{
-    *((int64_t *)&DT0) = float128_to_int64_round_to_zero(QT1, &env->fp_status);
-}
-
-void helper_faligndata(void)
-{
-    uint64_t tmp;
-
-    tmp = (*((uint64_t *)&DT0)) << ((env->gsr & 7) * 8);
-    /* on many architectures a shift of 64 does nothing */
-    if ((env->gsr & 7) != 0) {
-        tmp |= (*((uint64_t *)&DT1)) >> (64 - (env->gsr & 7) * 8);
-    }
-    *((uint64_t *)&DT0) = tmp;
-}
-
-#ifdef HOST_WORDS_BIGENDIAN
-#define VIS_B64(n) b[7 - (n)]
-#define VIS_W64(n) w[3 - (n)]
-#define VIS_SW64(n) sw[3 - (n)]
-#define VIS_L64(n) l[1 - (n)]
-#define VIS_B32(n) b[3 - (n)]
-#define VIS_W32(n) w[1 - (n)]
-#else
-#define VIS_B64(n) b[n]
-#define VIS_W64(n) w[n]
-#define VIS_SW64(n) sw[n]
-#define VIS_L64(n) l[n]
-#define VIS_B32(n) b[n]
-#define VIS_W32(n) w[n]
-#endif
-
-typedef union {
-    uint8_t b[8];
-    uint16_t w[4];
-    int16_t sw[4];
-    uint32_t l[2];
-    uint64_t ll;
-    float64 d;
-} vis64;
-
-typedef union {
-    uint8_t b[4];
-    uint16_t w[2];
-    uint32_t l;
-    float32 f;
-} vis32;
-
-void helper_fpmerge(void)
-{
-    vis64 s, d;
-
-    s.d = DT0;
-    d.d = DT1;
-
-    // Reverse calculation order to handle overlap
-    d.VIS_B64(7) = s.VIS_B64(3);
-    d.VIS_B64(6) = d.VIS_B64(3);
-    d.VIS_B64(5) = s.VIS_B64(2);
-    d.VIS_B64(4) = d.VIS_B64(2);
-    d.VIS_B64(3) = s.VIS_B64(1);
-    d.VIS_B64(2) = d.VIS_B64(1);
-    d.VIS_B64(1) = s.VIS_B64(0);
-    //d.VIS_B64(0) = d.VIS_B64(0);
-
-    DT0 = d.d;
-}
-
-void helper_fmul8x16(void)
-{
-    vis64 s, d;
-    uint32_t tmp;
-
-    s.d = DT0;
-    d.d = DT1;
-
-#define PMUL(r)                                                 \
-    tmp = (int32_t)d.VIS_SW64(r) * (int32_t)s.VIS_B64(r);       \
-    if ((tmp & 0xff) > 0x7f)                                    \
-        tmp += 0x100;                                           \
-    d.VIS_W64(r) = tmp >> 8;
-
-    PMUL(0);
-    PMUL(1);
-    PMUL(2);
-    PMUL(3);
-#undef PMUL
-
-    DT0 = d.d;
-}
-
-void helper_fmul8x16al(void)
-{
-    vis64 s, d;
-    uint32_t tmp;
-
-    s.d = DT0;
-    d.d = DT1;
-
-#define PMUL(r)                                                 \
-    tmp = (int32_t)d.VIS_SW64(1) * (int32_t)s.VIS_B64(r);       \
-    if ((tmp & 0xff) > 0x7f)                                    \
-        tmp += 0x100;                                           \
-    d.VIS_W64(r) = tmp >> 8;
-
-    PMUL(0);
-    PMUL(1);
-    PMUL(2);
-    PMUL(3);
-#undef PMUL
-
-    DT0 = d.d;
-}
-
-void helper_fmul8x16au(void)
-{
-    vis64 s, d;
-    uint32_t tmp;
-
-    s.d = DT0;
-    d.d = DT1;
-
-#define PMUL(r)                                                 \
-    tmp = (int32_t)d.VIS_SW64(0) * (int32_t)s.VIS_B64(r);       \
-    if ((tmp & 0xff) > 0x7f)                                    \
-        tmp += 0x100;                                           \
-    d.VIS_W64(r) = tmp >> 8;
-
-    PMUL(0);
-    PMUL(1);
-    PMUL(2);
-    PMUL(3);
-#undef PMUL
-
-    DT0 = d.d;
-}
-
-void helper_fmul8sux16(void)
-{
-    vis64 s, d;
-    uint32_t tmp;
-
-    s.d = DT0;
-    d.d = DT1;
-
-#define PMUL(r)                                                         \
-    tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8);       \
-    if ((tmp & 0xff) > 0x7f)                                            \
-        tmp += 0x100;                                                   \
-    d.VIS_W64(r) = tmp >> 8;
-
-    PMUL(0);
-    PMUL(1);
-    PMUL(2);
-    PMUL(3);
-#undef PMUL
-
-    DT0 = d.d;
-}
-
-void helper_fmul8ulx16(void)
-{
-    vis64 s, d;
-    uint32_t tmp;
-
-    s.d = DT0;
-    d.d = DT1;
-
-#define PMUL(r)                                                         \
-    tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2));        \
-    if ((tmp & 0xff) > 0x7f)                                            \
-        tmp += 0x100;                                                   \
-    d.VIS_W64(r) = tmp >> 8;
-
-    PMUL(0);
-    PMUL(1);
-    PMUL(2);
-    PMUL(3);
-#undef PMUL
-
-    DT0 = d.d;
-}
-
-void helper_fmuld8sux16(void)
-{
-    vis64 s, d;
-    uint32_t tmp;
-
-    s.d = DT0;
-    d.d = DT1;
-
-#define PMUL(r)                                                         \
-    tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8);       \
-    if ((tmp & 0xff) > 0x7f)                                            \
-        tmp += 0x100;                                                   \
-    d.VIS_L64(r) = tmp;
-
-    // Reverse calculation order to handle overlap
-    PMUL(1);
-    PMUL(0);
-#undef PMUL
-
-    DT0 = d.d;
-}
-
-void helper_fmuld8ulx16(void)
-{
-    vis64 s, d;
-    uint32_t tmp;
-
-    s.d = DT0;
-    d.d = DT1;
-
-#define PMUL(r)                                                         \
-    tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2));        \
-    if ((tmp & 0xff) > 0x7f)                                            \
-        tmp += 0x100;                                                   \
-    d.VIS_L64(r) = tmp;
-
-    // Reverse calculation order to handle overlap
-    PMUL(1);
-    PMUL(0);
-#undef PMUL
-
-    DT0 = d.d;
-}
-
-void helper_fexpand(void)
-{
-    vis32 s;
-    vis64 d;
-
-    s.l = (uint32_t)(*(uint64_t *)&DT0 & 0xffffffff);
-    d.d = DT1;
-    d.VIS_W64(0) = s.VIS_B32(0) << 4;
-    d.VIS_W64(1) = s.VIS_B32(1) << 4;
-    d.VIS_W64(2) = s.VIS_B32(2) << 4;
-    d.VIS_W64(3) = s.VIS_B32(3) << 4;
-
-    DT0 = d.d;
-}
-
-#define VIS_HELPER(name, F)                             \
-    void name##16(void)                                 \
-    {                                                   \
-        vis64 s, d;                                     \
-                                                        \
-        s.d = DT0;                                      \
-        d.d = DT1;                                      \
-                                                        \
-        d.VIS_W64(0) = F(d.VIS_W64(0), s.VIS_W64(0));   \
-        d.VIS_W64(1) = F(d.VIS_W64(1), s.VIS_W64(1));   \
-        d.VIS_W64(2) = F(d.VIS_W64(2), s.VIS_W64(2));   \
-        d.VIS_W64(3) = F(d.VIS_W64(3), s.VIS_W64(3));   \
-                                                        \
-        DT0 = d.d;                                      \
-    }                                                   \
-                                                        \
-    uint32_t name##16s(uint32_t src1, uint32_t src2)    \
-    {                                                   \
-        vis32 s, d;                                     \
-                                                        \
-        s.l = src1;                                     \
-        d.l = src2;                                     \
-                                                        \
-        d.VIS_W32(0) = F(d.VIS_W32(0), s.VIS_W32(0));   \
-        d.VIS_W32(1) = F(d.VIS_W32(1), s.VIS_W32(1));   \
-                                                        \
-        return d.l;                                     \
-    }                                                   \
-                                                        \
-    void name##32(void)                                 \
-    {                                                   \
-        vis64 s, d;                                     \
-                                                        \
-        s.d = DT0;                                      \
-        d.d = DT1;                                      \
-                                                        \
-        d.VIS_L64(0) = F(d.VIS_L64(0), s.VIS_L64(0));   \
-        d.VIS_L64(1) = F(d.VIS_L64(1), s.VIS_L64(1));   \
-                                                        \
-        DT0 = d.d;                                      \
-    }                                                   \
-                                                        \
-    uint32_t name##32s(uint32_t src1, uint32_t src2)    \
-    {                                                   \
-        vis32 s, d;                                     \
-                                                        \
-        s.l = src1;                                     \
-        d.l = src2;                                     \
-                                                        \
-        d.l = F(d.l, s.l);                              \
-                                                        \
-        return d.l;                                     \
-    }
-
-#define FADD(a, b) ((a) + (b))
-#define FSUB(a, b) ((a) - (b))
-VIS_HELPER(helper_fpadd, FADD)
-VIS_HELPER(helper_fpsub, FSUB)
-
-#define VIS_CMPHELPER(name, F)                                        \
-    uint64_t name##16(void)                                       \
-    {                                                             \
-        vis64 s, d;                                               \
-                                                                  \
-        s.d = DT0;                                                \
-        d.d = DT1;                                                \
-                                                                  \
-        d.VIS_W64(0) = F(s.VIS_W64(0), d.VIS_W64(0)) ? 1 : 0;     \
-        d.VIS_W64(0) |= F(s.VIS_W64(1), d.VIS_W64(1)) ? 2 : 0;    \
-        d.VIS_W64(0) |= F(s.VIS_W64(2), d.VIS_W64(2)) ? 4 : 0;    \
-        d.VIS_W64(0) |= F(s.VIS_W64(3), d.VIS_W64(3)) ? 8 : 0;    \
-        d.VIS_W64(1) = d.VIS_W64(2) = d.VIS_W64(3) = 0;           \
-                                                                  \
-        return d.ll;                                              \
-    }                                                             \
-                                                                  \
-    uint64_t name##32(void)                                       \
-    {                                                             \
-        vis64 s, d;                                               \
-                                                                  \
-        s.d = DT0;                                                \
-        d.d = DT1;                                                \
-                                                                  \
-        d.VIS_L64(0) = F(s.VIS_L64(0), d.VIS_L64(0)) ? 1 : 0;     \
-        d.VIS_L64(0) |= F(s.VIS_L64(1), d.VIS_L64(1)) ? 2 : 0;    \
-        d.VIS_L64(1) = 0;                                         \
-                                                                  \
-        return d.ll;                                              \
-    }
-
-#define FCMPGT(a, b) ((a) > (b))
-#define FCMPEQ(a, b) ((a) == (b))
-#define FCMPLE(a, b) ((a) <= (b))
-#define FCMPNE(a, b) ((a) != (b))
-
-VIS_CMPHELPER(helper_fcmpgt, FCMPGT)
-VIS_CMPHELPER(helper_fcmpeq, FCMPEQ)
-VIS_CMPHELPER(helper_fcmple, FCMPLE)
-VIS_CMPHELPER(helper_fcmpne, FCMPNE)
-#endif
-
-void helper_check_ieee_exceptions(void)
-{
-    target_ulong status;
-
-    status = get_float_exception_flags(&env->fp_status);
-    if (status) {
-        /* Copy IEEE 754 flags into FSR */
-        if (status & float_flag_invalid)
-            env->fsr |= FSR_NVC;
-        if (status & float_flag_overflow)
-            env->fsr |= FSR_OFC;
-        if (status & float_flag_underflow)
-            env->fsr |= FSR_UFC;
-        if (status & float_flag_divbyzero)
-            env->fsr |= FSR_DZC;
-        if (status & float_flag_inexact)
-            env->fsr |= FSR_NXC;
-
-        if ((env->fsr & FSR_CEXC_MASK) & ((env->fsr & FSR_TEM_MASK) >> 23)) {
-            /* Unmasked exception, generate a trap */
-            env->fsr |= FSR_FTT_IEEE_EXCP;
-            raise_exception(TT_FP_EXCP);
-        } else {
-            /* Accumulate exceptions */
-            env->fsr |= (env->fsr & FSR_CEXC_MASK) << 5;
-        }
-    }
-}
-
-void helper_clear_float_exceptions(void)
-{
-    set_float_exception_flags(0, &env->fp_status);
-}
-
-float32 helper_fabss(float32 src)
-{
-    return float32_abs(src);
-}
-
-#ifdef TARGET_SPARC64
-void helper_fabsd(void)
-{
-    DT0 = float64_abs(DT1);
-}
-
-void helper_fabsq(void)
-{
-    QT0 = float128_abs(QT1);
-}
-#endif
-
-float32 helper_fsqrts(float32 src)
-{
-    return float32_sqrt(src, &env->fp_status);
-}
-
-void helper_fsqrtd(void)
-{
-    DT0 = float64_sqrt(DT1, &env->fp_status);
-}
-
-void helper_fsqrtq(void)
-{
-    QT0 = float128_sqrt(QT1, &env->fp_status);
-}
-
-#define GEN_FCMP(name, size, reg1, reg2, FS, E)                         \
-    void glue(helper_, name) (void)                                     \
-    {                                                                   \
-        env->fsr &= FSR_FTT_NMASK;                                      \
-        if (E && (glue(size, _is_any_nan)(reg1) ||                      \
-                     glue(size, _is_any_nan)(reg2)) &&                  \
-            (env->fsr & FSR_NVM)) {                                     \
-            env->fsr |= FSR_NVC;                                        \
-            env->fsr |= FSR_FTT_IEEE_EXCP;                              \
-            raise_exception(TT_FP_EXCP);                                \
-        }                                                               \
-        switch (glue(size, _compare) (reg1, reg2, &env->fp_status)) {   \
-        case float_relation_unordered:                                  \
-            if ((env->fsr & FSR_NVM)) {                                 \
-                env->fsr |= FSR_NVC;                                    \
-                env->fsr |= FSR_FTT_IEEE_EXCP;                          \
-                raise_exception(TT_FP_EXCP);                            \
-            } else {                                                    \
-                env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);             \
-                env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS;                \
-                env->fsr |= FSR_NVA;                                    \
-            }                                                           \
-            break;                                                      \
-        case float_relation_less:                                       \
-            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
-            env->fsr |= FSR_FCC0 << FS;                                 \
-            break;                                                      \
-        case float_relation_greater:                                    \
-            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
-            env->fsr |= FSR_FCC1 << FS;                                 \
-            break;                                                      \
-        default:                                                        \
-            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
-            break;                                                      \
-        }                                                               \
-    }
-#define GEN_FCMPS(name, size, FS, E)                                    \
-    void glue(helper_, name)(float32 src1, float32 src2)                \
-    {                                                                   \
-        env->fsr &= FSR_FTT_NMASK;                                      \
-        if (E && (glue(size, _is_any_nan)(src1) ||                      \
-                     glue(size, _is_any_nan)(src2)) &&                  \
-            (env->fsr & FSR_NVM)) {                                     \
-            env->fsr |= FSR_NVC;                                        \
-            env->fsr |= FSR_FTT_IEEE_EXCP;                              \
-            raise_exception(TT_FP_EXCP);                                \
-        }                                                               \
-        switch (glue(size, _compare) (src1, src2, &env->fp_status)) {   \
-        case float_relation_unordered:                                  \
-            if ((env->fsr & FSR_NVM)) {                                 \
-                env->fsr |= FSR_NVC;                                    \
-                env->fsr |= FSR_FTT_IEEE_EXCP;                          \
-                raise_exception(TT_FP_EXCP);                            \
-            } else {                                                    \
-                env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);             \
-                env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS;                \
-                env->fsr |= FSR_NVA;                                    \
-            }                                                           \
-            break;                                                      \
-        case float_relation_less:                                       \
-            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
-            env->fsr |= FSR_FCC0 << FS;                                 \
-            break;                                                      \
-        case float_relation_greater:                                    \
-            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
-            env->fsr |= FSR_FCC1 << FS;                                 \
-            break;                                                      \
-        default:                                                        \
-            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
-            break;                                                      \
-        }                                                               \
-    }
-
-GEN_FCMPS(fcmps, float32, 0, 0);
-GEN_FCMP(fcmpd, float64, DT0, DT1, 0, 0);
-
-GEN_FCMPS(fcmpes, float32, 0, 1);
-GEN_FCMP(fcmped, float64, DT0, DT1, 0, 1);
-
-GEN_FCMP(fcmpq, float128, QT0, QT1, 0, 0);
-GEN_FCMP(fcmpeq, float128, QT0, QT1, 0, 1);
-
-static uint32_t compute_all_flags(void)
-{
-    return env->psr & PSR_ICC;
-}
-
-static uint32_t compute_C_flags(void)
-{
-    return env->psr & PSR_CARRY;
-}
-
-static inline uint32_t get_NZ_icc(int32_t dst)
-{
-    uint32_t ret = 0;
-
-    if (dst == 0) {
-        ret = PSR_ZERO;
-    } else if (dst < 0) {
-        ret = PSR_NEG;
-    }
-    return ret;
-}
-
-#ifdef TARGET_SPARC64
-static uint32_t compute_all_flags_xcc(void)
-{
-    return env->xcc & PSR_ICC;
-}
-
-static uint32_t compute_C_flags_xcc(void)
-{
-    return env->xcc & PSR_CARRY;
-}
-
-static inline uint32_t get_NZ_xcc(target_long dst)
-{
-    uint32_t ret = 0;
-
-    if (!dst) {
-        ret = PSR_ZERO;
-    } else if (dst < 0) {
-        ret = PSR_NEG;
-    }
-    return ret;
-}
-#endif
-
-static inline uint32_t get_V_div_icc(target_ulong src2)
-{
-    uint32_t ret = 0;
-
-    if (src2 != 0) {
-        ret = PSR_OVF;
-    }
-    return ret;
-}
-
-static uint32_t compute_all_div(void)
-{
-    uint32_t ret;
-
-    ret = get_NZ_icc(CC_DST);
-    ret |= get_V_div_icc(CC_SRC2);
-    return ret;
-}
-
-static uint32_t compute_C_div(void)
-{
-    return 0;
-}
-
-static inline uint32_t get_C_add_icc(uint32_t dst, uint32_t src1)
-{
-    uint32_t ret = 0;
-
-    if (dst < src1) {
-        ret = PSR_CARRY;
-    }
-    return ret;
-}
-
-static inline uint32_t get_C_addx_icc(uint32_t dst, uint32_t src1,
-                                      uint32_t src2)
-{
-    uint32_t ret = 0;
-
-    if (((src1 & src2) | (~dst & (src1 | src2))) & (1U << 31)) {
-        ret = PSR_CARRY;
-    }
-    return ret;
-}
-
-static inline uint32_t get_V_add_icc(uint32_t dst, uint32_t src1,
-                                     uint32_t src2)
-{
-    uint32_t ret = 0;
-
-    if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1U << 31)) {
-        ret = PSR_OVF;
-    }
-    return ret;
-}
-
-#ifdef TARGET_SPARC64
-static inline uint32_t get_C_add_xcc(target_ulong dst, target_ulong src1)
-{
-    uint32_t ret = 0;
-
-    if (dst < src1) {
-        ret = PSR_CARRY;
-    }
-    return ret;
-}
-
-static inline uint32_t get_C_addx_xcc(target_ulong dst, target_ulong src1,
-                                      target_ulong src2)
-{
-    uint32_t ret = 0;
-
-    if (((src1 & src2) | (~dst & (src1 | src2))) & (1ULL << 63)) {
-        ret = PSR_CARRY;
-    }
-    return ret;
-}
-
-static inline uint32_t get_V_add_xcc(target_ulong dst, target_ulong src1,
-                                         target_ulong src2)
-{
-    uint32_t ret = 0;
-
-    if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1ULL << 63)) {
-        ret = PSR_OVF;
-    }
-    return ret;
-}
-
-static uint32_t compute_all_add_xcc(void)
-{
-    uint32_t ret;
-
-    ret = get_NZ_xcc(CC_DST);
-    ret |= get_C_add_xcc(CC_DST, CC_SRC);
-    ret |= get_V_add_xcc(CC_DST, CC_SRC, CC_SRC2);
-    return ret;
-}
-
-static uint32_t compute_C_add_xcc(void)
-{
-    return get_C_add_xcc(CC_DST, CC_SRC);
-}
-#endif
-
-static uint32_t compute_all_add(void)
-{
-    uint32_t ret;
-
-    ret = get_NZ_icc(CC_DST);
-    ret |= get_C_add_icc(CC_DST, CC_SRC);
-    ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
-    return ret;
-}
-
-static uint32_t compute_C_add(void)
-{
-    return get_C_add_icc(CC_DST, CC_SRC);
-}
-
-#ifdef TARGET_SPARC64
-static uint32_t compute_all_addx_xcc(void)
-{
-    uint32_t ret;
-
-    ret = get_NZ_xcc(CC_DST);
-    ret |= get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2);
-    ret |= get_V_add_xcc(CC_DST, CC_SRC, CC_SRC2);
-    return ret;
-}
-
-static uint32_t compute_C_addx_xcc(void)
-{
-    uint32_t ret;
-
-    ret = get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2);
-    return ret;
-}
-#endif
-
-static uint32_t compute_all_addx(void)
-{
-    uint32_t ret;
-
-    ret = get_NZ_icc(CC_DST);
-    ret |= get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2);
-    ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
-    return ret;
-}
-
-static uint32_t compute_C_addx(void)
-{
-    uint32_t ret;
-
-    ret = get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2);
-    return ret;
-}
-
-static inline uint32_t get_V_tag_icc(target_ulong src1, target_ulong src2)
-{
-    uint32_t ret = 0;
-
-    if ((src1 | src2) & 0x3) {
-        ret = PSR_OVF;
-    }
-    return ret;
-}
-
-static uint32_t compute_all_tadd(void)
-{
-    uint32_t ret;
-
-    ret = get_NZ_icc(CC_DST);
-    ret |= get_C_add_icc(CC_DST, CC_SRC);
-    ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
-    ret |= get_V_tag_icc(CC_SRC, CC_SRC2);
-    return ret;
-}
-
-static uint32_t compute_all_taddtv(void)
-{
-    uint32_t ret;
-
-    ret = get_NZ_icc(CC_DST);
-    ret |= get_C_add_icc(CC_DST, CC_SRC);
-    return ret;
-}
-
-static inline uint32_t get_C_sub_icc(uint32_t src1, uint32_t src2)
-{
-    uint32_t ret = 0;
-
-    if (src1 < src2) {
-        ret = PSR_CARRY;
-    }
-    return ret;
-}
-
-static inline uint32_t get_C_subx_icc(uint32_t dst, uint32_t src1,
-                                      uint32_t src2)
-{
-    uint32_t ret = 0;
-
-    if (((~src1 & src2) | (dst & (~src1 | src2))) & (1U << 31)) {
-        ret = PSR_CARRY;
-    }
-    return ret;
-}
-
-static inline uint32_t get_V_sub_icc(uint32_t dst, uint32_t src1,
-                                     uint32_t src2)
-{
-    uint32_t ret = 0;
-
-    if (((src1 ^ src2) & (src1 ^ dst)) & (1U << 31)) {
-        ret = PSR_OVF;
-    }
-    return ret;
-}
-
-
-#ifdef TARGET_SPARC64
-static inline uint32_t get_C_sub_xcc(target_ulong src1, target_ulong src2)
-{
-    uint32_t ret = 0;
-
-    if (src1 < src2) {
-        ret = PSR_CARRY;
-    }
-    return ret;
-}
-
-static inline uint32_t get_C_subx_xcc(target_ulong dst, target_ulong src1,
-                                      target_ulong src2)
-{
-    uint32_t ret = 0;
-
-    if (((~src1 & src2) | (dst & (~src1 | src2))) & (1ULL << 63)) {
-        ret = PSR_CARRY;
-    }
-    return ret;
-}
-
-static inline uint32_t get_V_sub_xcc(target_ulong dst, target_ulong src1,
-                                     target_ulong src2)
-{
-    uint32_t ret = 0;
-
-    if (((src1 ^ src2) & (src1 ^ dst)) & (1ULL << 63)) {
-        ret = PSR_OVF;
-    }
-    return ret;
-}
-
-static uint32_t compute_all_sub_xcc(void)
-{
-    uint32_t ret;
-
-    ret = get_NZ_xcc(CC_DST);
-    ret |= get_C_sub_xcc(CC_SRC, CC_SRC2);
-    ret |= get_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2);
-    return ret;
-}
-
-static uint32_t compute_C_sub_xcc(void)
-{
-    return get_C_sub_xcc(CC_SRC, CC_SRC2);
-}
-#endif
-
-static uint32_t compute_all_sub(void)
-{
-    uint32_t ret;
-
-    ret = get_NZ_icc(CC_DST);
-    ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
-    ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
-    return ret;
-}
-
-static uint32_t compute_C_sub(void)
-{
-    return get_C_sub_icc(CC_SRC, CC_SRC2);
-}
-
-#ifdef TARGET_SPARC64
-static uint32_t compute_all_subx_xcc(void)
-{
-    uint32_t ret;
-
-    ret = get_NZ_xcc(CC_DST);
-    ret |= get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2);
-    ret |= get_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2);
-    return ret;
-}
-
-static uint32_t compute_C_subx_xcc(void)
-{
-    uint32_t ret;
-
-    ret = get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2);
-    return ret;
-}
-#endif
-
-static uint32_t compute_all_subx(void)
-{
-    uint32_t ret;
-
-    ret = get_NZ_icc(CC_DST);
-    ret |= get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2);
-    ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
-    return ret;
-}
-
-static uint32_t compute_C_subx(void)
-{
-    uint32_t ret;
-
-    ret = get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2);
-    return ret;
-}
-
-static uint32_t compute_all_tsub(void)
-{
-    uint32_t ret;
-
-    ret = get_NZ_icc(CC_DST);
-    ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
-    ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
-    ret |= get_V_tag_icc(CC_SRC, CC_SRC2);
-    return ret;
-}
-
-static uint32_t compute_all_tsubtv(void)
-{
-    uint32_t ret;
-
-    ret = get_NZ_icc(CC_DST);
-    ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
-    return ret;
-}
-
-static uint32_t compute_all_logic(void)
-{
-    return get_NZ_icc(CC_DST);
-}
-
-static uint32_t compute_C_logic(void)
-{
-    return 0;
-}
-
-#ifdef TARGET_SPARC64
-static uint32_t compute_all_logic_xcc(void)
-{
-    return get_NZ_xcc(CC_DST);
-}
-#endif
-
-typedef struct CCTable {
-    uint32_t (*compute_all)(void); /* return all the flags */
-    uint32_t (*compute_c)(void);  /* return the C flag */
-} CCTable;
-
-static const CCTable icc_table[CC_OP_NB] = {
-    /* CC_OP_DYNAMIC should never happen */
-    [CC_OP_FLAGS] = { compute_all_flags, compute_C_flags },
-    [CC_OP_DIV] = { compute_all_div, compute_C_div },
-    [CC_OP_ADD] = { compute_all_add, compute_C_add },
-    [CC_OP_ADDX] = { compute_all_addx, compute_C_addx },
-    [CC_OP_TADD] = { compute_all_tadd, compute_C_add },
-    [CC_OP_TADDTV] = { compute_all_taddtv, compute_C_add },
-    [CC_OP_SUB] = { compute_all_sub, compute_C_sub },
-    [CC_OP_SUBX] = { compute_all_subx, compute_C_subx },
-    [CC_OP_TSUB] = { compute_all_tsub, compute_C_sub },
-    [CC_OP_TSUBTV] = { compute_all_tsubtv, compute_C_sub },
-    [CC_OP_LOGIC] = { compute_all_logic, compute_C_logic },
-};
-
-#ifdef TARGET_SPARC64
-static const CCTable xcc_table[CC_OP_NB] = {
-    /* CC_OP_DYNAMIC should never happen */
-    [CC_OP_FLAGS] = { compute_all_flags_xcc, compute_C_flags_xcc },
-    [CC_OP_DIV] = { compute_all_logic_xcc, compute_C_logic },
-    [CC_OP_ADD] = { compute_all_add_xcc, compute_C_add_xcc },
-    [CC_OP_ADDX] = { compute_all_addx_xcc, compute_C_addx_xcc },
-    [CC_OP_TADD] = { compute_all_add_xcc, compute_C_add_xcc },
-    [CC_OP_TADDTV] = { compute_all_add_xcc, compute_C_add_xcc },
-    [CC_OP_SUB] = { compute_all_sub_xcc, compute_C_sub_xcc },
-    [CC_OP_SUBX] = { compute_all_subx_xcc, compute_C_subx_xcc },
-    [CC_OP_TSUB] = { compute_all_sub_xcc, compute_C_sub_xcc },
-    [CC_OP_TSUBTV] = { compute_all_sub_xcc, compute_C_sub_xcc },
-    [CC_OP_LOGIC] = { compute_all_logic_xcc, compute_C_logic },
-};
-#endif
-
-void helper_compute_psr(void)
-{
-    uint32_t new_psr;
-
-    new_psr = icc_table[CC_OP].compute_all();
-    env->psr = new_psr;
-#ifdef TARGET_SPARC64
-    new_psr = xcc_table[CC_OP].compute_all();
-    env->xcc = new_psr;
-#endif
-    CC_OP = CC_OP_FLAGS;
-}
-
-uint32_t helper_compute_C_icc(void)
-{
-    uint32_t ret;
-
-    ret = icc_table[CC_OP].compute_c() >> PSR_CARRY_SHIFT;
-    return ret;
-}
-
-static inline void memcpy32(target_ulong *dst, const target_ulong *src)
-{
-    dst[0] = src[0];
-    dst[1] = src[1];
-    dst[2] = src[2];
-    dst[3] = src[3];
-    dst[4] = src[4];
-    dst[5] = src[5];
-    dst[6] = src[6];
-    dst[7] = src[7];
-}
-
-static void set_cwp(int new_cwp)
-{
-    /* put the modified wrap registers at their proper location */
-    if (env->cwp == env->nwindows - 1) {
-        memcpy32(env->regbase, env->regbase + env->nwindows * 16);
-    }
-    env->cwp = new_cwp;
-
-    /* put the wrap registers at their temporary location */
-    if (new_cwp == env->nwindows - 1) {
-        memcpy32(env->regbase + env->nwindows * 16, env->regbase);
-    }
-    env->regwptr = env->regbase + (new_cwp * 16);
-}
-
-void cpu_set_cwp(CPUState *env1, int new_cwp)
-{
-    CPUState *saved_env;
-
-    saved_env = env;
-    env = env1;
-    set_cwp(new_cwp);
-    env = saved_env;
-}
-
-static target_ulong get_psr(void)
-{
-    helper_compute_psr();
-
-#if !defined (TARGET_SPARC64)
-    return env->version | (env->psr & PSR_ICC) |
-        (env->psref? PSR_EF : 0) |
-        (env->psrpil << 8) |
-        (env->psrs? PSR_S : 0) |
-        (env->psrps? PSR_PS : 0) |
-        (env->psret? PSR_ET : 0) | env->cwp;
-#else
-    return env->psr & PSR_ICC;
-#endif
-}
-
-target_ulong cpu_get_psr(CPUState *env1)
-{
-    CPUState *saved_env;
-    target_ulong ret;
-
-    saved_env = env;
-    env = env1;
-    ret = get_psr();
-    env = saved_env;
-    return ret;
-}
-
-static void put_psr(target_ulong val)
-{
-    env->psr = val & PSR_ICC;
-#if !defined (TARGET_SPARC64)
-    env->psref = (val & PSR_EF)? 1 : 0;
-    env->psrpil = (val & PSR_PIL) >> 8;
-#endif
-#if ((!defined (TARGET_SPARC64)) && !defined(CONFIG_USER_ONLY))
-    cpu_check_irqs(env);
-#endif
-#if !defined (TARGET_SPARC64)
-    env->psrs = (val & PSR_S)? 1 : 0;
-    env->psrps = (val & PSR_PS)? 1 : 0;
-    env->psret = (val & PSR_ET)? 1 : 0;
-    set_cwp(val & PSR_CWP);
-#endif
-    env->cc_op = CC_OP_FLAGS;
-}
-
-void cpu_put_psr(CPUState *env1, target_ulong val)
-{
-    CPUState *saved_env;
-
-    saved_env = env;
-    env = env1;
-    put_psr(val);
-    env = saved_env;
-}
-
-static int cwp_inc(int cwp)
-{
-    if (unlikely(cwp >= env->nwindows)) {
-        cwp -= env->nwindows;
-    }
-    return cwp;
-}
-
-int cpu_cwp_inc(CPUState *env1, int cwp)
-{
-    CPUState *saved_env;
-    target_ulong ret;
-
-    saved_env = env;
-    env = env1;
-    ret = cwp_inc(cwp);
-    env = saved_env;
-    return ret;
-}
-
-static int cwp_dec(int cwp)
-{
-    if (unlikely(cwp < 0)) {
-        cwp += env->nwindows;
-    }
-    return cwp;
-}
-
-int cpu_cwp_dec(CPUState *env1, int cwp)
-{
-    CPUState *saved_env;
-    target_ulong ret;
-
-    saved_env = env;
-    env = env1;
-    ret = cwp_dec(cwp);
-    env = saved_env;
-    return ret;
-}
-
-#ifdef TARGET_SPARC64
-GEN_FCMPS(fcmps_fcc1, float32, 22, 0);
-GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22, 0);
-GEN_FCMP(fcmpq_fcc1, float128, QT0, QT1, 22, 0);
-
-GEN_FCMPS(fcmps_fcc2, float32, 24, 0);
-GEN_FCMP(fcmpd_fcc2, float64, DT0, DT1, 24, 0);
-GEN_FCMP(fcmpq_fcc2, float128, QT0, QT1, 24, 0);
-
-GEN_FCMPS(fcmps_fcc3, float32, 26, 0);
-GEN_FCMP(fcmpd_fcc3, float64, DT0, DT1, 26, 0);
-GEN_FCMP(fcmpq_fcc3, float128, QT0, QT1, 26, 0);
-
-GEN_FCMPS(fcmpes_fcc1, float32, 22, 1);
-GEN_FCMP(fcmped_fcc1, float64, DT0, DT1, 22, 1);
-GEN_FCMP(fcmpeq_fcc1, float128, QT0, QT1, 22, 1);
-
-GEN_FCMPS(fcmpes_fcc2, float32, 24, 1);
-GEN_FCMP(fcmped_fcc2, float64, DT0, DT1, 24, 1);
-GEN_FCMP(fcmpeq_fcc2, float128, QT0, QT1, 24, 1);
-
-GEN_FCMPS(fcmpes_fcc3, float32, 26, 1);
-GEN_FCMP(fcmped_fcc3, float64, DT0, DT1, 26, 1);
-GEN_FCMP(fcmpeq_fcc3, float128, QT0, QT1, 26, 1);
-#endif
-#undef GEN_FCMPS
-
-#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) && \
-    defined(DEBUG_MXCC)
-static void dump_mxcc(CPUState *env)
-{
-    printf("mxccdata: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64
-           "\n",
-           env->mxccdata[0], env->mxccdata[1],
-           env->mxccdata[2], env->mxccdata[3]);
-    printf("mxccregs: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64
-           "\n"
-           "          %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64
-           "\n",
-           env->mxccregs[0], env->mxccregs[1],
-           env->mxccregs[2], env->mxccregs[3],
-           env->mxccregs[4], env->mxccregs[5],
-           env->mxccregs[6], env->mxccregs[7]);
-}
-#endif
-
-#if (defined(TARGET_SPARC64) || !defined(CONFIG_USER_ONLY)) \
-    && defined(DEBUG_ASI)
-static void dump_asi(const char *txt, target_ulong addr, int asi, int size,
-                     uint64_t r1)
-{
-    switch (size)
-    {
-    case 1:
-        DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %02" PRIx64 "\n", txt,
-                    addr, asi, r1 & 0xff);
-        break;
-    case 2:
-        DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %04" PRIx64 "\n", txt,
-                    addr, asi, r1 & 0xffff);
-        break;
-    case 4:
-        DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %08" PRIx64 "\n", txt,
-                    addr, asi, r1 & 0xffffffff);
-        break;
-    case 8:
-        DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %016" PRIx64 "\n", txt,
-                    addr, asi, r1);
-        break;
-    }
-}
-#endif
-
-#ifndef TARGET_SPARC64
-#ifndef CONFIG_USER_ONLY
-
-
-/* Leon3 cache control */
-
-static void leon3_cache_control_int(void)
-{
-    uint32_t state = 0;
-
-    if (env->cache_control & CACHE_CTRL_IF) {
-        /* Instruction cache state */
-        state = env->cache_control & CACHE_STATE_MASK;
-        if (state == CACHE_ENABLED) {
-            state = CACHE_FROZEN;
-            DPRINTF_CACHE_CONTROL("Instruction cache: freeze\n");
-        }
-
-        env->cache_control &= ~CACHE_STATE_MASK;
-        env->cache_control |= state;
-    }
-
-    if (env->cache_control & CACHE_CTRL_DF) {
-        /* Data cache state */
-        state = (env->cache_control >> 2) & CACHE_STATE_MASK;
-        if (state == CACHE_ENABLED) {
-            state = CACHE_FROZEN;
-            DPRINTF_CACHE_CONTROL("Data cache: freeze\n");
-        }
-
-        env->cache_control &= ~(CACHE_STATE_MASK << 2);
-        env->cache_control |= (state << 2);
-    }
-}
-
-static void leon3_cache_control_st(target_ulong addr, uint64_t val, int size)
-{
-    DPRINTF_CACHE_CONTROL("st addr:%08x, val:%" PRIx64 ", size:%d\n",
-                          addr, val, size);
-
-    if (size != 4) {
-        DPRINTF_CACHE_CONTROL("32bits only\n");
-        return;
-    }
-
-    switch (addr) {
-    case 0x00:              /* Cache control */
-
-        /* These values must always be read as zeros */
-        val &= ~CACHE_CTRL_FD;
-        val &= ~CACHE_CTRL_FI;
-        val &= ~CACHE_CTRL_IB;
-        val &= ~CACHE_CTRL_IP;
-        val &= ~CACHE_CTRL_DP;
-
-        env->cache_control = val;
-        break;
-    case 0x04:              /* Instruction cache configuration */
-    case 0x08:              /* Data cache configuration */
-        /* Read Only */
-        break;
-    default:
-        DPRINTF_CACHE_CONTROL("write unknown register %08x\n", addr);
-        break;
-    };
-}
-
-static uint64_t leon3_cache_control_ld(target_ulong addr, int size)
-{
-    uint64_t ret = 0;
-
-    if (size != 4) {
-        DPRINTF_CACHE_CONTROL("32bits only\n");
-        return 0;
-    }
-
-    switch (addr) {
-    case 0x00:              /* Cache control */
-        ret = env->cache_control;
-        break;
-
-        /* Configuration registers are read and only always keep those
-           predefined values */
-
-    case 0x04:              /* Instruction cache configuration */
-        ret = 0x10220000;
-        break;
-    case 0x08:              /* Data cache configuration */
-        ret = 0x18220000;
-        break;
-    default:
-        DPRINTF_CACHE_CONTROL("read unknown register %08x\n", addr);
-        break;
-    };
-    DPRINTF_CACHE_CONTROL("ld addr:%08x, ret:0x%" PRIx64 ", size:%d\n",
-                          addr, ret, size);
-    return ret;
-}
-
-void leon3_irq_manager(void *irq_manager, int intno)
-{
-    leon3_irq_ack(irq_manager, intno);
-    leon3_cache_control_int();
-}
-
-uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
-{
-    uint64_t ret = 0;
-#if defined(DEBUG_MXCC) || defined(DEBUG_ASI)
-    uint32_t last_addr = addr;
-#endif
-
-    helper_check_align(addr, size - 1);
-    switch (asi) {
-    case 2: /* SuperSparc MXCC registers and Leon3 cache control */
-        switch (addr) {
-        case 0x00:          /* Leon3 Cache Control */
-        case 0x08:          /* Leon3 Instruction Cache config */
-        case 0x0C:          /* Leon3 Date Cache config */
-            if (env->def->features & CPU_FEATURE_CACHE_CTRL) {
-                ret = leon3_cache_control_ld(addr, size);
-            }
-            break;
-        case 0x01c00a00: /* MXCC control register */
-            if (size == 8)
-                ret = env->mxccregs[3];
-            else
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            break;
-        case 0x01c00a04: /* MXCC control register */
-            if (size == 4)
-                ret = env->mxccregs[3];
-            else
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            break;
-        case 0x01c00c00: /* Module reset register */
-            if (size == 8) {
-                ret = env->mxccregs[5];
-                // should we do something here?
-            } else
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            break;
-        case 0x01c00f00: /* MBus port address register */
-            if (size == 8)
-                ret = env->mxccregs[7];
-            else
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            break;
-        default:
-            DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", addr,
-                         size);
-            break;
-        }
-        DPRINTF_MXCC("asi = %d, size = %d, sign = %d, "
-                     "addr = %08x -> ret = %" PRIx64 ","
-                     "addr = %08x\n", asi, size, sign, last_addr, ret, addr);
-#ifdef DEBUG_MXCC
-        dump_mxcc(env);
-#endif
-        break;
-    case 3: /* MMU probe */
-        {
-            int mmulev;
-
-            mmulev = (addr >> 8) & 15;
-            if (mmulev > 4)
-                ret = 0;
-            else
-                ret = mmu_probe(env, addr, mmulev);
-            DPRINTF_MMU("mmu_probe: 0x%08x (lev %d) -> 0x%08" PRIx64 "\n",
-                        addr, mmulev, ret);
-        }
-        break;
-    case 4: /* read MMU regs */
-        {
-            int reg = (addr >> 8) & 0x1f;
-
-            ret = env->mmuregs[reg];
-            if (reg == 3) /* Fault status cleared on read */
-                env->mmuregs[3] = 0;
-            else if (reg == 0x13) /* Fault status read */
-                ret = env->mmuregs[3];
-            else if (reg == 0x14) /* Fault address read */
-                ret = env->mmuregs[4];
-            DPRINTF_MMU("mmu_read: reg[%d] = 0x%08" PRIx64 "\n", reg, ret);
-        }
-        break;
-    case 5: // Turbosparc ITLB Diagnostic
-    case 6: // Turbosparc DTLB Diagnostic
-    case 7: // Turbosparc IOTLB Diagnostic
-        break;
-    case 9: /* Supervisor code access */
-        switch(size) {
-        case 1:
-            ret = ldub_code(addr);
-            break;
-        case 2:
-            ret = lduw_code(addr);
-            break;
-        default:
-        case 4:
-            ret = ldl_code(addr);
-            break;
-        case 8:
-            ret = ldq_code(addr);
-            break;
-        }
-        break;
-    case 0xa: /* User data access */
-        switch(size) {
-        case 1:
-            ret = ldub_user(addr);
-            break;
-        case 2:
-            ret = lduw_user(addr);
-            break;
-        default:
-        case 4:
-            ret = ldl_user(addr);
-            break;
-        case 8:
-            ret = ldq_user(addr);
-            break;
-        }
-        break;
-    case 0xb: /* Supervisor data access */
-        switch(size) {
-        case 1:
-            ret = ldub_kernel(addr);
-            break;
-        case 2:
-            ret = lduw_kernel(addr);
-            break;
-        default:
-        case 4:
-            ret = ldl_kernel(addr);
-            break;
-        case 8:
-            ret = ldq_kernel(addr);
-            break;
-        }
-        break;
-    case 0xc: /* I-cache tag */
-    case 0xd: /* I-cache data */
-    case 0xe: /* D-cache tag */
-    case 0xf: /* D-cache data */
-        break;
-    case 0x20: /* MMU passthrough */
-        switch(size) {
-        case 1:
-            ret = ldub_phys(addr);
-            break;
-        case 2:
-            ret = lduw_phys(addr);
-            break;
-        default:
-        case 4:
-            ret = ldl_phys(addr);
-            break;
-        case 8:
-            ret = ldq_phys(addr);
-            break;
-        }
-        break;
-    case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */
-        switch(size) {
-        case 1:
-            ret = ldub_phys((target_phys_addr_t)addr
-                            | ((target_phys_addr_t)(asi & 0xf) << 32));
-            break;
-        case 2:
-            ret = lduw_phys((target_phys_addr_t)addr
-                            | ((target_phys_addr_t)(asi & 0xf) << 32));
-            break;
-        default:
-        case 4:
-            ret = ldl_phys((target_phys_addr_t)addr
-                           | ((target_phys_addr_t)(asi & 0xf) << 32));
-            break;
-        case 8:
-            ret = ldq_phys((target_phys_addr_t)addr
-                           | ((target_phys_addr_t)(asi & 0xf) << 32));
-            break;
-        }
-        break;
-    case 0x30: // Turbosparc secondary cache diagnostic
-    case 0x31: // Turbosparc RAM snoop
-    case 0x32: // Turbosparc page table descriptor diagnostic
-    case 0x39: /* data cache diagnostic register */
-        ret = 0;
-        break;
-    case 0x38: /* SuperSPARC MMU Breakpoint Control Registers */
-        {
-            int reg = (addr >> 8) & 3;
-
-            switch(reg) {
-            case 0: /* Breakpoint Value (Addr) */
-                ret = env->mmubpregs[reg];
-                break;
-            case 1: /* Breakpoint Mask */
-                ret = env->mmubpregs[reg];
-                break;
-            case 2: /* Breakpoint Control */
-                ret = env->mmubpregs[reg];
-                break;
-            case 3: /* Breakpoint Status */
-                ret = env->mmubpregs[reg];
-                env->mmubpregs[reg] = 0ULL;
-                break;
-            }
-            DPRINTF_MMU("read breakpoint reg[%d] 0x%016" PRIx64 "\n", reg,
-                        ret);
-        }
-        break;
-    case 0x49: /* SuperSPARC MMU Counter Breakpoint Value */
-        ret = env->mmubpctrv;
-        break;
-    case 0x4a: /* SuperSPARC MMU Counter Breakpoint Control */
-        ret = env->mmubpctrc;
-        break;
-    case 0x4b: /* SuperSPARC MMU Counter Breakpoint Status */
-        ret = env->mmubpctrs;
-        break;
-    case 0x4c: /* SuperSPARC MMU Breakpoint Action */
-        ret = env->mmubpaction;
-        break;
-    case 8: /* User code access, XXX */
-    default:
-        do_unassigned_access(addr, 0, 0, asi, size);
-        ret = 0;
-        break;
-    }
-    if (sign) {
-        switch(size) {
-        case 1:
-            ret = (int8_t) ret;
-            break;
-        case 2:
-            ret = (int16_t) ret;
-            break;
-        case 4:
-            ret = (int32_t) ret;
-            break;
-        default:
-            break;
-        }
-    }
-#ifdef DEBUG_ASI
-    dump_asi("read ", last_addr, asi, size, ret);
-#endif
-    return ret;
-}
-
-void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
-{
-    helper_check_align(addr, size - 1);
-    switch(asi) {
-    case 2: /* SuperSparc MXCC registers and Leon3 cache control */
-        switch (addr) {
-        case 0x00:          /* Leon3 Cache Control */
-        case 0x08:          /* Leon3 Instruction Cache config */
-        case 0x0C:          /* Leon3 Date Cache config */
-            if (env->def->features & CPU_FEATURE_CACHE_CTRL) {
-                leon3_cache_control_st(addr, val, size);
-            }
-            break;
-
-        case 0x01c00000: /* MXCC stream data register 0 */
-            if (size == 8)
-                env->mxccdata[0] = val;
-            else
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            break;
-        case 0x01c00008: /* MXCC stream data register 1 */
-            if (size == 8)
-                env->mxccdata[1] = val;
-            else
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            break;
-        case 0x01c00010: /* MXCC stream data register 2 */
-            if (size == 8)
-                env->mxccdata[2] = val;
-            else
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            break;
-        case 0x01c00018: /* MXCC stream data register 3 */
-            if (size == 8)
-                env->mxccdata[3] = val;
-            else
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            break;
-        case 0x01c00100: /* MXCC stream source */
-            if (size == 8)
-                env->mxccregs[0] = val;
-            else
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            env->mxccdata[0] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
-                                        0);
-            env->mxccdata[1] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
-                                        8);
-            env->mxccdata[2] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
-                                        16);
-            env->mxccdata[3] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
-                                        24);
-            break;
-        case 0x01c00200: /* MXCC stream destination */
-            if (size == 8)
-                env->mxccregs[1] = val;
-            else
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            stq_phys((env->mxccregs[1] & 0xffffffffULL) +  0,
-                     env->mxccdata[0]);
-            stq_phys((env->mxccregs[1] & 0xffffffffULL) +  8,
-                     env->mxccdata[1]);
-            stq_phys((env->mxccregs[1] & 0xffffffffULL) + 16,
-                     env->mxccdata[2]);
-            stq_phys((env->mxccregs[1] & 0xffffffffULL) + 24,
-                     env->mxccdata[3]);
-            break;
-        case 0x01c00a00: /* MXCC control register */
-            if (size == 8)
-                env->mxccregs[3] = val;
-            else
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            break;
-        case 0x01c00a04: /* MXCC control register */
-            if (size == 4)
-                env->mxccregs[3] = (env->mxccregs[3] & 0xffffffff00000000ULL)
-                    | val;
-            else
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            break;
-        case 0x01c00e00: /* MXCC error register  */
-            // writing a 1 bit clears the error
-            if (size == 8)
-                env->mxccregs[6] &= ~val;
-            else
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            break;
-        case 0x01c00f00: /* MBus port address register */
-            if (size == 8)
-                env->mxccregs[7] = val;
-            else
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            break;
-        default:
-            DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", addr,
-                         size);
-            break;
-        }
-        DPRINTF_MXCC("asi = %d, size = %d, addr = %08x, val = %" PRIx64 "\n",
-                     asi, size, addr, val);
-#ifdef DEBUG_MXCC
-        dump_mxcc(env);
-#endif
-        break;
-    case 3: /* MMU flush */
-        {
-            int mmulev;
-
-            mmulev = (addr >> 8) & 15;
-            DPRINTF_MMU("mmu flush level %d\n", mmulev);
-            switch (mmulev) {
-            case 0: // flush page
-                tlb_flush_page(env, addr & 0xfffff000);
-                break;
-            case 1: // flush segment (256k)
-            case 2: // flush region (16M)
-            case 3: // flush context (4G)
-            case 4: // flush entire
-                tlb_flush(env, 1);
-                break;
-            default:
-                break;
-            }
-#ifdef DEBUG_MMU
-            dump_mmu(stdout, fprintf, env);
-#endif
-        }
-        break;
-    case 4: /* write MMU regs */
-        {
-            int reg = (addr >> 8) & 0x1f;
-            uint32_t oldreg;
-
-            oldreg = env->mmuregs[reg];
-            switch(reg) {
-            case 0: // Control Register
-                env->mmuregs[reg] = (env->mmuregs[reg] & 0xff000000) |
-                                    (val & 0x00ffffff);
-                // Mappings generated during no-fault mode or MMU
-                // disabled mode are invalid in normal mode
-                if ((oldreg & (MMU_E | MMU_NF | env->def->mmu_bm)) !=
-                    (env->mmuregs[reg] & (MMU_E | MMU_NF | env->def->mmu_bm)))
-                    tlb_flush(env, 1);
-                break;
-            case 1: // Context Table Pointer Register
-                env->mmuregs[reg] = val & env->def->mmu_ctpr_mask;
-                break;
-            case 2: // Context Register
-                env->mmuregs[reg] = val & env->def->mmu_cxr_mask;
-                if (oldreg != env->mmuregs[reg]) {
-                    /* we flush when the MMU context changes because
-                       QEMU has no MMU context support */
-                    tlb_flush(env, 1);
-                }
-                break;
-            case 3: // Synchronous Fault Status Register with Clear
-            case 4: // Synchronous Fault Address Register
-                break;
-            case 0x10: // TLB Replacement Control Register
-                env->mmuregs[reg] = val & env->def->mmu_trcr_mask;
-                break;
-            case 0x13: // Synchronous Fault Status Register with Read and Clear
-                env->mmuregs[3] = val & env->def->mmu_sfsr_mask;
-                break;
-            case 0x14: // Synchronous Fault Address Register
-                env->mmuregs[4] = val;
-                break;
-            default:
-                env->mmuregs[reg] = val;
-                break;
-            }
-            if (oldreg != env->mmuregs[reg]) {
-                DPRINTF_MMU("mmu change reg[%d]: 0x%08x -> 0x%08x\n",
-                            reg, oldreg, env->mmuregs[reg]);
-            }
-#ifdef DEBUG_MMU
-            dump_mmu(stdout, fprintf, env);
-#endif
-        }
-        break;
-    case 5: // Turbosparc ITLB Diagnostic
-    case 6: // Turbosparc DTLB Diagnostic
-    case 7: // Turbosparc IOTLB Diagnostic
-        break;
-    case 0xa: /* User data access */
-        switch(size) {
-        case 1:
-            stb_user(addr, val);
-            break;
-        case 2:
-            stw_user(addr, val);
-            break;
-        default:
-        case 4:
-            stl_user(addr, val);
-            break;
-        case 8:
-            stq_user(addr, val);
-            break;
-        }
-        break;
-    case 0xb: /* Supervisor data access */
-        switch(size) {
-        case 1:
-            stb_kernel(addr, val);
-            break;
-        case 2:
-            stw_kernel(addr, val);
-            break;
-        default:
-        case 4:
-            stl_kernel(addr, val);
-            break;
-        case 8:
-            stq_kernel(addr, val);
-            break;
-        }
-        break;
-    case 0xc: /* I-cache tag */
-    case 0xd: /* I-cache data */
-    case 0xe: /* D-cache tag */
-    case 0xf: /* D-cache data */
-    case 0x10: /* I/D-cache flush page */
-    case 0x11: /* I/D-cache flush segment */
-    case 0x12: /* I/D-cache flush region */
-    case 0x13: /* I/D-cache flush context */
-    case 0x14: /* I/D-cache flush user */
-        break;
-    case 0x17: /* Block copy, sta access */
-        {
-            // val = src
-            // addr = dst
-            // copy 32 bytes
-            unsigned int i;
-            uint32_t src = val & ~3, dst = addr & ~3, temp;
-
-            for (i = 0; i < 32; i += 4, src += 4, dst += 4) {
-                temp = ldl_kernel(src);
-                stl_kernel(dst, temp);
-            }
-        }
-        break;
-    case 0x1f: /* Block fill, stda access */
-        {
-            // addr = dst
-            // fill 32 bytes with val
-            unsigned int i;
-            uint32_t dst = addr & 7;
-
-            for (i = 0; i < 32; i += 8, dst += 8)
-                stq_kernel(dst, val);
-        }
-        break;
-    case 0x20: /* MMU passthrough */
-        {
-            switch(size) {
-            case 1:
-                stb_phys(addr, val);
-                break;
-            case 2:
-                stw_phys(addr, val);
-                break;
-            case 4:
-            default:
-                stl_phys(addr, val);
-                break;
-            case 8:
-                stq_phys(addr, val);
-                break;
-            }
-        }
-        break;
-    case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */
-        {
-            switch(size) {
-            case 1:
-                stb_phys((target_phys_addr_t)addr
-                         | ((target_phys_addr_t)(asi & 0xf) << 32), val);
-                break;
-            case 2:
-                stw_phys((target_phys_addr_t)addr
-                         | ((target_phys_addr_t)(asi & 0xf) << 32), val);
-                break;
-            case 4:
-            default:
-                stl_phys((target_phys_addr_t)addr
-                         | ((target_phys_addr_t)(asi & 0xf) << 32), val);
-                break;
-            case 8:
-                stq_phys((target_phys_addr_t)addr
-                         | ((target_phys_addr_t)(asi & 0xf) << 32), val);
-                break;
-            }
-        }
-        break;
-    case 0x30: // store buffer tags or Turbosparc secondary cache diagnostic
-    case 0x31: // store buffer data, Ross RT620 I-cache flush or
-               // Turbosparc snoop RAM
-    case 0x32: // store buffer control or Turbosparc page table
-               // descriptor diagnostic
-    case 0x36: /* I-cache flash clear */
-    case 0x37: /* D-cache flash clear */
-        break;
-    case 0x38: /* SuperSPARC MMU Breakpoint Control Registers*/
-        {
-            int reg = (addr >> 8) & 3;
-
-            switch(reg) {
-            case 0: /* Breakpoint Value (Addr) */
-                env->mmubpregs[reg] = (val & 0xfffffffffULL);
-                break;
-            case 1: /* Breakpoint Mask */
-                env->mmubpregs[reg] = (val & 0xfffffffffULL);
-                break;
-            case 2: /* Breakpoint Control */
-                env->mmubpregs[reg] = (val & 0x7fULL);
-                break;
-            case 3: /* Breakpoint Status */
-                env->mmubpregs[reg] = (val & 0xfULL);
-                break;
-            }
-            DPRINTF_MMU("write breakpoint reg[%d] 0x%016x\n", reg,
-                        env->mmuregs[reg]);
-        }
-        break;
-    case 0x49: /* SuperSPARC MMU Counter Breakpoint Value */
-        env->mmubpctrv = val & 0xffffffff;
-        break;
-    case 0x4a: /* SuperSPARC MMU Counter Breakpoint Control */
-        env->mmubpctrc = val & 0x3;
-        break;
-    case 0x4b: /* SuperSPARC MMU Counter Breakpoint Status */
-        env->mmubpctrs = val & 0x3;
-        break;
-    case 0x4c: /* SuperSPARC MMU Breakpoint Action */
-        env->mmubpaction = val & 0x1fff;
-        break;
-    case 8: /* User code access, XXX */
-    case 9: /* Supervisor code access, XXX */
-    default:
-        do_unassigned_access(addr, 1, 0, asi, size);
-        break;
-    }
-#ifdef DEBUG_ASI
-    dump_asi("write", addr, asi, size, val);
-#endif
-}
-
-#endif /* CONFIG_USER_ONLY */
-#else /* TARGET_SPARC64 */
-
-#ifdef CONFIG_USER_ONLY
-uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
-{
-    uint64_t ret = 0;
-#if defined(DEBUG_ASI)
-    target_ulong last_addr = addr;
-#endif
-
-    if (asi < 0x80)
-        raise_exception(TT_PRIV_ACT);
-
-    helper_check_align(addr, size - 1);
-    addr = asi_address_mask(env, asi, addr);
-
-    switch (asi) {
-    case 0x82: // Primary no-fault
-    case 0x8a: // Primary no-fault LE
-        if (page_check_range(addr, size, PAGE_READ) == -1) {
-#ifdef DEBUG_ASI
-            dump_asi("read ", last_addr, asi, size, ret);
-#endif
-            return 0;
-        }
-        // Fall through
-    case 0x80: // Primary
-    case 0x88: // Primary LE
-        {
-            switch(size) {
-            case 1:
-                ret = ldub_raw(addr);
-                break;
-            case 2:
-                ret = lduw_raw(addr);
-                break;
-            case 4:
-                ret = ldl_raw(addr);
-                break;
-            default:
-            case 8:
-                ret = ldq_raw(addr);
-                break;
-            }
-        }
-        break;
-    case 0x83: // Secondary no-fault
-    case 0x8b: // Secondary no-fault LE
-        if (page_check_range(addr, size, PAGE_READ) == -1) {
-#ifdef DEBUG_ASI
-            dump_asi("read ", last_addr, asi, size, ret);
-#endif
-            return 0;
-        }
-        // Fall through
-    case 0x81: // Secondary
-    case 0x89: // Secondary LE
-        // XXX
-        break;
-    default:
-        break;
-    }
-
-    /* Convert from little endian */
-    switch (asi) {
-    case 0x88: // Primary LE
-    case 0x89: // Secondary LE
-    case 0x8a: // Primary no-fault LE
-    case 0x8b: // Secondary no-fault LE
-        switch(size) {
-        case 2:
-            ret = bswap16(ret);
-            break;
-        case 4:
-            ret = bswap32(ret);
-            break;
-        case 8:
-            ret = bswap64(ret);
-            break;
-        default:
-            break;
-        }
-    default:
-        break;
-    }
-
-    /* Convert to signed number */
-    if (sign) {
-        switch(size) {
-        case 1:
-            ret = (int8_t) ret;
-            break;
-        case 2:
-            ret = (int16_t) ret;
-            break;
-        case 4:
-            ret = (int32_t) ret;
-            break;
-        default:
-            break;
-        }
-    }
-#ifdef DEBUG_ASI
-    dump_asi("read ", last_addr, asi, size, ret);
-#endif
-    return ret;
-}
-
-void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
-{
-#ifdef DEBUG_ASI
-    dump_asi("write", addr, asi, size, val);
-#endif
-    if (asi < 0x80)
-        raise_exception(TT_PRIV_ACT);
-
-    helper_check_align(addr, size - 1);
-    addr = asi_address_mask(env, asi, addr);
-
-    /* Convert to little endian */
-    switch (asi) {
-    case 0x88: // Primary LE
-    case 0x89: // Secondary LE
-        switch(size) {
-        case 2:
-            val = bswap16(val);
-            break;
-        case 4:
-            val = bswap32(val);
-            break;
-        case 8:
-            val = bswap64(val);
-            break;
-        default:
-            break;
-        }
-    default:
-        break;
-    }
-
-    switch(asi) {
-    case 0x80: // Primary
-    case 0x88: // Primary LE
-        {
-            switch(size) {
-            case 1:
-                stb_raw(addr, val);
-                break;
-            case 2:
-                stw_raw(addr, val);
-                break;
-            case 4:
-                stl_raw(addr, val);
-                break;
-            case 8:
-            default:
-                stq_raw(addr, val);
-                break;
-            }
-        }
-        break;
-    case 0x81: // Secondary
-    case 0x89: // Secondary LE
-        // XXX
-        return;
-
-    case 0x82: // Primary no-fault, RO
-    case 0x83: // Secondary no-fault, RO
-    case 0x8a: // Primary no-fault LE, RO
-    case 0x8b: // Secondary no-fault LE, RO
-    default:
-        do_unassigned_access(addr, 1, 0, 1, size);
-        return;
-    }
-}
-
-#else /* CONFIG_USER_ONLY */
-
-uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
-{
-    uint64_t ret = 0;
-#if defined(DEBUG_ASI)
-    target_ulong last_addr = addr;
-#endif
-
-    asi &= 0xff;
-
-    if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
-        || (cpu_has_hypervisor(env)
-            && asi >= 0x30 && asi < 0x80
-            && !(env->hpstate & HS_PRIV)))
-        raise_exception(TT_PRIV_ACT);
-
-    helper_check_align(addr, size - 1);
-    addr = asi_address_mask(env, asi, addr);
-
-    /* process nonfaulting loads first */
-    if ((asi & 0xf6) == 0x82) {
-        int mmu_idx;
-
-        /* secondary space access has lowest asi bit equal to 1 */
-        if (env->pstate & PS_PRIV) {
-            mmu_idx = (asi & 1) ? MMU_KERNEL_SECONDARY_IDX : MMU_KERNEL_IDX;
-        } else {
-            mmu_idx = (asi & 1) ? MMU_USER_SECONDARY_IDX : MMU_USER_IDX;
-        }
-
-        if (cpu_get_phys_page_nofault(env, addr, mmu_idx) == -1ULL) {
-#ifdef DEBUG_ASI
-            dump_asi("read ", last_addr, asi, size, ret);
-#endif
-            /* env->exception_index is set in get_physical_address_data(). */
-            raise_exception(env->exception_index);
-        }
-
-        /* convert nonfaulting load ASIs to normal load ASIs */
-        asi &= ~0x02;
-    }
-
-    switch (asi) {
-    case 0x10: // As if user primary
-    case 0x11: // As if user secondary
-    case 0x18: // As if user primary LE
-    case 0x19: // As if user secondary LE
-    case 0x80: // Primary
-    case 0x81: // Secondary
-    case 0x88: // Primary LE
-    case 0x89: // Secondary LE
-    case 0xe2: // UA2007 Primary block init
-    case 0xe3: // UA2007 Secondary block init
-        if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
-            if (cpu_hypervisor_mode(env)) {
-                switch(size) {
-                case 1:
-                    ret = ldub_hypv(addr);
-                    break;
-                case 2:
-                    ret = lduw_hypv(addr);
-                    break;
-                case 4:
-                    ret = ldl_hypv(addr);
-                    break;
-                default:
-                case 8:
-                    ret = ldq_hypv(addr);
-                    break;
-                }
-            } else {
-                /* secondary space access has lowest asi bit equal to 1 */
-                if (asi & 1) {
-                    switch(size) {
-                    case 1:
-                        ret = ldub_kernel_secondary(addr);
-                        break;
-                    case 2:
-                        ret = lduw_kernel_secondary(addr);
-                        break;
-                    case 4:
-                        ret = ldl_kernel_secondary(addr);
-                        break;
-                    default:
-                    case 8:
-                        ret = ldq_kernel_secondary(addr);
-                        break;
-                    }
-                } else {
-                    switch(size) {
-                    case 1:
-                        ret = ldub_kernel(addr);
-                        break;
-                    case 2:
-                        ret = lduw_kernel(addr);
-                        break;
-                    case 4:
-                        ret = ldl_kernel(addr);
-                        break;
-                    default:
-                    case 8:
-                        ret = ldq_kernel(addr);
-                        break;
-                    }
-                }
-            }
-        } else {
-            /* secondary space access has lowest asi bit equal to 1 */
-            if (asi & 1) {
-                switch(size) {
-                case 1:
-                    ret = ldub_user_secondary(addr);
-                    break;
-                case 2:
-                    ret = lduw_user_secondary(addr);
-                    break;
-                case 4:
-                    ret = ldl_user_secondary(addr);
-                    break;
-                default:
-                case 8:
-                    ret = ldq_user_secondary(addr);
-                    break;
-                }
-            } else {
-                switch(size) {
-                case 1:
-                    ret = ldub_user(addr);
-                    break;
-                case 2:
-                    ret = lduw_user(addr);
-                    break;
-                case 4:
-                    ret = ldl_user(addr);
-                    break;
-                default:
-                case 8:
-                    ret = ldq_user(addr);
-                    break;
-                }
-            }
-        }
-        break;
-    case 0x14: // Bypass
-    case 0x15: // Bypass, non-cacheable
-    case 0x1c: // Bypass LE
-    case 0x1d: // Bypass, non-cacheable LE
-        {
-            switch(size) {
-            case 1:
-                ret = ldub_phys(addr);
-                break;
-            case 2:
-                ret = lduw_phys(addr);
-                break;
-            case 4:
-                ret = ldl_phys(addr);
-                break;
-            default:
-            case 8:
-                ret = ldq_phys(addr);
-                break;
-            }
-            break;
-        }
-    case 0x24: // Nucleus quad LDD 128 bit atomic
-    case 0x2c: // Nucleus quad LDD 128 bit atomic LE
-        //  Only ldda allowed
-        raise_exception(TT_ILL_INSN);
-        return 0;
-    case 0x04: // Nucleus
-    case 0x0c: // Nucleus Little Endian (LE)
-    {
-        switch(size) {
-        case 1:
-            ret = ldub_nucleus(addr);
-            break;
-        case 2:
-            ret = lduw_nucleus(addr);
-            break;
-        case 4:
-            ret = ldl_nucleus(addr);
-            break;
-        default:
-        case 8:
-            ret = ldq_nucleus(addr);
-            break;
-        }
-        break;
-    }
-    case 0x4a: // UPA config
-        // XXX
-        break;
-    case 0x45: // LSU
-        ret = env->lsu;
-        break;
-    case 0x50: // I-MMU regs
-        {
-            int reg = (addr >> 3) & 0xf;
-
-            if (reg == 0) {
-                // I-TSB Tag Target register
-                ret = ultrasparc_tag_target(env->immu.tag_access);
-            } else {
-                ret = env->immuregs[reg];
-            }
-
-            break;
-        }
-    case 0x51: // I-MMU 8k TSB pointer
-        {
-            // env->immuregs[5] holds I-MMU TSB register value
-            // env->immuregs[6] holds I-MMU Tag Access register value
-            ret = ultrasparc_tsb_pointer(env->immu.tsb, env->immu.tag_access,
-                                         8*1024);
-            break;
-        }
-    case 0x52: // I-MMU 64k TSB pointer
-        {
-            // env->immuregs[5] holds I-MMU TSB register value
-            // env->immuregs[6] holds I-MMU Tag Access register value
-            ret = ultrasparc_tsb_pointer(env->immu.tsb, env->immu.tag_access,
-                                         64*1024);
-            break;
-        }
-    case 0x55: // I-MMU data access
-        {
-            int reg = (addr >> 3) & 0x3f;
-
-            ret = env->itlb[reg].tte;
-            break;
-        }
-    case 0x56: // I-MMU tag read
-        {
-            int reg = (addr >> 3) & 0x3f;
-
-            ret = env->itlb[reg].tag;
-            break;
-        }
-    case 0x58: // D-MMU regs
-        {
-            int reg = (addr >> 3) & 0xf;
-
-            if (reg == 0) {
-                // D-TSB Tag Target register
-                ret = ultrasparc_tag_target(env->dmmu.tag_access);
-            } else {
-                ret = env->dmmuregs[reg];
-            }
-            break;
-        }
-    case 0x59: // D-MMU 8k TSB pointer
-        {
-            // env->dmmuregs[5] holds D-MMU TSB register value
-            // env->dmmuregs[6] holds D-MMU Tag Access register value
-            ret = ultrasparc_tsb_pointer(env->dmmu.tsb, env->dmmu.tag_access,
-                                         8*1024);
-            break;
-        }
-    case 0x5a: // D-MMU 64k TSB pointer
-        {
-            // env->dmmuregs[5] holds D-MMU TSB register value
-            // env->dmmuregs[6] holds D-MMU Tag Access register value
-            ret = ultrasparc_tsb_pointer(env->dmmu.tsb, env->dmmu.tag_access,
-                                         64*1024);
-            break;
-        }
-    case 0x5d: // D-MMU data access
-        {
-            int reg = (addr >> 3) & 0x3f;
-
-            ret = env->dtlb[reg].tte;
-            break;
-        }
-    case 0x5e: // D-MMU tag read
-        {
-            int reg = (addr >> 3) & 0x3f;
-
-            ret = env->dtlb[reg].tag;
-            break;
-        }
-    case 0x46: // D-cache data
-    case 0x47: // D-cache tag access
-    case 0x4b: // E-cache error enable
-    case 0x4c: // E-cache asynchronous fault status
-    case 0x4d: // E-cache asynchronous fault address
-    case 0x4e: // E-cache tag data
-    case 0x66: // I-cache instruction access
-    case 0x67: // I-cache tag access
-    case 0x6e: // I-cache predecode
-    case 0x6f: // I-cache LRU etc.
-    case 0x76: // E-cache tag
-    case 0x7e: // E-cache tag
-        break;
-    case 0x5b: // D-MMU data pointer
-    case 0x48: // Interrupt dispatch, RO
-    case 0x49: // Interrupt data receive
-    case 0x7f: // Incoming interrupt vector, RO
-        // XXX
-        break;
-    case 0x54: // I-MMU data in, WO
-    case 0x57: // I-MMU demap, WO
-    case 0x5c: // D-MMU data in, WO
-    case 0x5f: // D-MMU demap, WO
-    case 0x77: // Interrupt vector, WO
-    default:
-        do_unassigned_access(addr, 0, 0, 1, size);
-        ret = 0;
-        break;
-    }
-
-    /* Convert from little endian */
-    switch (asi) {
-    case 0x0c: // Nucleus Little Endian (LE)
-    case 0x18: // As if user primary LE
-    case 0x19: // As if user secondary LE
-    case 0x1c: // Bypass LE
-    case 0x1d: // Bypass, non-cacheable LE
-    case 0x88: // Primary LE
-    case 0x89: // Secondary LE
-        switch(size) {
-        case 2:
-            ret = bswap16(ret);
-            break;
-        case 4:
-            ret = bswap32(ret);
-            break;
-        case 8:
-            ret = bswap64(ret);
-            break;
-        default:
-            break;
-        }
-    default:
-        break;
-    }
-
-    /* Convert to signed number */
-    if (sign) {
-        switch(size) {
-        case 1:
-            ret = (int8_t) ret;
-            break;
-        case 2:
-            ret = (int16_t) ret;
-            break;
-        case 4:
-            ret = (int32_t) ret;
-            break;
-        default:
-            break;
-        }
-    }
-#ifdef DEBUG_ASI
-    dump_asi("read ", last_addr, asi, size, ret);
-#endif
-    return ret;
-}
-
-void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
-{
-#ifdef DEBUG_ASI
-    dump_asi("write", addr, asi, size, val);
-#endif
-
-    asi &= 0xff;
-
-    if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
-        || (cpu_has_hypervisor(env)
-            && asi >= 0x30 && asi < 0x80
-            && !(env->hpstate & HS_PRIV)))
-        raise_exception(TT_PRIV_ACT);
-
-    helper_check_align(addr, size - 1);
-    addr = asi_address_mask(env, asi, addr);
-
-    /* Convert to little endian */
-    switch (asi) {
-    case 0x0c: // Nucleus Little Endian (LE)
-    case 0x18: // As if user primary LE
-    case 0x19: // As if user secondary LE
-    case 0x1c: // Bypass LE
-    case 0x1d: // Bypass, non-cacheable LE
-    case 0x88: // Primary LE
-    case 0x89: // Secondary LE
-        switch(size) {
-        case 2:
-            val = bswap16(val);
-            break;
-        case 4:
-            val = bswap32(val);
-            break;
-        case 8:
-            val = bswap64(val);
-            break;
-        default:
-            break;
-        }
-    default:
-        break;
-    }
-
-    switch(asi) {
-    case 0x10: // As if user primary
-    case 0x11: // As if user secondary
-    case 0x18: // As if user primary LE
-    case 0x19: // As if user secondary LE
-    case 0x80: // Primary
-    case 0x81: // Secondary
-    case 0x88: // Primary LE
-    case 0x89: // Secondary LE
-    case 0xe2: // UA2007 Primary block init
-    case 0xe3: // UA2007 Secondary block init
-        if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
-            if (cpu_hypervisor_mode(env)) {
-                switch(size) {
-                case 1:
-                    stb_hypv(addr, val);
-                    break;
-                case 2:
-                    stw_hypv(addr, val);
-                    break;
-                case 4:
-                    stl_hypv(addr, val);
-                    break;
-                case 8:
-                default:
-                    stq_hypv(addr, val);
-                    break;
-                }
-            } else {
-                /* secondary space access has lowest asi bit equal to 1 */
-                if (asi & 1) {
-                    switch(size) {
-                    case 1:
-                        stb_kernel_secondary(addr, val);
-                        break;
-                    case 2:
-                        stw_kernel_secondary(addr, val);
-                        break;
-                    case 4:
-                        stl_kernel_secondary(addr, val);
-                        break;
-                    case 8:
-                    default:
-                        stq_kernel_secondary(addr, val);
-                        break;
-                    }
-                } else {
-                    switch(size) {
-                    case 1:
-                        stb_kernel(addr, val);
-                        break;
-                    case 2:
-                        stw_kernel(addr, val);
-                        break;
-                    case 4:
-                        stl_kernel(addr, val);
-                        break;
-                    case 8:
-                    default:
-                        stq_kernel(addr, val);
-                        break;
-                    }
-                }
-            }
-        } else {
-            /* secondary space access has lowest asi bit equal to 1 */
-            if (asi & 1) {
-                switch(size) {
-                case 1:
-                    stb_user_secondary(addr, val);
-                    break;
-                case 2:
-                    stw_user_secondary(addr, val);
-                    break;
-                case 4:
-                    stl_user_secondary(addr, val);
-                    break;
-                case 8:
-                default:
-                    stq_user_secondary(addr, val);
-                    break;
-                }
-            } else {
-                switch(size) {
-                case 1:
-                    stb_user(addr, val);
-                    break;
-                case 2:
-                    stw_user(addr, val);
-                    break;
-                case 4:
-                    stl_user(addr, val);
-                    break;
-                case 8:
-                default:
-                    stq_user(addr, val);
-                    break;
-                }
-            }
-        }
-        break;
-    case 0x14: // Bypass
-    case 0x15: // Bypass, non-cacheable
-    case 0x1c: // Bypass LE
-    case 0x1d: // Bypass, non-cacheable LE
-        {
-            switch(size) {
-            case 1:
-                stb_phys(addr, val);
-                break;
-            case 2:
-                stw_phys(addr, val);
-                break;
-            case 4:
-                stl_phys(addr, val);
-                break;
-            case 8:
-            default:
-                stq_phys(addr, val);
-                break;
-            }
-        }
-        return;
-    case 0x24: // Nucleus quad LDD 128 bit atomic
-    case 0x2c: // Nucleus quad LDD 128 bit atomic LE
-        //  Only ldda allowed
-        raise_exception(TT_ILL_INSN);
-        return;
-    case 0x04: // Nucleus
-    case 0x0c: // Nucleus Little Endian (LE)
-    {
-        switch(size) {
-        case 1:
-            stb_nucleus(addr, val);
-            break;
-        case 2:
-            stw_nucleus(addr, val);
-            break;
-        case 4:
-            stl_nucleus(addr, val);
-            break;
-        default:
-        case 8:
-            stq_nucleus(addr, val);
-            break;
-        }
-        break;
-    }
-
-    case 0x4a: // UPA config
-        // XXX
-        return;
-    case 0x45: // LSU
-        {
-            uint64_t oldreg;
-
-            oldreg = env->lsu;
-            env->lsu = val & (DMMU_E | IMMU_E);
-            // Mappings generated during D/I MMU disabled mode are
-            // invalid in normal mode
-            if (oldreg != env->lsu) {
-                DPRINTF_MMU("LSU change: 0x%" PRIx64 " -> 0x%" PRIx64 "\n",
-                            oldreg, env->lsu);
-#ifdef DEBUG_MMU
-                dump_mmu(stdout, fprintf, env1);
-#endif
-                tlb_flush(env, 1);
-            }
-            return;
-        }
-    case 0x50: // I-MMU regs
-        {
-            int reg = (addr >> 3) & 0xf;
-            uint64_t oldreg;
-
-            oldreg = env->immuregs[reg];
-            switch(reg) {
-            case 0: // RO
-                return;
-            case 1: // Not in I-MMU
-            case 2:
-                return;
-            case 3: // SFSR
-                if ((val & 1) == 0)
-                    val = 0; // Clear SFSR
-                env->immu.sfsr = val;
-                break;
-            case 4: // RO
-                return;
-            case 5: // TSB access
-                DPRINTF_MMU("immu TSB write: 0x%016" PRIx64 " -> 0x%016"
-                            PRIx64 "\n", env->immu.tsb, val);
-                env->immu.tsb = val;
-                break;
-            case 6: // Tag access
-                env->immu.tag_access = val;
-                break;
-            case 7:
-            case 8:
-                return;
-            default:
-                break;
-            }
-
-            if (oldreg != env->immuregs[reg]) {
-                DPRINTF_MMU("immu change reg[%d]: 0x%016" PRIx64 " -> 0x%016"
-                            PRIx64 "\n", reg, oldreg, env->immuregs[reg]);
-            }
-#ifdef DEBUG_MMU
-            dump_mmu(stdout, fprintf, env);
-#endif
-            return;
-        }
-    case 0x54: // I-MMU data in
-        replace_tlb_1bit_lru(env->itlb, env->immu.tag_access, val, "immu", env);
-        return;
-    case 0x55: // I-MMU data access
-        {
-            // TODO: auto demap
-
-            unsigned int i = (addr >> 3) & 0x3f;
-
-            replace_tlb_entry(&env->itlb[i], env->immu.tag_access, val, env);
-
-#ifdef DEBUG_MMU
-            DPRINTF_MMU("immu data access replaced entry [%i]\n", i);
-            dump_mmu(stdout, fprintf, env);
-#endif
-            return;
-        }
-    case 0x57: // I-MMU demap
-        demap_tlb(env->itlb, addr, "immu", env);
-        return;
-    case 0x58: // D-MMU regs
-        {
-            int reg = (addr >> 3) & 0xf;
-            uint64_t oldreg;
-
-            oldreg = env->dmmuregs[reg];
-            switch(reg) {
-            case 0: // RO
-            case 4:
-                return;
-            case 3: // SFSR
-                if ((val & 1) == 0) {
-                    val = 0; // Clear SFSR, Fault address
-                    env->dmmu.sfar = 0;
-                }
-                env->dmmu.sfsr = val;
-                break;
-            case 1: // Primary context
-                env->dmmu.mmu_primary_context = val;
-                /* can be optimized to only flush MMU_USER_IDX
-                   and MMU_KERNEL_IDX entries */
-                tlb_flush(env, 1);
-                break;
-            case 2: // Secondary context
-                env->dmmu.mmu_secondary_context = val;
-                /* can be optimized to only flush MMU_USER_SECONDARY_IDX
-                   and MMU_KERNEL_SECONDARY_IDX entries */
-                tlb_flush(env, 1);
-                break;
-            case 5: // TSB access
-                DPRINTF_MMU("dmmu TSB write: 0x%016" PRIx64 " -> 0x%016"
-                            PRIx64 "\n", env->dmmu.tsb, val);
-                env->dmmu.tsb = val;
-                break;
-            case 6: // Tag access
-                env->dmmu.tag_access = val;
-                break;
-            case 7: // Virtual Watchpoint
-            case 8: // Physical Watchpoint
-            default:
-                env->dmmuregs[reg] = val;
-                break;
-            }
-
-            if (oldreg != env->dmmuregs[reg]) {
-                DPRINTF_MMU("dmmu change reg[%d]: 0x%016" PRIx64 " -> 0x%016"
-                            PRIx64 "\n", reg, oldreg, env->dmmuregs[reg]);
-            }
-#ifdef DEBUG_MMU
-            dump_mmu(stdout, fprintf, env);
-#endif
-            return;
-        }
-    case 0x5c: // D-MMU data in
-        replace_tlb_1bit_lru(env->dtlb, env->dmmu.tag_access, val, "dmmu", env);
-        return;
-    case 0x5d: // D-MMU data access
-        {
-            unsigned int i = (addr >> 3) & 0x3f;
-
-            replace_tlb_entry(&env->dtlb[i], env->dmmu.tag_access, val, env);
-
-#ifdef DEBUG_MMU
-            DPRINTF_MMU("dmmu data access replaced entry [%i]\n", i);
-            dump_mmu(stdout, fprintf, env);
-#endif
-            return;
-        }
-    case 0x5f: // D-MMU demap
-        demap_tlb(env->dtlb, addr, "dmmu", env);
-        return;
-    case 0x49: // Interrupt data receive
-        // XXX
-        return;
-    case 0x46: // D-cache data
-    case 0x47: // D-cache tag access
-    case 0x4b: // E-cache error enable
-    case 0x4c: // E-cache asynchronous fault status
-    case 0x4d: // E-cache asynchronous fault address
-    case 0x4e: // E-cache tag data
-    case 0x66: // I-cache instruction access
-    case 0x67: // I-cache tag access
-    case 0x6e: // I-cache predecode
-    case 0x6f: // I-cache LRU etc.
-    case 0x76: // E-cache tag
-    case 0x7e: // E-cache tag
-        return;
-    case 0x51: // I-MMU 8k TSB pointer, RO
-    case 0x52: // I-MMU 64k TSB pointer, RO
-    case 0x56: // I-MMU tag read, RO
-    case 0x59: // D-MMU 8k TSB pointer, RO
-    case 0x5a: // D-MMU 64k TSB pointer, RO
-    case 0x5b: // D-MMU data pointer, RO
-    case 0x5e: // D-MMU tag read, RO
-    case 0x48: // Interrupt dispatch, RO
-    case 0x7f: // Incoming interrupt vector, RO
-    case 0x82: // Primary no-fault, RO
-    case 0x83: // Secondary no-fault, RO
-    case 0x8a: // Primary no-fault LE, RO
-    case 0x8b: // Secondary no-fault LE, RO
-    default:
-        do_unassigned_access(addr, 1, 0, 1, size);
-        return;
-    }
-}
-#endif /* CONFIG_USER_ONLY */
-
-void helper_ldda_asi(target_ulong addr, int asi, int rd)
-{
-    if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
-        || (cpu_has_hypervisor(env)
-            && asi >= 0x30 && asi < 0x80
-            && !(env->hpstate & HS_PRIV)))
-        raise_exception(TT_PRIV_ACT);
-
-    addr = asi_address_mask(env, asi, addr);
-
-    switch (asi) {
-#if !defined(CONFIG_USER_ONLY)
-    case 0x24: // Nucleus quad LDD 128 bit atomic
-    case 0x2c: // Nucleus quad LDD 128 bit atomic LE
-        helper_check_align(addr, 0xf);
-        if (rd == 0) {
-            env->gregs[1] = ldq_nucleus(addr + 8);
-            if (asi == 0x2c)
-                bswap64s(&env->gregs[1]);
-        } else if (rd < 8) {
-            env->gregs[rd] = ldq_nucleus(addr);
-            env->gregs[rd + 1] = ldq_nucleus(addr + 8);
-            if (asi == 0x2c) {
-                bswap64s(&env->gregs[rd]);
-                bswap64s(&env->gregs[rd + 1]);
-            }
-        } else {
-            env->regwptr[rd] = ldq_nucleus(addr);
-            env->regwptr[rd + 1] = ldq_nucleus(addr + 8);
-            if (asi == 0x2c) {
-                bswap64s(&env->regwptr[rd]);
-                bswap64s(&env->regwptr[rd + 1]);
-            }
-        }
-        break;
-#endif
-    default:
-        helper_check_align(addr, 0x3);
-        if (rd == 0)
-            env->gregs[1] = helper_ld_asi(addr + 4, asi, 4, 0);
-        else if (rd < 8) {
-            env->gregs[rd] = helper_ld_asi(addr, asi, 4, 0);
-            env->gregs[rd + 1] = helper_ld_asi(addr + 4, asi, 4, 0);
-        } else {
-            env->regwptr[rd] = helper_ld_asi(addr, asi, 4, 0);
-            env->regwptr[rd + 1] = helper_ld_asi(addr + 4, asi, 4, 0);
-        }
-        break;
-    }
-}
-
-void helper_ldf_asi(target_ulong addr, int asi, int size, int rd)
-{
-    unsigned int i;
-    CPU_DoubleU u;
-
-    helper_check_align(addr, 3);
-    addr = asi_address_mask(env, asi, addr);
-
-    switch (asi) {
-    case 0xf0: /* UA2007/JPS1 Block load primary */
-    case 0xf1: /* UA2007/JPS1 Block load secondary */
-    case 0xf8: /* UA2007/JPS1 Block load primary LE */
-    case 0xf9: /* UA2007/JPS1 Block load secondary LE */
-        if (rd & 7) {
-            raise_exception(TT_ILL_INSN);
-            return;
-        }
-        helper_check_align(addr, 0x3f);
-        for (i = 0; i < 16; i++) {
-            *(uint32_t *)&env->fpr[rd++] = helper_ld_asi(addr, asi & 0x8f, 4,
-                                                         0);
-            addr += 4;
-        }
-
-        return;
-    case 0x16: /* UA2007 Block load primary, user privilege */
-    case 0x17: /* UA2007 Block load secondary, user privilege */
-    case 0x1e: /* UA2007 Block load primary LE, user privilege */
-    case 0x1f: /* UA2007 Block load secondary LE, user privilege */
-    case 0x70: /* JPS1 Block load primary, user privilege */
-    case 0x71: /* JPS1 Block load secondary, user privilege */
-    case 0x78: /* JPS1 Block load primary LE, user privilege */
-    case 0x79: /* JPS1 Block load secondary LE, user privilege */
-        if (rd & 7) {
-            raise_exception(TT_ILL_INSN);
-            return;
-        }
-        helper_check_align(addr, 0x3f);
-        for (i = 0; i < 16; i++) {
-            *(uint32_t *)&env->fpr[rd++] = helper_ld_asi(addr, asi & 0x19, 4,
-                                                         0);
-            addr += 4;
-        }
-
-        return;
-    default:
-        break;
-    }
-
-    switch(size) {
-    default:
-    case 4:
-        *((uint32_t *)&env->fpr[rd]) = helper_ld_asi(addr, asi, size, 0);
-        break;
-    case 8:
-        u.ll = helper_ld_asi(addr, asi, size, 0);
-        *((uint32_t *)&env->fpr[rd++]) = u.l.upper;
-        *((uint32_t *)&env->fpr[rd++]) = u.l.lower;
-        break;
-    case 16:
-        u.ll = helper_ld_asi(addr, asi, 8, 0);
-        *((uint32_t *)&env->fpr[rd++]) = u.l.upper;
-        *((uint32_t *)&env->fpr[rd++]) = u.l.lower;
-        u.ll = helper_ld_asi(addr + 8, asi, 8, 0);
-        *((uint32_t *)&env->fpr[rd++]) = u.l.upper;
-        *((uint32_t *)&env->fpr[rd++]) = u.l.lower;
-        break;
-    }
-}
-
-void helper_stf_asi(target_ulong addr, int asi, int size, int rd)
-{
-    unsigned int i;
-    target_ulong val = 0;
-    CPU_DoubleU u;
-
-    helper_check_align(addr, 3);
-    addr = asi_address_mask(env, asi, addr);
-
-    switch (asi) {
-    case 0xe0: /* UA2007/JPS1 Block commit store primary (cache flush) */
-    case 0xe1: /* UA2007/JPS1 Block commit store secondary (cache flush) */
-    case 0xf0: /* UA2007/JPS1 Block store primary */
-    case 0xf1: /* UA2007/JPS1 Block store secondary */
-    case 0xf8: /* UA2007/JPS1 Block store primary LE */
-    case 0xf9: /* UA2007/JPS1 Block store secondary LE */
-        if (rd & 7) {
-            raise_exception(TT_ILL_INSN);
-            return;
-        }
-        helper_check_align(addr, 0x3f);
-        for (i = 0; i < 16; i++) {
-            val = *(uint32_t *)&env->fpr[rd++];
-            helper_st_asi(addr, val, asi & 0x8f, 4);
-            addr += 4;
-        }
-
-        return;
-    case 0x16: /* UA2007 Block load primary, user privilege */
-    case 0x17: /* UA2007 Block load secondary, user privilege */
-    case 0x1e: /* UA2007 Block load primary LE, user privilege */
-    case 0x1f: /* UA2007 Block load secondary LE, user privilege */
-    case 0x70: /* JPS1 Block store primary, user privilege */
-    case 0x71: /* JPS1 Block store secondary, user privilege */
-    case 0x78: /* JPS1 Block load primary LE, user privilege */
-    case 0x79: /* JPS1 Block load secondary LE, user privilege */
-        if (rd & 7) {
-            raise_exception(TT_ILL_INSN);
-            return;
-        }
-        helper_check_align(addr, 0x3f);
-        for (i = 0; i < 16; i++) {
-            val = *(uint32_t *)&env->fpr[rd++];
-            helper_st_asi(addr, val, asi & 0x19, 4);
-            addr += 4;
-        }
-
-        return;
-    default:
-        break;
-    }
-
-    switch(size) {
-    default:
-    case 4:
-        helper_st_asi(addr, *(uint32_t *)&env->fpr[rd], asi, size);
-        break;
-    case 8:
-        u.l.upper = *(uint32_t *)&env->fpr[rd++];
-        u.l.lower = *(uint32_t *)&env->fpr[rd++];
-        helper_st_asi(addr, u.ll, asi, size);
-        break;
-    case 16:
-        u.l.upper = *(uint32_t *)&env->fpr[rd++];
-        u.l.lower = *(uint32_t *)&env->fpr[rd++];
-        helper_st_asi(addr, u.ll, asi, 8);
-        u.l.upper = *(uint32_t *)&env->fpr[rd++];
-        u.l.lower = *(uint32_t *)&env->fpr[rd++];
-        helper_st_asi(addr + 8, u.ll, asi, 8);
-        break;
-    }
-}
-
-target_ulong helper_cas_asi(target_ulong addr, target_ulong val1,
-                            target_ulong val2, uint32_t asi)
-{
-    target_ulong ret;
-
-    val2 &= 0xffffffffUL;
-    ret = helper_ld_asi(addr, asi, 4, 0);
-    ret &= 0xffffffffUL;
-    if (val2 == ret)
-        helper_st_asi(addr, val1 & 0xffffffffUL, asi, 4);
-    return ret;
-}
-
-target_ulong helper_casx_asi(target_ulong addr, target_ulong val1,
-                             target_ulong val2, uint32_t asi)
-{
-    target_ulong ret;
-
-    ret = helper_ld_asi(addr, asi, 8, 0);
-    if (val2 == ret)
-        helper_st_asi(addr, val1, asi, 8);
-    return ret;
-}
-#endif /* TARGET_SPARC64 */
-
-#ifndef TARGET_SPARC64
-void helper_rett(void)
-{
-    unsigned int cwp;
-
-    if (env->psret == 1)
-        raise_exception(TT_ILL_INSN);
-
-    env->psret = 1;
-    cwp = cwp_inc(env->cwp + 1) ;
-    if (env->wim & (1 << cwp)) {
-        raise_exception(TT_WIN_UNF);
-    }
-    set_cwp(cwp);
-    env->psrs = env->psrps;
-}
-#endif
-
-static target_ulong helper_udiv_common(target_ulong a, target_ulong b, int cc)
-{
-    int overflow = 0;
-    uint64_t x0;
-    uint32_t x1;
-
-    x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
-    x1 = (b & 0xffffffff);
-
-    if (x1 == 0) {
-        raise_exception(TT_DIV_ZERO);
-    }
-
-    x0 = x0 / x1;
-    if (x0 > 0xffffffff) {
-        x0 = 0xffffffff;
-        overflow = 1;
-    }
-
-    if (cc) {
-        env->cc_dst = x0;
-        env->cc_src2 = overflow;
-        env->cc_op = CC_OP_DIV;
-    }
-    return x0;
-}
-
-target_ulong helper_udiv(target_ulong a, target_ulong b)
-{
-    return helper_udiv_common(a, b, 0);
-}
-
-target_ulong helper_udiv_cc(target_ulong a, target_ulong b)
-{
-    return helper_udiv_common(a, b, 1);
-}
-
-static target_ulong helper_sdiv_common(target_ulong a, target_ulong b, int cc)
-{
-    int overflow = 0;
-    int64_t x0;
-    int32_t x1;
-
-    x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
-    x1 = (b & 0xffffffff);
-
-    if (x1 == 0) {
-        raise_exception(TT_DIV_ZERO);
-    }
-
-    x0 = x0 / x1;
-    if ((int32_t) x0 != x0) {
-        x0 = x0 < 0 ? 0x80000000: 0x7fffffff;
-        overflow = 1;
-    }
-
-    if (cc) {
-        env->cc_dst = x0;
-        env->cc_src2 = overflow;
-        env->cc_op = CC_OP_DIV;
-    }
-    return x0;
-}
-
-target_ulong helper_sdiv(target_ulong a, target_ulong b)
-{
-    return helper_sdiv_common(a, b, 0);
-}
-
-target_ulong helper_sdiv_cc(target_ulong a, target_ulong b)
-{
-    return helper_sdiv_common(a, b, 1);
-}
-
-void helper_stdf(target_ulong addr, int mem_idx)
-{
-    helper_check_align(addr, 7);
-#if !defined(CONFIG_USER_ONLY)
-    switch (mem_idx) {
-    case MMU_USER_IDX:
-        stfq_user(addr, DT0);
-        break;
-    case MMU_KERNEL_IDX:
-        stfq_kernel(addr, DT0);
-        break;
-#ifdef TARGET_SPARC64
-    case MMU_HYPV_IDX:
-        stfq_hypv(addr, DT0);
-        break;
-#endif
-    default:
-        DPRINTF_MMU("helper_stdf: need to check MMU idx %d\n", mem_idx);
-        break;
-    }
-#else
-    stfq_raw(address_mask(env, addr), DT0);
-#endif
-}
-
-void helper_lddf(target_ulong addr, int mem_idx)
-{
-    helper_check_align(addr, 7);
-#if !defined(CONFIG_USER_ONLY)
-    switch (mem_idx) {
-    case MMU_USER_IDX:
-        DT0 = ldfq_user(addr);
-        break;
-    case MMU_KERNEL_IDX:
-        DT0 = ldfq_kernel(addr);
-        break;
-#ifdef TARGET_SPARC64
-    case MMU_HYPV_IDX:
-        DT0 = ldfq_hypv(addr);
-        break;
-#endif
-    default:
-        DPRINTF_MMU("helper_lddf: need to check MMU idx %d\n", mem_idx);
-        break;
-    }
-#else
-    DT0 = ldfq_raw(address_mask(env, addr));
-#endif
-}
-
-void helper_ldqf(target_ulong addr, int mem_idx)
-{
-    // XXX add 128 bit load
-    CPU_QuadU u;
-
-    helper_check_align(addr, 7);
-#if !defined(CONFIG_USER_ONLY)
-    switch (mem_idx) {
-    case MMU_USER_IDX:
-        u.ll.upper = ldq_user(addr);
-        u.ll.lower = ldq_user(addr + 8);
-        QT0 = u.q;
-        break;
-    case MMU_KERNEL_IDX:
-        u.ll.upper = ldq_kernel(addr);
-        u.ll.lower = ldq_kernel(addr + 8);
-        QT0 = u.q;
-        break;
-#ifdef TARGET_SPARC64
-    case MMU_HYPV_IDX:
-        u.ll.upper = ldq_hypv(addr);
-        u.ll.lower = ldq_hypv(addr + 8);
-        QT0 = u.q;
-        break;
-#endif
-    default:
-        DPRINTF_MMU("helper_ldqf: need to check MMU idx %d\n", mem_idx);
-        break;
-    }
-#else
-    u.ll.upper = ldq_raw(address_mask(env, addr));
-    u.ll.lower = ldq_raw(address_mask(env, addr + 8));
-    QT0 = u.q;
-#endif
-}
-
-void helper_stqf(target_ulong addr, int mem_idx)
-{
-    // XXX add 128 bit store
-    CPU_QuadU u;
-
-    helper_check_align(addr, 7);
-#if !defined(CONFIG_USER_ONLY)
-    switch (mem_idx) {
-    case MMU_USER_IDX:
-        u.q = QT0;
-        stq_user(addr, u.ll.upper);
-        stq_user(addr + 8, u.ll.lower);
-        break;
-    case MMU_KERNEL_IDX:
-        u.q = QT0;
-        stq_kernel(addr, u.ll.upper);
-        stq_kernel(addr + 8, u.ll.lower);
-        break;
-#ifdef TARGET_SPARC64
-    case MMU_HYPV_IDX:
-        u.q = QT0;
-        stq_hypv(addr, u.ll.upper);
-        stq_hypv(addr + 8, u.ll.lower);
-        break;
-#endif
-    default:
-        DPRINTF_MMU("helper_stqf: need to check MMU idx %d\n", mem_idx);
-        break;
-    }
-#else
-    u.q = QT0;
-    stq_raw(address_mask(env, addr), u.ll.upper);
-    stq_raw(address_mask(env, addr + 8), u.ll.lower);
-#endif
-}
-
-static inline void set_fsr(void)
-{
-    int rnd_mode;
-
-    switch (env->fsr & FSR_RD_MASK) {
-    case FSR_RD_NEAREST:
-        rnd_mode = float_round_nearest_even;
-        break;
-    default:
-    case FSR_RD_ZERO:
-        rnd_mode = float_round_to_zero;
-        break;
-    case FSR_RD_POS:
-        rnd_mode = float_round_up;
-        break;
-    case FSR_RD_NEG:
-        rnd_mode = float_round_down;
-        break;
-    }
-    set_float_rounding_mode(rnd_mode, &env->fp_status);
-}
-
-void helper_ldfsr(uint32_t new_fsr)
-{
-    env->fsr = (new_fsr & FSR_LDFSR_MASK) | (env->fsr & FSR_LDFSR_OLDMASK);
-    set_fsr();
-}
-
-#ifdef TARGET_SPARC64
-void helper_ldxfsr(uint64_t new_fsr)
-{
-    env->fsr = (new_fsr & FSR_LDXFSR_MASK) | (env->fsr & FSR_LDXFSR_OLDMASK);
-    set_fsr();
-}
-#endif
-
-void helper_debug(void)
-{
-    env->exception_index = EXCP_DEBUG;
-    cpu_loop_exit(env);
-}
-
-#ifndef TARGET_SPARC64
-/* XXX: use another pointer for %iN registers to avoid slow wrapping
-   handling ? */
-void helper_save(void)
-{
-    uint32_t cwp;
-
-    cwp = cwp_dec(env->cwp - 1);
-    if (env->wim & (1 << cwp)) {
-        raise_exception(TT_WIN_OVF);
-    }
-    set_cwp(cwp);
-}
-
-void helper_restore(void)
-{
-    uint32_t cwp;
-
-    cwp = cwp_inc(env->cwp + 1);
-    if (env->wim & (1 << cwp)) {
-        raise_exception(TT_WIN_UNF);
-    }
-    set_cwp(cwp);
-}
-
-void helper_wrpsr(target_ulong new_psr)
-{
-    if ((new_psr & PSR_CWP) >= env->nwindows) {
-        raise_exception(TT_ILL_INSN);
-    } else {
-        cpu_put_psr(env, new_psr);
-    }
-}
-
-target_ulong helper_rdpsr(void)
-{
-    return get_psr();
-}
-
-#else
-/* XXX: use another pointer for %iN registers to avoid slow wrapping
-   handling ? */
-void helper_save(void)
-{
-    uint32_t cwp;
-
-    cwp = cwp_dec(env->cwp - 1);
-    if (env->cansave == 0) {
-        raise_exception(TT_SPILL | (env->otherwin != 0 ?
-                                    (TT_WOTHER | ((env->wstate & 0x38) >> 1)):
-                                    ((env->wstate & 0x7) << 2)));
-    } else {
-        if (env->cleanwin - env->canrestore == 0) {
-            // XXX Clean windows without trap
-            raise_exception(TT_CLRWIN);
-        } else {
-            env->cansave--;
-            env->canrestore++;
-            set_cwp(cwp);
-        }
-    }
-}
-
-void helper_restore(void)
-{
-    uint32_t cwp;
-
-    cwp = cwp_inc(env->cwp + 1);
-    if (env->canrestore == 0) {
-        raise_exception(TT_FILL | (env->otherwin != 0 ?
-                                   (TT_WOTHER | ((env->wstate & 0x38) >> 1)):
-                                   ((env->wstate & 0x7) << 2)));
-    } else {
-        env->cansave++;
-        env->canrestore--;
-        set_cwp(cwp);
-    }
-}
-
-void helper_flushw(void)
-{
-    if (env->cansave != env->nwindows - 2) {
-        raise_exception(TT_SPILL | (env->otherwin != 0 ?
-                                    (TT_WOTHER | ((env->wstate & 0x38) >> 1)):
-                                    ((env->wstate & 0x7) << 2)));
-    }
-}
-
-void helper_saved(void)
-{
-    env->cansave++;
-    if (env->otherwin == 0)
-        env->canrestore--;
-    else
-        env->otherwin--;
-}
-
-void helper_restored(void)
-{
-    env->canrestore++;
-    if (env->cleanwin < env->nwindows - 1)
-        env->cleanwin++;
-    if (env->otherwin == 0)
-        env->cansave--;
-    else
-        env->otherwin--;
-}
-
-static target_ulong get_ccr(void)
-{
-    target_ulong psr;
-
-    psr = get_psr();
-
-    return ((env->xcc >> 20) << 4) | ((psr & PSR_ICC) >> 20);
-}
-
-target_ulong cpu_get_ccr(CPUState *env1)
-{
-    CPUState *saved_env;
-    target_ulong ret;
-
-    saved_env = env;
-    env = env1;
-    ret = get_ccr();
-    env = saved_env;
-    return ret;
-}
-
-static void put_ccr(target_ulong val)
-{
-    env->xcc = (val >> 4) << 20;
-    env->psr = (val & 0xf) << 20;
-    CC_OP = CC_OP_FLAGS;
-}
-
-void cpu_put_ccr(CPUState *env1, target_ulong val)
-{
-    CPUState *saved_env;
-
-    saved_env = env;
-    env = env1;
-    put_ccr(val);
-    env = saved_env;
-}
-
-static target_ulong get_cwp64(void)
-{
-    return env->nwindows - 1 - env->cwp;
-}
-
-target_ulong cpu_get_cwp64(CPUState *env1)
-{
-    CPUState *saved_env;
-    target_ulong ret;
-
-    saved_env = env;
-    env = env1;
-    ret = get_cwp64();
-    env = saved_env;
-    return ret;
-}
-
-static void put_cwp64(int cwp)
-{
-    if (unlikely(cwp >= env->nwindows || cwp < 0)) {
-        cwp %= env->nwindows;
-    }
-    set_cwp(env->nwindows - 1 - cwp);
-}
-
-void cpu_put_cwp64(CPUState *env1, int cwp)
-{
-    CPUState *saved_env;
-
-    saved_env = env;
-    env = env1;
-    put_cwp64(cwp);
-    env = saved_env;
-}
-
-target_ulong helper_rdccr(void)
-{
-    return get_ccr();
-}
-
-void helper_wrccr(target_ulong new_ccr)
-{
-    put_ccr(new_ccr);
-}
-
-// CWP handling is reversed in V9, but we still use the V8 register
-// order.
-target_ulong helper_rdcwp(void)
-{
-    return get_cwp64();
-}
-
-void helper_wrcwp(target_ulong new_cwp)
-{
-    put_cwp64(new_cwp);
-}
-
-// This function uses non-native bit order
-#define GET_FIELD(X, FROM, TO)                                  \
-    ((X) >> (63 - (TO)) & ((1ULL << ((TO) - (FROM) + 1)) - 1))
-
-// This function uses the order in the manuals, i.e. bit 0 is 2^0
-#define GET_FIELD_SP(X, FROM, TO)               \
-    GET_FIELD(X, 63 - (TO), 63 - (FROM))
-
-target_ulong helper_array8(target_ulong pixel_addr, target_ulong cubesize)
-{
-    return (GET_FIELD_SP(pixel_addr, 60, 63) << (17 + 2 * cubesize)) |
-        (GET_FIELD_SP(pixel_addr, 39, 39 + cubesize - 1) << (17 + cubesize)) |
-        (GET_FIELD_SP(pixel_addr, 17 + cubesize - 1, 17) << 17) |
-        (GET_FIELD_SP(pixel_addr, 56, 59) << 13) |
-        (GET_FIELD_SP(pixel_addr, 35, 38) << 9) |
-        (GET_FIELD_SP(pixel_addr, 13, 16) << 5) |
-        (((pixel_addr >> 55) & 1) << 4) |
-        (GET_FIELD_SP(pixel_addr, 33, 34) << 2) |
-        GET_FIELD_SP(pixel_addr, 11, 12);
-}
-
-target_ulong helper_alignaddr(target_ulong addr, target_ulong offset)
-{
-    uint64_t tmp;
-
-    tmp = addr + offset;
-    env->gsr &= ~7ULL;
-    env->gsr |= tmp & 7ULL;
-    return tmp & ~7ULL;
-}
-
-target_ulong helper_popc(target_ulong val)
-{
-    return ctpop64(val);
-}
-
-static inline uint64_t *get_gregset(uint32_t pstate)
-{
-    switch (pstate) {
-    default:
-        DPRINTF_PSTATE("ERROR in get_gregset: active pstate bits=%x%s%s%s\n",
-                pstate,
-                (pstate & PS_IG) ? " IG" : "",
-                (pstate & PS_MG) ? " MG" : "",
-                (pstate & PS_AG) ? " AG" : "");
-        /* pass through to normal set of global registers */
-    case 0:
-        return env->bgregs;
-    case PS_AG:
-        return env->agregs;
-    case PS_MG:
-        return env->mgregs;
-    case PS_IG:
-        return env->igregs;
-    }
-}
-
-static inline void change_pstate(uint32_t new_pstate)
-{
-    uint32_t pstate_regs, new_pstate_regs;
-    uint64_t *src, *dst;
-
-    if (env->def->features & CPU_FEATURE_GL) {
-        // PS_AG is not implemented in this case
-        new_pstate &= ~PS_AG;
-    }
-
-    pstate_regs = env->pstate & 0xc01;
-    new_pstate_regs = new_pstate & 0xc01;
-
-    if (new_pstate_regs != pstate_regs) {
-        DPRINTF_PSTATE("change_pstate: switching regs old=%x new=%x\n",
-                       pstate_regs, new_pstate_regs);
-        // Switch global register bank
-        src = get_gregset(new_pstate_regs);
-        dst = get_gregset(pstate_regs);
-        memcpy32(dst, env->gregs);
-        memcpy32(env->gregs, src);
-    }
-    else {
-        DPRINTF_PSTATE("change_pstate: regs new=%x (unchanged)\n",
-                       new_pstate_regs);
-    }
-    env->pstate = new_pstate;
-}
-
-void helper_wrpstate(target_ulong new_state)
-{
-    change_pstate(new_state & 0xf3f);
-
-#if !defined(CONFIG_USER_ONLY)
-    if (cpu_interrupts_enabled(env)) {
-        cpu_check_irqs(env);
-    }
-#endif
-}
-
-void cpu_change_pstate(CPUState *env1, uint32_t new_pstate)
-{
-    CPUState *saved_env;
-
-    saved_env = env;
-    env = env1;
-    change_pstate(new_pstate);
-    env = saved_env;
-}
-
-void helper_wrpil(target_ulong new_pil)
-{
-#if !defined(CONFIG_USER_ONLY)
-    DPRINTF_PSTATE("helper_wrpil old=%x new=%x\n",
-                   env->psrpil, (uint32_t)new_pil);
-
-    env->psrpil = new_pil;
-
-    if (cpu_interrupts_enabled(env)) {
-        cpu_check_irqs(env);
-    }
-#endif
-}
-
-void helper_done(void)
-{
-    trap_state* tsptr = cpu_tsptr(env);
-
-    env->pc = tsptr->tnpc;
-    env->npc = tsptr->tnpc + 4;
-    put_ccr(tsptr->tstate >> 32);
-    env->asi = (tsptr->tstate >> 24) & 0xff;
-    change_pstate((tsptr->tstate >> 8) & 0xf3f);
-    put_cwp64(tsptr->tstate & 0xff);
-    env->tl--;
-
-    DPRINTF_PSTATE("... helper_done tl=%d\n", env->tl);
-
-#if !defined(CONFIG_USER_ONLY)
-    if (cpu_interrupts_enabled(env)) {
-        cpu_check_irqs(env);
-    }
-#endif
-}
-
-void helper_retry(void)
-{
-    trap_state* tsptr = cpu_tsptr(env);
-
-    env->pc = tsptr->tpc;
-    env->npc = tsptr->tnpc;
-    put_ccr(tsptr->tstate >> 32);
-    env->asi = (tsptr->tstate >> 24) & 0xff;
-    change_pstate((tsptr->tstate >> 8) & 0xf3f);
-    put_cwp64(tsptr->tstate & 0xff);
-    env->tl--;
-
-    DPRINTF_PSTATE("... helper_retry tl=%d\n", env->tl);
-
-#if !defined(CONFIG_USER_ONLY)
-    if (cpu_interrupts_enabled(env)) {
-        cpu_check_irqs(env);
-    }
-#endif
-}
-
-static void do_modify_softint(const char* operation, uint32_t value)
-{
-    if (env->softint != value) {
-        env->softint = value;
-        DPRINTF_PSTATE(": %s new %08x\n", operation, env->softint);
-#if !defined(CONFIG_USER_ONLY)
-        if (cpu_interrupts_enabled(env)) {
-            cpu_check_irqs(env);
-        }
-#endif
-    }
-}
-
-void helper_set_softint(uint64_t value)
-{
-    do_modify_softint("helper_set_softint", env->softint | (uint32_t)value);
-}
-
-void helper_clear_softint(uint64_t value)
-{
-    do_modify_softint("helper_clear_softint", env->softint & (uint32_t)~value);
-}
-
-void helper_write_softint(uint64_t value)
-{
-    do_modify_softint("helper_write_softint", (uint32_t)value);
-}
-#endif
-
-#ifdef TARGET_SPARC64
-trap_state* cpu_tsptr(CPUState* env)
-{
-    return &env->ts[env->tl & MAXTL_MASK];
-}
-#endif
-
-#if !defined(CONFIG_USER_ONLY)
-
 static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
                                 void *retaddr);
 
@@ -4218,7 +47,7 @@
            "\n", addr, env->pc);
 #endif
     cpu_restore_state2(retaddr);
-    raise_exception(TT_UNALIGNED);
+    helper_raise_exception(env, TT_UNALIGNED);
 }
 
 /* try to fill the TLB and return an exception if error. If retaddr is
@@ -4243,122 +72,3 @@
 }
 
 #endif /* !CONFIG_USER_ONLY */
-
-#ifndef TARGET_SPARC64
-#if !defined(CONFIG_USER_ONLY)
-static void do_unassigned_access(target_phys_addr_t addr, int is_write,
-                                 int is_exec, int is_asi, int size)
-{
-    int fault_type;
-
-#ifdef DEBUG_UNASSIGNED
-    if (is_asi)
-        printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx
-               " asi 0x%02x from " TARGET_FMT_lx "\n",
-               is_exec ? "exec" : is_write ? "write" : "read", size,
-               size == 1 ? "" : "s", addr, is_asi, env->pc);
-    else
-        printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx
-               " from " TARGET_FMT_lx "\n",
-               is_exec ? "exec" : is_write ? "write" : "read", size,
-               size == 1 ? "" : "s", addr, env->pc);
-#endif
-    /* Don't overwrite translation and access faults */
-    fault_type = (env->mmuregs[3] & 0x1c) >> 2;
-    if ((fault_type > 4) || (fault_type == 0)) {
-        env->mmuregs[3] = 0; /* Fault status register */
-        if (is_asi)
-            env->mmuregs[3] |= 1 << 16;
-        if (env->psrs)
-            env->mmuregs[3] |= 1 << 5;
-        if (is_exec)
-            env->mmuregs[3] |= 1 << 6;
-        if (is_write)
-            env->mmuregs[3] |= 1 << 7;
-        env->mmuregs[3] |= (5 << 2) | 2;
-        /* SuperSPARC will never place instruction fault addresses in the FAR */
-        if (!is_exec) {
-            env->mmuregs[4] = addr; /* Fault address register */
-        }
-    }
-    /* overflow (same type fault was not read before another fault) */
-    if (fault_type == ((env->mmuregs[3] & 0x1c)) >> 2) {
-        env->mmuregs[3] |= 1;
-    }
-
-    if ((env->mmuregs[0] & MMU_E) && !(env->mmuregs[0] & MMU_NF)) {
-        if (is_exec)
-            raise_exception(TT_CODE_ACCESS);
-        else
-            raise_exception(TT_DATA_ACCESS);
-    }
-
-    /* flush neverland mappings created during no-fault mode,
-       so the sequential MMU faults report proper fault types */
-    if (env->mmuregs[0] & MMU_NF) {
-        tlb_flush(env, 1);
-    }
-}
-#endif
-#else
-#if defined(CONFIG_USER_ONLY)
-static void do_unassigned_access(target_ulong addr, int is_write, int is_exec,
-                          int is_asi, int size)
-#else
-static void do_unassigned_access(target_phys_addr_t addr, int is_write,
-                                 int is_exec, int is_asi, int size)
-#endif
-{
-#ifdef DEBUG_UNASSIGNED
-    printf("Unassigned mem access to " TARGET_FMT_plx " from " TARGET_FMT_lx
-           "\n", addr, env->pc);
-#endif
-
-    if (is_exec)
-        raise_exception(TT_CODE_ACCESS);
-    else
-        raise_exception(TT_DATA_ACCESS);
-}
-#endif
-
-
-#ifdef TARGET_SPARC64
-void helper_tick_set_count(void *opaque, uint64_t count)
-{
-#if !defined(CONFIG_USER_ONLY)
-    cpu_tick_set_count(opaque, count);
-#endif
-}
-
-uint64_t helper_tick_get_count(void *opaque)
-{
-#if !defined(CONFIG_USER_ONLY)
-    return cpu_tick_get_count(opaque);
-#else
-    return 0;
-#endif
-}
-
-void helper_tick_set_limit(void *opaque, uint64_t limit)
-{
-#if !defined(CONFIG_USER_ONLY)
-    cpu_tick_set_limit(opaque, limit);
-#endif
-}
-#endif
-
-#if !defined(CONFIG_USER_ONLY)
-void cpu_unassigned_access(CPUState *env1, target_phys_addr_t addr,
-                           int is_write, int is_exec, int is_asi, int size)
-{
-    CPUState *saved_env;
-
-    saved_env = env;
-    env = env1;
-    /* Ignore unassigned accesses outside of CPU context */
-    if (env1) {
-        do_unassigned_access(addr, is_write, is_exec, is_asi, size);
-    }
-    env = saved_env;
-}
-#endif
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index dee67b3..383fd9c 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -294,7 +294,7 @@
     tcg_gen_andi_tl(r_temp, r_temp, (1ULL << 31));
     tcg_gen_brcondi_tl(TCG_COND_EQ, r_temp, 0, l1);
     r_const = tcg_const_i32(TT_TOVF);
-    gen_helper_raise_exception(r_const);
+    gen_helper_raise_exception(cpu_env, r_const);
     tcg_temp_free_i32(r_const);
     gen_set_label(l1);
     tcg_temp_free(r_temp);
@@ -310,7 +310,7 @@
     tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, 0x3);
     tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_tmp0, 0, l1);
     r_const = tcg_const_i32(TT_TOVF);
-    gen_helper_raise_exception(r_const);
+    gen_helper_raise_exception(cpu_env, r_const);
     tcg_temp_free_i32(r_const);
     gen_set_label(l1);
 }
@@ -428,7 +428,7 @@
     default:
         /* We need external help to produce the carry.  */
         carry_32 = tcg_temp_new_i32();
-        gen_helper_compute_C_icc(carry_32);
+        gen_helper_compute_C_icc(carry_32, cpu_env);
         break;
     }
 
@@ -492,7 +492,7 @@
     tcg_gen_andi_tl(r_temp, r_temp, (1ULL << 31));
     tcg_gen_brcondi_tl(TCG_COND_EQ, r_temp, 0, l1);
     r_const = tcg_const_i32(TT_TOVF);
-    gen_helper_raise_exception(r_const);
+    gen_helper_raise_exception(cpu_env, r_const);
     tcg_temp_free_i32(r_const);
     gen_set_label(l1);
     tcg_temp_free(r_temp);
@@ -567,7 +567,7 @@
     default:
         /* We need external help to produce the carry.  */
         carry_32 = tcg_temp_new_i32();
-        gen_helper_compute_C_icc(carry_32);
+        gen_helper_compute_C_icc(carry_32, cpu_env);
         break;
     }
 
@@ -719,7 +719,7 @@
     l1 = gen_new_label();
     tcg_gen_brcondi_tl(TCG_COND_NE, divisor, 0, l1);
     r_const = tcg_const_i32(TT_DIV_ZERO);
-    gen_helper_raise_exception(r_const);
+    gen_helper_raise_exception(cpu_env, r_const);
     tcg_temp_free_i32(r_const);
     gen_set_label(l1);
 }
@@ -1091,7 +1091,7 @@
     /* flush pending conditional evaluations before exposing cpu state */
     if (dc->cc_op != CC_OP_FLAGS) {
         dc->cc_op = CC_OP_FLAGS;
-        gen_helper_compute_psr();
+        gen_helper_compute_psr(cpu_env);
     }
     save_npc(dc, cond);
 }
@@ -1133,7 +1133,7 @@
     case CC_OP_FLAGS:
         break;
     default:
-        gen_helper_compute_psr();
+        gen_helper_compute_psr(cpu_env);
         dc->cc_op = CC_OP_FLAGS;
         break;
     }
@@ -1405,16 +1405,16 @@
 {
     switch (fccno) {
     case 0:
-        gen_helper_fcmps(r_rs1, r_rs2);
+        gen_helper_fcmps(cpu_env, r_rs1, r_rs2);
         break;
     case 1:
-        gen_helper_fcmps_fcc1(r_rs1, r_rs2);
+        gen_helper_fcmps_fcc1(cpu_env, r_rs1, r_rs2);
         break;
     case 2:
-        gen_helper_fcmps_fcc2(r_rs1, r_rs2);
+        gen_helper_fcmps_fcc2(cpu_env, r_rs1, r_rs2);
         break;
     case 3:
-        gen_helper_fcmps_fcc3(r_rs1, r_rs2);
+        gen_helper_fcmps_fcc3(cpu_env, r_rs1, r_rs2);
         break;
     }
 }
@@ -1423,16 +1423,16 @@
 {
     switch (fccno) {
     case 0:
-        gen_helper_fcmpd();
+        gen_helper_fcmpd(cpu_env);
         break;
     case 1:
-        gen_helper_fcmpd_fcc1();
+        gen_helper_fcmpd_fcc1(cpu_env);
         break;
     case 2:
-        gen_helper_fcmpd_fcc2();
+        gen_helper_fcmpd_fcc2(cpu_env);
         break;
     case 3:
-        gen_helper_fcmpd_fcc3();
+        gen_helper_fcmpd_fcc3(cpu_env);
         break;
     }
 }
@@ -1441,16 +1441,16 @@
 {
     switch (fccno) {
     case 0:
-        gen_helper_fcmpq();
+        gen_helper_fcmpq(cpu_env);
         break;
     case 1:
-        gen_helper_fcmpq_fcc1();
+        gen_helper_fcmpq_fcc1(cpu_env);
         break;
     case 2:
-        gen_helper_fcmpq_fcc2();
+        gen_helper_fcmpq_fcc2(cpu_env);
         break;
     case 3:
-        gen_helper_fcmpq_fcc3();
+        gen_helper_fcmpq_fcc3(cpu_env);
         break;
     }
 }
@@ -1459,16 +1459,16 @@
 {
     switch (fccno) {
     case 0:
-        gen_helper_fcmpes(r_rs1, r_rs2);
+        gen_helper_fcmpes(cpu_env, r_rs1, r_rs2);
         break;
     case 1:
-        gen_helper_fcmpes_fcc1(r_rs1, r_rs2);
+        gen_helper_fcmpes_fcc1(cpu_env, r_rs1, r_rs2);
         break;
     case 2:
-        gen_helper_fcmpes_fcc2(r_rs1, r_rs2);
+        gen_helper_fcmpes_fcc2(cpu_env, r_rs1, r_rs2);
         break;
     case 3:
-        gen_helper_fcmpes_fcc3(r_rs1, r_rs2);
+        gen_helper_fcmpes_fcc3(cpu_env, r_rs1, r_rs2);
         break;
     }
 }
@@ -1477,16 +1477,16 @@
 {
     switch (fccno) {
     case 0:
-        gen_helper_fcmped();
+        gen_helper_fcmped(cpu_env);
         break;
     case 1:
-        gen_helper_fcmped_fcc1();
+        gen_helper_fcmped_fcc1(cpu_env);
         break;
     case 2:
-        gen_helper_fcmped_fcc2();
+        gen_helper_fcmped_fcc2(cpu_env);
         break;
     case 3:
-        gen_helper_fcmped_fcc3();
+        gen_helper_fcmped_fcc3(cpu_env);
         break;
     }
 }
@@ -1495,16 +1495,16 @@
 {
     switch (fccno) {
     case 0:
-        gen_helper_fcmpeq();
+        gen_helper_fcmpeq(cpu_env);
         break;
     case 1:
-        gen_helper_fcmpeq_fcc1();
+        gen_helper_fcmpeq_fcc1(cpu_env);
         break;
     case 2:
-        gen_helper_fcmpeq_fcc2();
+        gen_helper_fcmpeq_fcc2(cpu_env);
         break;
     case 3:
-        gen_helper_fcmpeq_fcc3();
+        gen_helper_fcmpeq_fcc3(cpu_env);
         break;
     }
 }
@@ -1513,32 +1513,32 @@
 
 static inline void gen_op_fcmps(int fccno, TCGv r_rs1, TCGv r_rs2)
 {
-    gen_helper_fcmps(r_rs1, r_rs2);
+    gen_helper_fcmps(cpu_env, r_rs1, r_rs2);
 }
 
 static inline void gen_op_fcmpd(int fccno)
 {
-    gen_helper_fcmpd();
+    gen_helper_fcmpd(cpu_env);
 }
 
 static inline void gen_op_fcmpq(int fccno)
 {
-    gen_helper_fcmpq();
+    gen_helper_fcmpq(cpu_env);
 }
 
 static inline void gen_op_fcmpes(int fccno, TCGv r_rs1, TCGv r_rs2)
 {
-    gen_helper_fcmpes(r_rs1, r_rs2);
+    gen_helper_fcmpes(cpu_env, r_rs1, r_rs2);
 }
 
 static inline void gen_op_fcmped(int fccno)
 {
-    gen_helper_fcmped();
+    gen_helper_fcmped(cpu_env);
 }
 
 static inline void gen_op_fcmpeq(int fccno)
 {
-    gen_helper_fcmpeq();
+    gen_helper_fcmpeq(cpu_env);
 }
 #endif
 
@@ -1549,7 +1549,7 @@
     tcg_gen_andi_tl(cpu_fsr, cpu_fsr, FSR_FTT_NMASK);
     tcg_gen_ori_tl(cpu_fsr, cpu_fsr, fsr_flags);
     r_const = tcg_const_i32(TT_FP_EXCP);
-    gen_helper_raise_exception(r_const);
+    gen_helper_raise_exception(cpu_env, r_const);
     tcg_temp_free_i32(r_const);
 }
 
@@ -1561,7 +1561,7 @@
 
         save_state(dc, r_cond);
         r_const = tcg_const_i32(TT_NFPU_INSN);
-        gen_helper_raise_exception(r_const);
+        gen_helper_raise_exception(cpu_env, r_const);
         tcg_temp_free_i32(r_const);
         dc->is_br = 1;
         return 1;
@@ -1584,7 +1584,7 @@
 
 static inline void gen_clear_float_exceptions(void)
 {
-    gen_helper_clear_float_exceptions();
+    gen_helper_clear_float_exceptions(cpu_env);
 }
 
 /* asi moves */
@@ -2038,7 +2038,7 @@
                         gen_helper_shutdown();
 
                     } else {
-                        gen_helper_raise_exception(cpu_tmp32);
+                        gen_helper_raise_exception(cpu_env, cpu_tmp32);
                     }
                 } else if (cond != 0) {
                     TCGv r_cond = tcg_temp_new();
@@ -2068,7 +2068,7 @@
                         tcg_gen_andi_tl(cpu_dst, cpu_dst, V8_TRAP_MASK);
                     tcg_gen_addi_tl(cpu_dst, cpu_dst, TT_TRAP);
                     tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_dst);
-                    gen_helper_raise_exception(cpu_tmp32);
+                    gen_helper_raise_exception(cpu_env, cpu_tmp32);
 
                     gen_set_label(l1);
                     tcg_temp_free(r_cond);
@@ -2106,8 +2106,8 @@
                     break;
 #ifdef TARGET_SPARC64
                 case 0x2: /* V9 rdccr */
-                    gen_helper_compute_psr();
-                    gen_helper_rdccr(cpu_dst);
+                    gen_helper_compute_psr(cpu_env);
+                    gen_helper_rdccr(cpu_dst, cpu_env);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x3: /* V9 rdasi */
@@ -2182,9 +2182,9 @@
 #ifndef TARGET_SPARC64
                 if (!supervisor(dc))
                     goto priv_insn;
-                gen_helper_compute_psr();
+                gen_helper_compute_psr(cpu_env);
                 dc->cc_op = CC_OP_FLAGS;
-                gen_helper_rdpsr(cpu_dst);
+                gen_helper_rdpsr(cpu_dst, cpu_env);
 #else
                 CHECK_IU_FEATURE(dc, HYPV);
                 if (!hypervisor(dc))
@@ -2297,7 +2297,7 @@
                     tcg_gen_ext_i32_tl(cpu_tmp0, cpu_tmp32);
                     break;
                 case 9: // cwp
-                    gen_helper_rdcwp(cpu_tmp0);
+                    gen_helper_rdcwp(cpu_tmp0, cpu_env);
                     break;
                 case 10: // cansave
                     tcg_gen_ld_i32(cpu_tmp32, cpu_env,
@@ -2351,7 +2351,7 @@
             } else if (xop == 0x2b) { /* rdtbr / V9 flushw */
 #ifdef TARGET_SPARC64
                 save_state(dc, cpu_cond);
-                gen_helper_flushw();
+                gen_helper_flushw(cpu_env);
 #else
                 if (!supervisor(dc))
                     goto priv_insn;
@@ -2383,8 +2383,8 @@
                 case 0x29: /* fsqrts */
                     CHECK_FPU_FEATURE(dc, FSQRT);
                     gen_clear_float_exceptions();
-                    gen_helper_fsqrts(cpu_tmp32, cpu_fpr[rs2]);
-                    gen_helper_check_ieee_exceptions();
+                    gen_helper_fsqrts(cpu_tmp32, cpu_env, cpu_fpr[rs2]);
+                    gen_helper_check_ieee_exceptions(cpu_env);
                     tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
                     gen_update_fprs_dirty(rd);
                     break;
@@ -2392,8 +2392,8 @@
                     CHECK_FPU_FEATURE(dc, FSQRT);
                     gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_clear_float_exceptions();
-                    gen_helper_fsqrtd();
-                    gen_helper_check_ieee_exceptions();
+                    gen_helper_fsqrtd(cpu_env);
+                    gen_helper_check_ieee_exceptions(cpu_env);
                     gen_op_store_DT0_fpr(DFPREG(rd));
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
@@ -2401,15 +2401,16 @@
                     CHECK_FPU_FEATURE(dc, FLOAT128);
                     gen_op_load_fpr_QT1(QFPREG(rs2));
                     gen_clear_float_exceptions();
-                    gen_helper_fsqrtq();
-                    gen_helper_check_ieee_exceptions();
+                    gen_helper_fsqrtq(cpu_env);
+                    gen_helper_check_ieee_exceptions(cpu_env);
                     gen_op_store_QT0_fpr(QFPREG(rd));
                     gen_update_fprs_dirty(QFPREG(rd));
                     break;
                 case 0x41: /* fadds */
                     gen_clear_float_exceptions();
-                    gen_helper_fadds(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]);
-                    gen_helper_check_ieee_exceptions();
+                    gen_helper_fadds(cpu_tmp32, cpu_env, cpu_fpr[rs1],
+                                     cpu_fpr[rs2]);
+                    gen_helper_check_ieee_exceptions(cpu_env);
                     tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
                     gen_update_fprs_dirty(rd);
                     break;
@@ -2417,8 +2418,8 @@
                     gen_op_load_fpr_DT0(DFPREG(rs1));
                     gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_clear_float_exceptions();
-                    gen_helper_faddd();
-                    gen_helper_check_ieee_exceptions();
+                    gen_helper_faddd(cpu_env);
+                    gen_helper_check_ieee_exceptions(cpu_env);
                     gen_op_store_DT0_fpr(DFPREG(rd));
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
@@ -2427,15 +2428,16 @@
                     gen_op_load_fpr_QT0(QFPREG(rs1));
                     gen_op_load_fpr_QT1(QFPREG(rs2));
                     gen_clear_float_exceptions();
-                    gen_helper_faddq();
-                    gen_helper_check_ieee_exceptions();
+                    gen_helper_faddq(cpu_env);
+                    gen_helper_check_ieee_exceptions(cpu_env);
                     gen_op_store_QT0_fpr(QFPREG(rd));
                     gen_update_fprs_dirty(QFPREG(rd));
                     break;
                 case 0x45: /* fsubs */
                     gen_clear_float_exceptions();
-                    gen_helper_fsubs(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]);
-                    gen_helper_check_ieee_exceptions();
+                    gen_helper_fsubs(cpu_tmp32, cpu_env, cpu_fpr[rs1],
+                                     cpu_fpr[rs2]);
+                    gen_helper_check_ieee_exceptions(cpu_env);
                     tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
                     gen_update_fprs_dirty(rd);
                     break;
@@ -2443,8 +2445,8 @@
                     gen_op_load_fpr_DT0(DFPREG(rs1));
                     gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_clear_float_exceptions();
-                    gen_helper_fsubd();
-                    gen_helper_check_ieee_exceptions();
+                    gen_helper_fsubd(cpu_env);
+                    gen_helper_check_ieee_exceptions(cpu_env);
                     gen_op_store_DT0_fpr(DFPREG(rd));
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
@@ -2453,16 +2455,17 @@
                     gen_op_load_fpr_QT0(QFPREG(rs1));
                     gen_op_load_fpr_QT1(QFPREG(rs2));
                     gen_clear_float_exceptions();
-                    gen_helper_fsubq();
-                    gen_helper_check_ieee_exceptions();
+                    gen_helper_fsubq(cpu_env);
+                    gen_helper_check_ieee_exceptions(cpu_env);
                     gen_op_store_QT0_fpr(QFPREG(rd));
                     gen_update_fprs_dirty(QFPREG(rd));
                     break;
                 case 0x49: /* fmuls */
                     CHECK_FPU_FEATURE(dc, FMUL);
                     gen_clear_float_exceptions();
-                    gen_helper_fmuls(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]);
-                    gen_helper_check_ieee_exceptions();
+                    gen_helper_fmuls(cpu_tmp32, cpu_env, cpu_fpr[rs1],
+                                     cpu_fpr[rs2]);
+                    gen_helper_check_ieee_exceptions(cpu_env);
                     tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
                     gen_update_fprs_dirty(rd);
                     break;
@@ -2471,8 +2474,8 @@
                     gen_op_load_fpr_DT0(DFPREG(rs1));
                     gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_clear_float_exceptions();
-                    gen_helper_fmuld();
-                    gen_helper_check_ieee_exceptions();
+                    gen_helper_fmuld(cpu_env);
+                    gen_helper_check_ieee_exceptions(cpu_env);
                     gen_op_store_DT0_fpr(DFPREG(rd));
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
@@ -2482,15 +2485,16 @@
                     gen_op_load_fpr_QT0(QFPREG(rs1));
                     gen_op_load_fpr_QT1(QFPREG(rs2));
                     gen_clear_float_exceptions();
-                    gen_helper_fmulq();
-                    gen_helper_check_ieee_exceptions();
+                    gen_helper_fmulq(cpu_env);
+                    gen_helper_check_ieee_exceptions(cpu_env);
                     gen_op_store_QT0_fpr(QFPREG(rd));
                     gen_update_fprs_dirty(QFPREG(rd));
                     break;
                 case 0x4d: /* fdivs */
                     gen_clear_float_exceptions();
-                    gen_helper_fdivs(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]);
-                    gen_helper_check_ieee_exceptions();
+                    gen_helper_fdivs(cpu_tmp32, cpu_env, cpu_fpr[rs1],
+                                     cpu_fpr[rs2]);
+                    gen_helper_check_ieee_exceptions(cpu_env);
                     tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
                     gen_update_fprs_dirty(rd);
                     break;
@@ -2498,8 +2502,8 @@
                     gen_op_load_fpr_DT0(DFPREG(rs1));
                     gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_clear_float_exceptions();
-                    gen_helper_fdivd();
-                    gen_helper_check_ieee_exceptions();
+                    gen_helper_fdivd(cpu_env);
+                    gen_helper_check_ieee_exceptions(cpu_env);
                     gen_op_store_DT0_fpr(DFPREG(rd));
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
@@ -2508,16 +2512,16 @@
                     gen_op_load_fpr_QT0(QFPREG(rs1));
                     gen_op_load_fpr_QT1(QFPREG(rs2));
                     gen_clear_float_exceptions();
-                    gen_helper_fdivq();
-                    gen_helper_check_ieee_exceptions();
+                    gen_helper_fdivq(cpu_env);
+                    gen_helper_check_ieee_exceptions(cpu_env);
                     gen_op_store_QT0_fpr(QFPREG(rd));
                     gen_update_fprs_dirty(QFPREG(rd));
                     break;
                 case 0x69: /* fsmuld */
                     CHECK_FPU_FEATURE(dc, FSMULD);
                     gen_clear_float_exceptions();
-                    gen_helper_fsmuld(cpu_fpr[rs1], cpu_fpr[rs2]);
-                    gen_helper_check_ieee_exceptions();
+                    gen_helper_fsmuld(cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
+                    gen_helper_check_ieee_exceptions(cpu_env);
                     gen_op_store_DT0_fpr(DFPREG(rd));
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
@@ -2526,23 +2530,23 @@
                     gen_op_load_fpr_DT0(DFPREG(rs1));
                     gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_clear_float_exceptions();
-                    gen_helper_fdmulq();
-                    gen_helper_check_ieee_exceptions();
+                    gen_helper_fdmulq(cpu_env);
+                    gen_helper_check_ieee_exceptions(cpu_env);
                     gen_op_store_QT0_fpr(QFPREG(rd));
                     gen_update_fprs_dirty(QFPREG(rd));
                     break;
                 case 0xc4: /* fitos */
                     gen_clear_float_exceptions();
-                    gen_helper_fitos(cpu_tmp32, cpu_fpr[rs2]);
-                    gen_helper_check_ieee_exceptions();
+                    gen_helper_fitos(cpu_tmp32, cpu_env, cpu_fpr[rs2]);
+                    gen_helper_check_ieee_exceptions(cpu_env);
                     tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
                     gen_update_fprs_dirty(rd);
                     break;
                 case 0xc6: /* fdtos */
                     gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_clear_float_exceptions();
-                    gen_helper_fdtos(cpu_tmp32);
-                    gen_helper_check_ieee_exceptions();
+                    gen_helper_fdtos(cpu_tmp32, cpu_env);
+                    gen_helper_check_ieee_exceptions(cpu_env);
                     tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
                     gen_update_fprs_dirty(rd);
                     break;
@@ -2550,18 +2554,18 @@
                     CHECK_FPU_FEATURE(dc, FLOAT128);
                     gen_op_load_fpr_QT1(QFPREG(rs2));
                     gen_clear_float_exceptions();
-                    gen_helper_fqtos(cpu_tmp32);
-                    gen_helper_check_ieee_exceptions();
+                    gen_helper_fqtos(cpu_tmp32, cpu_env);
+                    gen_helper_check_ieee_exceptions(cpu_env);
                     tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
                     gen_update_fprs_dirty(rd);
                     break;
                 case 0xc8: /* fitod */
-                    gen_helper_fitod(cpu_fpr[rs2]);
+                    gen_helper_fitod(cpu_env, cpu_fpr[rs2]);
                     gen_op_store_DT0_fpr(DFPREG(rd));
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0xc9: /* fstod */
-                    gen_helper_fstod(cpu_fpr[rs2]);
+                    gen_helper_fstod(cpu_env, cpu_fpr[rs2]);
                     gen_op_store_DT0_fpr(DFPREG(rd));
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
@@ -2569,42 +2573,42 @@
                     CHECK_FPU_FEATURE(dc, FLOAT128);
                     gen_op_load_fpr_QT1(QFPREG(rs2));
                     gen_clear_float_exceptions();
-                    gen_helper_fqtod();
-                    gen_helper_check_ieee_exceptions();
+                    gen_helper_fqtod(cpu_env);
+                    gen_helper_check_ieee_exceptions(cpu_env);
                     gen_op_store_DT0_fpr(DFPREG(rd));
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0xcc: /* fitoq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    gen_helper_fitoq(cpu_fpr[rs2]);
+                    gen_helper_fitoq(cpu_env, cpu_fpr[rs2]);
                     gen_op_store_QT0_fpr(QFPREG(rd));
                     gen_update_fprs_dirty(QFPREG(rd));
                     break;
                 case 0xcd: /* fstoq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    gen_helper_fstoq(cpu_fpr[rs2]);
+                    gen_helper_fstoq(cpu_env, cpu_fpr[rs2]);
                     gen_op_store_QT0_fpr(QFPREG(rd));
                     gen_update_fprs_dirty(QFPREG(rd));
                     break;
                 case 0xce: /* fdtoq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
                     gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fdtoq();
+                    gen_helper_fdtoq(cpu_env);
                     gen_op_store_QT0_fpr(QFPREG(rd));
                     gen_update_fprs_dirty(QFPREG(rd));
                     break;
                 case 0xd1: /* fstoi */
                     gen_clear_float_exceptions();
-                    gen_helper_fstoi(cpu_tmp32, cpu_fpr[rs2]);
-                    gen_helper_check_ieee_exceptions();
+                    gen_helper_fstoi(cpu_tmp32, cpu_env, cpu_fpr[rs2]);
+                    gen_helper_check_ieee_exceptions(cpu_env);
                     tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
                     gen_update_fprs_dirty(rd);
                     break;
                 case 0xd2: /* fdtoi */
                     gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_clear_float_exceptions();
-                    gen_helper_fdtoi(cpu_tmp32);
-                    gen_helper_check_ieee_exceptions();
+                    gen_helper_fdtoi(cpu_tmp32, cpu_env);
+                    gen_helper_check_ieee_exceptions(cpu_env);
                     tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
                     gen_update_fprs_dirty(rd);
                     break;
@@ -2612,8 +2616,8 @@
                     CHECK_FPU_FEATURE(dc, FLOAT128);
                     gen_op_load_fpr_QT1(QFPREG(rs2));
                     gen_clear_float_exceptions();
-                    gen_helper_fqtoi(cpu_tmp32);
-                    gen_helper_check_ieee_exceptions();
+                    gen_helper_fqtoi(cpu_tmp32, cpu_env);
+                    gen_helper_check_ieee_exceptions(cpu_env);
                     tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
                     gen_update_fprs_dirty(rd);
                     break;
@@ -2637,42 +2641,42 @@
                     break;
                 case 0x6: /* V9 fnegd */
                     gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fnegd();
+                    gen_helper_fnegd(cpu_env);
                     gen_op_store_DT0_fpr(DFPREG(rd));
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x7: /* V9 fnegq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
                     gen_op_load_fpr_QT1(QFPREG(rs2));
-                    gen_helper_fnegq();
+                    gen_helper_fnegq(cpu_env);
                     gen_op_store_QT0_fpr(QFPREG(rd));
                     gen_update_fprs_dirty(QFPREG(rd));
                     break;
                 case 0xa: /* V9 fabsd */
                     gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fabsd();
+                    gen_helper_fabsd(cpu_env);
                     gen_op_store_DT0_fpr(DFPREG(rd));
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0xb: /* V9 fabsq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
                     gen_op_load_fpr_QT1(QFPREG(rs2));
-                    gen_helper_fabsq();
+                    gen_helper_fabsq(cpu_env);
                     gen_op_store_QT0_fpr(QFPREG(rd));
                     gen_update_fprs_dirty(QFPREG(rd));
                     break;
                 case 0x81: /* V9 fstox */
                     gen_clear_float_exceptions();
-                    gen_helper_fstox(cpu_fpr[rs2]);
-                    gen_helper_check_ieee_exceptions();
+                    gen_helper_fstox(cpu_env, cpu_fpr[rs2]);
+                    gen_helper_check_ieee_exceptions(cpu_env);
                     gen_op_store_DT0_fpr(DFPREG(rd));
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x82: /* V9 fdtox */
                     gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_clear_float_exceptions();
-                    gen_helper_fdtox();
-                    gen_helper_check_ieee_exceptions();
+                    gen_helper_fdtox(cpu_env);
+                    gen_helper_check_ieee_exceptions(cpu_env);
                     gen_op_store_DT0_fpr(DFPREG(rd));
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
@@ -2680,24 +2684,24 @@
                     CHECK_FPU_FEATURE(dc, FLOAT128);
                     gen_op_load_fpr_QT1(QFPREG(rs2));
                     gen_clear_float_exceptions();
-                    gen_helper_fqtox();
-                    gen_helper_check_ieee_exceptions();
+                    gen_helper_fqtox(cpu_env);
+                    gen_helper_check_ieee_exceptions(cpu_env);
                     gen_op_store_DT0_fpr(DFPREG(rd));
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x84: /* V9 fxtos */
                     gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_clear_float_exceptions();
-                    gen_helper_fxtos(cpu_tmp32);
-                    gen_helper_check_ieee_exceptions();
+                    gen_helper_fxtos(cpu_tmp32, cpu_env);
+                    gen_helper_check_ieee_exceptions(cpu_env);
                     tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
                     gen_update_fprs_dirty(rd);
                     break;
                 case 0x88: /* V9 fxtod */
                     gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_clear_float_exceptions();
-                    gen_helper_fxtod();
-                    gen_helper_check_ieee_exceptions();
+                    gen_helper_fxtod(cpu_env);
+                    gen_helper_check_ieee_exceptions(cpu_env);
                     gen_op_store_DT0_fpr(DFPREG(rd));
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
@@ -2705,8 +2709,8 @@
                     CHECK_FPU_FEATURE(dc, FLOAT128);
                     gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_clear_float_exceptions();
-                    gen_helper_fxtoq();
-                    gen_helper_check_ieee_exceptions();
+                    gen_helper_fxtoq(cpu_env);
+                    gen_helper_check_ieee_exceptions(cpu_env);
                     gen_op_store_QT0_fpr(QFPREG(rd));
                     gen_update_fprs_dirty(QFPREG(rd));
                     break;
@@ -3267,19 +3271,23 @@
                     case 0xe: /* udiv */
                         CHECK_IU_FEATURE(dc, DIV);
                         if (xop & 0x10) {
-                            gen_helper_udiv_cc(cpu_dst, cpu_src1, cpu_src2);
+                            gen_helper_udiv_cc(cpu_dst, cpu_env, cpu_src1,
+                                               cpu_src2);
                             dc->cc_op = CC_OP_DIV;
                         } else {
-                            gen_helper_udiv(cpu_dst, cpu_src1, cpu_src2);
+                            gen_helper_udiv(cpu_dst, cpu_env, cpu_src1,
+                                            cpu_src2);
                         }
                         break;
                     case 0xf: /* sdiv */
                         CHECK_IU_FEATURE(dc, DIV);
                         if (xop & 0x10) {
-                            gen_helper_sdiv_cc(cpu_dst, cpu_src1, cpu_src2);
+                            gen_helper_sdiv_cc(cpu_dst, cpu_env, cpu_src1,
+                                               cpu_src2);
                             dc->cc_op = CC_OP_DIV;
                         } else {
-                            gen_helper_sdiv(cpu_dst, cpu_src1, cpu_src2);
+                            gen_helper_sdiv(cpu_dst, cpu_env, cpu_src1,
+                                            cpu_src2);
                         }
                         break;
                     default:
@@ -3317,7 +3325,7 @@
                         dc->cc_op = CC_OP_TSUBTV;
                         break;
                     case 0x24: /* mulscc */
-                        gen_helper_compute_psr();
+                        gen_helper_compute_psr(cpu_env);
                         gen_op_mulscc(cpu_dst, cpu_src1, cpu_src2);
                         gen_movl_TN_reg(rd, cpu_dst);
                         tcg_gen_movi_i32(cpu_cc_op, CC_OP_ADD);
@@ -3375,7 +3383,7 @@
 #else
                             case 0x2: /* V9 wrccr */
                                 tcg_gen_xor_tl(cpu_dst, cpu_src1, cpu_src2);
-                                gen_helper_wrccr(cpu_dst);
+                                gen_helper_wrccr(cpu_env, cpu_dst);
                                 tcg_gen_movi_i32(cpu_cc_op, CC_OP_FLAGS);
                                 dc->cc_op = CC_OP_FLAGS;
                                 break;
@@ -3408,19 +3416,19 @@
                                 if (!supervisor(dc))
                                     goto illegal_insn;
                                 tcg_gen_xor_tl(cpu_tmp64, cpu_src1, cpu_src2);
-                                gen_helper_set_softint(cpu_tmp64);
+                                gen_helper_set_softint(cpu_env, cpu_tmp64);
                                 break;
                             case 0x15: /* Softint clear */
                                 if (!supervisor(dc))
                                     goto illegal_insn;
                                 tcg_gen_xor_tl(cpu_tmp64, cpu_src1, cpu_src2);
-                                gen_helper_clear_softint(cpu_tmp64);
+                                gen_helper_clear_softint(cpu_env, cpu_tmp64);
                                 break;
                             case 0x16: /* Softint write */
                                 if (!supervisor(dc))
                                     goto illegal_insn;
                                 tcg_gen_xor_tl(cpu_tmp64, cpu_src1, cpu_src2);
-                                gen_helper_write_softint(cpu_tmp64);
+                                gen_helper_write_softint(cpu_env, cpu_tmp64);
                                 break;
                             case 0x17: /* Tick compare */
 #if !defined(CONFIG_USER_ONLY)
@@ -3495,10 +3503,10 @@
 #ifdef TARGET_SPARC64
                             switch (rd) {
                             case 0:
-                                gen_helper_saved();
+                                gen_helper_saved(cpu_env);
                                 break;
                             case 1:
-                                gen_helper_restored();
+                                gen_helper_restored(cpu_env);
                                 break;
                             case 2: /* UA2005 allclean */
                             case 3: /* UA2005 otherw */
@@ -3510,7 +3518,7 @@
                             }
 #else
                             tcg_gen_xor_tl(cpu_dst, cpu_src1, cpu_src2);
-                            gen_helper_wrpsr(cpu_dst);
+                            gen_helper_wrpsr(cpu_env, cpu_dst);
                             tcg_gen_movi_i32(cpu_cc_op, CC_OP_FLAGS);
                             dc->cc_op = CC_OP_FLAGS;
                             save_state(dc, cpu_cond);
@@ -3594,7 +3602,7 @@
 
                                     tcg_gen_mov_tl(r_tmp, cpu_tmp0);
                                     save_state(dc, cpu_cond);
-                                    gen_helper_wrpstate(r_tmp);
+                                    gen_helper_wrpstate(cpu_env, r_tmp);
                                     tcg_temp_free(r_tmp);
                                     dc->npc = DYNAMIC_PC;
                                 }
@@ -3613,10 +3621,10 @@
                                 }
                                 break;
                             case 8: // pil
-                                gen_helper_wrpil(cpu_tmp0);
+                                gen_helper_wrpil(cpu_env, cpu_tmp0);
                                 break;
                             case 9: // cwp
-                                gen_helper_wrcwp(cpu_tmp0);
+                                gen_helper_wrcwp(cpu_env, cpu_tmp0);
                                 break;
                             case 10: // cansave
                                 tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0);
@@ -3828,14 +3836,14 @@
                     CHECK_FPU_FEATURE(dc, VIS1);
                     cpu_src1 = get_src1(insn, cpu_src1);
                     gen_movl_reg_TN(rs2, cpu_src2);
-                    gen_helper_array8(cpu_dst, cpu_src1, cpu_src2);
+                    gen_helper_array8(cpu_dst, cpu_env, cpu_src1, cpu_src2);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x012: /* VIS I array16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     cpu_src1 = get_src1(insn, cpu_src1);
                     gen_movl_reg_TN(rs2, cpu_src2);
-                    gen_helper_array8(cpu_dst, cpu_src1, cpu_src2);
+                    gen_helper_array8(cpu_dst, cpu_env, cpu_src1, cpu_src2);
                     tcg_gen_shli_i64(cpu_dst, cpu_dst, 1);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
@@ -3843,7 +3851,7 @@
                     CHECK_FPU_FEATURE(dc, VIS1);
                     cpu_src1 = get_src1(insn, cpu_src1);
                     gen_movl_reg_TN(rs2, cpu_src2);
-                    gen_helper_array8(cpu_dst, cpu_src1, cpu_src2);
+                    gen_helper_array8(cpu_dst, cpu_env, cpu_src1, cpu_src2);
                     tcg_gen_shli_i64(cpu_dst, cpu_dst, 2);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
@@ -3851,7 +3859,7 @@
                     CHECK_FPU_FEATURE(dc, VIS1);
                     cpu_src1 = get_src1(insn, cpu_src1);
                     gen_movl_reg_TN(rs2, cpu_src2);
-                    gen_helper_alignaddr(cpu_dst, cpu_src1, cpu_src2);
+                    gen_helper_alignaddr(cpu_dst, cpu_env, cpu_src1, cpu_src2);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x019: /* VIS II bmask */
@@ -3862,63 +3870,63 @@
                     CHECK_FPU_FEATURE(dc, VIS1);
                     gen_op_load_fpr_DT0(DFPREG(rs1));
                     gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fcmple16(cpu_dst);
+                    gen_helper_fcmple16(cpu_dst, cpu_env);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x022: /* VIS I fcmpne16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     gen_op_load_fpr_DT0(DFPREG(rs1));
                     gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fcmpne16(cpu_dst);
+                    gen_helper_fcmpne16(cpu_dst, cpu_env);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x024: /* VIS I fcmple32 */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     gen_op_load_fpr_DT0(DFPREG(rs1));
                     gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fcmple32(cpu_dst);
+                    gen_helper_fcmple32(cpu_dst, cpu_env);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x026: /* VIS I fcmpne32 */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     gen_op_load_fpr_DT0(DFPREG(rs1));
                     gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fcmpne32(cpu_dst);
+                    gen_helper_fcmpne32(cpu_dst, cpu_env);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x028: /* VIS I fcmpgt16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     gen_op_load_fpr_DT0(DFPREG(rs1));
                     gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fcmpgt16(cpu_dst);
+                    gen_helper_fcmpgt16(cpu_dst, cpu_env);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x02a: /* VIS I fcmpeq16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     gen_op_load_fpr_DT0(DFPREG(rs1));
                     gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fcmpeq16(cpu_dst);
+                    gen_helper_fcmpeq16(cpu_dst, cpu_env);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x02c: /* VIS I fcmpgt32 */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     gen_op_load_fpr_DT0(DFPREG(rs1));
                     gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fcmpgt32(cpu_dst);
+                    gen_helper_fcmpgt32(cpu_dst, cpu_env);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x02e: /* VIS I fcmpeq32 */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     gen_op_load_fpr_DT0(DFPREG(rs1));
                     gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fcmpeq32(cpu_dst);
+                    gen_helper_fcmpeq32(cpu_dst, cpu_env);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x031: /* VIS I fmul8x16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     gen_op_load_fpr_DT0(DFPREG(rs1));
                     gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fmul8x16();
+                    gen_helper_fmul8x16(cpu_env);
                     gen_op_store_DT0_fpr(DFPREG(rd));
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
@@ -3926,7 +3934,7 @@
                     CHECK_FPU_FEATURE(dc, VIS1);
                     gen_op_load_fpr_DT0(DFPREG(rs1));
                     gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fmul8x16au();
+                    gen_helper_fmul8x16au(cpu_env);
                     gen_op_store_DT0_fpr(DFPREG(rd));
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
@@ -3934,7 +3942,7 @@
                     CHECK_FPU_FEATURE(dc, VIS1);
                     gen_op_load_fpr_DT0(DFPREG(rs1));
                     gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fmul8x16al();
+                    gen_helper_fmul8x16al(cpu_env);
                     gen_op_store_DT0_fpr(DFPREG(rd));
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
@@ -3942,7 +3950,7 @@
                     CHECK_FPU_FEATURE(dc, VIS1);
                     gen_op_load_fpr_DT0(DFPREG(rs1));
                     gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fmul8sux16();
+                    gen_helper_fmul8sux16(cpu_env);
                     gen_op_store_DT0_fpr(DFPREG(rd));
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
@@ -3950,7 +3958,7 @@
                     CHECK_FPU_FEATURE(dc, VIS1);
                     gen_op_load_fpr_DT0(DFPREG(rs1));
                     gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fmul8ulx16();
+                    gen_helper_fmul8ulx16(cpu_env);
                     gen_op_store_DT0_fpr(DFPREG(rd));
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
@@ -3958,7 +3966,7 @@
                     CHECK_FPU_FEATURE(dc, VIS1);
                     gen_op_load_fpr_DT0(DFPREG(rs1));
                     gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fmuld8sux16();
+                    gen_helper_fmuld8sux16(cpu_env);
                     gen_op_store_DT0_fpr(DFPREG(rd));
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
@@ -3966,7 +3974,7 @@
                     CHECK_FPU_FEATURE(dc, VIS1);
                     gen_op_load_fpr_DT0(DFPREG(rs1));
                     gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fmuld8ulx16();
+                    gen_helper_fmuld8ulx16(cpu_env);
                     gen_op_store_DT0_fpr(DFPREG(rd));
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
@@ -3980,7 +3988,7 @@
                     CHECK_FPU_FEATURE(dc, VIS1);
                     gen_op_load_fpr_DT0(DFPREG(rs1));
                     gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_faligndata();
+                    gen_helper_faligndata(cpu_env);
                     gen_op_store_DT0_fpr(DFPREG(rd));
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
@@ -3988,7 +3996,7 @@
                     CHECK_FPU_FEATURE(dc, VIS1);
                     gen_op_load_fpr_DT0(DFPREG(rs1));
                     gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fpmerge();
+                    gen_helper_fpmerge(cpu_env);
                     gen_op_store_DT0_fpr(DFPREG(rd));
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
@@ -3999,7 +4007,7 @@
                     CHECK_FPU_FEATURE(dc, VIS1);
                     gen_op_load_fpr_DT0(DFPREG(rs1));
                     gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fexpand();
+                    gen_helper_fexpand(cpu_env);
                     gen_op_store_DT0_fpr(DFPREG(rd));
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
@@ -4007,13 +4015,13 @@
                     CHECK_FPU_FEATURE(dc, VIS1);
                     gen_op_load_fpr_DT0(DFPREG(rs1));
                     gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fpadd16();
+                    gen_helper_fpadd16(cpu_env);
                     gen_op_store_DT0_fpr(DFPREG(rd));
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x051: /* VIS I fpadd16s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_helper_fpadd16s(cpu_fpr[rd],
+                    gen_helper_fpadd16s(cpu_fpr[rd], cpu_env,
                                         cpu_fpr[rs1], cpu_fpr[rs2]);
                     gen_update_fprs_dirty(rd);
                     break;
@@ -4021,13 +4029,13 @@
                     CHECK_FPU_FEATURE(dc, VIS1);
                     gen_op_load_fpr_DT0(DFPREG(rs1));
                     gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fpadd32();
+                    gen_helper_fpadd32(cpu_env);
                     gen_op_store_DT0_fpr(DFPREG(rd));
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x053: /* VIS I fpadd32s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_helper_fpadd32s(cpu_fpr[rd],
+                    gen_helper_fpadd32s(cpu_fpr[rd], cpu_env,
                                         cpu_fpr[rs1], cpu_fpr[rs2]);
                     gen_update_fprs_dirty(rd);
                     break;
@@ -4035,13 +4043,13 @@
                     CHECK_FPU_FEATURE(dc, VIS1);
                     gen_op_load_fpr_DT0(DFPREG(rs1));
                     gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fpsub16();
+                    gen_helper_fpsub16(cpu_env);
                     gen_op_store_DT0_fpr(DFPREG(rd));
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x055: /* VIS I fpsub16s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_helper_fpsub16s(cpu_fpr[rd],
+                    gen_helper_fpsub16s(cpu_fpr[rd], cpu_env,
                                         cpu_fpr[rs1], cpu_fpr[rs2]);
                     gen_update_fprs_dirty(rd);
                     break;
@@ -4049,13 +4057,13 @@
                     CHECK_FPU_FEATURE(dc, VIS1);
                     gen_op_load_fpr_DT0(DFPREG(rs1));
                     gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fpsub32();
+                    gen_helper_fpsub32(cpu_env);
                     gen_op_store_DT0_fpr(DFPREG(rd));
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x057: /* VIS I fpsub32s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_helper_fpsub32s(cpu_fpr[rd],
+                    gen_helper_fpsub32s(cpu_fpr[rd], cpu_env,
                                         cpu_fpr[rs1], cpu_fpr[rs2]);
                     gen_update_fprs_dirty(rd);
                     break;
@@ -4303,7 +4311,7 @@
                     } else
                         tcg_gen_mov_tl(cpu_dst, cpu_src1);
                 }
-                gen_helper_restore();
+                gen_helper_restore(cpu_env);
                 gen_mov_pc_npc(dc, cpu_cond);
                 r_const = tcg_const_i32(3);
                 gen_helper_check_align(cpu_dst, r_const);
@@ -4355,7 +4363,7 @@
                         tcg_temp_free_i32(r_const);
                         tcg_gen_mov_tl(cpu_npc, cpu_dst);
                         dc->npc = DYNAMIC_PC;
-                        gen_helper_rett();
+                        gen_helper_rett(cpu_env);
                     }
                     goto jmp_insn;
 #endif
@@ -4366,12 +4374,12 @@
                     break;
                 case 0x3c:      /* save */
                     save_state(dc, cpu_cond);
-                    gen_helper_save();
+                    gen_helper_save(cpu_env);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x3d:      /* restore */
                     save_state(dc, cpu_cond);
-                    gen_helper_restore();
+                    gen_helper_restore(cpu_env);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
 #if !defined(CONFIG_USER_ONLY) && defined(TARGET_SPARC64)
@@ -4383,14 +4391,14 @@
                                 goto priv_insn;
                             dc->npc = DYNAMIC_PC;
                             dc->pc = DYNAMIC_PC;
-                            gen_helper_done();
+                            gen_helper_done(cpu_env);
                             goto jmp_insn;
                         case 1:
                             if (!supervisor(dc))
                                 goto priv_insn;
                             dc->npc = DYNAMIC_PC;
                             dc->pc = DYNAMIC_PC;
-                            gen_helper_retry();
+                            gen_helper_retry(cpu_env);
                             goto jmp_insn;
                         default:
                             goto illegal_insn;
@@ -4413,7 +4421,7 @@
                cpu state */
             if (dc->cc_op != CC_OP_FLAGS) {
                 dc->cc_op = CC_OP_FLAGS;
-                gen_helper_compute_psr();
+                gen_helper_compute_psr(cpu_env);
             }
             cpu_src1 = get_src1(insn, cpu_src1);
             if (xop == 0x3c || xop == 0x3e) { // V9 casa/casxa
@@ -4659,16 +4667,16 @@
                     gen_address_mask(dc, cpu_addr);
                     if (rd == 1) {
                         tcg_gen_qemu_ld64(cpu_tmp64, cpu_addr, dc->mem_idx);
-                        gen_helper_ldxfsr(cpu_tmp64);
+                        gen_helper_ldxfsr(cpu_env, cpu_tmp64);
                     } else {
                         tcg_gen_qemu_ld32u(cpu_tmp0, cpu_addr, dc->mem_idx);
                         tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0);
-                        gen_helper_ldfsr(cpu_tmp32);
+                        gen_helper_ldfsr(cpu_env, cpu_tmp32);
                     }
 #else
                     {
                         tcg_gen_qemu_ld32u(cpu_tmp32, cpu_addr, dc->mem_idx);
-                        gen_helper_ldfsr(cpu_tmp32);
+                        gen_helper_ldfsr(cpu_env, cpu_tmp32);
                     }
 #endif
                     break;
@@ -4931,7 +4939,7 @@
 
         save_state(dc, cpu_cond);
         r_const = tcg_const_i32(TT_ILL_INSN);
-        gen_helper_raise_exception(r_const);
+        gen_helper_raise_exception(cpu_env, r_const);
         tcg_temp_free_i32(r_const);
         dc->is_br = 1;
     }
@@ -4942,7 +4950,7 @@
 
         save_state(dc, cpu_cond);
         r_const = tcg_const_i32(TT_UNIMP_FLUSH);
-        gen_helper_raise_exception(r_const);
+        gen_helper_raise_exception(cpu_env, r_const);
         tcg_temp_free_i32(r_const);
         dc->is_br = 1;
     }
@@ -4954,7 +4962,7 @@
 
         save_state(dc, cpu_cond);
         r_const = tcg_const_i32(TT_PRIV_INSN);
-        gen_helper_raise_exception(r_const);
+        gen_helper_raise_exception(cpu_env, r_const);
         tcg_temp_free_i32(r_const);
         dc->is_br = 1;
     }
@@ -4979,7 +4987,7 @@
 
         save_state(dc, cpu_cond);
         r_const = tcg_const_i32(TT_NCP_INSN);
-        gen_helper_raise_exception(r_const);
+        gen_helper_raise_exception(cpu_env, r_const);
         tcg_temp_free(r_const);
         dc->is_br = 1;
     }
@@ -5036,7 +5044,7 @@
                 if (bp->pc == dc->pc) {
                     if (dc->pc != pc_start)
                         save_state(dc, cpu_cond);
-                    gen_helper_debug();
+                    gen_helper_debug(cpu_env);
                     tcg_gen_exit_tb(0);
                     dc->is_br = 1;
                     goto exit_gen_loop;
@@ -5265,6 +5273,6 @@
 
     /* flush pending conditional evaluations before exposing cpu state */
     if (CC_OP != CC_OP_FLAGS) {
-        helper_compute_psr();
+        helper_compute_psr(env);
     }
 }
diff --git a/target-sparc/vis_helper.c b/target-sparc/vis_helper.c
new file mode 100644
index 0000000..a22c10b
--- /dev/null
+++ b/target-sparc/vis_helper.c
@@ -0,0 +1,406 @@
+/*
+ * VIS op helpers
+ *
+ *  Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * 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/>.
+ */
+
+#include "cpu.h"
+#include "helper.h"
+
+#define DT0 (env->dt0)
+#define DT1 (env->dt1)
+#define QT0 (env->qt0)
+#define QT1 (env->qt1)
+
+/* This function uses non-native bit order */
+#define GET_FIELD(X, FROM, TO)                                  \
+    ((X) >> (63 - (TO)) & ((1ULL << ((TO) - (FROM) + 1)) - 1))
+
+/* This function uses the order in the manuals, i.e. bit 0 is 2^0 */
+#define GET_FIELD_SP(X, FROM, TO)               \
+    GET_FIELD(X, 63 - (TO), 63 - (FROM))
+
+target_ulong helper_array8(CPUState *env, target_ulong pixel_addr,
+                           target_ulong cubesize)
+{
+    return (GET_FIELD_SP(pixel_addr, 60, 63) << (17 + 2 * cubesize)) |
+        (GET_FIELD_SP(pixel_addr, 39, 39 + cubesize - 1) << (17 + cubesize)) |
+        (GET_FIELD_SP(pixel_addr, 17 + cubesize - 1, 17) << 17) |
+        (GET_FIELD_SP(pixel_addr, 56, 59) << 13) |
+        (GET_FIELD_SP(pixel_addr, 35, 38) << 9) |
+        (GET_FIELD_SP(pixel_addr, 13, 16) << 5) |
+        (((pixel_addr >> 55) & 1) << 4) |
+        (GET_FIELD_SP(pixel_addr, 33, 34) << 2) |
+        GET_FIELD_SP(pixel_addr, 11, 12);
+}
+
+target_ulong helper_alignaddr(CPUState *env, target_ulong addr,
+                              target_ulong offset)
+{
+    uint64_t tmp;
+
+    tmp = addr + offset;
+    env->gsr &= ~7ULL;
+    env->gsr |= tmp & 7ULL;
+    return tmp & ~7ULL;
+}
+
+void helper_faligndata(CPUState *env)
+{
+    uint64_t tmp;
+
+    tmp = (*((uint64_t *)&DT0)) << ((env->gsr & 7) * 8);
+    /* on many architectures a shift of 64 does nothing */
+    if ((env->gsr & 7) != 0) {
+        tmp |= (*((uint64_t *)&DT1)) >> (64 - (env->gsr & 7) * 8);
+    }
+    *((uint64_t *)&DT0) = tmp;
+}
+
+#ifdef HOST_WORDS_BIGENDIAN
+#define VIS_B64(n) b[7 - (n)]
+#define VIS_W64(n) w[3 - (n)]
+#define VIS_SW64(n) sw[3 - (n)]
+#define VIS_L64(n) l[1 - (n)]
+#define VIS_B32(n) b[3 - (n)]
+#define VIS_W32(n) w[1 - (n)]
+#else
+#define VIS_B64(n) b[n]
+#define VIS_W64(n) w[n]
+#define VIS_SW64(n) sw[n]
+#define VIS_L64(n) l[n]
+#define VIS_B32(n) b[n]
+#define VIS_W32(n) w[n]
+#endif
+
+typedef union {
+    uint8_t b[8];
+    uint16_t w[4];
+    int16_t sw[4];
+    uint32_t l[2];
+    uint64_t ll;
+    float64 d;
+} VIS64;
+
+typedef union {
+    uint8_t b[4];
+    uint16_t w[2];
+    uint32_t l;
+    float32 f;
+} VIS32;
+
+void helper_fpmerge(CPUState *env)
+{
+    VIS64 s, d;
+
+    s.d = DT0;
+    d.d = DT1;
+
+    /* Reverse calculation order to handle overlap */
+    d.VIS_B64(7) = s.VIS_B64(3);
+    d.VIS_B64(6) = d.VIS_B64(3);
+    d.VIS_B64(5) = s.VIS_B64(2);
+    d.VIS_B64(4) = d.VIS_B64(2);
+    d.VIS_B64(3) = s.VIS_B64(1);
+    d.VIS_B64(2) = d.VIS_B64(1);
+    d.VIS_B64(1) = s.VIS_B64(0);
+    /* d.VIS_B64(0) = d.VIS_B64(0); */
+
+    DT0 = d.d;
+}
+
+void helper_fmul8x16(CPUState *env)
+{
+    VIS64 s, d;
+    uint32_t tmp;
+
+    s.d = DT0;
+    d.d = DT1;
+
+#define PMUL(r)                                                 \
+    tmp = (int32_t)d.VIS_SW64(r) * (int32_t)s.VIS_B64(r);       \
+    if ((tmp & 0xff) > 0x7f) {                                  \
+        tmp += 0x100;                                           \
+    }                                                           \
+    d.VIS_W64(r) = tmp >> 8;
+
+    PMUL(0);
+    PMUL(1);
+    PMUL(2);
+    PMUL(3);
+#undef PMUL
+
+    DT0 = d.d;
+}
+
+void helper_fmul8x16al(CPUState *env)
+{
+    VIS64 s, d;
+    uint32_t tmp;
+
+    s.d = DT0;
+    d.d = DT1;
+
+#define PMUL(r)                                                 \
+    tmp = (int32_t)d.VIS_SW64(1) * (int32_t)s.VIS_B64(r);       \
+    if ((tmp & 0xff) > 0x7f) {                                  \
+        tmp += 0x100;                                           \
+    }                                                           \
+    d.VIS_W64(r) = tmp >> 8;
+
+    PMUL(0);
+    PMUL(1);
+    PMUL(2);
+    PMUL(3);
+#undef PMUL
+
+    DT0 = d.d;
+}
+
+void helper_fmul8x16au(CPUState *env)
+{
+    VIS64 s, d;
+    uint32_t tmp;
+
+    s.d = DT0;
+    d.d = DT1;
+
+#define PMUL(r)                                                 \
+    tmp = (int32_t)d.VIS_SW64(0) * (int32_t)s.VIS_B64(r);       \
+    if ((tmp & 0xff) > 0x7f) {                                  \
+        tmp += 0x100;                                           \
+    }                                                           \
+    d.VIS_W64(r) = tmp >> 8;
+
+    PMUL(0);
+    PMUL(1);
+    PMUL(2);
+    PMUL(3);
+#undef PMUL
+
+    DT0 = d.d;
+}
+
+void helper_fmul8sux16(CPUState *env)
+{
+    VIS64 s, d;
+    uint32_t tmp;
+
+    s.d = DT0;
+    d.d = DT1;
+
+#define PMUL(r)                                                         \
+    tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8);       \
+    if ((tmp & 0xff) > 0x7f) {                                          \
+        tmp += 0x100;                                                   \
+    }                                                                   \
+    d.VIS_W64(r) = tmp >> 8;
+
+    PMUL(0);
+    PMUL(1);
+    PMUL(2);
+    PMUL(3);
+#undef PMUL
+
+    DT0 = d.d;
+}
+
+void helper_fmul8ulx16(CPUState *env)
+{
+    VIS64 s, d;
+    uint32_t tmp;
+
+    s.d = DT0;
+    d.d = DT1;
+
+#define PMUL(r)                                                         \
+    tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2));        \
+    if ((tmp & 0xff) > 0x7f) {                                          \
+        tmp += 0x100;                                                   \
+    }                                                                   \
+    d.VIS_W64(r) = tmp >> 8;
+
+    PMUL(0);
+    PMUL(1);
+    PMUL(2);
+    PMUL(3);
+#undef PMUL
+
+    DT0 = d.d;
+}
+
+void helper_fmuld8sux16(CPUState *env)
+{
+    VIS64 s, d;
+    uint32_t tmp;
+
+    s.d = DT0;
+    d.d = DT1;
+
+#define PMUL(r)                                                         \
+    tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8);       \
+    if ((tmp & 0xff) > 0x7f) {                                          \
+        tmp += 0x100;                                                   \
+    }                                                                   \
+    d.VIS_L64(r) = tmp;
+
+    /* Reverse calculation order to handle overlap */
+    PMUL(1);
+    PMUL(0);
+#undef PMUL
+
+    DT0 = d.d;
+}
+
+void helper_fmuld8ulx16(CPUState *env)
+{
+    VIS64 s, d;
+    uint32_t tmp;
+
+    s.d = DT0;
+    d.d = DT1;
+
+#define PMUL(r)                                                         \
+    tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2));        \
+    if ((tmp & 0xff) > 0x7f) {                                          \
+        tmp += 0x100;                                                   \
+    }                                                                   \
+    d.VIS_L64(r) = tmp;
+
+    /* Reverse calculation order to handle overlap */
+    PMUL(1);
+    PMUL(0);
+#undef PMUL
+
+    DT0 = d.d;
+}
+
+void helper_fexpand(CPUState *env)
+{
+    VIS32 s;
+    VIS64 d;
+
+    s.l = (uint32_t)(*(uint64_t *)&DT0 & 0xffffffff);
+    d.d = DT1;
+    d.VIS_W64(0) = s.VIS_B32(0) << 4;
+    d.VIS_W64(1) = s.VIS_B32(1) << 4;
+    d.VIS_W64(2) = s.VIS_B32(2) << 4;
+    d.VIS_W64(3) = s.VIS_B32(3) << 4;
+
+    DT0 = d.d;
+}
+
+#define VIS_HELPER(name, F)                             \
+    void name##16(CPUState *env)                        \
+    {                                                   \
+        VIS64 s, d;                                     \
+                                                        \
+        s.d = DT0;                                      \
+        d.d = DT1;                                      \
+                                                        \
+        d.VIS_W64(0) = F(d.VIS_W64(0), s.VIS_W64(0));   \
+        d.VIS_W64(1) = F(d.VIS_W64(1), s.VIS_W64(1));   \
+        d.VIS_W64(2) = F(d.VIS_W64(2), s.VIS_W64(2));   \
+        d.VIS_W64(3) = F(d.VIS_W64(3), s.VIS_W64(3));   \
+                                                        \
+        DT0 = d.d;                                      \
+    }                                                   \
+                                                        \
+    uint32_t name##16s(CPUState *env, uint32_t src1,    \
+                       uint32_t src2)                   \
+    {                                                   \
+        VIS32 s, d;                                     \
+                                                        \
+        s.l = src1;                                     \
+        d.l = src2;                                     \
+                                                        \
+        d.VIS_W32(0) = F(d.VIS_W32(0), s.VIS_W32(0));   \
+        d.VIS_W32(1) = F(d.VIS_W32(1), s.VIS_W32(1));   \
+                                                        \
+        return d.l;                                     \
+    }                                                   \
+                                                        \
+    void name##32(CPUState *env)                        \
+    {                                                   \
+        VIS64 s, d;                                     \
+                                                        \
+        s.d = DT0;                                      \
+        d.d = DT1;                                      \
+                                                        \
+        d.VIS_L64(0) = F(d.VIS_L64(0), s.VIS_L64(0));   \
+        d.VIS_L64(1) = F(d.VIS_L64(1), s.VIS_L64(1));   \
+                                                        \
+        DT0 = d.d;                                      \
+    }                                                   \
+                                                        \
+    uint32_t name##32s(CPUState *env, uint32_t src1,    \
+                       uint32_t src2)                   \
+    {                                                   \
+        VIS32 s, d;                                     \
+                                                        \
+        s.l = src1;                                     \
+        d.l = src2;                                     \
+                                                        \
+        d.l = F(d.l, s.l);                              \
+                                                        \
+        return d.l;                                     \
+    }
+
+#define FADD(a, b) ((a) + (b))
+#define FSUB(a, b) ((a) - (b))
+VIS_HELPER(helper_fpadd, FADD)
+VIS_HELPER(helper_fpsub, FSUB)
+
+#define VIS_CMPHELPER(name, F)                                    \
+    uint64_t name##16(CPUState *env)                              \
+    {                                                             \
+        VIS64 s, d;                                               \
+                                                                  \
+        s.d = DT0;                                                \
+        d.d = DT1;                                                \
+                                                                  \
+        d.VIS_W64(0) = F(s.VIS_W64(0), d.VIS_W64(0)) ? 1 : 0;     \
+        d.VIS_W64(0) |= F(s.VIS_W64(1), d.VIS_W64(1)) ? 2 : 0;    \
+        d.VIS_W64(0) |= F(s.VIS_W64(2), d.VIS_W64(2)) ? 4 : 0;    \
+        d.VIS_W64(0) |= F(s.VIS_W64(3), d.VIS_W64(3)) ? 8 : 0;    \
+        d.VIS_W64(1) = d.VIS_W64(2) = d.VIS_W64(3) = 0;           \
+                                                                  \
+        return d.ll;                                              \
+    }                                                             \
+                                                                  \
+    uint64_t name##32(CPUState *env)                              \
+    {                                                             \
+        VIS64 s, d;                                               \
+                                                                  \
+        s.d = DT0;                                                \
+        d.d = DT1;                                                \
+                                                                  \
+        d.VIS_L64(0) = F(s.VIS_L64(0), d.VIS_L64(0)) ? 1 : 0;     \
+        d.VIS_L64(0) |= F(s.VIS_L64(1), d.VIS_L64(1)) ? 2 : 0;    \
+        d.VIS_L64(1) = 0;                                         \
+                                                                  \
+        return d.ll;                                              \
+    }
+
+#define FCMPGT(a, b) ((a) > (b))
+#define FCMPEQ(a, b) ((a) == (b))
+#define FCMPLE(a, b) ((a) <= (b))
+#define FCMPNE(a, b) ((a) != (b))
+
+VIS_CMPHELPER(helper_fcmpgt, FCMPGT)
+VIS_CMPHELPER(helper_fcmpeq, FCMPEQ)
+VIS_CMPHELPER(helper_fcmple, FCMPLE)
+VIS_CMPHELPER(helper_fcmpne, FCMPNE)
diff --git a/target-sparc/win_helper.c b/target-sparc/win_helper.c
new file mode 100644
index 0000000..a68c649
--- /dev/null
+++ b/target-sparc/win_helper.c
@@ -0,0 +1,393 @@
+/*
+ * Helpers for CWP and PSTATE handling
+ *
+ *  Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * 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/>.
+ */
+
+#include "cpu.h"
+#include "helper.h"
+#include "trace.h"
+
+static inline void memcpy32(target_ulong *dst, const target_ulong *src)
+{
+    dst[0] = src[0];
+    dst[1] = src[1];
+    dst[2] = src[2];
+    dst[3] = src[3];
+    dst[4] = src[4];
+    dst[5] = src[5];
+    dst[6] = src[6];
+    dst[7] = src[7];
+}
+
+void cpu_set_cwp(CPUState *env, int new_cwp)
+{
+    /* put the modified wrap registers at their proper location */
+    if (env->cwp == env->nwindows - 1) {
+        memcpy32(env->regbase, env->regbase + env->nwindows * 16);
+    }
+    env->cwp = new_cwp;
+
+    /* put the wrap registers at their temporary location */
+    if (new_cwp == env->nwindows - 1) {
+        memcpy32(env->regbase + env->nwindows * 16, env->regbase);
+    }
+    env->regwptr = env->regbase + (new_cwp * 16);
+}
+
+target_ulong cpu_get_psr(CPUState *env)
+{
+    helper_compute_psr(env);
+
+#if !defined(TARGET_SPARC64)
+    return env->version | (env->psr & PSR_ICC) |
+        (env->psref ? PSR_EF : 0) |
+        (env->psrpil << 8) |
+        (env->psrs ? PSR_S : 0) |
+        (env->psrps ? PSR_PS : 0) |
+        (env->psret ? PSR_ET : 0) | env->cwp;
+#else
+    return env->psr & PSR_ICC;
+#endif
+}
+
+void cpu_put_psr(CPUState *env, target_ulong val)
+{
+    env->psr = val & PSR_ICC;
+#if !defined(TARGET_SPARC64)
+    env->psref = (val & PSR_EF) ? 1 : 0;
+    env->psrpil = (val & PSR_PIL) >> 8;
+#endif
+#if ((!defined(TARGET_SPARC64)) && !defined(CONFIG_USER_ONLY))
+    cpu_check_irqs(env);
+#endif
+#if !defined(TARGET_SPARC64)
+    env->psrs = (val & PSR_S) ? 1 : 0;
+    env->psrps = (val & PSR_PS) ? 1 : 0;
+    env->psret = (val & PSR_ET) ? 1 : 0;
+    cpu_set_cwp(env, val & PSR_CWP);
+#endif
+    env->cc_op = CC_OP_FLAGS;
+}
+
+int cpu_cwp_inc(CPUState *env, int cwp)
+{
+    if (unlikely(cwp >= env->nwindows)) {
+        cwp -= env->nwindows;
+    }
+    return cwp;
+}
+
+int cpu_cwp_dec(CPUState *env, int cwp)
+{
+    if (unlikely(cwp < 0)) {
+        cwp += env->nwindows;
+    }
+    return cwp;
+}
+
+#ifndef TARGET_SPARC64
+void helper_rett(CPUState *env)
+{
+    unsigned int cwp;
+
+    if (env->psret == 1) {
+        helper_raise_exception(env, TT_ILL_INSN);
+    }
+
+    env->psret = 1;
+    cwp = cpu_cwp_inc(env, env->cwp + 1) ;
+    if (env->wim & (1 << cwp)) {
+        helper_raise_exception(env, TT_WIN_UNF);
+    }
+    cpu_set_cwp(env, cwp);
+    env->psrs = env->psrps;
+}
+
+/* XXX: use another pointer for %iN registers to avoid slow wrapping
+   handling ? */
+void helper_save(CPUState *env)
+{
+    uint32_t cwp;
+
+    cwp = cpu_cwp_dec(env, env->cwp - 1);
+    if (env->wim & (1 << cwp)) {
+        helper_raise_exception(env, TT_WIN_OVF);
+    }
+    cpu_set_cwp(env, cwp);
+}
+
+void helper_restore(CPUState *env)
+{
+    uint32_t cwp;
+
+    cwp = cpu_cwp_inc(env, env->cwp + 1);
+    if (env->wim & (1 << cwp)) {
+        helper_raise_exception(env, TT_WIN_UNF);
+    }
+    cpu_set_cwp(env, cwp);
+}
+
+void helper_wrpsr(CPUState *env, target_ulong new_psr)
+{
+    if ((new_psr & PSR_CWP) >= env->nwindows) {
+        helper_raise_exception(env, TT_ILL_INSN);
+    } else {
+        cpu_put_psr(env, new_psr);
+    }
+}
+
+target_ulong helper_rdpsr(CPUState *env)
+{
+    return cpu_get_psr(env);
+}
+
+#else
+/* XXX: use another pointer for %iN registers to avoid slow wrapping
+   handling ? */
+void helper_save(CPUState *env)
+{
+    uint32_t cwp;
+
+    cwp = cpu_cwp_dec(env, env->cwp - 1);
+    if (env->cansave == 0) {
+        helper_raise_exception(env, TT_SPILL | (env->otherwin != 0 ?
+                                                (TT_WOTHER |
+                                                 ((env->wstate & 0x38) >> 1)) :
+                                                ((env->wstate & 0x7) << 2)));
+    } else {
+        if (env->cleanwin - env->canrestore == 0) {
+            /* XXX Clean windows without trap */
+            helper_raise_exception(env, TT_CLRWIN);
+        } else {
+            env->cansave--;
+            env->canrestore++;
+            cpu_set_cwp(env, cwp);
+        }
+    }
+}
+
+void helper_restore(CPUState *env)
+{
+    uint32_t cwp;
+
+    cwp = cpu_cwp_inc(env, env->cwp + 1);
+    if (env->canrestore == 0) {
+        helper_raise_exception(env, TT_FILL | (env->otherwin != 0 ?
+                                               (TT_WOTHER |
+                                                ((env->wstate & 0x38) >> 1)) :
+                                               ((env->wstate & 0x7) << 2)));
+    } else {
+        env->cansave++;
+        env->canrestore--;
+        cpu_set_cwp(env, cwp);
+    }
+}
+
+void helper_flushw(CPUState *env)
+{
+    if (env->cansave != env->nwindows - 2) {
+        helper_raise_exception(env, TT_SPILL | (env->otherwin != 0 ?
+                                                (TT_WOTHER |
+                                                 ((env->wstate & 0x38) >> 1)) :
+                                                ((env->wstate & 0x7) << 2)));
+    }
+}
+
+void helper_saved(CPUState *env)
+{
+    env->cansave++;
+    if (env->otherwin == 0) {
+        env->canrestore--;
+    } else {
+        env->otherwin--;
+    }
+}
+
+void helper_restored(CPUState *env)
+{
+    env->canrestore++;
+    if (env->cleanwin < env->nwindows - 1) {
+        env->cleanwin++;
+    }
+    if (env->otherwin == 0) {
+        env->cansave--;
+    } else {
+        env->otherwin--;
+    }
+}
+
+target_ulong cpu_get_ccr(CPUState *env)
+{
+    target_ulong psr;
+
+    psr = cpu_get_psr(env);
+
+    return ((env->xcc >> 20) << 4) | ((psr & PSR_ICC) >> 20);
+}
+
+void cpu_put_ccr(CPUState *env, target_ulong val)
+{
+    env->xcc = (val >> 4) << 20;
+    env->psr = (val & 0xf) << 20;
+    CC_OP = CC_OP_FLAGS;
+}
+
+target_ulong cpu_get_cwp64(CPUState *env)
+{
+    return env->nwindows - 1 - env->cwp;
+}
+
+void cpu_put_cwp64(CPUState *env, int cwp)
+{
+    if (unlikely(cwp >= env->nwindows || cwp < 0)) {
+        cwp %= env->nwindows;
+    }
+    cpu_set_cwp(env, env->nwindows - 1 - cwp);
+}
+
+target_ulong helper_rdccr(CPUState *env)
+{
+    return cpu_get_ccr(env);
+}
+
+void helper_wrccr(CPUState *env, target_ulong new_ccr)
+{
+    cpu_put_ccr(env, new_ccr);
+}
+
+/* CWP handling is reversed in V9, but we still use the V8 register
+   order. */
+target_ulong helper_rdcwp(CPUState *env)
+{
+    return cpu_get_cwp64(env);
+}
+
+void helper_wrcwp(CPUState *env, target_ulong new_cwp)
+{
+    cpu_put_cwp64(env, new_cwp);
+}
+
+static inline uint64_t *get_gregset(CPUState *env, uint32_t pstate)
+{
+    switch (pstate) {
+    default:
+        trace_win_helper_gregset_error(pstate);
+        /* pass through to normal set of global registers */
+    case 0:
+        return env->bgregs;
+    case PS_AG:
+        return env->agregs;
+    case PS_MG:
+        return env->mgregs;
+    case PS_IG:
+        return env->igregs;
+    }
+}
+
+void cpu_change_pstate(CPUState *env, uint32_t new_pstate)
+{
+    uint32_t pstate_regs, new_pstate_regs;
+    uint64_t *src, *dst;
+
+    if (env->def->features & CPU_FEATURE_GL) {
+        /* PS_AG is not implemented in this case */
+        new_pstate &= ~PS_AG;
+    }
+
+    pstate_regs = env->pstate & 0xc01;
+    new_pstate_regs = new_pstate & 0xc01;
+
+    if (new_pstate_regs != pstate_regs) {
+        trace_win_helper_switch_pstate(pstate_regs, new_pstate_regs);
+
+        /* Switch global register bank */
+        src = get_gregset(env, new_pstate_regs);
+        dst = get_gregset(env, pstate_regs);
+        memcpy32(dst, env->gregs);
+        memcpy32(env->gregs, src);
+    } else {
+        trace_win_helper_no_switch_pstate(new_pstate_regs);
+    }
+    env->pstate = new_pstate;
+}
+
+void helper_wrpstate(CPUState *env, target_ulong new_state)
+{
+    cpu_change_pstate(env, new_state & 0xf3f);
+
+#if !defined(CONFIG_USER_ONLY)
+    if (cpu_interrupts_enabled(env)) {
+        cpu_check_irqs(env);
+    }
+#endif
+}
+
+void helper_wrpil(CPUState *env, target_ulong new_pil)
+{
+#if !defined(CONFIG_USER_ONLY)
+    trace_win_helper_wrpil(env->psrpil, (uint32_t)new_pil);
+
+    env->psrpil = new_pil;
+
+    if (cpu_interrupts_enabled(env)) {
+        cpu_check_irqs(env);
+    }
+#endif
+}
+
+void helper_done(CPUState *env)
+{
+    trap_state *tsptr = cpu_tsptr(env);
+
+    env->pc = tsptr->tnpc;
+    env->npc = tsptr->tnpc + 4;
+    cpu_put_ccr(env, tsptr->tstate >> 32);
+    env->asi = (tsptr->tstate >> 24) & 0xff;
+    cpu_change_pstate(env, (tsptr->tstate >> 8) & 0xf3f);
+    cpu_put_cwp64(env, tsptr->tstate & 0xff);
+    env->tl--;
+
+    trace_win_helper_done(env->tl);
+
+#if !defined(CONFIG_USER_ONLY)
+    if (cpu_interrupts_enabled(env)) {
+        cpu_check_irqs(env);
+    }
+#endif
+}
+
+void helper_retry(CPUState *env)
+{
+    trap_state *tsptr = cpu_tsptr(env);
+
+    env->pc = tsptr->tpc;
+    env->npc = tsptr->tnpc;
+    cpu_put_ccr(env, tsptr->tstate >> 32);
+    env->asi = (tsptr->tstate >> 24) & 0xff;
+    cpu_change_pstate(env, (tsptr->tstate >> 8) & 0xf3f);
+    cpu_put_cwp64(env, tsptr->tstate & 0xff);
+    env->tl--;
+
+    trace_win_helper_retry(env->tl);
+
+#if !defined(CONFIG_USER_ONLY)
+    if (cpu_interrupts_enabled(env)) {
+        cpu_check_irqs(env);
+    }
+#endif
+}
+#endif
diff --git a/trace-events b/trace-events
index a06c6c5..820b1d6 100644
--- a/trace-events
+++ b/trace-events
@@ -61,6 +61,7 @@
 bdrv_aio_multiwrite(void *mcb, int num_callbacks, int num_reqs) "mcb %p num_callbacks %d num_reqs %d"
 bdrv_aio_multiwrite_earlyfail(void *mcb) "mcb %p"
 bdrv_aio_multiwrite_latefail(void *mcb, int i) "mcb %p i %d"
+bdrv_aio_discard(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p"
 bdrv_aio_flush(void *bs, void *opaque) "bs %p opaque %p"
 bdrv_aio_readv(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p"
 bdrv_aio_writev(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p"
@@ -552,3 +553,74 @@
 open_eth_reg_write(uint32_t addr, uint32_t v) "MAC[%02x] <- %08x"
 open_eth_desc_read(uint32_t addr, uint32_t v) "DESC[%04x] -> %08x"
 open_eth_desc_write(uint32_t addr, uint32_t v) "DESC[%04x] <- %08x"
+
+# hw/9pfs/virtio-9p.c
+complete_pdu(uint16_t tag, uint8_t id, int err) "tag %d id %d err %d"
+v9fs_version(uint16_t tag, uint8_t id, int32_t msize, char* version) "tag %d id %d msize %d version %s"
+v9fs_version_return(uint16_t tag, uint8_t id, int32_t msize, char* version) "tag %d id %d msize %d version %s"
+v9fs_attach(uint16_t tag, uint8_t id, int32_t fid, int32_t afid, char* uname, char* aname) "tag %u id %u fid %d afid %d uname %s aname %s"
+v9fs_attach_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path) "tag %d id %d type %d version %d path %"PRId64""
+v9fs_stat(uint16_t tag, uint8_t id, int32_t fid) "tag %d id %d fid %d"
+v9fs_stat_return(uint16_t tag, uint8_t id, int32_t mode, int32_t atime, int32_t mtime, int64_t length) "tag %d id %d stat={mode %d atime %d mtime %d length %"PRId64"}"
+v9fs_getattr(uint16_t tag, uint8_t id, int32_t fid, uint64_t request_mask) "tag %d id %d fid %d request_mask %"PRIu64""
+v9fs_getattr_return(uint16_t tag, uint8_t id, uint64_t result_mask, uint32_t mode, uint32_t uid, uint32_t gid) "tag %d id %d getattr={result_mask %"PRId64" mode %u uid %u gid %u}"
+v9fs_walk(uint16_t tag, uint8_t id, int32_t fid, int32_t newfid, uint16_t nwnames) "tag %d id %d fid %d newfid %d nwnames %d"
+v9fs_walk_return(uint16_t tag, uint8_t id, uint16_t nwnames, void* qids) "tag %d id %d nwnames %d qids %p"
+v9fs_open(uint16_t tag, uint8_t id, int32_t fid, int32_t mode) "tag %d id %d fid %d mode %d"
+v9fs_open_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path, int iounit) "tag %d id %d qid={type %d version %d path %"PRId64"} iounit %d"
+v9fs_lcreate(uint16_t tag, uint8_t id, int32_t dfid, int32_t flags, int32_t mode, uint32_t gid) "tag %d id %d dfid %d flags %d mode %d gid %u"
+v9fs_lcreate_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path, int32_t iounit) "tag %d id %d qid={type %d version %d path %"PRId64"} iounit %d"
+v9fs_fsync(uint16_t tag, uint8_t id, int32_t fid, int datasync) "tag %d id %d fid %d datasync %d"
+v9fs_clunk(uint16_t tag, uint8_t id, int32_t fid) "tag %d id %d fid %d"
+v9fs_read(uint16_t tag, uint8_t id, int32_t fid, int64_t off, int32_t max_count) "tag %d id %d fid %d off %"PRId64" max_count %d"
+v9fs_read_return(uint16_t tag, uint8_t id, int32_t count, ssize_t err) "tag %d id %d count %d err %zd"
+v9fs_readdir(uint16_t tag, uint8_t id, int32_t fid, int64_t offset, int32_t max_count) "tag %d id %d fid %d offset %"PRId64" max_count %d"
+v9fs_readdir_return(uint16_t tag, uint8_t id, int32_t count, ssize_t retval) "tag %d id %d count %d retval %zd"
+v9fs_write(uint16_t tag, uint8_t id, int32_t fid, int64_t off, int32_t count, int cnt) "tag %d id %d fid %d off %"PRId64" count %d cnt %d"
+v9fs_write_return(uint16_t tag, uint8_t id, int32_t total, ssize_t err) "tag %d id %d total %d err %zd"
+v9fs_create(uint16_t tag, uint8_t id, int32_t fid, char* name, int32_t perm, int8_t mode) "tag %d id %d fid %d name %s perm %d mode %d"
+v9fs_create_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path, int iounit) "tag %d id %d qid={type %d version %d path %"PRId64"} iounit %d"
+v9fs_symlink(uint16_t tag, uint8_t id, int32_t fid,  char* name, char* symname, uint32_t gid) "tag %d id %d fid %d name %s symname %s gid %u"
+v9fs_symlink_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path) "tag %d id %d qid={type %d version %d path %"PRId64"}"
+v9fs_flush(uint16_t tag, uint8_t id, int16_t flush_tag) "tag %d id %d flush_tag %d"
+v9fs_link(uint16_t tag, uint8_t id, int32_t dfid, int32_t oldfid, char* name) "tag %d id %d dfid %d oldfid %d name %s"
+v9fs_remove(uint16_t tag, uint8_t id, int32_t fid) "tag %d id %d fid %d"
+v9fs_wstat(uint16_t tag, uint8_t id, int32_t fid, int32_t mode, int32_t atime, int32_t mtime) "tag %u id %u fid %d stat={mode %d atime %d mtime %d}"
+v9fs_mknod(uint16_t tag, uint8_t id, int32_t fid, int mode, int major, int minor) "tag %d id %d fid %d mode %d major %d minor %d"
+v9fs_mknod_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path) "tag %d id %d qid={type %d version %d path %"PRId64"}"
+v9fs_lock(uint16_t tag, uint8_t id, int32_t fid, uint8_t type, uint64_t start, uint64_t length) "tag %d id %d fid %d type %d start %"PRIu64" length %"PRIu64""
+v9fs_lock_return(uint16_t tag, uint8_t id, int8_t status) "tag %d id %d status %d"
+v9fs_getlock(uint16_t tag, uint8_t id, int32_t fid, uint8_t type, uint64_t start, uint64_t length)"tag %d id %d fid %d type %d start %"PRIu64" length %"PRIu64""
+v9fs_getlock_return(uint16_t tag, uint8_t id, uint8_t type, uint64_t start, uint64_t length, uint32_t proc_id) "tag %d id %d type %d start %"PRIu64" length %"PRIu64" proc_id %u"
+v9fs_mkdir(uint16_t tag, uint8_t id, int32_t fid, char* name, int mode, uint32_t gid) "tag %u id %u fid %d name %s mode %d gid %u"
+v9fs_mkdir_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path, int err) "tag %u id %u qid={type %d version %d path %"PRId64"} err %d"
+v9fs_xattrwalk(uint16_t tag, uint8_t id, int32_t fid, int32_t newfid, char* name) "tag %d id %d fid %d newfid %d name %s"
+v9fs_xattrwalk_return(uint16_t tag, uint8_t id, int64_t size) "tag %d id %d size %"PRId64""
+v9fs_xattrcreate(uint16_t tag, uint8_t id, int32_t fid, char* name, int64_t size, int flags) "tag %d id %d fid %d name %s size %"PRId64" flags %d"
+v9fs_readlink(uint16_t tag, uint8_t id, int32_t fid) "tag %d id %d fid %d"
+v9fs_readlink_return(uint16_t tag, uint8_t id, char* target) "tag %d id %d name %s"
+
+# target-sparc/mmu_helper.c
+mmu_helper_dfault(uint64_t address, uint64_t context, int mmu_idx, uint32_t tl) "DFAULT at %"PRIx64" context %"PRIx64" mmu_idx=%d tl=%d"
+mmu_helper_dprot(uint64_t address, uint64_t context, int mmu_idx, uint32_t tl) "DPROT at %"PRIx64" context %"PRIx64" mmu_idx=%d tl=%d"
+mmu_helper_dmiss(uint64_t address, uint64_t context) "DMISS at %"PRIx64" context %"PRIx64""
+mmu_helper_tfault(uint64_t address, uint64_t context) "TFAULT at %"PRIx64" context %"PRIx64""
+mmu_helper_tmiss(uint64_t address, uint64_t context) "TMISS at %"PRIx64" context %"PRIx64""
+mmu_helper_get_phys_addr_code(uint32_t tl, int mmu_idx, uint64_t prim_context, uint64_t sec_context, uint64_t address) "tl=%d mmu_idx=%d primary context=%"PRIx64" secondary context=%"PRIx64" address=%"PRIx64""
+mmu_helper_get_phys_addr_data(uint32_t tl, int mmu_idx, uint64_t prim_context, uint64_t sec_context, uint64_t address) "tl=%d mmu_idx=%d primary context=%"PRIx64" secondary context=%"PRIx64" address=%"PRIx64""
+mmu_helper_mmu_fault(uint64_t address, uint64_t paddr, int mmu_idx, uint32_t tl, uint64_t prim_context, uint64_t sec_context) "Translate at %"PRIx64" -> %"PRIx64", mmu_idx=%d tl=%d primary context=%"PRIx64" secondary context=%"PRIx64""
+
+# target-sparc/int_helper.c
+int_helper_set_softint(uint32_t softint) "new %08x"
+int_helper_clear_softint(uint32_t softint) "new %08x"
+int_helper_write_softint(uint32_t softint) "new %08x"
+int_helper_icache_freeze(void) "Instruction cache: freeze"
+int_helper_dcache_freeze(void) "Data cache: freeze"
+
+# target-sparc/win_helper.c
+win_helper_gregset_error(uint32_t pstate) "ERROR in get_gregset: active pstate bits=%x"
+win_helper_switch_pstate(uint32_t pstate_regs, uint32_t new_pstate_regs) "change_pstate: switching regs old=%x new=%x"
+win_helper_no_switch_pstate(uint32_t new_pstate_regs) "change_pstate: regs new=%x (unchanged)"
+win_helper_wrpil(uint32_t psrpil, uint32_t new_pil) "old=%x new=%x"
+win_helper_done(uint32_t tl) "tl=%d"
+win_helper_retry(uint32_t tl) "tl=%d"
diff --git a/ui/spice-core.c b/ui/spice-core.c
index 3cbc721..b33366e 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -447,9 +447,9 @@
 
 static void migration_state_notifier(Notifier *notifier, void *data)
 {
-    int state = get_migration_state();
+    MigrationState *s = data;
 
-    if (state == MIG_STATE_COMPLETED) {
+    if (migration_has_finished(s)) {
 #if SPICE_SERVER_VERSION >= 0x000701 /* 0.7.1 */
         spice_server_migrate_switch(spice_server);
 #endif
diff --git a/vl.c b/vl.c
index 2dce3ae..1ddb17b 100644
--- a/vl.c
+++ b/vl.c
@@ -148,6 +148,7 @@
 #include "qemu-objects.h"
 #include "qemu-options.h"
 #include "qmp-commands.h"
+#include "main-loop.h"
 #ifdef CONFIG_VIRTFS
 #include "fsdev/qemu-fsdev.h"
 #endif
@@ -337,16 +338,20 @@
     { RUN_STATE_INMIGRATE, RUN_STATE_PRELAUNCH },
 
     { RUN_STATE_INTERNAL_ERROR, RUN_STATE_PAUSED },
+    { RUN_STATE_INTERNAL_ERROR, RUN_STATE_FINISH_MIGRATE },
 
     { RUN_STATE_IO_ERROR, RUN_STATE_RUNNING },
+    { RUN_STATE_IO_ERROR, RUN_STATE_FINISH_MIGRATE },
 
     { RUN_STATE_PAUSED, RUN_STATE_RUNNING },
+    { RUN_STATE_PAUSED, RUN_STATE_FINISH_MIGRATE },
 
     { RUN_STATE_POSTMIGRATE, RUN_STATE_RUNNING },
+    { RUN_STATE_POSTMIGRATE, RUN_STATE_FINISH_MIGRATE },
 
     { RUN_STATE_PRELAUNCH, RUN_STATE_RUNNING },
+    { RUN_STATE_PRELAUNCH, RUN_STATE_FINISH_MIGRATE },
     { RUN_STATE_PRELAUNCH, RUN_STATE_INMIGRATE },
-    { RUN_STATE_PRELAUNCH, RUN_STATE_POSTMIGRATE },
 
     { RUN_STATE_FINISH_MIGRATE, RUN_STATE_RUNNING },
     { RUN_STATE_FINISH_MIGRATE, RUN_STATE_POSTMIGRATE },
@@ -366,8 +371,10 @@
     { RUN_STATE_SAVE_VM, RUN_STATE_RUNNING },
 
     { RUN_STATE_SHUTDOWN, RUN_STATE_PAUSED },
+    { RUN_STATE_SHUTDOWN, RUN_STATE_FINISH_MIGRATE },
 
     { RUN_STATE_WATCHDOG, RUN_STATE_RUNNING },
+    { RUN_STATE_WATCHDOG, RUN_STATE_FINISH_MIGRATE },
 
     { RUN_STATE_MAX, RUN_STATE_MAX },
 };
@@ -393,9 +400,12 @@
 /* This function will abort() on invalid state transitions */
 void runstate_set(RunState new_state)
 {
-    if (new_state >= RUN_STATE_MAX ||
-        !runstate_valid_transitions[current_run_state][new_state]) {
-        fprintf(stderr, "invalid runstate transition\n");
+    assert(new_state < RUN_STATE_MAX);
+
+    if (!runstate_valid_transitions[current_run_state][new_state]) {
+        fprintf(stderr, "ERROR: invalid runstate transition: '%s' -> '%s'\n",
+                RunState_lookup[current_run_state],
+                RunState_lookup[new_state]);
         abort();
     }
 
@@ -1416,142 +1426,51 @@
     qemu_notify_event();
 }
 
-static GPollFD poll_fds[1024 * 2]; /* this is probably overkill */
-static int n_poll_fds;
-static int max_priority;
-
-static void glib_select_fill(int *max_fd, fd_set *rfds, fd_set *wfds,
-                             fd_set *xfds, struct timeval *tv)
-{
-    GMainContext *context = g_main_context_default();
-    int i;
-    int timeout = 0, cur_timeout;
-
-    g_main_context_prepare(context, &max_priority);
-
-    n_poll_fds = g_main_context_query(context, max_priority, &timeout,
-                                      poll_fds, ARRAY_SIZE(poll_fds));
-    g_assert(n_poll_fds <= ARRAY_SIZE(poll_fds));
-
-    for (i = 0; i < n_poll_fds; i++) {
-        GPollFD *p = &poll_fds[i];
-
-        if ((p->events & G_IO_IN)) {
-            FD_SET(p->fd, rfds);
-            *max_fd = MAX(*max_fd, p->fd);
-        }
-        if ((p->events & G_IO_OUT)) {
-            FD_SET(p->fd, wfds);
-            *max_fd = MAX(*max_fd, p->fd);
-        }
-        if ((p->events & G_IO_ERR)) {
-            FD_SET(p->fd, xfds);
-            *max_fd = MAX(*max_fd, p->fd);
-        }
-    }
-
-    cur_timeout = (tv->tv_sec * 1000) + ((tv->tv_usec + 500) / 1000);
-    if (timeout >= 0 && timeout < cur_timeout) {
-        tv->tv_sec = timeout / 1000;
-        tv->tv_usec = (timeout % 1000) * 1000;
-    }
-}
-
-static void glib_select_poll(fd_set *rfds, fd_set *wfds, fd_set *xfds,
-                             bool err)
-{
-    GMainContext *context = g_main_context_default();
-
-    if (!err) {
-        int i;
-
-        for (i = 0; i < n_poll_fds; i++) {
-            GPollFD *p = &poll_fds[i];
-
-            if ((p->events & G_IO_IN) && FD_ISSET(p->fd, rfds)) {
-                p->revents |= G_IO_IN;
-            }
-            if ((p->events & G_IO_OUT) && FD_ISSET(p->fd, wfds)) {
-                p->revents |= G_IO_OUT;
-            }
-            if ((p->events & G_IO_ERR) && FD_ISSET(p->fd, xfds)) {
-                p->revents |= G_IO_ERR;
-            }
-        }
-    }
-
-    if (g_main_context_check(context, max_priority, poll_fds, n_poll_fds)) {
-        g_main_context_dispatch(context);
-    }
-}
-
-int main_loop_wait(int nonblocking)
-{
-    fd_set rfds, wfds, xfds;
-    int ret, nfds;
-    struct timeval tv;
-    int timeout;
-
-    if (nonblocking)
-        timeout = 0;
-    else {
-        timeout = qemu_calculate_timeout();
-        qemu_bh_update_timeout(&timeout);
-    }
-
-    os_host_main_loop_wait(&timeout);
-
-    tv.tv_sec = timeout / 1000;
-    tv.tv_usec = (timeout % 1000) * 1000;
-
-    /* poll any events */
-    /* XXX: separate device handlers from system ones */
-    nfds = -1;
-    FD_ZERO(&rfds);
-    FD_ZERO(&wfds);
-    FD_ZERO(&xfds);
-
-    qemu_iohandler_fill(&nfds, &rfds, &wfds, &xfds);
-    slirp_select_fill(&nfds, &rfds, &wfds, &xfds);
-    glib_select_fill(&nfds, &rfds, &wfds, &xfds, &tv);
-
-    if (timeout > 0) {
-        qemu_mutex_unlock_iothread();
-    }
-
-    ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv);
-
-    if (timeout > 0) {
-        qemu_mutex_lock_iothread();
-    }
-
-    qemu_iohandler_poll(&rfds, &wfds, &xfds, ret);
-    slirp_select_poll(&rfds, &wfds, &xfds, (ret < 0));
-    glib_select_poll(&rfds, &wfds, &xfds, (ret < 0));
-
-    qemu_run_all_timers();
-
-    /* Check bottom-halves last in case any of the earlier events triggered
-       them.  */
-    qemu_bh_poll();
-
-    return ret;
-}
-
 qemu_irq qemu_system_powerdown;
 
+static bool main_loop_should_exit(void)
+{
+    RunState r;
+    if (qemu_debug_requested()) {
+        vm_stop(RUN_STATE_DEBUG);
+    }
+    if (qemu_shutdown_requested()) {
+        qemu_kill_report();
+        monitor_protocol_event(QEVENT_SHUTDOWN, NULL);
+        if (no_shutdown) {
+            vm_stop(RUN_STATE_SHUTDOWN);
+        } else {
+            return true;
+        }
+    }
+    if (qemu_reset_requested()) {
+        pause_all_vcpus();
+        cpu_synchronize_all_states();
+        qemu_system_reset(VMRESET_REPORT);
+        resume_all_vcpus();
+        if (runstate_check(RUN_STATE_INTERNAL_ERROR) ||
+            runstate_check(RUN_STATE_SHUTDOWN)) {
+            runstate_set(RUN_STATE_PAUSED);
+        }
+    }
+    if (qemu_powerdown_requested()) {
+        monitor_protocol_event(QEVENT_POWERDOWN, NULL);
+        qemu_irq_raise(qemu_system_powerdown);
+    }
+    if (qemu_vmstop_requested(&r)) {
+        vm_stop(r);
+    }
+    return false;
+}
+
 static void main_loop(void)
 {
     bool nonblocking;
-    int last_io __attribute__ ((unused)) = 0;
+    int last_io = 0;
 #ifdef CONFIG_PROFILER
     int64_t ti;
 #endif
-    RunState r;
-
-    qemu_main_loop_start();
-
-    for (;;) {
+    do {
         nonblocking = !kvm_enabled() && last_io > 0;
 #ifdef CONFIG_PROFILER
         ti = profile_getclock();
@@ -1560,38 +1479,7 @@
 #ifdef CONFIG_PROFILER
         dev_time += profile_getclock() - ti;
 #endif
-
-        if (qemu_debug_requested()) {
-            vm_stop(RUN_STATE_DEBUG);
-        }
-        if (qemu_shutdown_requested()) {
-            qemu_kill_report();
-            monitor_protocol_event(QEVENT_SHUTDOWN, NULL);
-            if (no_shutdown) {
-                vm_stop(RUN_STATE_SHUTDOWN);
-            } else
-                break;
-        }
-        if (qemu_reset_requested()) {
-            pause_all_vcpus();
-            cpu_synchronize_all_states();
-            qemu_system_reset(VMRESET_REPORT);
-            resume_all_vcpus();
-            if (runstate_check(RUN_STATE_INTERNAL_ERROR) ||
-                runstate_check(RUN_STATE_SHUTDOWN)) {
-                runstate_set(RUN_STATE_PAUSED);
-            }
-        }
-        if (qemu_powerdown_requested()) {
-            monitor_protocol_event(QEVENT_POWERDOWN, NULL);
-            qemu_irq_raise(qemu_system_powerdown);
-        }
-        if (qemu_vmstop_requested(&r)) {
-            vm_stop(r);
-        }
-    }
-    bdrv_close_all();
-    pause_all_vcpus();
+    } while (!main_loop_should_exit());
 }
 
 static void version(void)
@@ -2302,6 +2190,7 @@
     runstate_init();
 
     init_clocks();
+    rtc_clock = host_clock;
 
     qemu_cache_utils_init(envp);
 
@@ -2774,6 +2663,7 @@
             case QEMU_OPTION_virtfs: {
                 QemuOpts *fsdev;
                 QemuOpts *device;
+                const char *writeout;
 
                 olist = qemu_find_opts("virtfs");
                 if (!olist) {
@@ -2786,16 +2676,14 @@
                     exit(1);
                 }
 
-                if (qemu_opt_get(opts, "fstype") == NULL ||
+                if (qemu_opt_get(opts, "fsdriver") == NULL ||
                         qemu_opt_get(opts, "mount_tag") == NULL ||
-                        qemu_opt_get(opts, "path") == NULL ||
-                        qemu_opt_get(opts, "security_model") == NULL) {
-                    fprintf(stderr, "Usage: -virtfs fstype,path=/share_path/,"
-                            "security_model=[mapped|passthrough|none],"
+                        qemu_opt_get(opts, "path") == NULL) {
+                    fprintf(stderr, "Usage: -virtfs fsdriver,path=/share_path/,"
+                            "[security_model={mapped|passthrough|none}],"
                             "mount_tag=tag.\n");
                     exit(1);
                 }
-
                 fsdev = qemu_opts_create(qemu_find_opts("fsdev"),
                                          qemu_opt_get(opts, "mount_tag"), 1);
                 if (!fsdev) {
@@ -2803,7 +2691,18 @@
                             qemu_opt_get(opts, "mount_tag"));
                     exit(1);
                 }
-                qemu_opt_set(fsdev, "fstype", qemu_opt_get(opts, "fstype"));
+
+                writeout = qemu_opt_get(opts, "writeout");
+                if (writeout) {
+#ifdef CONFIG_SYNC_FILE_RANGE
+                    qemu_opt_set(fsdev, "writeout", writeout);
+#else
+                    fprintf(stderr, "writeout=immediate not supported on "
+                            "this platform\n");
+                    exit(1);
+#endif
+                }
+                qemu_opt_set(fsdev, "fsdriver", qemu_opt_get(opts, "fsdriver"));
                 qemu_opt_set(fsdev, "path", qemu_opt_get(opts, "path"));
                 qemu_opt_set(fsdev, "security_model",
                              qemu_opt_get(opts, "security_model"));
@@ -3279,6 +3178,7 @@
 
     configure_accelerator();
 
+    qemu_init_cpu_loop();
     if (qemu_init_main_loop()) {
         fprintf(stderr, "qemu_init_main_loop failed\n");
         exit(1);
@@ -3545,8 +3445,10 @@
 
     os_setup_post();
 
+    resume_all_vcpus();
     main_loop();
-    quit_timers();
+    bdrv_close_all();
+    pause_all_vcpus();
     net_cleanup();
     res_free();